Problema com update campo image no Postgrees

16 respostas
luisbizzan

Pessoal estou com um problema aqui que não consigo resolver nem fodendo !!! Quando eu executo esse script em um banco de dados SQL Server funciona normal, agora quando estou executando no Postgrees não vai de maneira alguma, não da erro e não faz update, alguem tem alguma ideia ?

int id = 35;
boolean retorno = false;
String resDirectory = gb.getPropertyAplication("Path")+gb.getPropertyAplication("ResDirectory");
String nameRel = "";

StringBuffer sql = new StringBuffer("SELECT titulo, xml FROM "+gb.getPropertyAplication("RelatoriosJava")+" WHERE idrelatorio = ");
sql.append(Query.toSQL(id, Query.Number_TYPE));

ResultSet rs = Query.getResultSet(sql.toString(), gb.st);
if (rs == null) throw new Exception("Relatório não existe");

if (rs.next()){
    try{
        nameRel = rs.getString("titulo");
        net.sf.jasperreports.engine.design.JasperDesign jasperDesign = net.sf.jasperreports.engine.xml.JRXmlLoader.load(new java.io.ByteArrayInputStream((rs.getString("xml")).getBytes("UTF-8")));
        jasperDesign.addImport("com.sil.util.*");

        net.sf.jasperreports.engine.JasperCompileManager.compileReportToFile(jasperDesign, resDirectory+"/"+nameRel+".jasper");
        InputStream isLayout = new FileInputStream(resDirectory+"/"+nameRel+".jasper");

        PreparedStatement pStUpdate = gb.st.getConnection().prepareStatement("UPDATE "+gb.getPropertyAplication("RelatoriosJava")+" set layout = ? WHERE idrelatorio = ?");
        pStUpdate.setBinaryStream(1, isLayout, isLayout.available());
        pStUpdate.setInt(2, id);
        pStUpdate.execute();

        isLayout.close();
        File f = new File(resDirectory+"/"+nameRel+".jasper");
        f.delete();

        if (pStUpdate != null) pStUpdate.close();
        if (rs != null) rs.close();

        retorno = true;
    }catch(Exception e){ retorno = false; }
}

Ele cria o arquivo Jasper normalmente, mas na hora de fazer o update não vai !!!

16 Respostas

E

qual o erro e qual o tipo de dados que está usando no postgres?

luisbizzan

Então evefuji, o incrivel que não da erro, a coluna ao qual eu quero gravar é do tipo bytea, estou tentando salvar o .jasper gerado pelo JasperReports dentro de uma coluna da tabela, no SQL Server essa coluna é do tipo “image”, e a gravação ocorre normalmente, ja no postgres que é a bytea não apresenta erro porem tb não salva, estou desconfiado que seja o tamanho do arquivo, mas meu arquivo tem apenas 20KB, estranho né? Será q tem como eu verificar a sintaxe SQL que ele esta tentando rodar no banco ?

Abraço

E

acho que o problema está no:

isLayout.available()

Se me lembro bem deveria ser o lenght() do arquivo.

luisbizzan

Bom ja fiz esse teste mais irei realizar novamente para verificar se ouve correção e ja lhe respondo ok?

Abraço

luisbizzan

Bom cara realizei o teste como eu havia lhe falado e nada olha como ficou a implementação:

int id = 35;
boolean retorno = false;
String resDirectory = gb.getPropertyAplication("Path")+gb.getPropertyAplication("ResDirectory");
String nameRel = "";

StringBuffer sql = new StringBuffer("SELECT titulo, xml FROM "+gb.getPropertyAplication("RelatoriosJava")+" WHERE idrelatorio = ");
sql.append(Query.toSQL(id, Query.Number_TYPE));

ResultSet rs = Query.getResultSet(sql.toString(), gb.st);
if (rs == null) throw new Exception("Relatório não existe");

if (rs.next()){
    try{
        nameRel = rs.getString("titulo");
        net.sf.jasperreports.engine.design.JasperDesign jasperDesign = net.sf.jasperreports.engine.xml.JRXmlLoader.load(new java.io.ByteArrayInputStream((rs.getString("xml")).getBytes("UTF-8")));
        jasperDesign.addImport("com.sil.util.*");

        net.sf.jasperreports.engine.JasperCompileManager.compileReportToFile(jasperDesign, resDirectory+"/"+nameRel+".jasper");
        File f = new File(resDirectory+"/"+nameRel+".jasper");
        InputStream isLayout = new FileInputStream(f);
        //InputStream isLayout = new FileInputStream(resDirectory+"/"+nameRel+".jasper");

        PreparedStatement pStUpdate = gb.st.getConnection().prepareStatement("UPDATE "+gb.getPropertyAplication("RelatoriosJava")+" set layout = ? WHERE idrelatorio = ?");
        pStUpdate.setBinaryStream(1, isLayout, (int)f.length());
        pStUpdate.setInt(2, id);
        pStUpdate.executeUpdate();

        isLayout.close();
        
        //f.delete();

        if (pStUpdate != null) pStUpdate.close();
        if (rs != null) rs.close();

        retorno = true;
    }catch(Exception e){
    	if(true) throw new Exception(e.toString());
    	retorno = false;
    }
}

