From: <pj...@us...> - 2009-07-31 04:52:42
|
Revision: 6610 http://jython.svn.sourceforge.net/jython/?rev=6610&view=rev Author: pjenvey Date: 2009-07-31 04:52:17 +0000 (Fri, 31 Jul 2009) Log Message: ----------- o read CLOBs into unicode instead of str o cleanup the DataHandler.read and have them close their input Modified Paths: -------------- trunk/jython/src/com/ziclix/python/sql/DataHandler.java trunk/jython/src/com/ziclix/python/sql/JDBC20DataHandler.java trunk/jython/src/com/ziclix/python/sql/handler/InformixDataHandler.java trunk/jython/src/com/ziclix/python/sql/handler/OracleDataHandler.java Modified: trunk/jython/src/com/ziclix/python/sql/DataHandler.java =================================================================== --- trunk/jython/src/com/ziclix/python/sql/DataHandler.java 2009-07-30 15:11:03 UTC (rev 6609) +++ trunk/jython/src/com/ziclix/python/sql/DataHandler.java 2009-07-31 04:52:17 UTC (rev 6610) @@ -14,6 +14,7 @@ import org.python.core.PyList; import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.Reader; @@ -48,7 +49,7 @@ */ public class DataHandler { - // default size for buffers + /** Default size for buffers. */ private static final int INITIAL_SIZE = 1024 * 4; private static final String[] SYSTEM_DATAHANDLERS = { @@ -153,7 +154,8 @@ * @param type the <i>java.sql.Types</i> for which this PyObject should be bound * @throws SQLException */ - public void setJDBCObject(PreparedStatement stmt, int index, PyObject object, int type) throws SQLException { + public void setJDBCObject(PreparedStatement stmt, int index, PyObject object, int type) + throws SQLException { try { if (checkNull(stmt, index, object, type)) { return; @@ -163,19 +165,16 @@ case Types.DATE: Date date = (Date) object.__tojava__(Date.class); - stmt.setDate(index, date); break; case Types.TIME: Time time = (Time) object.__tojava__(Time.class); - stmt.setTime(index, time); break; case Types.TIMESTAMP: Timestamp timestamp = (Timestamp) object.__tojava__(Timestamp.class); - stmt.setTimestamp(index, timestamp); break; @@ -203,7 +202,8 @@ break; } } catch (Exception e) { - SQLException cause = null, ex = new SQLException("error setting index [" + index + "], type [" + type + "]"); + SQLException cause = null, ex = new SQLException("error setting index [" + index + + "], type [" + type + "]"); if (e instanceof SQLException) { cause = (SQLException) e; @@ -212,7 +212,6 @@ } ex.setNextException(cause); - throw ex; } } @@ -229,7 +228,6 @@ * @throws SQLException if the type is unmappable */ public PyObject getPyObject(ResultSet set, int col, int type) throws SQLException { - PyObject obj = Py.None; switch (type) { @@ -309,7 +307,7 @@ throw new SQLException(msg); } - return (set.wasNull() || (obj == null)) ? Py.None : obj; + return set.wasNull() || obj == null ? Py.None : obj; } /** @@ -322,7 +320,6 @@ * @throws SQLException if the type is unmappable */ public PyObject getPyObject(CallableStatement stmt, int col, int type) throws SQLException { - PyObject obj = Py.None; switch (type) { @@ -331,14 +328,12 @@ case Types.VARCHAR: case Types.LONGVARCHAR: String string = stmt.getString(col); - obj = (string == null) ? Py.None : Py.newUnicode(string); break; case Types.NUMERIC: case Types.DECIMAL: BigDecimal bd = stmt.getBigDecimal(col); - obj = (bd == null) ? Py.None : Py.newFloat(bd.doubleValue()); break; @@ -398,7 +393,7 @@ throw new SQLException(msg); } - return (stmt.wasNull() || (obj == null)) ? Py.None : obj; + return stmt.wasNull() || obj == null ? Py.None : obj; } /** @@ -414,7 +409,8 @@ * @throws SQLException * */ - public void registerOut(CallableStatement statement, int index, int colType, int dataType, String dataTypeName) throws SQLException { + public void registerOut(CallableStatement statement, int index, int colType, int dataType, + String dataTypeName) throws SQLException { try { statement.registerOutParameter(index, dataType); @@ -439,7 +435,8 @@ * * @return true if the object is null and was set on the statement, false otherwise */ - public static final boolean checkNull(PreparedStatement stmt, int index, PyObject object, int type) throws SQLException { + public static final boolean checkNull(PreparedStatement stmt, int index, PyObject object, + int type) throws SQLException { if ((object == null) || (Py.None == object)) { stmt.setNull(index, type); @@ -449,54 +446,57 @@ } /** - * Since the driver needs to the know the length of all streams, - * read it into a byte[] array. + * Consume the InputStream into an byte array and close the InputStream. * - * @return the stream as a byte[] + * @return the contents of the InputStream a byte[] */ public static final byte[] read(InputStream stream) { + int size = 0; + byte[] buffer = new byte[INITIAL_SIZE]; + ByteArrayOutputStream baos = new ByteArrayOutputStream(INITIAL_SIZE); - int b = -1, read = 0; - byte[] results = new byte[INITIAL_SIZE]; - try { - while ((b = stream.read()) != -1) { - if (results.length < (read + 1)) { - byte[] tmp = results; - results = new byte[results.length * 2]; - System.arraycopy(tmp, 0, results, 0, tmp.length); - } - results[read++] = (byte) b; + while ((size = stream.read(buffer)) != -1) { + baos.write(buffer, 0, size); } - } catch (IOException e) { - throw zxJDBC.makeException(e); + } catch (IOException ioe) { + throw zxJDBC.makeException(ioe); + } finally { + try { + stream.close(); + } catch (IOException ioe) { + throw zxJDBC.makeException(ioe); + } } - byte[] tmp = results; - results = new byte[read]; - System.arraycopy(tmp, 0, results, 0, read); - return results; + return baos.toByteArray(); } /** - * Read all the chars from the Reader into the String. + * Consume the Reader into a String and close the Reader. * - * @return the contents of the Reader in a String + * @return the contents of the Reader as a String */ - public static final String read(Reader reader) { + public static String read(Reader reader) { + int size = 0; + char[] buffer = new char[INITIAL_SIZE]; + StringBuilder builder = new StringBuilder(INITIAL_SIZE); - int c = 0; - StringBuffer buffer = new StringBuffer(INITIAL_SIZE); - try { - while ((c = reader.read()) != -1) { - buffer.append((char) c); + while ((size = reader.read(buffer)) != -1) { + builder.append(buffer, 0, size); } - } catch (IOException e) { - throw zxJDBC.makeException(e); + } catch (IOException ioe) { + throw zxJDBC.makeException(ioe); + } finally { + try { + reader.close(); + } catch (IOException ioe) { + throw zxJDBC.makeException(ioe); + } } - return buffer.toString(); + return builder.toString(); } /** @@ -509,8 +509,8 @@ for (String element : SYSTEM_DATAHANDLERS) { try { - Class c = Class.forName(element); - Constructor cons = c.getConstructor(new Class[]{DataHandler.class}); + Class<?> c = Class.forName(element); + Constructor<?> cons = c.getConstructor(new Class<?>[]{DataHandler.class}); dh = (DataHandler) cons.newInstance(new Object[]{dh}); } catch (Throwable t) {} } @@ -530,6 +530,7 @@ /** * Returns the classname of this datahandler. */ + @Override public String toString() { return getClass().getName(); } Modified: trunk/jython/src/com/ziclix/python/sql/JDBC20DataHandler.java =================================================================== --- trunk/jython/src/com/ziclix/python/sql/JDBC20DataHandler.java 2009-07-30 15:11:03 UTC (rev 6609) +++ trunk/jython/src/com/ziclix/python/sql/JDBC20DataHandler.java 2009-07-31 04:52:17 UTC (rev 6610) @@ -9,10 +9,8 @@ package com.ziclix.python.sql; import java.io.BufferedInputStream; -import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.InputStream; -import java.io.InputStreamReader; import java.io.Reader; import java.math.BigDecimal; import java.sql.Array; @@ -92,7 +90,7 @@ // it really is unfortunate that I need to send the length of the stream if (jobject instanceof InputStream) { - lob = DataHandler.read(new BufferedInputStream((InputStream) jobject)); + lob = read((InputStream) jobject); } else if (jobject instanceof byte[]) { lob = (byte[]) jobject; } @@ -135,60 +133,13 @@ break; case Types.CLOB: - - /* - * It seems some drivers (well at least Informix) don't clean up after themselves - * if the Clob is requested. The engine keeps a handle to an open table for each - * row requested and cleans up fully only when the ResultSet or Connection is closed. - * While this generally will never be noticed because the number of CLOBs or BLOBs - * queried will likely be small in the event a large number are queried, it is a huge - * problem. So, handle it as low as possible by managing the stream directly. I've - * decided to leave this in the generic JDBC20 handler because it works for all engines - * I've tested and seems to perform quite well to boot. - */ - Reader reader = null; - - try { - InputStream stream = set.getBinaryStream(col); - - if (stream == null) { - obj = Py.None; - } else { - reader = new InputStreamReader(stream); - reader = new BufferedReader(reader); - obj = Py.newString(DataHandler.read(reader)); - } - } finally { - if (reader != null) { - try { - reader.close(); - } catch (Exception e) { - } - } - } + Reader reader = set.getCharacterStream(col); + obj = reader == null ? Py.None : Py.newUnicode(read(reader)); break; case Types.BLOB: Blob blob = set.getBlob(col); - - if (blob == null) { - obj = Py.None; - } else { - InputStream stream = null; - - try { - stream = blob.getBinaryStream(); - stream = new BufferedInputStream(stream); - obj = Py.java2py(DataHandler.read(stream)); - } finally { - if (stream != null) { - try { - stream.close(); - } catch (Exception e) { - } - } - } - } + obj = blob == null ? Py.None : Py.java2py(read(blob.getBinaryStream())); break; case Types.ARRAY: Modified: trunk/jython/src/com/ziclix/python/sql/handler/InformixDataHandler.java =================================================================== --- trunk/jython/src/com/ziclix/python/sql/handler/InformixDataHandler.java 2009-07-30 15:11:03 UTC (rev 6609) +++ trunk/jython/src/com/ziclix/python/sql/handler/InformixDataHandler.java 2009-07-31 04:52:17 UTC (rev 6610) @@ -8,12 +8,10 @@ */ package com.ziclix.python.sql.handler; +import com.informix.jdbc.IfmxStatement; + import com.ziclix.python.sql.DataHandler; import com.ziclix.python.sql.FilterDataHandler; -import org.python.core.Py; -import org.python.core.PyFile; -import org.python.core.PyObject; -import org.python.core.PyString; import java.io.InputStream; import java.sql.Blob; @@ -23,6 +21,11 @@ import java.sql.Statement; import java.sql.Types; +import org.python.core.Py; +import org.python.core.PyFile; +import org.python.core.PyObject; +import org.python.core.PyString; + /** * Informix specific data handling. * @@ -48,12 +51,11 @@ * @return PyObject * @throws SQLException */ + @Override public PyObject getRowId(Statement stmt) throws SQLException { - - if (stmt instanceof com.informix.jdbc.IfmxStatement) { - return Py.newInteger(((com.informix.jdbc.IfmxStatement) stmt).getSerial()); + if (stmt instanceof IfmxStatement) { + return Py.newInteger(((IfmxStatement) stmt).getSerial()); } - return super.getRowId(stmt); } @@ -66,8 +68,9 @@ * @param type * @throws SQLException */ - public void setJDBCObject(PreparedStatement stmt, int index, PyObject object, int type) throws SQLException { - + @Override + public void setJDBCObject(PreparedStatement stmt, int index, PyObject object, int type) + throws SQLException { if (DataHandler.checkNull(stmt, index, object, type)) { return; } @@ -105,9 +108,11 @@ * @param object * @throws SQLException */ - public void setJDBCObject(PreparedStatement stmt, int index, PyObject object) throws SQLException { - - // there is a bug in the Ifx driver when using setObject() with a String for a prepared statement + @Override + public void setJDBCObject(PreparedStatement stmt, int index, PyObject object) + throws SQLException { + // there is a bug in the Ifx driver when using setObject() with a String for a + // prepared statement if (object instanceof PyString) { super.setJDBCObject(stmt, index, object, Types.VARCHAR); } else { @@ -125,6 +130,7 @@ * @throws SQLException thrown for a sql exception */ @SuppressWarnings("fallthrough") + @Override public PyObject getPyObject(ResultSet set, int col, int type) throws SQLException { PyObject obj = Py.None; @@ -133,7 +139,6 @@ case Types.OTHER: try { - // informix returns boolean as OTHERs, so let's give that a try obj = set.getBoolean(col) ? Py.One : Py.Zero; } catch (SQLException e) { @@ -145,33 +150,15 @@ int major = set.getStatement().getConnection().getMetaData().getDriverMajorVersion(); int minor = set.getStatement().getConnection().getMetaData().getDriverMinorVersion(); - if ((major <= 2) && (minor <= 11)) { + if (major <= 2 && minor <= 11) { Blob blob = set.getBlob(col); - - if (blob == null) { - obj = Py.None; - } else { - InputStream is = null; - - try { - - // the available() bug means we CANNOT buffer this stream - is = blob.getBinaryStream(); - obj = Py.java2py(DataHandler.read(is)); - } finally { - try { - is.close(); - } catch (Exception e) { - } - } - } - + obj = blob == null ? Py.None : Py.java2py(read(blob.getBinaryStream())); break; } default : obj = super.getPyObject(set, col, type); } - return (set.wasNull() || (obj == null)) ? Py.None : obj; + return set.wasNull() || obj == null ? Py.None : obj; } } Modified: trunk/jython/src/com/ziclix/python/sql/handler/OracleDataHandler.java =================================================================== --- trunk/jython/src/com/ziclix/python/sql/handler/OracleDataHandler.java 2009-07-30 15:11:03 UTC (rev 6609) +++ trunk/jython/src/com/ziclix/python/sql/handler/OracleDataHandler.java 2009-07-31 04:52:17 UTC (rev 6610) @@ -48,18 +48,18 @@ * @param name * @return String */ + @Override public String getMetaDataName(PyObject name) { - String metaName = super.getMetaDataName(name); - return (metaName == null) ? null : metaName.toUpperCase(); } /** * Provide functionality for Oracle specific types, such as ROWID. */ - public void setJDBCObject(PreparedStatement stmt, int index, PyObject object, int type) throws SQLException { - + @Override + public void setJDBCObject(PreparedStatement stmt, int index, PyObject object, int type) + throws SQLException { if (DataHandler.checkNull(stmt, index, object, type)) { return; } @@ -102,22 +102,15 @@ /** * Provide functionality for Oracle specific types, such as ROWID. */ + @Override public PyObject getPyObject(ResultSet set, int col, int type) throws SQLException { - PyObject obj = Py.None; switch (type) { case Types.BLOB: BLOB blob = ((OracleResultSet) set).getBLOB(col); - - if (blob == null) { - return Py.None; - } - - InputStream stream = new BufferedInputStream(blob.getBinaryStream()); - - obj = Py.java2py(DataHandler.read(stream)); + obj = blob == null ? Py.None : Py.java2py(read(blob.getBinaryStream())); break; case OracleTypes.ROWID: @@ -132,7 +125,7 @@ obj = super.getPyObject(set, col, type); } - return (set.wasNull() ? Py.None : obj); + return set.wasNull() ? Py.None : obj; } /** @@ -146,7 +139,9 @@ * @param dataTypeName the JDBC datatype name * @throws SQLException */ - public void registerOut(CallableStatement statement, int index, int colType, int dataType, String dataTypeName) throws SQLException { + @Override + public void registerOut(CallableStatement statement, int index, int colType, int dataType, + String dataTypeName) throws SQLException { if (dataType == Types.OTHER) { if ("REF CURSOR".equals(dataTypeName)) { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |