|
From: <otm...@us...> - 2010-09-28 05:35:28
|
Revision: 7127
http://jython.svn.sourceforge.net/jython/?rev=7127&view=rev
Author: otmarhumbel
Date: 2010-09-28 05:35:21 +0000 (Tue, 28 Sep 2010)
Log Message:
-----------
handle more SQL types in zxJDBC DataHandler
(fixes issue #1647)
thanks to Stephen Layland for the first patch
thanks to Patrick Reinhart for discovering the missing types
Modified Paths:
--------------
trunk/jython/NEWS
trunk/jython/src/com/ziclix/python/sql/DataHandler.java
trunk/jython/src/com/ziclix/python/sql/Jython22DataHandler.java
trunk/jython/src/com/ziclix/python/sql/handler/OracleDataHandler.java
trunk/jython/src/com/ziclix/python/sql/handler/PostgresqlDataHandler.java
trunk/jython/src/com/ziclix/python/sql/resource/zxJDBCMessages.properties
Added Paths:
-----------
trunk/jython/tests/java/com/
trunk/jython/tests/java/com/ziclix/
trunk/jython/tests/java/com/ziclix/python/
trunk/jython/tests/java/com/ziclix/python/sql/
trunk/jython/tests/java/com/ziclix/python/sql/DataHandlerTest.java
Modified: trunk/jython/NEWS
===================================================================
--- trunk/jython/NEWS 2010-09-27 13:14:22 UTC (rev 7126)
+++ trunk/jython/NEWS 2010-09-28 05:35:21 UTC (rev 7127)
@@ -1,5 +1,9 @@
Jython NEWS
+Jython 2.5.2rc1
+ Bugs Fixed
+ - [ 1647 ] zxJDBC does not handle NVARCHAR
+
Jython 2.5.2b2
Bugs Fixed
- [ 1327 ] Classloaders cannot GC, which exhausts permgen (partial bug fix)
Modified: trunk/jython/src/com/ziclix/python/sql/DataHandler.java
===================================================================
--- trunk/jython/src/com/ziclix/python/sql/DataHandler.java 2010-09-27 13:14:22 UTC (rev 7126)
+++ trunk/jython/src/com/ziclix/python/sql/DataHandler.java 2010-09-28 05:35:21 UTC (rev 7127)
@@ -8,11 +8,6 @@
*/
package com.ziclix.python.sql;
-import org.python.core.Py;
-import org.python.core.PyFile;
-import org.python.core.PyObject;
-import org.python.core.PyList;
-
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -20,9 +15,11 @@
import java.io.Reader;
import java.io.StringReader;
import java.lang.reflect.Constructor;
+import java.math.BigDecimal;
import java.math.BigInteger;
-import java.math.BigDecimal;
+import java.sql.Blob;
import java.sql.CallableStatement;
+import java.sql.Clob;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
@@ -32,6 +29,11 @@
import java.sql.Timestamp;
import java.sql.Types;
+import org.python.core.Py;
+import org.python.core.PyFile;
+import org.python.core.PyList;
+import org.python.core.PyObject;
+
/**
* The DataHandler is responsible mapping the JDBC data type to
* a Jython object. Depending on the version of the JDBC
@@ -250,6 +252,7 @@
break;
case Types.BIT:
+ case Types.BOOLEAN:
obj = set.getBoolean(col) ? Py.True : Py.False;
break;
@@ -291,6 +294,7 @@
break;
case Types.OTHER:
+ case Types.JAVA_OBJECT:
obj = Py.java2py(set.getObject(col));
break;
@@ -300,16 +304,41 @@
obj = Py.java2py(set.getBytes(col));
break;
+ case Types.BLOB:
+ Blob blob = set.getBlob(col);
+ obj = blob == null ? Py.None : Py.java2py(read(blob.getBinaryStream()));
+ break;
+
+ case Types.CLOB:
+ Clob clob = set.getClob(col);
+ obj = clob == null ? Py.None : Py.java2py(read(clob.getCharacterStream()));
+ break;
+
+ // TODO can we support these?
+ case Types.ARRAY:
+ throw createUnsupportedTypeSQLException("ARRAY", col);
+ case Types.DATALINK:
+ throw createUnsupportedTypeSQLException("DATALINK", col);
+ case Types.DISTINCT:
+ throw createUnsupportedTypeSQLException("DISTINCT", col);
+ case Types.REF:
+ throw createUnsupportedTypeSQLException("REF", col);
+ case Types.STRUCT:
+ throw createUnsupportedTypeSQLException("STRUCT", col);
+
default :
- Integer[] vals = {new Integer(col), new Integer(type)};
- String msg = zxJDBC.getString("errorGettingIndex", vals);
-
- throw new SQLException(msg);
+ throw createUnsupportedTypeSQLException(new Integer(type), col);
}
return set.wasNull() || obj == null ? Py.None : obj;
}
+ protected final SQLException createUnsupportedTypeSQLException(Object type, int col) {
+ Object[] vals = {type, new Integer(col)};
+ String msg = zxJDBC.getString("unsupportedTypeForColumn", vals);
+ return new SQLException(msg);
+ }
+
/**
* Given a CallableStatement, column and type, return the appropriate
* Jython object.
@@ -387,10 +416,7 @@
break;
default :
- Integer[] vals = {new Integer(col), new Integer(type)};
- String msg = zxJDBC.getString("errorGettingIndex", vals);
-
- throw new SQLException(msg);
+ createUnsupportedTypeSQLException(type, col);
}
return stmt.wasNull() || obj == null ? Py.None : obj;
Modified: trunk/jython/src/com/ziclix/python/sql/Jython22DataHandler.java
===================================================================
--- trunk/jython/src/com/ziclix/python/sql/Jython22DataHandler.java 2010-09-27 13:14:22 UTC (rev 7126)
+++ trunk/jython/src/com/ziclix/python/sql/Jython22DataHandler.java 2010-09-28 05:35:21 UTC (rev 7127)
@@ -51,6 +51,7 @@
* most notably Oracle. This callback allows a DataHandler to affect the
* name.
*/
+ @Override
public String getMetaDataName(PyObject name) {
return ((name == Py.None) ? null : name.__str__().toString());
}
@@ -63,6 +64,7 @@
* @return an instance of a Procedure
* @throws SQLException
*/
+ @Override
public Procedure getProcedure(PyCursor cursor, PyObject name) throws SQLException {
return new Procedure(cursor, name);
}
@@ -75,6 +77,7 @@
* @throws SQLException thrown if an exception occurs
*
*/
+ @Override
public PyObject getRowId(Statement stmt) throws SQLException {
return Py.None;
}
@@ -83,6 +86,7 @@
* A callback prior to each execution of the statement. If the statement is
* a PreparedStatement, all the parameters will have been set.
*/
+ @Override
public void preExecute(Statement stmt) throws SQLException {
return;
}
@@ -90,6 +94,7 @@
/**
* A callback after successfully executing the statement.
*/
+ @Override
public void postExecute(Statement stmt) throws SQLException {
return;
}
@@ -103,6 +108,7 @@
* @param object the PyObject in question
* @throws SQLException
*/
+ @Override
public void setJDBCObject(PreparedStatement stmt, int index, PyObject object) throws SQLException {
try {
@@ -133,6 +139,7 @@
* @param type the <i>java.sql.Types</i> for which this PyObject should be bound
* @throws SQLException
*/
+ @Override
public void setJDBCObject(PreparedStatement stmt, int index, PyObject object, int type) throws SQLException {
try {
@@ -209,6 +216,7 @@
* @param type the column type
* @throws SQLException if the type is unmappable
*/
+ @Override
@SuppressWarnings("deprecation")
public PyObject getPyObject(ResultSet set, int col, int type) throws SQLException {
@@ -308,10 +316,7 @@
break;
default :
- Integer[] vals = {new Integer(col), new Integer(type)};
- String msg = zxJDBC.getString("errorGettingIndex", vals);
-
- throw new SQLException(msg);
+ throw createUnsupportedTypeSQLException(new Integer(type), col);
}
return (set.wasNull() || (obj == null)) ? Py.None : obj;
@@ -326,6 +331,7 @@
* @param type the column type
* @throws SQLException if the type is unmappable
*/
+ @Override
@SuppressWarnings("deprecation")
public PyObject getPyObject(CallableStatement stmt, int col, int type) throws SQLException {
@@ -398,10 +404,7 @@
break;
default :
- Integer[] vals = {new Integer(col), new Integer(type)};
- String msg = zxJDBC.getString("errorGettingIndex", vals);
-
- throw new SQLException(msg);
+ throw createUnsupportedTypeSQLException(new Integer(type), col);
}
return (stmt.wasNull() || (obj == null)) ? Py.None : obj;
@@ -420,6 +423,7 @@
* @throws SQLException
*
*/
+ @Override
public void registerOut(CallableStatement statement, int index, int colType, int dataType, String dataTypeName) throws SQLException {
try {
@@ -445,6 +449,7 @@
*
* @return a list of datahandlers
*/
+ @Override
public PyObject __chain__() {
return new PyList(Py.javas2pys(this));
}
Modified: trunk/jython/src/com/ziclix/python/sql/handler/OracleDataHandler.java
===================================================================
--- trunk/jython/src/com/ziclix/python/sql/handler/OracleDataHandler.java 2010-09-27 13:14:22 UTC (rev 7126)
+++ trunk/jython/src/com/ziclix/python/sql/handler/OracleDataHandler.java 2010-09-28 05:35:21 UTC (rev 7127)
@@ -8,26 +8,25 @@
*/
package com.ziclix.python.sql.handler;
-import com.ziclix.python.sql.DataHandler;
-import com.ziclix.python.sql.FilterDataHandler;
-import com.ziclix.python.sql.zxJDBC;
+import java.sql.CallableStatement;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+import java.sql.Types;
+
import oracle.jdbc.OracleResultSet;
import oracle.jdbc.OracleTypes;
import oracle.sql.BLOB;
import oracle.sql.ROWID;
+
import org.python.core.Py;
import org.python.core.PyInteger;
import org.python.core.PyObject;
-import java.io.BufferedInputStream;
-import java.io.InputStream;
-import java.sql.CallableStatement;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.ResultSetMetaData;
-import java.sql.SQLException;
-import java.sql.Timestamp;
-import java.sql.Types;
+import com.ziclix.python.sql.DataHandler;
+import com.ziclix.python.sql.FilterDataHandler;
/**
* Oracle specific data handling.
@@ -96,13 +95,6 @@
super.setJDBCObject(stmt, index, object, Types.DOUBLE);
break;
- case Types.BLOB:
- case Types.CLOB:
- Integer[] vals = {new Integer(index), new Integer(type)};
- String msg = zxJDBC.getString("errorSettingIndex", vals);
-
- throw new SQLException(msg);
-
case OracleTypes.ROWID:
stmt.setString(index, (String) object.__tojava__(String.class));
break;
Modified: trunk/jython/src/com/ziclix/python/sql/handler/PostgresqlDataHandler.java
===================================================================
--- trunk/jython/src/com/ziclix/python/sql/handler/PostgresqlDataHandler.java 2010-09-27 13:14:22 UTC (rev 7126)
+++ trunk/jython/src/com/ziclix/python/sql/handler/PostgresqlDataHandler.java 2010-09-28 05:35:21 UTC (rev 7127)
@@ -38,6 +38,7 @@
super(datahandler);
}
+ @Override
protected String getRowIdMethodName() {
return "getLastOID";
}
@@ -51,6 +52,7 @@
* @return the mapped Python object
* @throws SQLException thrown for a sql exception
*/
+ @Override
public PyObject getPyObject(ResultSet set, int col, int type) throws SQLException {
PyObject obj = Py.None;
@@ -90,6 +92,7 @@
* @param type
* @throws SQLException
*/
+ @Override
public void setJDBCObject(PreparedStatement stmt, int index, PyObject object, int type) throws SQLException {
if (DataHandler.checkNull(stmt, index, object, type)) {
@@ -115,6 +118,8 @@
super.setJDBCObject(stmt, index, object, type);
}
}
+
+ @Override
public void setJDBCObject(PreparedStatement stmt, int index, PyObject object) throws SQLException {
// PostgreSQL doesn't support BigIntegers without explicitely setting the
// type.
Modified: trunk/jython/src/com/ziclix/python/sql/resource/zxJDBCMessages.properties
===================================================================
--- trunk/jython/src/com/ziclix/python/sql/resource/zxJDBCMessages.properties 2010-09-27 13:14:22 UTC (rev 7126)
+++ trunk/jython/src/com/ziclix/python/sql/resource/zxJDBCMessages.properties 2010-09-28 05:35:21 UTC (rev 7127)
@@ -94,8 +94,7 @@
noColInfo=unable to obtain column info
excludedAllCols=excluded all columns
invalidTableName=invalid table name [None]
-errorSettingIndex=error setting index [{0}], type [{1}]
-errorGettingIndex=error getting index [{0}], type [{1}]
+unsupportedTypeForColumn=type [{0}] is not supported for column index: {1}
maybeCallproc=use .callproc() for stored procedures
nodynamiccursors=this version of jdbc does not support dynamic cursors
nocallprocsupport=dynamic cursor does not support .callproc; use static cursors instead
Added: trunk/jython/tests/java/com/ziclix/python/sql/DataHandlerTest.java
===================================================================
--- trunk/jython/tests/java/com/ziclix/python/sql/DataHandlerTest.java (rev 0)
+++ trunk/jython/tests/java/com/ziclix/python/sql/DataHandlerTest.java 2010-09-28 05:35:21 UTC (rev 7127)
@@ -0,0 +1,95 @@
+package com.ziclix.python.sql;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.Arrays;
+import java.util.List;
+
+import org.python.core.PySystemState;
+
+import junit.framework.TestCase;
+
+public class DataHandlerTest extends TestCase {
+
+ private DataHandler _handler;
+
+ @Override
+ protected void setUp() throws Exception {
+ PySystemState.initialize();
+ _handler = new DataHandler();
+ }
+
+ /**
+ * make sure we handle every {@link java.sql.Types} somehow
+ *
+ * @throws Exception
+ */
+ public void testGetPyObjectResultSetIntInt() throws Exception {
+ ResultSet rs = (ResultSet)Proxy.newProxyInstance(getClass().getClassLoader(),
+ new Class<?>[] {ResultSet.class},
+ new DefaultReturnHandler());
+ List<String> unsupportedTypes = Arrays.asList("ARRAY",
+ "DATALINK",
+ "DISTINCT",
+ "REF",
+ "STRUCT");
+ for (Field field : Types.class.getDeclaredFields()) {
+ String typeName = field.getName();
+ int type = field.getInt(null);
+ if (unsupportedTypes.contains(typeName)) {
+ try {
+ _handler.getPyObject(rs, 1, type);
+ fail("SQLException expected");
+ } catch (SQLException sqle) {
+ // expected
+ }
+ } else {
+ assertNotNull(typeName + " should return None", _handler.getPyObject(rs, 1, type));
+ }
+ }
+ }
+
+ /**
+ * This is a poor man's mock - i cannot introduce a mock framework at this point in time
+ */
+ static class DefaultReturnHandler implements InvocationHandler {
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ Class<?> returnType = method.getReturnType();
+ if (returnType.equals(Boolean.class) || returnType.equals(Boolean.TYPE)) {
+ return Boolean.FALSE;
+ } else if (Character.TYPE.equals(returnType)) {
+ return Character.valueOf('0');
+ } else if (Byte.TYPE.equals(returnType)) {
+ return Byte.valueOf((byte)0);
+ } else if (Short.TYPE.equals(returnType)) {
+ return Short.valueOf((short)0);
+ } else if (Integer.TYPE.equals(returnType)) {
+ return Integer.valueOf(0);
+ } else if (Long.TYPE.equals(returnType)) {
+ return Long.valueOf(0L);
+ } else if (Float.TYPE.equals(returnType)) {
+ return Float.valueOf(0);
+ } else if (Double.TYPE.equals(returnType)) {
+ return Double.valueOf(0);
+ } else if (returnType.isPrimitive()) {
+ throw new RuntimeException("unhandled primitve type " + returnType);
+ } else if (returnType.isAssignableFrom(BigInteger.class)) {
+ return BigInteger.ZERO;
+ } else if (returnType.isAssignableFrom(BigDecimal.class)) {
+ return BigDecimal.ZERO;
+ } else if (returnType.isAssignableFrom(Number.class)) {
+ return 0;
+ } else {
+ return null;
+ }
+ }
+ }
+}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|