Estou achando que pode ser meu drive de conexao viu, pois eu inclui a informação na coluna da tabela via banco mesmo, e na leitura esta dando uma mensagem “2”, e no stacktrace esta apresentando um metodo do JDBC. Mas é uma ideia só, vc tem mais alguma ai ?

Abraço

E

vc pode fazer um System.out.println(pStUpdate.toString()) para ver o SQL que ele gera. (mas nunca monitorei isso com BinaryStream, acredito que vá colocar uma String Hexadecimal)

Isso não deve ter nada a ver, mas eu costumo utilizar o executeUpdate() no lugar do execute(). (se me lembro bem, a única diferença é que retorna o número de linhas, mas já vi alguns drivers/sgbd não funcionarem bem com o execute para fazer update/insert, por não dar commit)

E

Aqui tem um exemplo usando Large Object, http://jdbc.postgresql.org/documentation/84/binary-data.html

O exemplo usando BinaryStream me parece estar semelhante.

luisbizzan

Cara fiz como vc tinha me falado, coloquei o commit mudei para pStUpdate.executeUpdate(); e nada, o ingraçado que rodo isso no postgres e ele faz o update, agora buscanco pelo driver nao vai !!! ele até me apresenta a excessão da sintaxe

UPDATE RelatoriosJava set layout = <stream of 20436 bytes> WHERE idrelatorio = 35

Mas mesmo assim não vai, estou pensando em trocar o tipo de dados para varchar de 8000 e ver como ele faz,

tem alguma outra ideia ?

Abraço

E

mas o executeUpdate retornou quanto?

luisbizzan

retornou 1 ainda, mas a coluna nada de atualizar !!! ta muito estranho isso !!!

E

a conexão está com autocommit? Se você tenta recuperar nessa mesma conexão o objeto através de uma consulta ele retorna certo?

luisbizzan

Eu inseri um autocommit(false), e depois commit abaixo do executeUpdate, e busquei o resultado apos isso !

int id = 35;
boolean retorno = false;
String resDirectory = gb.getPropertyAplication("Path")+gb.getPropertyAplication("ResDirectory");
String nameRel = "";

StringBuffer sql = new StringBuffer("SELECT titulo, xml FROM "+gb.getPropertyAplication("RelatoriosJava")+" WHERE idrelatorio = ");
sql.append(Query.toSQL(id, Query.Number_TYPE));

ResultSet rs = Query.getResultSet(sql.toString(), gb.st);
if (rs == null) throw new Exception("Relatório não existe");

if (rs.next()){

    Connection cn = gb.getCn();
    cn.setAutoCommit(false);
    
    try{     

        nameRel = rs.getString("titulo");
        net.sf.jasperreports.engine.design.JasperDesign jasperDesign = net.sf.jasperreports.engine.xml.JRXmlLoader.load(new java.io.ByteArrayInputStream((rs.getString("xml")).getBytes("UTF-8")));
        jasperDesign.addImport("com.sil.util.*");

        net.sf.jasperreports.engine.JasperCompileManager.compileReportToFile(jasperDesign, resDirectory+"/"+nameRel+".jasper");
        File f = new File(resDirectory+"/"+nameRel+".jasper");
        InputStream isLayout = new FileInputStream(f);
        //InputStream isLayout = new FileInputStream(resDirectory+"/"+nameRel+".jasper");

        PreparedStatement pStUpdate = gb.st.getConnection().prepareStatement("UPDATE "+gb.getPropertyAplication("RelatoriosJava")+" set layout = ? WHERE idrelatorio = ?");
        pStUpdate.setBinaryStream(1, isLayout, (int)f.length());
        pStUpdate.setInt(2, id);
        int i = pStUpdate.executeUpdate();

        isLayout.close();
        
        //f.delete();

        //if (pStUpdate != null) pStUpdate.close();
        if (rs != null) rs.close();

        retorno = true;

	cn.commit();
    	if(true) throw new Exception(i+"..."+pStUpdate.toString());
    }catch(Exception e){
    	cn.rollback();
    	retorno = false;
    	if(true) throw new Exception(e.toString());

    }finally{
    	cn.setAutoCommit(true);
    }                
}

Vc fala pra fazer um select dentro dela mesmo para ver oque ele retorna ?

luisbizzan

Cara estou achando que o campo bytea do postgres, pois fiz o teste no dql server e funciona normalmente… tem alguma ideia de que datatype poço testar para mudar esse bytea ?

E

olhei na doc do postgre, tem também o OID, que você pode usar o código para LargeObjects que tem naquele link que te mandei lá em cima.

