changeset 51:c592d8a72627 embedded

More defensive approach for tables. Only the table name and schema are cached.
author Pedro Ferreira <pedro.ferreira@monetdbsolutions.com>
date Wed, 16 Nov 2016 21:21:26 +0100 (2016-11-16)
parents 3b97ec05f6b1
children 5f12b8a08204
files src/main/java/nl/cwi/monetdb/embedded/env/AbstractConnectionResult.java src/main/java/nl/cwi/monetdb/embedded/env/MonetDBEmbeddedConnection.java src/main/java/nl/cwi/monetdb/embedded/mapping/AbstractColumn.java src/main/java/nl/cwi/monetdb/embedded/mapping/AbstractResultTable.java src/main/java/nl/cwi/monetdb/embedded/mapping/MonetDBEmbeddedBlob.java src/main/java/nl/cwi/monetdb/embedded/mapping/MonetDBRow.java src/main/java/nl/cwi/monetdb/embedded/resultset/QueryResultRowSet.java src/main/java/nl/cwi/monetdb/embedded/resultset/QueryResultSet.java src/main/java/nl/cwi/monetdb/embedded/resultset/QueryResultSetColumn.java src/main/java/nl/cwi/monetdb/embedded/resultset/UpdateResultSet.java src/main/java/nl/cwi/monetdb/embedded/tables/IMonetDBTableBaseIterator.java src/main/java/nl/cwi/monetdb/embedded/tables/IMonetDBTableUpdater.java src/main/java/nl/cwi/monetdb/embedded/tables/MonetDBTable.java src/main/java/nl/cwi/monetdb/embedded/tables/MonetDBTableColumn.java src/main/java/nl/cwi/monetdb/embedded/tables/RowIterator.java src/main/java/nl/cwi/monetdb/embedded/tables/RowRemover.java src/main/java/nl/cwi/monetdb/embedded/tables/RowUpdater.java
diffstat 17 files changed, 416 insertions(+), 286 deletions(-) [+]
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;
 }