Changeset: 2d6f35cb428f for MonetDB URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=2d6f35cb428f Added Files: java/src/nl/cwi/monetdb/jdbc/types/INET.java java/src/nl/cwi/monetdb/jdbc/types/URL.java java/tests/Test_PSsqldata.java java/tests/Test_Rsqldata.java Modified Files: java/ChangeLog.Oct2012 java/src/nl/cwi/monetdb/jdbc/MonetConnection.java java/src/nl/cwi/monetdb/jdbc/MonetPreparedStatement.java java/src/nl/cwi/monetdb/jdbc/MonetResultSet.java java/tests/build.xml Branch: Oct2012 Log Message:
JDBC: implemented Connection's type map support Custom mapping between server types and Java classes can now be made, using the SQLData interface for UDTs. Two tests to deal with INET and URL types have been added. diffs (truncated from 881 to 300 lines): diff --git a/java/ChangeLog.Oct2012 b/java/ChangeLog.Oct2012 --- a/java/ChangeLog.Oct2012 +++ b/java/ChangeLog.Oct2012 @@ -1,6 +1,13 @@ # ChangeLog file for java # This file is updated with Maddlog +* Fri Nov 23 2012 Fabian Groffen <fab...@monetdb.org> +- Implemented type map support of Connection to allow custom mapping + of UDTs to Java classes. By default the INET and URL UDTs are + now mapped to nl.cwi.monetdb.jdbc.types.{INET,URL}. Most notably, + ResultSet.getObject() and PreparedStatement.setObject() deal with the + type map. + * Thu Nov 22 2012 Fabian Groffen <fab...@monetdb.org> - Fixed a problem in PreparedStatement where the prepared statement's ResultSetMetaData (on its columns to be produced) incorrectly threw diff --git a/java/src/nl/cwi/monetdb/jdbc/MonetConnection.java b/java/src/nl/cwi/monetdb/jdbc/MonetConnection.java --- a/java/src/nl/cwi/monetdb/jdbc/MonetConnection.java +++ b/java/src/nl/cwi/monetdb/jdbc/MonetConnection.java @@ -52,6 +52,8 @@ import java.util.concurrent.locks.Condit import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; +import nl.cwi.monetdb.jdbc.types.INET; +import nl.cwi.monetdb.jdbc.types.URL; import nl.cwi.monetdb.mcl.MCLException; import nl.cwi.monetdb.mcl.io.BufferedMCLReader; import nl.cwi.monetdb.mcl.io.BufferedMCLWriter; @@ -114,8 +116,11 @@ public class MonetConnection extends Mon /** The stack of warnings for this Connection object */ private SQLWarning warnings = null; /** The Connection specific mapping of user defined types to Java - * types (not used) */ - private Map<String,Class<?>> typeMap = new HashMap<String,Class<?>>(); + * types */ + private Map<String,Class<?>> typeMap = new HashMap<String,Class<?>>() {{ + put("inet", INET.class); + put("url", URL.class); + }}; // See javadoc for documentation about WeakHashMap if you don't know what // it does !!!NOW!!! (only when you deal with it of course) diff --git a/java/src/nl/cwi/monetdb/jdbc/MonetPreparedStatement.java b/java/src/nl/cwi/monetdb/jdbc/MonetPreparedStatement.java --- a/java/src/nl/cwi/monetdb/jdbc/MonetPreparedStatement.java +++ b/java/src/nl/cwi/monetdb/jdbc/MonetPreparedStatement.java @@ -833,7 +833,16 @@ public class MonetPreparedStatement * @throws SQLException if a database access error occurs */ public String getParameterClassName(int param) throws SQLException { - return MonetResultSet.getClassForType(javaType[getParamIdx(param)]).getName(); + Map map = getConnection().getTypeMap(); + Class c; + if (map.containsKey(monetdbType[getParamIdx(param)])) { + c = (Class)map.get(monetdbType[getParamIdx(param)]); + } else { + c = MonetResultSet.getClassForType( + javaType[getParamIdx(param)] + ); + } + return c.getName(); } /** @@ -1911,10 +1920,126 @@ public class MonetPreparedStatement } else if (x instanceof SQLXML) { throw new SQLFeatureNotSupportedException("Operation setObject() with object of type SQLXML currently not supported!", "0A000"); } else if (x instanceof SQLData) { // not in JDBC4.1??? - // do something with: - // ((SQLData)x).writeSQL( [java.sql.SQLOutput] ); - // needs an SQLOutput stream... bit too far away from reality - throw new SQLFeatureNotSupportedException("Operation setObject() with object of type SQLData currently not supported!", "0A000"); + SQLData sx = (SQLData)x; + final int paramnr = parameterIndex; + final String sqltype = sx.getSQLTypeName(); + SQLOutput out = new SQLOutput() { + public void writeString(String x) throws SQLException { + // special situation, this is when a string + // representation is given, but we need to prefix it + // with the actual sqltype the server expects, or we + // will get an error back + setValue( + paramnr, + sqltype + " '" + x.replaceAll("\\\\", "\\\\\\\\").replaceAll("'", "\\\\'") + "'" + ); + } + + public void writeBoolean(boolean x) throws SQLException { + setBoolean(paramnr, x); + } + + public void writeByte(byte x) throws SQLException { + setByte(paramnr, x); + } + + public void writeShort(short x) throws SQLException { + setShort(paramnr, x); + } + + public void writeInt(int x) throws SQLException { + setInt(paramnr, x); + } + + public void writeLong(long x) throws SQLException { + setLong(paramnr, x); + } + + public void writeFloat(float x) throws SQLException { + setFloat(paramnr, x); + } + + public void writeDouble(double x) throws SQLException { + setDouble(paramnr, x); + } + + public void writeBigDecimal(BigDecimal x) throws SQLException { + setBigDecimal(paramnr, x); + } + + public void writeBytes(byte[] x) throws SQLException { + setBytes(paramnr, x); + } + + public void writeDate(java.sql.Date x) throws SQLException { + setDate(paramnr, x); + } + + public void writeTime(java.sql.Time x) throws SQLException { + setTime(paramnr, x); + } + + public void writeTimestamp(Timestamp x) throws SQLException { + setTimestamp(paramnr, x); + } + + public void writeCharacterStream(Reader x) throws SQLException { + setCharacterStream(paramnr, x); + } + + public void writeAsciiStream(InputStream x) throws SQLException { + setAsciiStream(paramnr, x); + } + + public void writeBinaryStream(InputStream x) throws SQLException { + setBinaryStream(paramnr, x); + } + + public void writeObject(SQLData x) throws SQLException { + setObject(paramnr, x); + } + + public void writeRef(Ref x) throws SQLException { + setRef(paramnr, x); + } + + public void writeBlob(Blob x) throws SQLException { + setBlob(paramnr, x); + } + + public void writeClob(Clob x) throws SQLException { + setClob(paramnr, x); + } + + public void writeStruct(Struct x) throws SQLException { + setObject(paramnr, x); + } + + public void writeArray(Array x) throws SQLException { + setArray(paramnr, x); + } + + public void writeURL(URL x) throws SQLException { + setURL(paramnr, x); + } + + public void writeNString(String x) throws SQLException { + setNString(paramnr, x); + } + + public void writeNClob(NClob x) throws SQLException { + setNClob(paramnr, x); + } + + public void writeRowId(RowId x) throws SQLException { + setRowId(paramnr, x); + } + + public void writeSQLXML(SQLXML x) throws SQLException { + setSQLXML(paramnr, x); + } + }; + sx.writeSQL(out); } else { // java Class throw new SQLFeatureNotSupportedException("Operation setObject() with object of type Class currently not supported!", "0A000"); } diff --git a/java/src/nl/cwi/monetdb/jdbc/MonetResultSet.java b/java/src/nl/cwi/monetdb/jdbc/MonetResultSet.java --- a/java/src/nl/cwi/monetdb/jdbc/MonetResultSet.java +++ b/java/src/nl/cwi/monetdb/jdbc/MonetResultSet.java @@ -25,6 +25,8 @@ import java.util.*; import java.math.*; import java.net.*; import java.text.*; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; import nl.cwi.monetdb.mcl.parser.*; /** @@ -1293,9 +1295,17 @@ public class MonetResultSet extends Mone */ public String getColumnClassName(int column) throws SQLException { try { - return getClassForType( - getJavaType(types[column - 1]) - ).getName(); + Class type; + Map map = getStatement().getConnection().getTypeMap(); + if (map.containsKey(types[column - 1])) { + type = (Class)map.get(types[column - 1]); + } else { + type = getClassForType(getJavaType(types[column - 1])); + } + if (type != null) + return type.getName(); + throw new SQLException("column type mapping null: " + + types[column - 1], "M0M03"); } catch (IndexOutOfBoundsException e) { throw new SQLException("No such column " + column, "M1M05"); } @@ -1419,6 +1429,15 @@ public class MonetResultSet extends Mone return getObject(columnIndex, this.getStatement().getConnection().getTypeMap()); } + private boolean classImplementsSQLData(Class cl) { + Class[] cls = cl.getInterfaces(); + for (int i = 0; i < cls.length; i++) { + if (cls[i] == SQLData.class) + return true; + } + return false; + } + /** * Retrieves the value of the designated column in the current row of this * ResultSet object as an Object in the Java programming language. If the @@ -1475,6 +1494,136 @@ public class MonetResultSet extends Mone return getClob(i); } else if (type == Blob.class) { return getBlob(i); + } else if (classImplementsSQLData(type)) { + SQLData x; + try { + Constructor<? extends SQLData> ctor = + ((Class)type).getConstructor(); + x = ctor.newInstance(); + } catch (NoSuchMethodException nsme) { + throw new SQLException(nsme.getMessage(), "M0M27"); + } catch (InstantiationException ie) { + throw new SQLException(ie.getMessage(), "M0M27"); + } catch (IllegalAccessException iae) { + throw new SQLException(iae.getMessage(), "M0M27"); + } catch (IllegalArgumentException ige) { + throw new SQLException(ige.getMessage(), "M0M27"); + } catch (InvocationTargetException ite) { + throw new SQLException(ite.getMessage(), "M0M27"); + } + final int colnum = i; + final boolean valwasnull = wasNull(); + SQLInput input = new SQLInput() { + public String readString() throws SQLException { + return getString(colnum); + } + + public boolean readBoolean() throws SQLException { + return getBoolean(colnum); + } + + public byte readByte() throws SQLException { + return getByte(colnum); + } + + public short readShort() throws SQLException { + return getShort(colnum); + } + + public int readInt() throws SQLException { + return getInt(colnum); + } + + public long readLong() throws SQLException { + return getLong(colnum); + } + + public float readFloat() throws SQLException { + return getFloat(colnum); + } + + public double readDouble() throws SQLException { + return getDouble(colnum); + } + _______________________________________________ checkin-list mailing list checkin-list@monetdb.org http://mail.monetdb.org/mailman/listinfo/checkin-list