Mercurial > hg > monetdb-java
changeset 51:c592d8a72627 embedded
More defensive approach for tables. Only the table name and schema are cached.
line wrap: on
line diff
--- a/src/main/java/nl/cwi/monetdb/embedded/env/AbstractConnectionResult.java +++ b/src/main/java/nl/cwi/monetdb/embedded/env/AbstractConnectionResult.java @@ -22,9 +22,7 @@ public abstract class AbstractConnection */ private final MonetDBEmbeddedConnection connection; - protected AbstractConnectionResult(MonetDBEmbeddedConnection connection) { - this.connection = connection; - } + protected AbstractConnectionResult(MonetDBEmbeddedConnection connection) { this.connection = connection; } /** * Get the corresponding connection to this statement result. @@ -33,8 +31,10 @@ public abstract class AbstractConnection */ public MonetDBEmbeddedConnection getConnection() { return connection; } + protected long getConnectionPointer() { return connection.connectionPointer; } + /** - * To be called by the connection when is closing, to avoid concurrency problems on the iteration. + * To be called by the connection when is closing. */ protected abstract void closeImplementation();
--- a/src/main/java/nl/cwi/monetdb/embedded/env/MonetDBEmbeddedConnection.java +++ b/src/main/java/nl/cwi/monetdb/embedded/env/MonetDBEmbeddedConnection.java @@ -27,7 +27,7 @@ public class MonetDBEmbeddedConnection { private final MonetDBEmbeddedDatabase database; - private final long connectionPointer; + protected final long connectionPointer; private final Set<AbstractConnectionResult> results = new HashSet<>(); @@ -44,7 +44,7 @@ public class MonetDBEmbeddedConnection { */ public String getCurrentSchema() throws MonetDBEmbeddedException { QueryResultSet eqr = this.sendQuery("SELECT current_schema FROM sys.var();"); - QueryResultSetColumn<String> col = eqr.getColumn(0); + QueryResultSetColumn<String> col = eqr.getColumnByIndex(0); String res = col.fetchFirstNColumnValues(1)[0]; eqr.close(); return res;
--- a/src/main/java/nl/cwi/monetdb/embedded/mapping/AbstractColumn.java +++ b/src/main/java/nl/cwi/monetdb/embedded/mapping/AbstractColumn.java @@ -11,59 +11,17 @@ package nl.cwi.monetdb.embedded.mapping; /** * A single Java representation of a MonetDB column. * - * @param <T> A Java class mapped to a MonetDB data type * @author <a href="mailto:pedro.ferreira@monetdbsolutions.com">Pedro Ferreira</a> */ -public abstract class AbstractColumn<T> { - - /** - * The column index on the result set. - */ - protected final int resultSetIndex; - - /** - * The name of the columns in the query result. - */ - protected final String columnName; +public abstract class AbstractColumn { /** * The Mapping between MonetDB type and the Java Class. */ protected final MonetDBToJavaMapping mapping; - /** - * The number of digits (radix 2) for numeric types or max length for character/binary strings. - */ - protected final int columnDigits; - - /** - * The precision after decimal point. Only applicable for decimal/numeric types. - */ - protected final int columnScale; - - protected AbstractColumn(int resultSetIndex, String columnName, String columnType, int columnDigits, - int columnScale) { - this.resultSetIndex = resultSetIndex; - this.columnName = columnName; + protected AbstractColumn(String columnType) { this.mapping = MonetDBToJavaMapping.GetJavaMappingFromMonetDBString(columnType); - this.columnDigits = columnDigits; - this.columnScale = columnScale; - } - - /** - * Gets the result set index of the column. - * - * @return The index number - */ - public int getResultSetIndex() { return resultSetIndex; } - - /** - * Gets the name of the column. - * - * @return The column name - */ - public String getColumnName() { - return columnName; } /** @@ -71,7 +29,7 @@ public abstract class AbstractColumn<T> * * @return The Column type */ - public String getColumnType() { return mapping.toString(); } + public String getColumnInternalTypeName() { return mapping.toString(); } /** * Gets the Java mapping of the column. @@ -81,16 +39,23 @@ public abstract class AbstractColumn<T> public MonetDBToJavaMapping getMapping() { return mapping; } /** + * Gets the name of the column. + * + * @return The column name + */ + public abstract String getColumnName(); + + /** * Gets the number digits of the column. * * @return The number of digits */ - public int getColumnDigits() { return columnDigits; } + public abstract int getColumnDigits(); /** * Gets the scale of the column. * * @return The scale */ - public int getColumnScale() { return columnScale; } + public abstract int getColumnScale(); }
--- a/src/main/java/nl/cwi/monetdb/embedded/mapping/AbstractResultTable.java +++ b/src/main/java/nl/cwi/monetdb/embedded/mapping/AbstractResultTable.java @@ -13,13 +13,6 @@ public abstract class AbstractResultTabl public AbstractResultTable(MonetDBEmbeddedConnection connection) { super(connection); } /** - * Returns an array of columns in the result set. - * - * @return An array of columns in the result set - */ - protected abstract AbstractColumn<?>[] getColumns(); - - /** * Returns the number of columns in the result set. * * @return Number of columns @@ -38,68 +31,33 @@ public abstract class AbstractResultTabl * * @return The columns names array */ - public String[] getColumnNames() { - int i = 0; - String[] result = new String[this.getNumberOfColumns()]; - for(AbstractColumn col : this.getColumns()) { - result[i] = col.getColumnName(); - } - return result; - } + public abstract String[] getColumnNames(); /** * Gets the columns types as a string array. * * @return The columns types array */ - public String[] getColumnTypes() { - int i = 0; - String[] result = new String[this.getNumberOfColumns()]; - for(AbstractColumn col : this.getColumns()) { - result[i] = col.getColumnType(); - } - return result; - } + public abstract String[] getColumnTypes(); /** * Gets the Java mappings as a MonetDBToJavaMapping array. * * @return The columns MonetDBToJavaMapping array */ - public MonetDBToJavaMapping[] getMappings() { - int i = 0; - MonetDBToJavaMapping[] result = new MonetDBToJavaMapping[this.getNumberOfColumns()]; - for(AbstractColumn col : this.getColumns()) { - result[i] = col.getMapping(); - } - return result; - } + public abstract MonetDBToJavaMapping[] getMappings(); /** * Gets the columns digits as an integer array. * * @return The columns digits array */ - public int[] getColumnDigits() { - int i = 0; - int[] result = new int[this.getNumberOfColumns()]; - for(AbstractColumn col : this.getColumns()) { - result[i] = col.getColumnDigits(); - } - return result; - } + public abstract int[] getColumnDigits(); /** * Gets the columns scales as an integer array. * * @return The columns scales array */ - public int[] getColumnScales() { - int i = 0; - int[] result = new int[this.getNumberOfColumns()]; - for(AbstractColumn col :this.getColumns()) { - result[i] = col.getColumnScale(); - } - return result; - } + public abstract int[] getColumnScales(); }
--- a/src/main/java/nl/cwi/monetdb/embedded/mapping/MonetDBEmbeddedBlob.java +++ b/src/main/java/nl/cwi/monetdb/embedded/mapping/MonetDBEmbeddedBlob.java @@ -22,7 +22,7 @@ public class MonetDBEmbeddedBlob impleme * * @return A Java byte array containing the BLOB itself */ - public byte[] getBlob() { return blob; } + public byte[] getBlob() { return this.blob; } /** * Overriding the equals method for the byte array.
--- a/src/main/java/nl/cwi/monetdb/embedded/mapping/MonetDBRow.java +++ b/src/main/java/nl/cwi/monetdb/embedded/mapping/MonetDBRow.java @@ -65,7 +65,7 @@ public class MonetDBRow implements Itera * @param javaClass The Java class * @return The column value as a Java class */ - public <T> T getColumn(int index, Class<T> javaClass) { return javaClass.cast(columns[index]); } + public <T> T getColumnByIndex(int index, Class<T> javaClass) { return javaClass.cast(columns[index]); } /** * Gets a column value as a Java class using the default mapping. @@ -74,7 +74,7 @@ public class MonetDBRow implements Itera * @param index The index of the column * @return The column value as a Java class */ - public <T> T getColumn(int index) { + public <T> T getColumnByIndex(int index) { Class<T> javaClass = this.originalSet.mappings[index].getJavaClass(); return javaClass.cast(columns[index]); } @@ -86,7 +86,7 @@ public class MonetDBRow implements Itera * @param index The index of the column * @param value The value to set */ - public <T> void setColumn(int index, T value) { + public <T> void setColumnByIndex(int index, T value) { this.columns[index] = this.originalSet.mappings[index].getJavaClass().cast(value); } @@ -98,7 +98,7 @@ public class MonetDBRow implements Itera * @param javaClass The Java class * @param value The value to set */ - public <T> void setColumn(int index, Class<T> javaClass, T value) { + public <T> void setColumnByIndex(int index, Class<T> javaClass, T value) { this.columns[index] = javaClass.cast(value); }
--- a/src/main/java/nl/cwi/monetdb/embedded/resultset/QueryResultRowSet.java +++ b/src/main/java/nl/cwi/monetdb/embedded/resultset/QueryResultRowSet.java @@ -71,8 +71,8 @@ public class QueryResultRowSet extends A * @param javaClass The Java class to map * @return The value mapped to a instance of the provided class */ - public <T> T getSingleValue(int row, int column, Class<T> javaClass) { - return javaClass.cast(this.rows[row].getColumn(column)); + public <T> T getSingleValueByIndex(int row, int column, Class<T> javaClass) { + return javaClass.cast(this.rows[row].getColumnByIndex(column)); } /** @@ -83,9 +83,50 @@ public class QueryResultRowSet extends A * @param column The index of the column to retrieve * @return The value mapped to a instance of the provided class */ - public <T> T getSingleValue(int row, int column) { + public <T> T getSingleValueByIndex(int row, int column) { Class<T> javaClass = this.mappings[column].getJavaClass(); - return javaClass.cast(this.rows[row].getColumn(column)); + return javaClass.cast(this.rows[row].getColumnByIndex(column)); + } + + /** + * Gets a single value in this set as a Java class. + * + * @param <T> A Java class mapped to a MonetDB data type + * @param row The index of the row to retrieve + * @param columnName The name of the column to retrieve + * @param javaClass The Java class to map + * @return The value mapped to a instance of the provided class + */ + public <T> T getSingleValueByName(int row, String columnName, Class<T> javaClass) { + String[] colNames = this.getQueryResultSet().getColumnNames(); + int index = 0; + for (String colName : colNames) { + if (columnName.equals(colName)) { + return this.getSingleValueByIndex(row, index, javaClass); + } + index++; + } + throw new ArrayIndexOutOfBoundsException("The column is not present in the result set!"); + } + + /** + * Gets a single value in this set as a Java class using the default mapping. + * + * @param <T> A Java class mapped to a MonetDB data type + * @param row The index of the row to retrieve + * @param columnName The name of the column to retrieve + * @return The value mapped to a instance of the provided class + */ + public <T> T getSingleValueByName(int row, String columnName) { + String[] colNames = this.getQueryResultSet().getColumnNames(); + int index = 0; + for (String colName : colNames) { + if (columnName.equals(colName)) { + return this.getSingleValueByIndex(row, index); + } + index++; + } + throw new ArrayIndexOutOfBoundsException("The column is not present in the result set!"); } /** @@ -97,10 +138,10 @@ public class QueryResultRowSet extends A * @return The value mapped to a instance of the provided class */ @SuppressWarnings("unchecked") - public <T> T[] getColumn(int column, Class<T> javaClass) { + public <T> T[] getColumnByIndex(int column, Class<T> javaClass) { T[] res = (T[]) Array.newInstance(javaClass, this.rows.length); for(int i = 0 ; i < this.rows.length ; i++) { - res[i] = this.rows[i].getColumn(column); + res[i] = this.rows[i].getColumnByIndex(column); } return res; } @@ -113,14 +154,53 @@ public class QueryResultRowSet extends A * @return The value mapped to a instance of the provided class */ @SuppressWarnings("unchecked") - public <T> T[] getColumn(int column) { + public <T> T[] getColumnByIndex(int column) { T[] res = (T[]) Array.newInstance(this.mappings[column].getJavaClass(), this.rows.length); for(int i = 0 ; i < this.rows.length ; i++) { - res[i] = this.rows[i].getColumn(column); + res[i] = this.rows[i].getColumnByIndex(column); } return res; } + /** + * Gets a column in this set as a Java class. + * + * @param <T> A Java class mapped to a MonetDB data type + * @param name The name of the column to retrieve + * @param javaClass The Java class + * @return The value mapped to a instance of the provided class + */ + public <T> T[] getColumnByName(String name, Class<T> javaClass) { + String[] colNames = this.getQueryResultSet().getColumnNames(); + int index = 0; + for (String colName : colNames) { + if (name.equals(colName)) { + return this.getColumnByIndex(index, javaClass); + } + index++; + } + throw new ArrayIndexOutOfBoundsException("The column is not present in the result set!"); + } + + /** + * Gets a column in this set as a Java class using the default mapping. + * + * @param <T> A Java class mapped to a MonetDB data type + * @param name The name of the column to retrieve + * @return The value mapped to a instance of the provided class + */ + public <T> T[] getColumnByName(String name) { + String[] colNames = this.getQueryResultSet().getColumnNames(); + int index = 0; + for (String colName : colNames) { + if (name.equals(colName)) { + return this.getColumnByIndex(index); + } + index++; + } + throw new ArrayIndexOutOfBoundsException("The column is not present in the result set!"); + } + @Override public ListIterator<MonetDBRow> iterator() { return Arrays.asList(this.rows).listIterator(); } }
--- a/src/main/java/nl/cwi/monetdb/embedded/resultset/QueryResultSet.java +++ b/src/main/java/nl/cwi/monetdb/embedded/resultset/QueryResultSet.java @@ -8,11 +8,11 @@ package nl.cwi.monetdb.embedded.resultset; -import nl.cwi.monetdb.embedded.mapping.AbstractColumn; import nl.cwi.monetdb.embedded.mapping.AbstractResultTable; import nl.cwi.monetdb.embedded.env.MonetDBEmbeddedConnection; import nl.cwi.monetdb.embedded.env.MonetDBEmbeddedException; import nl.cwi.monetdb.embedded.mapping.MonetDBRow; +import nl.cwi.monetdb.embedded.mapping.MonetDBToJavaMapping; import java.util.Arrays; import java.util.ListIterator; @@ -28,11 +28,9 @@ import java.util.ListIterator; public class QueryResultSet extends AbstractResultTable implements Iterable { /** - * Pointer to the native result set. - * We need to keep it around for getting columns. - * The native result set is kept until the the close method is called. + * The table C pointer. */ - protected long resultPointer; + protected long tablePointer; /** * The query result set columns listing. @@ -44,63 +42,105 @@ public class QueryResultSet extends Abst */ protected final int numberOfRows; - protected QueryResultSet(MonetDBEmbeddedConnection connection, long resultPointer, - QueryResultSetColumn<?>[] columns, int numberOfRows) { + protected QueryResultSet(MonetDBEmbeddedConnection connection, long tablePointer, QueryResultSetColumn<?>[] columns, + int numberOfRows) { super(connection); - this.resultPointer = resultPointer; + this.tablePointer = tablePointer; this.numberOfRows = numberOfRows; this.columns = columns; } - /** - * Closes the query data so no more new results can be retrieved. - */ - @Override - public void closeImplementation() { - this.cleanupResultInternal(this.resultPointer); - this.resultPointer = 0; - } - - @Override - protected AbstractColumn<?>[] getColumns() { return columns; } - @Override public int getNumberOfRows() { return this.numberOfRows; } @Override public int getNumberOfColumns() { return this.columns.length; } + @Override + protected void closeImplementation() { this.cleanResultSet(this.tablePointer); } + + @Override + public String[] getColumnNames() { + int i = 0; + String[] result = new String[this.getNumberOfColumns()]; + for(QueryResultSetColumn col : this.columns) { + result[i] = col.getColumnName(); + } + return result; + } + + @Override + public String[] getColumnTypes() { + int i = 0; + String[] result = new String[this.getNumberOfColumns()]; + for(QueryResultSetColumn col : this.columns) { + result[i] = col.getColumnInternalTypeName(); + } + return result; + } + + @Override + public MonetDBToJavaMapping[] getMappings() { + int i = 0; + MonetDBToJavaMapping[] result = new MonetDBToJavaMapping[this.getNumberOfColumns()]; + for(QueryResultSetColumn col : this.columns) { + result[i] = col.getMapping(); + } + return result; + } + + @Override + public int[] getColumnDigits() { + int i = 0; + int[] result = new int[this.getNumberOfColumns()]; + for(QueryResultSetColumn col : this.columns) { + result[i] = col.getColumnDigits(); + } + return result; + } + + @Override + public int[] getColumnScales() { + int i = 0; + int[] result = new int[this.getNumberOfColumns()]; + for(QueryResultSetColumn col : this.columns) { + result[i] = col.getColumnScale(); + } + return result; + } + /** * Tells if the connection of this statement result has been closed or not. * * @return A boolean indicating if the statement result has been cleaned or not */ - public boolean isStatementClosed() { return this.resultPointer == 0; } + public boolean isStatementClosed() { return this.tablePointer == 0; } /** * Gets a column from the result set by index. * * @param index QueryResultSetColumn index (starting from 0) - * @return The columns, {@code null} if index not in bounds + * @return The column */ @SuppressWarnings("unchecked") - public <T> QueryResultSetColumn<T> getColumn(int index) { return (QueryResultSetColumn<T>) columns[index]; } + public <T> QueryResultSetColumn<T> getColumnByIndex(int index) { return (QueryResultSetColumn<T>) columns[index]; } /** * Gets a column from the result set by name. * * @param name QueryResultSetColumn name - * @return The columns + * @return The column */ - public <T> QueryResultSetColumn<T> getColumn(String name) { + @SuppressWarnings("unchecked") + public <T> QueryResultSetColumn<T> getColumnByName(String name) { int index = 0; - for (AbstractColumn col : this.columns) { + for (QueryResultSetColumn col : this.columns) { if (col.getColumnName().equals(name)) { - return this.getColumn(index); + return (QueryResultSetColumn<T>) this.columns[index]; } index++; } - throw new ArrayIndexOutOfBoundsException("The columns is not present in the result set!"); + throw new ArrayIndexOutOfBoundsException("The column is not present in the result set!"); } /** @@ -198,8 +238,5 @@ public class QueryResultSet extends Abst } } - /** - * Internal implementation to clean the result set. - */ - private native void cleanupResultInternal(long resultPointer); + private native void cleanResultSet(long tablePointer); }
--- a/src/main/java/nl/cwi/monetdb/embedded/resultset/QueryResultSetColumn.java +++ b/src/main/java/nl/cwi/monetdb/embedded/resultset/QueryResultSetColumn.java @@ -21,18 +21,26 @@ import java.util.ListIterator; * @param <T> A Java class mapped to a MonetDB data type * @author <a href="mailto:pedro.ferreira@monetdbsolutions.com">Pedro Ferreira</a> */ -public class QueryResultSetColumn<T> extends AbstractColumn<T> implements Iterable<T> { +public class QueryResultSetColumn<T> extends AbstractColumn implements Iterable<T> { /** - * The C pointer of the result set of the column. + * Internal C pointer of the column, */ - protected final long resultSetPointer; + protected long tablePointer; /** * Array with the retrieved values. */ private final T[] values; + private final int resultSetIndex; + + private final String columnName; + + private final int columnDigits; + + private final int columnScale; + /** * The number of rows in this column. */ @@ -49,22 +57,36 @@ public class QueryResultSetColumn<T> ext private int lastRetrievedIndex; @SuppressWarnings("unchecked") - protected QueryResultSetColumn(int resultSetIndex, String columnName, String columnType, int columnDigits, - int columnScale, long resultSetPointer, int numberOfRows) { - super(resultSetIndex, columnName, columnType, columnDigits, columnScale); - this.resultSetPointer = resultSetPointer; + protected QueryResultSetColumn(String columnType, long tablePointer, int resultSetIndex, String columnName, int columnDigits, int columnScale, int numberOfRows) { + super(columnType); + this.tablePointer = tablePointer; + this.resultSetIndex = resultSetIndex; + this.columnName = columnName; + this.columnDigits = columnDigits; + this.columnScale = columnScale; this.numberOfRows = numberOfRows; this.firstRetrievedIndex = numberOfRows; this.lastRetrievedIndex = 0; this.values = (T[]) Array.newInstance(this.mapping.getJavaClass(), numberOfRows); } + @Override + public String getColumnName() { return this.columnName; } + + @Override + public int getColumnDigits() { return this.columnDigits; } + + @Override + public int getColumnScale() { return this.columnScale; } + /** * Get the number of rows in this column. * * @return The number of rows */ - public int getNumberOfRows() { return numberOfRows; } + public int getNumberOfRows() { return this.numberOfRows; } + + public int getResultSetIndex() { return resultSetIndex; } /** * Maps columns values into the Java representation. @@ -103,10 +125,10 @@ public class QueryResultSetColumn<T> ext hasToConvert = true; } if(hasToConvert) { - if(this.resultSetPointer == 0) { + if(this.tablePointer == 0) { throw new MonetDBEmbeddedException("Connection closed!"); } - T[] newvalues = this.fetchValuesInternal(this.resultSetPointer, this.resultSetIndex, + T[] newvalues = this.fetchValuesInternal(this.tablePointer, this.resultSetIndex, (Class<T>) this.mapping.getJavaClass(), this.mapping.ordinal(), firstIndexToFetch, lastIndexToFetch); System.arraycopy(newvalues, 0, this.values, firstIndexToFetch, newvalues.length); } @@ -255,6 +277,6 @@ public class QueryResultSetColumn<T> ext /** * Internal implementation to fetch values from the column. */ - private native T[] fetchValuesInternal(long resultPointer, int resultSetIndex, Class<T> jclass, int enumEntry, - int first, int last) throws MonetDBEmbeddedException; + private native T[] fetchValuesInternal(long tablePointer, int resultSetIndex, Class<T> jclass, int javaIndex, int first, int last) + throws MonetDBEmbeddedException; }
--- a/src/main/java/nl/cwi/monetdb/embedded/resultset/UpdateResultSet.java +++ b/src/main/java/nl/cwi/monetdb/embedded/resultset/UpdateResultSet.java @@ -23,5 +23,6 @@ public class UpdateResultSet extends Abs /** * Close this result set. */ + @Override public void closeImplementation() {} }
--- a/src/main/java/nl/cwi/monetdb/embedded/tables/IMonetDBTableBaseIterator.java +++ b/src/main/java/nl/cwi/monetdb/embedded/tables/IMonetDBTableBaseIterator.java @@ -8,7 +8,7 @@ package nl.cwi.monetdb.embedded.tables; public interface IMonetDBTableBaseIterator { /** - * Specify the first row in the table to iterate. If a negative number is provided, then the iteration + * Specify the first row in the table to iterate starting from 1. If a lower number is provided, then the iteration * will start on the first row. * * @return The first row in the table to iterate @@ -16,8 +16,8 @@ public interface IMonetDBTableBaseIterat int getFirstRowToIterate(); /** - * Specify the last row in the table to iterate. If a negative number or a number larger than the number of rows - * is provided, then the iteration will end on the last row of the table. + * Specify the last row in the table to iterate. If a number larger than the number of rows is provided, then the + * iteration will end on the last row of the table. * * @return The last row in the table to iterate */
--- a/src/main/java/nl/cwi/monetdb/embedded/tables/IMonetDBTableUpdater.java +++ b/src/main/java/nl/cwi/monetdb/embedded/tables/IMonetDBTableUpdater.java @@ -9,7 +9,7 @@ public interface IMonetDBTableUpdater ex /** * The business logic for the iterator. Use the - * {@link nl.cwi.monetdb.embedded.tables.RowUpdater#updateColumn(int, Object) setColumn} + * {@link nl.cwi.monetdb.embedded.tables.RowUpdater#updateColumnByIndex(int, Class, Object)} * method in <code>processNextRow</code> to update the current row. * * @param nextRow The next row in the iteration.
--- a/src/main/java/nl/cwi/monetdb/embedded/tables/MonetDBTable.java +++ b/src/main/java/nl/cwi/monetdb/embedded/tables/MonetDBTable.java @@ -1,10 +1,10 @@ package nl.cwi.monetdb.embedded.tables; import nl.cwi.monetdb.embedded.env.MonetDBEmbeddedException; -import nl.cwi.monetdb.embedded.mapping.AbstractColumn; import nl.cwi.monetdb.embedded.mapping.AbstractResultTable; import nl.cwi.monetdb.embedded.env.MonetDBEmbeddedConnection; import nl.cwi.monetdb.embedded.mapping.MonetDBRow; +import nl.cwi.monetdb.embedded.mapping.MonetDBToJavaMapping; import nl.cwi.monetdb.embedded.resultset.QueryResultSet; import nl.cwi.monetdb.embedded.resultset.QueryResultSetColumn; @@ -16,66 +16,21 @@ import nl.cwi.monetdb.embedded.resultset */ public class MonetDBTable extends AbstractResultTable { - /** - * The table's schema. - */ - private final String schemaName; + private final String tableSchema; - /** - * The table's name. - */ private final String tableName; - /** - * The table's columns. - */ - private final MonetDBTableColumn<?>[] columns; - - /** - * The connection's C pointer. - */ - private long connectionPointer; - - /** - * These arrays are used for table imports. - */ - private final int[] columnsJavaIndexes; - private final int[] columnsMonetDBIndexes; - private final String[] columnsNames; - private final Class[] columnsClasses; - - public MonetDBTable(MonetDBEmbeddedConnection connection, long connectionPointer, String schemaName, - String tableName, MonetDBTableColumn<?>[] columns) { + protected MonetDBTable(MonetDBEmbeddedConnection connection, String tableSchema, String tableName) { super(connection); - this.connectionPointer = connectionPointer; - this.schemaName = schemaName; + this.tableSchema = tableSchema; this.tableName = tableName; - this.columns = columns; - this.columnsJavaIndexes = new int[columns.length]; - this.columnsMonetDBIndexes = new int[columns.length]; - this.columnsNames = new String[columns.length]; - this.columnsClasses = new Class[columns.length]; - int i = 0; - for(MonetDBTableColumn col : this.columns) { - this.columnsJavaIndexes[i] = col.getMapping().ordinal(); - this.columnsMonetDBIndexes[i] = col.getInternalMonetDBTypeIndex(); - this.columnsNames[i] = col.getColumnName(); - this.columnsClasses[i] = col.getMapping().getJavaClass(); - i++; - } } @Override - protected void closeImplementation() { this.connectionPointer = 0; } - - @Override - protected AbstractColumn<?>[] getColumns() { return this.columns; } - - @Override - public int getNumberOfColumns() { return this.columns.length; } + public native int getNumberOfColumns(); /** - * Gets the current number of rows in the table, or -1 if an error in the database has ocurred. + * Gets the current number of rows in the table, or -1 if an error in the database has occurred. * * @return The number of rows in the table. */ @@ -83,9 +38,9 @@ public class MonetDBTable extends Abstra public int getNumberOfRows() { int res; try { - String query = "SELECT COUNT(*) FROM " + this.schemaName + "." + this.tableName + ";"; + String query = "SELECT COUNT(*) FROM " + this.getTableSchema() + "." + this.getTableName() + ";"; QueryResultSet eqr = this.getConnection().sendQuery(query); - QueryResultSetColumn<Long> eqc = eqr.getColumn(0); + QueryResultSetColumn<Long> eqc = eqr.getColumnByIndex(0); res = eqc.fetchFirstNColumnValues(1)[0].intValue(); eqr.close(); } catch (MonetDBEmbeddedException ex) { @@ -94,47 +49,71 @@ public class MonetDBTable extends Abstra return res; } + @Override + public native String[] getColumnNames(); + + @Override + public native String[] getColumnTypes(); + + @Override + public native MonetDBToJavaMapping[] getMappings(); + + @Override + public native int[] getColumnDigits(); + + @Override + public native int[] getColumnScales(); + /** * Gets the table schema name. * * @return The table schema name */ - public String getSchemaName() { return schemaName; } + public String getTableSchema() { return this.tableSchema; } /** * Gets the table name. * * @return The table name */ - public String getTableName() { return tableName; } + public String getTableName() { return this.tableName; } /** * Gets the columns nullable indexes as an array. * * @return The columns nullable indexes as an array */ - public boolean[] getColumnNullableIndexes() { - int i = 0; - boolean[] result = new boolean[this.getNumberOfColumns()]; - for(MonetDBTableColumn col : this.columns) { - result[i] = col.isNullable(); - } - return result; - } + public native boolean[] getColumnNullableIndexes(); /** * Gets the columns default values in an array. * * @return The columns default values in an array */ - public String[] getColumnDefaultValues() { - int i = 0; - String[] result = new String[this.getNumberOfColumns()]; - for(MonetDBTableColumn col : this.columns) { - result[i] = col.getDefaultValue(); - } - return result; - } + public native String[] getColumnDefaultValues(); + + /** + * Gets a column metadata by index. + * + * @param index The column index (starting from 0) + * @return The column metadata, {@code null} if index not in bounds + */ + public native MonetDBTableColumn getColumnMetadataByIndex(int index); + + /** + * Gets a column metadata by name. + * + * @param name The column name + * @return The column metadata, {@code null} if not found + */ + public native MonetDBTableColumn getColumnMetadataByName(String name); + + /** + * Gets all columns metadata. + * + * @return An array instance of columns metadata + */ + public native MonetDBTableColumn[] getAllColumnsMetadata(); /** * Private method to check the limits of iteration. @@ -142,7 +121,7 @@ public class MonetDBTable extends Abstra * @param iterator The iterator to check * @return An integer array with the limits fixed */ - private int[] checkIterator(IMonetDBTableBaseIterator iterator) { + private int[] prepareIterator(IMonetDBTableBaseIterator iterator) { int[] res = {iterator.getFirstRowToIterate(), iterator.getLastRowToIterate()}; if(res[1] < res[0]) { int aux = res[0]; @@ -167,9 +146,9 @@ public class MonetDBTable extends Abstra * @throws MonetDBEmbeddedException If an error in the database occurred */ public int iterateTable(IMonetDBTableCursor cursor) throws MonetDBEmbeddedException { - int[] limits = this.checkIterator(cursor); + int[] limits = this.prepareIterator(cursor); int res = 0, total = limits[1] - limits[0] + 1; - String query = new StringBuffer("SELECT * FROM ").append(this.schemaName).append(".").append(this.tableName) + String query = new StringBuffer("SELECT * FROM ").append(this.getTableSchema()).append(".").append(this.getTableName()) .append(" LIMIT ").append(total).append(" OFFSET ").append(limits[0] - 1).append(";").toString(); QueryResultSet eqr = this.getConnection().sendQuery(query); @@ -209,7 +188,7 @@ public class MonetDBTable extends Abstra * @throws MonetDBEmbeddedException If an error in the database occurred */ /*public int updateRows(IMonetDBTableUpdater updater) throws MonetDBEmbeddedException { - int[] limits = this.checkIterator(updater); + int[] limits = this.prepareIterator(updater); RowUpdater ru = this.getRowUpdaterInternal(this.connectionPointer, this.schemaName, this.tableName, limits[0], limits[1]); while(ru.tryContinueIteration()) { @@ -239,7 +218,7 @@ public class MonetDBTable extends Abstra * @throws MonetDBEmbeddedException If an error in the database occurred */ /*public int removeRows(IMonetDBTableRemover remover) throws MonetDBEmbeddedException { - int[] limits = this.checkIterator(remover); + int[] limits = this.prepareIterator(remover); RowRemover rr = this.getRowRemoverInternal(this.connectionPointer, this.schemaName, this.tableName, limits[0], limits[1]); while(rr.tryContinueIteration()) { @@ -285,23 +264,23 @@ public class MonetDBTable extends Abstra * {@link nl.cwi.monetdb.embedded.tables.MonetDBTable#appendColumns(Object[][]) appendColumns} is preferable * over this one. * - * @param rows An array of rows to append + * @param data An array of rows to append * @return The number of rows appended * @throws MonetDBEmbeddedException If an error in the database occurred */ - public int appendRows(Object[][] rows) throws MonetDBEmbeddedException { - int numberOfRows = rows.length, numberOfColumns = this.getNumberOfColumns(); + public int appendRows(Object[][] data) throws MonetDBEmbeddedException { + int numberOfRows = data.length, numberOfColumns = this.getNumberOfColumns(); if(numberOfRows == 0) { throw new ArrayStoreException("Appending 0 rows?"); } Object[][] transposed = new Object[numberOfColumns][numberOfRows]; for (int i = 0; i < numberOfRows; i++) { - if(rows[i].length != numberOfColumns) { + if(data[i].length != numberOfColumns) { throw new ArrayStoreException("The values array at row " + i + " differs from the number of columns!"); } for (int j = 0; j < numberOfColumns; j++) { - transposed[j][i] = rows[i][j]; + transposed[j][i] = data[i][j]; } } return this.appendColumns(transposed); @@ -322,25 +301,31 @@ public class MonetDBTable extends Abstra * Appends new rows to the table column-wise. As MonetDB's storage is column-wise, this method is preferable over * {@link nl.cwi.monetdb.embedded.tables.MonetDBTable#appendRows(Object[][]) appendRows} method. * - * @param columns An array of columns to append + * @param data An array of columns to append * @return The number of rows appended * @throws MonetDBEmbeddedException If an error in the database occurred */ - public int appendColumns(Object[][] columns) throws MonetDBEmbeddedException { - int numberOfRows = columns[0].length, numberOfColumns = this.getNumberOfColumns(); - if (columns.length != numberOfColumns) { + public int appendColumns(Object[][] data) throws MonetDBEmbeddedException { + MonetDBToJavaMapping[] mappings = this.getMappings(); + int numberOfRowsToInsert = data[0].length, numberOfColumns = mappings.length; + if (data.length != numberOfColumns) { throw new ArrayStoreException("The number of columns differs from the table's number of columns!"); } - if(numberOfRows == 0) { + if(numberOfRowsToInsert == 0) { throw new ArrayStoreException("Appending 0 rows?"); } for (int i = 0; i < numberOfColumns; i++) { - if(columns[i].length != numberOfRows) { + if(data[i].length != numberOfRowsToInsert) { throw new ArrayStoreException("The number of rows in each column is not consistent!"); } } - return this.appendColumnsInternal(this.connectionPointer, this.schemaName, this.tableName, this.columnsJavaIndexes, - this.columnsMonetDBIndexes, this.columnsNames, this.columnsClasses, columns); + Class[] jClasses = new Class[mappings.length]; + int[] javaIndexes = new int[mappings.length]; + for (int i = 0; i < mappings.length; i++) { + jClasses[i] = mappings[i].getJavaClass(); + javaIndexes[i] = mappings[i].ordinal(); + } + return this.appendColumnsInternal(jClasses, javaIndexes, data, numberOfRowsToInsert); } /** @@ -360,11 +345,9 @@ public class MonetDBTable extends Abstra /*private native int truncateTableInternal(long connectionPointer, String schemaName, String tableName) throws MonetDBEmbeddedException;*/ - /** - * Internal implementation of columns insertion. - */ - private native int appendColumnsInternal(long connectionPointer, String schemaName, String tableName, - int[] javaindexes, int[] monetDBindexes, String[] columnsNames, - Class[] classes, Object[][] columns) + @Override + protected void closeImplementation() {} + + private native int appendColumnsInternal(Class[] jClasses, int[] javaIndexes, Object[][] data, int numberOfRows) throws MonetDBEmbeddedException; }
--- a/src/main/java/nl/cwi/monetdb/embedded/tables/MonetDBTableColumn.java +++ b/src/main/java/nl/cwi/monetdb/embedded/tables/MonetDBTableColumn.java @@ -7,44 +7,48 @@ import nl.cwi.monetdb.embedded.mapping.A * * @author <a href="mailto:pedro.ferreira@monetdbsolutions.com">Pedro Ferreira</a> */ -public class MonetDBTableColumn<T> extends AbstractColumn<T> { +public class MonetDBTableColumn extends AbstractColumn { + + private final String columnName; - /** - * A String representation of the default value if exists, otherwise is null. - */ + private final int columnDigits; + + private final int columnScale; + private final String defaultValue; - /** - * A boolean indication if the column is nullable. - */ private final boolean isNullable; - /** - * Internal MonetDB index of the column. - */ - private final int internalMonetDBTypeIndex; - - public MonetDBTableColumn(int resultSetIndex, String columnName, String columnType, int columnDigits, - int columnScale, String defaultValue, boolean isNullable, int internalMonetDBTypeIndex) { - super(resultSetIndex, columnName, columnType, columnDigits, columnScale); + protected MonetDBTableColumn(String columnType, String columnName, int columnDigits, int columnScale, + String defaultValue, boolean isNullable) { + super(columnType); + this.columnName = columnName; + this.columnDigits = columnDigits; + this.columnScale = columnScale; this.defaultValue = defaultValue; this.isNullable = isNullable; - this.internalMonetDBTypeIndex = internalMonetDBTypeIndex; } + @Override + public String getColumnName() { return this.columnName; } + + @Override + public int getColumnDigits() { return this.columnDigits; } + + @Override + public int getColumnScale() { return this.columnScale; } + /** * Get the default value if there is one, or null if none. * * @return The default value if there is one, or null if none */ - public String getDefaultValue() { return defaultValue; } + public String getDefaultValue() { return this.defaultValue; } /** * Get the indication if the column is nullable. * * @return The indication if the column is nullable */ - public boolean isNullable() { return isNullable; } - - protected int getInternalMonetDBTypeIndex() { return internalMonetDBTypeIndex; } + public boolean isNullable() { return this.isNullable; } }
--- a/src/main/java/nl/cwi/monetdb/embedded/tables/RowIterator.java +++ b/src/main/java/nl/cwi/monetdb/embedded/tables/RowIterator.java @@ -96,8 +96,8 @@ public class RowIterator extends Abstrac * @param javaClass The Java class * @return The column value as a Java class */ - public <T> T getColumn(int index, Class<T> javaClass) { - return javaClass.cast(this.getCurrentRow().getColumn(index, javaClass)); + public <T> T getColumnByIndex(int index, Class<T> javaClass) { + return javaClass.cast(this.getCurrentRow().getColumnByIndex(index, javaClass)); } /** @@ -107,9 +107,48 @@ public class RowIterator extends Abstrac * @param index The index of the column * @return The column value as a Java class */ - public <T> T getColumn(int index) { + public <T> T getColumnByIndex(int index) { Class<T> javaClass = this.mappings[index].getJavaClass(); - return javaClass.cast(this.getCurrentRow().getColumn(index)); + return javaClass.cast(this.getCurrentRow().getColumnByIndex(index)); + } + + /** + * Gets a column value as a Java class. + * + * @param <T> A Java class mapped to a MonetDB data type + * @param name The name of the column + * @param javaClass The Java class + * @return The column value as a Java class + */ + public <T> T getColumnByName(String name, Class<T> javaClass) { + String[] colNames = this.getTable().getColumnNames(); + int index = 0; + for (String colName : colNames) { + if (name.equals(colName)) { + return this.getColumnByIndex(index, javaClass); + } + index++; + } + throw new ArrayIndexOutOfBoundsException("The column is not present in the result set!"); + } + + /** + * Gets a column value as a Java class using the default mapping. + * + * @param <T> A Java class mapped to a MonetDB data type + * @param name The name of the column + * @return The column value as a Java class + */ + public <T> T getColumnByName(String name) { + String[] colNames = this.getTable().getColumnNames(); + int index = 0; + for (String colName : colNames) { + if (name.equals(colName)) { + return this.getColumnByIndex(index); + } + index++; + } + throw new ArrayIndexOutOfBoundsException("The column is not present in the result set!"); } /**
--- a/src/main/java/nl/cwi/monetdb/embedded/tables/RowRemover.java +++ b/src/main/java/nl/cwi/monetdb/embedded/tables/RowRemover.java @@ -38,5 +38,5 @@ public class RowRemover extends RowItera * * @return The number of rows deleted */ - protected native int submitDeletes() throws MonetDBEmbeddedException; + //protected native int submitDeletes() throws MonetDBEmbeddedException; }
--- a/src/main/java/nl/cwi/monetdb/embedded/tables/RowUpdater.java +++ b/src/main/java/nl/cwi/monetdb/embedded/tables/RowUpdater.java @@ -28,8 +28,8 @@ public class RowUpdater extends RowItera * @param index The index of the column * @param value The value to set */ - public <T> void updateColumn(int index, T value) { - this.getCurrentRow().setColumn(index, value); + public <T> void updateColumnByIndex(int index, T value) { + this.getCurrentRow().setColumnByIndex(index, value); this.updatedIndexes[this.getCurrentIterationNumber()][index] = true; } @@ -41,12 +41,53 @@ public class RowUpdater extends RowItera * @param javaClass The Java class * @param value The value to set */ - public <T> void updateColumn(int index, Class<T> javaClass, T value) { - this.getCurrentRow().setColumn(index, javaClass, value); + public <T> void updateColumnByIndex(int index, Class<T> javaClass, T value) { + this.getCurrentRow().setColumnByIndex(index, javaClass, value); this.updatedIndexes[this.getCurrentIterationNumber()][index] = true; } /** + * Updates a column value. + * + * @param <T> A Java class mapped to a MonetDB data type + * @param name The name of the column + * @param value The value to set + */ + public <T> void updateColumnByName(String name, T value) { + String[] colNames = this.getTable().getColumnNames(); + int index = 0; + for (String colName : colNames) { + if (name.equals(colName)) { + this.updateColumnByIndex(index, value); + return; + } + index++; + } + throw new ArrayIndexOutOfBoundsException("The column is not present in the result set!"); + } + + /** + * Updates a column value. + * + * @param <T> A Java class mapped to a MonetDB data type + * @param name The name of the column + * @param javaClass The Java class + * @param value The value to set + */ + public <T> void updateColumnByName(String name, Class<T> javaClass, T value) { + String[] colNames = this.getTable().getColumnNames(); + int index = 0; + for (String colName : colNames) { + if (name.equals(colName)) { + this.updateColumnByIndex(index, javaClass, value); + return; + } + index++; + } + throw new ArrayIndexOutOfBoundsException("The column is not present in the result set!"); + } + + /** * Updates all column values. * * @param values The values to set @@ -84,5 +125,5 @@ public class RowUpdater extends RowItera * * @return The number of rows updated */ - protected native int submitUpdates() throws MonetDBEmbeddedException; + //protected native int submitUpdates() throws MonetDBEmbeddedException; }