Oops, sorry. Red Hat Linux 6.2J (Japanese); that's the reason why added >java lobtest -s guessed encoding caused this error... Postgresql-7.1.2 (not RPM, separately installed one.) $ ./configure --enable-multibyte=EUC_JP --with-java are used. jdk1.2.2 Intel Pentium-2 processor
----- Original Message ----- From: "Akira Kumakiri" <[EMAIL PROTECTED]> To: <[EMAIL PROTECTED]> Sent: Saturday, August 18, 2001 6:55 PM Subject: [BUGS] JDBC Large Object getBinaryStream returns -1 before EOF > 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 ( [EMAIL PROTECTED] ) 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 ([EMAIL PROTECTED] or [EMAIL PROTECTED] ) > > /* > * 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. > > > > ---------------------------(end of broadcast)--------------------------- > TIP 2: you can get off all lists at once with the unregister command > (send "unregister YourEmailAddressHere" to [EMAIL PROTECTED]) > ---------------------------(end of broadcast)--------------------------- TIP 2: you can get off all lists at once with the unregister command (send "unregister YourEmailAddressHere" to [EMAIL PROTECTED])