Skip site navigation (1) Skip section navigation (2)

JDBC Large Object getBinaryStream returns -1 before EOF

From: "Akira Kumakiri" <kumakiri(at)ekuma(dot)net>
To: <pgsql-bugs(at)postgresql(dot)org>
Subject: JDBC Large Object getBinaryStream returns -1 before EOF
Date: 2001-08-18 09:55:03
Message-ID: 006201c127cb$dad63400$de09713d@ekuma.net (view raw or flat)
Thread:
Lists: pgsql-bugs
Hi,

I'm making some code handling several kinds of files as large object.  I found the
JDBC driver returned without finish reading the file.  I made the test program
named lobtest.java, which is added at the end of this mail.

This test program read a file (default is "tomcat.gif" which is fetched from
Tomcat home page, but you can specify the name.), and write it into data base
named "lobtest".  And then read it just after writing.  But the size between the
original one and write/read one is different.  Everytime, the file after
write/read is smaller.

Some one in Postgres Mailing List in Japan ( pgsql-jp(at)sra(dot)co(dot)jp ) found the same
problem and checked inside the JDBC driver source code.  He thinks read() in
BlobInputStream.java has something wrong at the following part, then changed a
liitle bit, and worked fine.  He says he does not know all the JDBC driver codes,
and is not clear whether this is the correct fix or not.

The following is the part of  org/postgresql/largeobject/BlobInputStream.java

  /**
   * The minimum required to implement input stream
   */
  public int read() throws java.io.IOException {
    try {
      if(buffer==null || bpos>=buffer.length) {
        buffer=lo.read(bsize);
        bpos=0;
      }

      // Handle EOF
      if(bpos>=buffer.length)
        return -1;

      int tmp = (int)buffer[bpos++];  //**** originally return
(int)buffer[bpos++];
      if (tmp<0) tmp = tmp+256;     //****  but, replaced using tmp as left side
shows.
      return tmp;                        //****  and worked fine.
    } catch(SQLException se) {
      throw new IOException(se.toString());
    }
  }

You can reproduce this by the follwoing steps.

1) > createdb lobtest

2) >psql lobtest
  lobtest=# CREATE TABLE tests (
  index  serial,
  imgname text,
  imgoid oid
  );

3) copy the following test program into file (lobtest.java), then compile it.
   Some unexpected CR may be added by mailer.  Please remove these.

4) type  >java lobtest -i foo.gif
    or whatever file you have on the same directory as lobtest.class file.
    From my experience, all the gif file causes an error.
    > java lobtest ?  shows help.

5) lobtest reads file, stores it onto db as large object, then reads it again, and
writes it on the same directory.  If the file is tomcat.gif, then r_tomcat.gif is
created.  Please check the file size on both.

6) If I use getBytes("imgoid"), then no error.

Thank you for reading my poor English.

akira (ricky(at)ekuma(dot)net or kumakiri(at)ekuma(dot)net )

