[RESOLVIDO] Stored Procedures (Functions) do postgres no TopLink

4 respostas
H

Bem pessoal, primeiramente boa noite;

Sou bem novo no Java, mas estou aprendendo rápido, e sempre existe a primeira vez de postar uma dúvida no fórum não é mesmo!? Então acredito estar no lugar correto.
Bem, estou desenvolvendo uma aplicação que vai interagir muito com o banco, e estamos utilizando o PostgreSQL. Criei uma stored procedure (function) no banco que faz a leitura de uma tabela de produtos e lança em uma tabela de movimento determinados movimentos de acordo com alguns critérios que criei na própria function.

O problema pareceu simples de início, mas depois de três dias de intensas tentativas cheguei a conclusão que não consigo efetuar essa tarefa. Pesquisei documentação do TopLink, algumas classes como StoredFunctionCall, Query e seu método createNativeQuery, dentre outras do TopLink, mas todas sem sucesso. A maioria das tentativas me diziam que a minha instrução estava errada.

Gostaria de saber dos senhores se existe uma forma padrão para chamar stored procedures no JAVA, que estão especificamente no PostgreSQL, no formato de linguagem PL/PgSQL. Abaixo vai minha última tentativa frustrada, e o seu respectivo erro.

Desde já agradeço a atenção de todos!

package br.com.projeto2.bean;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Types;
import javax.swing.JOptionPane;

public class CallProcedure {

    public void storedProcedure() {
        try {
            String url = "jdbc:postgresql://Localhost:5432/banco_tcc";
            String usr = "postgres";
            String pas = "******";

            Class.forName("org.postgresql.Driver");
            Connection MinhaConexao = DriverManager.getConnection(url, usr, pas);

            MinhaConexao.setAutoCommit(false);

            CallableStatement proc = MinhaConexao.prepareCall("{? = popula_tb_movimento_estoque()}");
            
            proc.registerOutParameter(1, Types.INTEGER);

            proc.execute();
            proc.close();


        } catch (ClassNotFoundException ex) {
            System.out.println("Driver JDBC- nao encontrado");
        } catch (SQLException ex) {
            JOptionPane.showMessageDialog(null, "Nao houve Inclusao. Erro: " + ex.getMessage() + "", "Inclusão sem sucesso.", JOptionPane.ERROR_MESSAGE);
            ex.printStackTrace();
        }
    }
}

[color=red]Erro Gerado:[/color]

[EL Info]: 2012-08-24 20:23:03.687--ServerSession(7079781)--EclipseLink, version: Eclipse Persistence Services - 2.3.2.v20111125-r10461
[EL Info]: 2012-08-24 20:23:04.15--ServerSession(7079781)--file:/C:/Users/Holyspear/Documents/NetBeansProjects/projeto_TCC2/build/classes/_banco_tccPU login successful
org.postgresql.util.PSQLException: Malformed function or procedure escape syntax at offset 5.

4 Respostas

A

De acordo com esta documentação
http://jdbc.postgresql.org/documentation/80/callproc.html

sua chamada à procedure deveria ser alterada para

CallableStatement proc = MinhaConexao.prepareCall("{? = call popula_tb_movimento_estoque()}");
H

Obrigado pela resposta Ademilton… já é um começo! Pelo menos não deu erro, porém… não executou nada no banco. Bem, eu alterei o código para o que segue:

String url = "jdbc:postgresql://Localhost:5432/banco_tcc";
            String usr = "postgres";
            String pas = "abencoado";

            Class.forName("org.postgresql.Driver");
            Connection MinhaConexao = DriverManager.getConnection(url, usr, pas);

            MinhaConexao.setAutoCommit(false);
            
            CallableStatement proc = MinhaConexao.prepareCall("{ ? = call popula_tb_movimento_estoque() }");
            proc.registerOutParameter(1, Types.INTEGER);
            proc.execute();
            Integer results = (Integer) proc.getInt(1);
            proc.close();

O novo código não produziu o efeito esperado no Postgree. Na verdade não executou nada, nenhum efeito no banco, nenhum retorno. Para testes, eu construi a seguinte função:

CREATE OR REPLACE FUNCTION popula_tb_movimento_estoque()
  RETURNS integer AS
$BODY$
    DECLARE
        id_estoque      integer;
        id_produto      integer;
        tp_movimento    numeric(15,2);
        dt_movimento    numeric(12);
        qtd_movimentada numeric(15,2);
        produtos_view	record;
    
    BEGIN     
        
        FOR produtos_view IN SELECT p.id_produto FROM tb_produtos p
	LOOP
            
            INSERT INTO tb_movimento_estoque(tp_movimento, dt_movimento, qtd_movimentada, id_produto)
            VALUES ('E', '2012/08/01', 10, produtos_view.id_produto);
            
        END LOOP;
	
	RETURN 1;

    END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
ALTER FUNCTION popula_tb_movimento_estoque()
  OWNER TO postgres;

Quem puder ajudar galera, eu agradeço desde já!
Abraços! :wink:

A

Não estaria faltando um commit dentro da sua procedure ?

H

Desculpem galera, mas já resolvi o problema!!!

Fica aqui para quem tiver problemas, pois foi bem complicado encontrar (talvez para outros iniciantes como eu seja de grande valia).

O que ocorreu é que eu configurei a seguinte linha:

MinhaConexao.setAutoCommit(false);

Sendo que a minha conexão não “finalizava”, então eu setei para TRUE e a alteração no banco ocorreu!!!
Ao tentar incluir um commit na procedure, o Postgree não aceitou a cláusula e aconselhou outros métodos. Eu achei melhor controlar o commit pelo java mesmo, uma vez que abri uma conexão específica para essa ação.

Muito obrigado mesmo Ademilton, me ajudou bastante. Abraços amigo!

Criado 24 de agosto de 2012
Ultima resposta 24 de ago. de 2012
Respostas 4
Participantes 2