diff -r 5a24a24d4111 -r 613c41bada72 src/net/lemnik/eodsql/QueryTool.java --- a/src/net/lemnik/eodsql/QueryTool.java Sat Sep 18 22:46:51 2010 +0200 +++ b/src/net/lemnik/eodsql/QueryTool.java Sat Sep 18 23:22:58 2010 +0200 @@ -22,6 +22,7 @@ import net.lemnik.eodsql.spi.MethodImplementationFactory; import net.lemnik.eodsql.spi.util.DataObjectBinding; +import net.lemnik.eodsql.spi.util.MapDataObjectBinding; /** *

@@ -486,6 +487,118 @@ } /** + *

+ * Sometimes you need to perform a less structured "SELECT" than a Query interface allows. Although this method + * is significantly slower than building a Query interface, it provides needed functionality that a Query + * interface cannot. The returned {@link DataSet} will be connected to the database + * and the Connection will be taken from the {@link #setDefaultDataSource(DataSource) defaultDataSource}. + *

+ * This method does no caching of any sort, and the query will be re-parsed each time it is executed. It however + * provides the same primitive-type abstraction that a Query interface provides you with. The query string is + * parsed in the same way as a query string passed to an {@link Select @Select} annotation. + *

+ * This method is the same as calling select(getDefaultDataSource(), type, query, parameters). + *

+ * + * @param query the SQL query to be executed + * @param parameters the parameters to be used in conjunction with the query string. + * @return a connected {@code DataSet} containing the selected rows + * reflected as a map where each key is one column name + * @see #select(DataSource, Class, String, Object...) + * @throws InvalidQueryException if the query string given cannot + * be parsed, or doesn't match the given parameters + * @throws IllegalStateException is the defaultDataSource has not yet been set + */ + public static DataSet> select( + final String query, + final Object... parameters) + throws InvalidDataTypeException, + InvalidQueryException { + + if(defaultDataSource != null) { + return select(defaultDataSource, + MapDataObjectBinding.getStringObjectMapObjectType(), + query, + parameters); + } else { + throw new IllegalStateException( + "the default DataSource has not been set."); + } + } + + /** + *

+ * Sometimes you need to perform a less structured "SELECT" than a Query interface allows. Although this method + * is significantly slower than building a Query interface, it provides needed functionality that a Query + * interface cannot. The returned {@link DataSet} will be connected to the database + * and the Connection is obtained from the DataSource provided. + *

+ * This method does no caching of any sort, and the query will be re-parsed each time it is executed. It however + * provides the same primitive-type abstraction that a Query interface provides you with. The query string is + * parsed in the same way as a query string passed to an {@link Select @Select} annotation. + *

+ * + * @param dataSource the DataSource to obtain a database connection through + * @param query the SQL query to be executed + * @param parameters the parameters to be used in conjunction + * with the query string. + * @return a connected {@code DataSet} containing the selected rows + * reflected as a map where each key is one column name + * @throws InvalidQueryException if the query string given cannot + * be parsed, or doesn't match the given parameters + * @throws IllegalArgumentException is the DataSource + * provided is null + */ + public static DataSet> select( + final DataSource dataSource, + final String query, + final Object... parameters) + throws InvalidDataTypeException, + InvalidQueryException { + + return select(dataSource, + MapDataObjectBinding.getStringObjectMapObjectType(), + query, + parameters); + } + + /** + *

+ * Sometimes you need to perform a less structured "SELECT" than a Query interface allows. Although this method + * is significantly slower than building a Query interface, it provides needed functionality that a Query + * interface cannot. The returned {@link DataSet} will be connected to the database . + *

+ * This method does no caching of any sort, and the query will be re-parsed each time it is executed. It however + * provides the same primitive-type abstraction that a Query interface provides you with. The query string is + * parsed in the same way as a query string passed to an {@link Select @Select} annotation. + *

+ * + * @param connection the Connection to use to perform the query, closing the + * {@code DataSet} will not close this {@code Connection} + * @param query the SQL query to be executed + * @param parameters the parameters to be used in + * conjunction with the query string. + * @return a connected {@code DataSet} containing the selected rows + * reflected as a map where each key is one column name + * @throws InvalidQueryException if the query string given cannot + * be parsed, or doesn't match the given parameters + * @throws IllegalArgumentException is the DataSource + * provided is null + */ + public static DataSet> select( + final Connection connection, + final String query, + final Object... parameters) + throws InvalidDataTypeException, + InvalidQueryException { + + return select(connection, + MapDataObjectBinding.getStringObjectMapObjectType(), + query, + parameters); + } + + /** *

* Returns the Map that specifies how Java types should * be mapped to SQL types and back again. This Map may be diff -r 5a24a24d4111 -r 613c41bada72 src/net/lemnik/eodsql/spi/util/DataObjectBinding.java --- a/src/net/lemnik/eodsql/spi/util/DataObjectBinding.java Sat Sep 18 22:46:51 2010 +0200 +++ b/src/net/lemnik/eodsql/spi/util/DataObjectBinding.java Sat Sep 18 23:22:58 2010 +0200 @@ -38,6 +38,10 @@ private static Constructor DEFAULT_BINDING_CONSTRUCTOR = null; + static { + setDataObjectBinding(MapDataObjectBinding.getStringObjectMapObjectType(), MapDataObjectBinding.class); + } + /** * An empty array of String's that can be used when there are no key columns * known for the data-object type. This should only be returned when this diff -r 5a24a24d4111 -r 613c41bada72 src/net/lemnik/eodsql/spi/util/MapDataObjectBinding.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/net/lemnik/eodsql/spi/util/MapDataObjectBinding.java Sat Sep 18 23:22:58 2010 +0200 @@ -0,0 +1,177 @@ +package net.lemnik.eodsql.spi.util; + +import java.math.BigDecimal; +import java.sql.Array; +import java.sql.Date; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Time; +import java.sql.Timestamp; +import java.sql.Types; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import net.lemnik.eodsql.EoDException; + +/** + * A {@link DataObjectBinding} that stores the {@link ResultSet} in a + * {@link HashMap}. + * + * @author Bernd Rinn + */ +public class MapDataObjectBinding extends DataObjectBinding> { + @Override + public Class> getObjectType() { + return getStringObjectMapObjectType(); + } + + @SuppressWarnings("unchecked") + public static Class> getStringObjectMapObjectType() { + return (Class>) Collections. emptyMap().getClass(); + } + + @Override + public Map newInstance() throws EoDException { + return new HashMap(); + } + + @Override + public void marshall(Map from, ResultSet results) + throws SQLException, EoDException { + final ResultSetMetaData metaData = results.getMetaData(); + for (Map.Entry entry : from.entrySet()) { + final int i = results.findColumn(entry.getKey()); + final int type = metaData.getColumnType(i); + if (entry.getValue() == null) { + results.updateNull(i); + continue; + } + switch (type) { + case Types.BIT: + case Types.BOOLEAN: + results.updateBoolean(i, (Boolean) entry.getValue()); + break; + case Types.CHAR: + case Types.VARCHAR: + case Types.LONGVARCHAR: + results.updateString(i, entry.getValue().toString()); + break; + case Types.DATE: + results.updateDate(i, new Date(((java.util.Date) entry + .getValue()).getTime())); + break; + case Types.TIME: + results.updateTime(i, new Time(((java.util.Date) entry + .getValue()).getTime())); + break; + case Types.TIMESTAMP: + results.updateTimestamp(i, new Timestamp( + ((java.util.Date) entry.getValue()).getTime())); + break; + case Types.DECIMAL: + case Types.NUMERIC: + results.updateBigDecimal(i, (BigDecimal) entry.getValue()); + break; + case Types.REAL: + results.updateFloat(i, (Float) entry.getValue()); + break; + case Types.DOUBLE: + case Types.FLOAT: + results.updateDouble(i, (Double) entry.getValue()); + break; + case Types.TINYINT: + results.updateByte(i, (Byte) entry.getValue()); + break; + case Types.SMALLINT: + results.updateShort(i, (Short) entry.getValue()); + break; + case Types.INTEGER: + results.updateInt(i, (Integer) entry.getValue()); + break; + case Types.BIGINT: + results.updateLong(i, (Long) entry.getValue()); + break; + case Types.BINARY: + case Types.VARBINARY: + case Types.LONGVARBINARY: + results.updateBytes(i, (byte[]) entry.getValue()); + break; + case Types.JAVA_OBJECT: + results.updateObject(i, entry.getValue()); + break; + case Types.ARRAY: + results.updateArray(i, (Array) entry.getValue()); + break; + } + } + } + + @Override + public void unmarshall(ResultSet row, Map into) + throws SQLException, EoDException { + final ResultSetMetaData metaData = row.getMetaData(); + for (int i = 1; i <= metaData.getColumnCount(); ++i) { + final int type = metaData.getColumnType(i); + final String name = metaData.getColumnName(i); + switch (type) { + case Types.BIT: + case Types.BOOLEAN: + into.put(name, row.getBoolean(i)); + break; + case Types.CHAR: + case Types.VARCHAR: + case Types.LONGVARCHAR: + into.put(name, row.getString(i)); + break; + case Types.DATE: + into.put(name, row.getDate(i)); + break; + case Types.TIME: + into.put(name, row.getTime(i)); + break; + case Types.TIMESTAMP: + into.put(name, row.getTimestamp(i)); + break; + case Types.DECIMAL: + case Types.NUMERIC: + into.put(name, row.getBigDecimal(i)); + break; + case Types.REAL: + into.put(name, row.getFloat(i)); + break; + case Types.DOUBLE: + case Types.FLOAT: + into.put(name, row.getDouble(i)); + break; + case Types.TINYINT: + into.put(name, row.getByte(i)); + break; + case Types.SMALLINT: + into.put(name, row.getShort(i)); + break; + case Types.INTEGER: + into.put(name, row.getInt(i)); + break; + case Types.BIGINT: + into.put(name, row.getLong(i)); + break; + case Types.BINARY: + case Types.VARBINARY: + case Types.LONGVARBINARY: + into.put(name, row.getBytes(i)); + break; + case Types.JAVA_OBJECT: + into.put(name, row.getObject(i)); + break; + case Types.ARRAY: + into.put(name, row.getArray(i)); + break; + } + if (row.wasNull()) { + into.put(name, null); + } + } + } +}