/*
 * lobtest.java
 *
 */

  import java.io.*;
  import java.lang.*;
  import java.sql.*;
  import java.util.*;
  import sun.io.*;

  class lobtest {
    static String index = null;
    static String filename = "tomcat.gif";
    static String url = "jdbc:postgresql:lobtest";
    static String account = "postgres";
    static String password = "postgrespassword";
    public static void main(String argv[]) {
      for (int optind = 0; optind < argv.length; optind++) {
        if (argv[optind].equals("-i")) {
   filename = argv[++optind];
        } else if (argv[optind].equals("-s")) {
     System.out.println("System default encoding = "
+System.getProperty("file.encoding"));
            System.out.println("ByteToCharConverter= "
+ByteToCharConverter.getDefault());
            System.out.println("CharToByteConverter= "
+CharToByteConverter.getDefault());
            System.exit(0);
        } else if (argv[optind].equals("--")) {
     optind++;
     break;
        } else if (argv[optind].startsWith("?")) {
     System.out.println("Usage: test [-i file] [-s] [?]");
            System.out.println("  (no param),  write large object on db, and read
it, then compare it.");
            System.out.println("  -i file,     specify file name, default is
tomcat.gif");
            System.out.println("  -s           show system parameters");
            System.out.println("   ?           show this help");
            System.exit(0);
        } else break;
      }

    try {    // establish DB connections.
      Class.forName("org.postgresql.Driver");
    } catch(ClassNotFoundException cnf) {
        cnf.printStackTrace();
        System.out.println("Class.forName() error.");
        System.exit(1);
    }

//  Starting...
//  Write file into DB as Large Object.
    String query = null;
    int length = 0;
    Connection connM = null;
    byte[] byteArray = null;
    try {
      File file = new File(filename);
      FileInputStream fis = new FileInputStream(file);
      int c = fis.available();
      byteArray = new byte[c];
      int get = fis.read(byteArray);
      fis.close();
      length = byteArray.length;
      System.out.println("c= " +c +" get= " +get +" byteArray.length= " +length);

      connM = DriverManager.getConnection(url, account, password);
      connM.setAutoCommit(false);
      InputStream bis = new ByteArrayInputStream(byteArray);
      query = "INSERT INTO tests (imgname, imgoid) VALUES ('" +filename +"', ?);";
      PreparedStatement ps = connM.prepareStatement(query);
      ps.setBinaryStream(1, bis, length);
      int result = ps.executeUpdate();
      connM.commit();
      ps.close();
      bis.close();
      System.out.println("filename= " +filename +" file.length= " +length +"
result= " +result);
    } catch(SQLException sql) {
        sql.printStackTrace();
    } catch(FileNotFoundException fnf) {
        fnf.printStackTrace();
    } catch(IOException ioe) {
        ioe.printStackTrace();
    } finally {
       try {
         connM.setAutoCommit(true);
       } catch (Exception againse) {
          System.out.print("write Exception again at setAutoCommit(true)");
          System.exit(1);
       }
    }


//  The follwoing is the way to read large object using InputStream, but
unexpected -1 returns.
//  BlobInputStream.java causes the error ???.
    try {
      connM.setAutoCommit(false);
      query = "SELECT imgoid FROM tests WHERE imgname='" +filename +"';";
      Statement st = connM.createStatement();
      ResultSet rs = st.executeQuery(query);

//  ****** Case 1 ******
      while(rs.next()) {
        InputStream is = rs.getBinaryStream("imgoid");
        BufferedInputStream bis = new BufferedInputStream(is);
        String pathname = "./r_" +filename;
        File file = new File(pathname);
        boolean del = file.delete();  // test this again and again, so delete old
one.
        if ( ! file.canRead()) { // always false.  debugging now.
          FileOutputStream fos = new FileOutputStream(file);
          int c;     // stream may return 0 when the method available() is called.
          int i = 0;
          while ((c=bis.read()) != -1) {fos.write(c); ++i;}// don't use
available() see java.sql
          fos.close();
          System.out.println("total read bytes  i= " +i);
          bis.close();
        }
      }

//  ***** Case 2 *****
//  You can avoid the above error by using getBytes() instead.
/*    while(rs.next()) {
        byte[] stb = rs.getBytes("imgoid");
        String pathname = "./r_" +filename;
        File file = new File(pathname);
        boolean del = file.delete();  // test this again and again, so delete old
one.
        if ( ! file.canRead()) { // always false.  debugging now.
          FileOutputStream fos = new FileOutputStream(file);
          fos.write(stb);
          fos.close();
          System.out.println("total read bytes  stb.length= " +stb.length);
        }
      } */

      connM.commit();
      rs.close();
      st.close();
    } catch(SQLException sql) {
        sql.printStackTrace();
    } catch(IOException ioe) {
        ioe.printStackTrace();
    } finally {
       try {
         connM.setAutoCommit(true);
       } catch (Exception againse) {
          System.out.print("read Exception again at setAutoCommit(true)");
          System.exit(1);
       }
    }

    }

  } // class end.



Responses

pgsql-bugs by date

Next:From: Akira KumakiriDate: 2001-08-18 10:32:49
Subject: Re: JDBC Large Object getBinaryStream returns -1 before EOF
Previous:From: RickyDate: 2001-08-18 09:36:48
Subject: JDBC Large Object getBinaryStream returns -1 before EOF

Privacy Policy | About PostgreSQL
Copyright © 1996-2014 The PostgreSQL Global Development Group