http://www.postgresql.org/docs/8.0/static/datatype-oid.html

Uma pergunta, porque isso?

if(true) throw new Exception(i+"..."+pStUpdate.toString());

Com isso ele sempre vai para o catch não?

E acho que não precisa dessa linha mais né?

if (rs != null) rs.close();

Faz um teste, atualiza junto nessa consulta um outro campo da tabela (inclui um só para fazer o teste, por exemplo, e adiciona a data), e vê se esse campo atualiza. Olha também nos logs do banco.

luisbizzan

é eu gero essa ecessão pois estou executando o script no BeanShell, mas eu criei uma classe tb para fazer um teste e esta ocorrendo o mesmo problema, e ainda pior o arquivo .jasper que eu faço o update no banco de dados tem 20kb, depois eu faço um select para buscar ele novamente e gero outro arquivo .jasper, ele esta me gerando com 40kb. Basicamente dúplicando.
Olha o código:

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package testebytea;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import net.sf.jasperreports.engine.JRException;

/**
 *
 * @author LGBIZZAN
 */
public class Main {

    /**
     * @param args the command line arguments
     */
    public static Connection conexao;
    public static String driver = "org.postgresql.Driver";
    public static String servidor = "192.168.5.14:5432";
    public static String base = "motorddw";
    public static String login = "smar";
    public static String senha = "@#smarapd#@";
    public static String url = "jdbc:postgresql://"+servidor+"/"+base;

    public static void main(String[] args) throws SQLException, JRException, UnsupportedEncodingException, FileNotFoundException, IOException {
        int id = 36;
        String nameRel = "";
        String resDirectory = "C:Temp/Teste";
        try {
            Class.forName(driver);
            conexao = DriverManager.getConnection(url,login,senha);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException s) {
            s.printStackTrace();
        }
        StringBuffer sql = new StringBuffer("SELECT titulo, xml FROM RelatoriosJava WHERE idrelatorio = "+id);
        PreparedStatement pSt = conexao.prepareStatement(sql.toString());
        ResultSet rs = pSt.executeQuery();
        if(rs != null){
            rs.next();
            nameRel = rs.getString("titulo");
            net.sf.jasperreports.engine.design.JasperDesign jasperDesign = net.sf.jasperreports.engine.xml.JRXmlLoader.load(new java.io.ByteArrayInputStream((rs.getString("xml")).getBytes("UTF-8")));
            jasperDesign.addImport("com.sil.util.*");

            net.sf.jasperreports.engine.JasperCompileManager.compileReportToFile(jasperDesign, resDirectory+"/"+nameRel+".jasper");
            File f = new File(resDirectory+"/"+nameRel+".jasper");
            InputStream isLayout = new FileInputStream(f);
            System.out.print(isLayout.available()+"\r\n"+isLayout.toString()+"\r\n");
            
            pSt = conexao.prepareStatement("UPDATE RelatoriosJava set layout = ? WHERE idrelatorio = ?");
            pSt.setBinaryStream(1, isLayout, (int)f.length());
            pSt.setInt(2, id);
            int i = pSt.executeUpdate();

            isLayout.close();
            System.out.print(i+"..."+pSt.toString()+"\r\n");

            StringBuffer sql2 = new StringBuffer("SELECT titulo, layout FROM RelatoriosJava WHERE idrelatorio = "+id);
            pSt = conexao.prepareStatement(sql2.toString());
            ResultSet rs2 = pSt.executeQuery();
            if(rs2 != null){
                rs2.next();
                InputStream ipsLayout = rs2.getBinaryStream("layout");
                byte[] by = rs2.getBytes("layout");
                System.out.print(ipsLayout.available()+"\r\n"+by.length);
                FileOutputStream FOS = new FileOutputStream( new File(resDirectory+"/"+nameRel+"2.jasper") );
                int count;
                int BUFFER = 2048;
                byte[] dados = new byte[BUFFER];

                // Efetua a leitura real e a gravação no outro arquivo
                while ((count = ipsLayout.read(dados, 0, BUFFER)) != -1) {
                    FOS.write(by, 0, count);
                }
            }

        }
    }

}

Agora esse novo datatype vou dar uma olhada nele e ja ti falo !!!

luisbizzan

Achei a razão do problema no PostgreSQL 9, o byte é representado como um hexadecimal (ou seja, 16 bits), enquanto q nas versões anteriores eram 8 bits só q ao ler, o Java lê bytes de 8 bits, então ele precisa de 2 bytes pra ler 1 do PostgreSQL. Foi lançado um novo drive Version 9.0-dev800 (2010-05-11) - “Support reading the new hex escaped bytea format. (jurka)” que faz essa correção. Caso alguem precise é do baixar do site http://jdbc.postgresql.org/download.html.

Obrigado pela ajuda !!!

Criado 2 de janeiro de 2012
Ultima resposta 6 de jan. de 2012
Respostas 16
Participantes 2