changeset 42:dfea8468cd1a embedded

Finished Java code for CRUD operations on tables and the documentation.
author Pedro Ferreira <pedro.ferreira@monetdbsolutions.com>
date Tue, 08 Nov 2016 14:57:26 +0100 (2016-11-08)
parents 3a19ebf83af6
children 2ab2b21cf930
files src/main/java/nl/cwi/monetdb/embedded/env/MonetDBEmbeddedConnection.java src/main/java/nl/cwi/monetdb/embedded/env/MonetDBEmbeddedDatabase.java src/main/java/nl/cwi/monetdb/embedded/env/MonetDBEmbeddedException.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/MonetDBToJavaMapping.java src/main/java/nl/cwi/monetdb/embedded/resultset/EmbeddedPreparedStatement.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/QueryResultSetRows.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/IMonetDBTableIterator.java src/main/java/nl/cwi/monetdb/embedded/tables/IMonetDBTableRemover.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 src/main/java/nl/cwi/monetdb/embedded/utils/StringEscaper.java
diffstat 22 files changed, 534 insertions(+), 182 deletions(-) [+]
line wrap: on
line diff
--- a/src/main/java/nl/cwi/monetdb/embedded/env/MonetDBEmbeddedConnection.java
+++ b/src/main/java/nl/cwi/monetdb/embedded/env/MonetDBEmbeddedConnection.java
@@ -8,10 +8,10 @@
 
 package nl.cwi.monetdb.embedded.env;
 
-import nl.cwi.monetdb.embedded.resultset.EmbeddedPreparedStatement;
-import nl.cwi.monetdb.embedded.resultset.QueryResultSet;
-import nl.cwi.monetdb.embedded.resultset.QueryResultSetColumn;
-import nl.cwi.monetdb.embedded.resultset.UpdateResultSet;
+import nl.cwi.monetdb.embedded.resultset.*;
+import nl.cwi.monetdb.embedded.tables.MonetDBTable;
+import nl.cwi.monetdb.embedded.tables.MonetDBTableColumn;
+import nl.cwi.monetdb.embedded.utils.StringEscaper;
 
 import java.util.HashSet;
 import java.util.Set;
@@ -44,7 +44,7 @@ public class MonetDBEmbeddedConnection {
      * @throws MonetDBEmbeddedException If an error in the database occurred
      */
     public String getCurrentSchema() throws MonetDBEmbeddedException {
-        QueryResultSet eqr = this.sendQuery("select current_schema from sys.var();");
+        QueryResultSet eqr = this.sendQuery("SELECT current_schema FROM sys.var();");
         QueryResultSetColumn<String> col = eqr.getColumn(0);
         String res = col.fetchFirstNColumnValues(1)[0];
         eqr.close();
@@ -54,12 +54,12 @@ public class MonetDBEmbeddedConnection {
     /**
      * Sets the current schema on the connection.
      *
-     * @param currentSchema Java String with the name of the schema
+     * @param newSchema Java String with the name of the schema
      * @throws MonetDBEmbeddedException If an error in the database occurred
      */
-    public void setCurrentSchema(String currentSchema) throws MonetDBEmbeddedException {
-        String valueToSubmit = "'" + currentSchema.replaceAll("\\\\", "\\\\\\\\").replaceAll("'", "\\\\'") + "';";
-        this.sendUpdate("SET SCHEMA " + valueToSubmit).close();
+    public void setCurrentSchema(String newSchema) throws MonetDBEmbeddedException {
+        newSchema = StringEscaper.SQLStringEscape(newSchema);
+        this.sendUpdate("SET SCHEMA " + newSchema + ";").close();
     }
 
     /**
@@ -152,12 +152,12 @@ public class MonetDBEmbeddedConnection {
      * @return An instance of EmbeddedPreparedStatement
      * @throws MonetDBEmbeddedException If an error in the database occurred
      */
-    public EmbeddedPreparedStatement createPreparedStatement(String query) throws MonetDBEmbeddedException {
+    /*public EmbeddedPreparedStatement createPreparedStatement(String query) throws MonetDBEmbeddedException {
         if (!query.endsWith(";")) {
             query += ";";
         }
         return this.createPreparedStatementInternal(this.connectionPointer, query);
-    }
+    }*/
 
     /**
      * Creates a prepared query statement likewise the PreparedStatement in JDBC asynchronously.
@@ -171,13 +171,56 @@ public class MonetDBEmbeddedConnection {
         throw new UnsupportedOperationException("Must wait for Java 8 :(");
     }*/
 
-    /*public MonetDBTable getMonetDBTable(String schemaName, String tableName) throws MonetDBEmbeddedException {
-        MonetDBTable res = this.getMonetDBTableInternal(schemaName, tableName, this.connectionPointer);
-        //results.add(res);
+    /**
+     * Retrieves a MonetDB Table for further operations
+     *
+     * @param schemaName The schema of the table
+     * @param tableName The name of the table
+     * @return A MonetDBTable instance with currentColumns details
+     * @throws MonetDBEmbeddedException If an error in the database occurred
+     */
+    public MonetDBTable getMonetDBTable(String schemaName, String tableName) throws MonetDBEmbeddedException {
+        String qschemaName = StringEscaper.SQLStringEscape(schemaName);
+        String qtableName = StringEscaper.SQLStringEscape(tableName);
+        String query = "SELECT currentColumns.\"name\" AS column, currentColumns.\"type\", currentColumns.\"type_digits\", currentColumns.\"type_scale\", currentColumns.\"default\", currentColumns.\"null\" FROM (SELECT \"id\", \"table_id\", \"name\", \"type\", \"type_digits\", \"type_scale\", \"default\", \"null\", \"number\" FROM sys.currentColumns) AS currentColumns INNER JOIN (SELECT \"id\", \"schema_id\" FROM sys.tables WHERE name="
+                + qtableName + ") AS tables ON (tables.\"id\"=currentColumns.\"table_id\") INNER JOIN (SELECT \"id\" FROM sys.schemas WHERE name="
+                + qschemaName + ") AS schemas ON (tables.\"schema_id\"=schemas.\"id\") ORDER BY currentColumns.\"number\";";
+
+        QueryResultSet eqr = this.sendQuery(query);
+        int numberOfRows = eqr.getNumberOfRows();
+        if(numberOfRows == 0) {
+            throw new MonetDBEmbeddedException("The table " + tableName + " on schema " + schemaName + " does not exist!");
+        }
+        QueryResultSetRows rows = eqr.fetchAllRowValues();
+        eqr.close();
+
+        MonetDBTableColumn<?>[] array = new MonetDBTableColumn<?>[numberOfRows];
+        int i = 0;
+        for(QueryResultSetRows.QueryResulSetRow row : rows.getAllRows()) {
+            String columnName = row.getColumn(0);
+            String columnType = row.getColumn(1);
+            int ndigits = row.getColumn(2);
+            int nscale = row.getColumn(3);
+            String defaultValue = row.getColumn(4);
+            boolean isNullable = row.getColumn(5);
+            array[i] = new MonetDBTableColumn(i, columnName, columnType, ndigits, nscale, defaultValue, isNullable);
+            i++;
+        }
+        MonetDBTable res = new MonetDBTable(this, schemaName, tableName, array);
+        results.add(res);
         return res;
     }
-        add the method from current schema
-    public MonetDBTable getMonetDBTableAsync(String schema, String tableName) throws MonetDBEmbeddedException {
+
+    /**
+     * Retrieves a MonetDB Table for further operations asynchronously.
+     *
+     * @param schemaName The schema of the table
+     * @param tableName The name of the table
+     * @return A MonetDBTable instance with currentColumns details
+     * @throws MonetDBEmbeddedException If an error in the database occurred
+     */
+    /*public MonetDBTable getMonetDBTableAsync(String schemaName, String tableName) throws MonetDBEmbeddedException {
+        CompletableFuture.supplyAsync(() -> this.getMonetDBTable(schemaName, tableName));
         throw new UnsupportedOperationException("Must wait for Java 8 :(");
     }*/
 
@@ -205,8 +248,10 @@ public class MonetDBEmbeddedConnection {
      * @throws MonetDBEmbeddedException If an error in the database occurred
      */
     public boolean checkIfTableExists(String schemaName, String tableName) throws MonetDBEmbeddedException {
+        schemaName = StringEscaper.SQLStringEscape(schemaName);
+        tableName = StringEscaper.SQLStringEscape(tableName);
         String query =
-                "select schemas.name as sn, tables.name as tn from sys.tables join sys.schemas on tables.schema_id=schemas.id where tables.system=true order by sn, tn and schemas.name ='" +
+                "select schemas.name as sn, tables.name as tn from sys.tables join sys.schemas on sys.tables.schema_id=schemas.id where tables.system=true order by sn, tn and schemas.name ='" +
                         schemaName + "' and tables.name ='" + tableName + "';";
         QueryResultSet eqr = this.sendQuery(query);
         eqr.close();
@@ -221,6 +266,8 @@ public class MonetDBEmbeddedConnection {
      * @throws MonetDBEmbeddedException If an error in the database occurred
      */
     public void removeTable(String schemaName, String tableName) throws MonetDBEmbeddedException {
+        schemaName = StringEscaper.SQLStringEscape(schemaName);
+        tableName = StringEscaper.SQLStringEscape(tableName);
         String query = "drop table " + schemaName + "." + tableName + ";";
         this.sendUpdate(query).close();
     }
@@ -258,17 +305,23 @@ public class MonetDBEmbeddedConnection {
         this.results.remove(res);
     }
 
+    /**
+     * Internal implementation of sendUpdate.
+     */
     private native UpdateResultSet sendUpdateInternal(long connectionPointer, String query, boolean execute)
             throws MonetDBEmbeddedException;
 
+    /**
+     * Internal implementation of sendQuery.
+     */
     private native QueryResultSet sendQueryInternal(long connectionPointer, String query, boolean execute)
             throws MonetDBEmbeddedException;
 
-    private native EmbeddedPreparedStatement createPreparedStatementInternal(long connectionPointer, String query)
-            throws MonetDBEmbeddedException;
-
-    /*private native MonetDBTable getMonetDBTableInternal(long connectionPointer, String schemaName, String tableName)
+    /*private native EmbeddedPreparedStatement createPreparedStatementInternal(long connectionPointer, String query)
             throws MonetDBEmbeddedException;*/
 
+    /**
+     * Internal implementation to close a connection.
+     */
     private native void closeConnectionInternal(long connectionPointer);
 }
--- a/src/main/java/nl/cwi/monetdb/embedded/env/MonetDBEmbeddedDatabase.java
+++ b/src/main/java/nl/cwi/monetdb/embedded/env/MonetDBEmbeddedDatabase.java
@@ -160,11 +160,20 @@ public class MonetDBEmbeddedDatabase {
         this.connections.remove(con);
     }
 
+    /**
+     * Internal implementation to start a database.
+     */
     private static native MonetDBEmbeddedDatabase StartDatabaseInternal(String dbDirectory, boolean silentFlag,
                                                                         boolean sequentialFlag)
             throws MonetDBEmbeddedException;
 
+    /**
+     * Internal implementation to stop a database.
+     */
     private native void stopDatabaseInternal();
 
+    /**
+     * Internal implementation to create a connection on this database.
+     */
     private native MonetDBEmbeddedConnection createConnectionInternal() throws MonetDBEmbeddedException;
 }
--- a/src/main/java/nl/cwi/monetdb/embedded/env/MonetDBEmbeddedException.java
+++ b/src/main/java/nl/cwi/monetdb/embedded/env/MonetDBEmbeddedException.java
@@ -15,7 +15,5 @@ package nl.cwi.monetdb.embedded.env;
  */
 public class MonetDBEmbeddedException extends Exception {
 
-    public MonetDBEmbeddedException(String message) {
-        super(message);
-    }
+    public MonetDBEmbeddedException(String message) { super(message); }
 }
--- a/src/main/java/nl/cwi/monetdb/embedded/mapping/AbstractColumn.java
+++ b/src/main/java/nl/cwi/monetdb/embedded/mapping/AbstractColumn.java
@@ -8,8 +8,6 @@
 
 package nl.cwi.monetdb.embedded.mapping;
 
-import nl.cwi.monetdb.embedded.mapping.MonetDBToJavaMapping;
-
 /**
  * A single Java representation of a MonetDB column.
  *
@@ -19,7 +17,7 @@ import nl.cwi.monetdb.embedded.mapping.M
 public abstract class AbstractColumn<T> {
 
     /**
-     * Index on the result set.
+     * The column index on the result set.
      */
     protected final int resultSetIndex;
 
@@ -39,7 +37,7 @@ public abstract class AbstractColumn<T> 
     protected final int columnDigits;
 
     /**
-     * 	The precision after decimal point. Only applicable for decimal/numeric types.
+     * The precision after decimal point. Only applicable for decimal/numeric types.
      */
     protected final int columnScale;
 
@@ -53,14 +51,14 @@ public abstract class AbstractColumn<T> 
     }
 
     /**
-     * Get the result set index of the column.
+     * Gets the result set index of the column.
      *
      * @return The index number
      */
     public int getResultSetIndex() { return resultSetIndex; }
 
     /**
-     * Get the name of the column.
+     * Gets the name of the column.
      *
      * @return The column name
      */
@@ -69,31 +67,30 @@ public abstract class AbstractColumn<T> 
     }
 
     /**
-     * Get the type of the column.
+     * Gets the type of the column.
      *
      * @return The Column type
      */
     public String getColumnType() { return mapping.toString(); }
 
     /**
-     * Get the Java mapping of the column.
+     * Gets the Java mapping of the column.
      *
      * @return A enum constant of the Java mapping
      */
     public MonetDBToJavaMapping getMapping() { return mapping; }
 
     /**
-     * Get column digits of the column.
+     * Gets the number digits of the column.
      *
      * @return The number of digits
      */
     public int getColumnDigits() { return columnDigits; }
 
     /**
-     * Get scale of the column.
+     * Gets the scale of the column.
      *
      * @return The scale
      */
     public int getColumnScale() { return columnScale; }
-
 }
--- a/src/main/java/nl/cwi/monetdb/embedded/mapping/AbstractResultTable.java
+++ b/src/main/java/nl/cwi/monetdb/embedded/mapping/AbstractResultTable.java
@@ -10,14 +10,12 @@ import nl.cwi.monetdb.embedded.env.Monet
  */
 public abstract class AbstractResultTable extends AbstractConnectionResult {
 
-    public AbstractResultTable(MonetDBEmbeddedConnection connection) {
-        super(connection);
-    }
+    public AbstractResultTable(MonetDBEmbeddedConnection connection) { super(connection); }
 
     /**
-     * Returns an array of columns in the result set;
+     * Returns an array of columns in the result set.
      *
-     * @return An array of columns in the result set;
+     * @return An array of columns in the result set
      */
     protected abstract AbstractColumn<?>[] getColumns();
 
@@ -36,7 +34,7 @@ public abstract class AbstractResultTabl
     public abstract int getNumberOfRows();
 
     /**
-     * Get the columns names as a string array.
+     * Gets the columns names as a string array.
      *
      * @return The columns names array
      */
@@ -50,7 +48,7 @@ public abstract class AbstractResultTabl
     }
 
     /**
-     * Get the columns types as a string array.
+     * Gets the columns types as a string array.
      *
      * @return The columns types array
      */
@@ -64,7 +62,7 @@ public abstract class AbstractResultTabl
     }
 
     /**
-     * Get the Java mappings as a MonetDBToJavaMapping array.
+     * Gets the Java mappings as a MonetDBToJavaMapping array.
      *
      * @return The columns MonetDBToJavaMapping array
      */
@@ -78,7 +76,7 @@ public abstract class AbstractResultTabl
     }
 
     /**
-     * Get the columns digits as a int array.
+     * Gets the columns digits as an integer array.
      *
      * @return The columns digits array
      */
@@ -92,7 +90,7 @@ public abstract class AbstractResultTabl
     }
 
     /**
-     * Get the columns scales as a int array.
+     * Gets the columns scales as an integer array.
      *
      * @return The columns scales array
      */
--- a/src/main/java/nl/cwi/monetdb/embedded/mapping/MonetDBEmbeddedBlob.java
+++ b/src/main/java/nl/cwi/monetdb/embedded/mapping/MonetDBEmbeddedBlob.java
@@ -1,24 +1,45 @@
 package nl.cwi.monetdb.embedded.mapping;
 
+import java.util.Arrays;
+
 /**
- * A Java representation for Blob data type. Added for more efficient data mapping when fetching from the database.
+ * A Java representation for the BLOB data type. Added for more efficient data mapping when fetching from the database.
  *
  * @author <a href="mailto:pedro.ferreira@monetdbsolutions.com">Pedro Ferreira</a>
  */
 public class MonetDBEmbeddedBlob {
 
+    /**
+     * The BLOB's content as a Java byte array.
+     */
     private final byte[] blob;
 
-    public MonetDBEmbeddedBlob(byte[] blob) {
-        this.blob = blob;
+    public MonetDBEmbeddedBlob(byte[] blob) { this.blob = blob; }
+
+    /**
+     * Get the BLOB content itself,
+     *
+     * @return A Java byte array containing the BLOB itself
+     */
+    public byte[] getBlob() { return blob; }
+
+    /**
+     * Overriding the equals method for the byte array.
+     */
+    @Override
+    public boolean equals(Object obj) {
+        return obj instanceof MonetDBEmbeddedBlob && Arrays.equals(this.blob, ((MonetDBEmbeddedBlob) obj).getBlob());
     }
 
-    public byte[] getBlob() {
-        return blob;
-    }
-
+    /**
+     * Overriding the hashCode method for the byte array.
+     */
     @Override
-    public String toString() {
-        return new String(this.blob);
-    }
+    public int hashCode() { return Arrays.hashCode(this.blob); }
+
+    /**
+     * Overriding the toString method for the byte array.
+     */
+    @Override
+    public String toString() { return Arrays.toString(blob); }
 }
--- a/src/main/java/nl/cwi/monetdb/embedded/mapping/MonetDBToJavaMapping.java
+++ b/src/main/java/nl/cwi/monetdb/embedded/mapping/MonetDBToJavaMapping.java
@@ -92,8 +92,5 @@ public enum MonetDBToJavaMapping {
      * @return The corresponding Java class for the enum value
      */
     @SuppressWarnings("unchecked")
-    public <T> Class<T> getJavaClass() {
-        return (Class<T>) this.javaClass;
-    }
-
+    public <T> Class<T> getJavaClass() { return (Class<T>) this.javaClass; }
 }
--- a/src/main/java/nl/cwi/monetdb/embedded/resultset/EmbeddedPreparedStatement.java
+++ b/src/main/java/nl/cwi/monetdb/embedded/resultset/EmbeddedPreparedStatement.java
@@ -12,6 +12,8 @@ import nl.cwi.monetdb.embedded.env.Monet
 import nl.cwi.monetdb.embedded.env.MonetDBEmbeddedException;
 import nl.cwi.monetdb.embedded.mapping.MonetDBEmbeddedBlob;
 import nl.cwi.monetdb.embedded.mapping.MonetDBToJavaMapping;
+import nl.cwi.monetdb.embedded.utils.StringEscaper;
+
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.math.RoundingMode;
@@ -350,8 +352,7 @@ public class EmbeddedPreparedStatement {
                 throw new MonetDBEmbeddedException("The class " + javaClass.getSimpleName() +
                         " is not supported by the mapping!");
             }
-            this.parsedValues[parameter] = "'" + valueToSubmit.replaceAll("\\\\", "\\\\\\\\")
-                    .replaceAll("'", "\\\\'") + "'";
+            this.parsedValues[parameter] = StringEscaper.SQLStringEscape(valueToSubmit);
         }
     }
 
@@ -360,9 +361,7 @@ public class EmbeddedPreparedStatement {
      *
      * @param parameter The index of the parameter
      */
-    public void setParameterNull(int parameter) {
-        this.parsedValues[parameter] = "NULL";
-    }
+    public void setParameterNull(int parameter) { this.parsedValues[parameter] = "NULL"; }
 
     /**
      * Creates the SQL String from the parsed parameters (adapted from the JDBC driver implementation).
--- a/src/main/java/nl/cwi/monetdb/embedded/resultset/QueryResultSet.java
+++ b/src/main/java/nl/cwi/monetdb/embedded/resultset/QueryResultSet.java
@@ -52,7 +52,7 @@ public class QueryResultSet extends Abst
 	}
 
     /**
-     * Close the query data so no more new results can be retrieved.
+     * Closes the query data so no more new results can be retrieved.
      */
     @Override
     public void closeImplementation() {
@@ -64,9 +64,7 @@ public class QueryResultSet extends Abst
     protected AbstractColumn<?>[] getColumns() { return columns; }
 
     @Override
-    public int getNumberOfRows() {
-        return this.numberOfRows;
-    }
+    public int getNumberOfRows() { return this.numberOfRows; }
 
     @Override
     public int getNumberOfColumns() { return this.columns.length; }
@@ -79,7 +77,7 @@ public class QueryResultSet extends Abst
     public boolean isStatementClosed() { return this.resultPointer == 0; }
 
     /**
-     * Get a columns' values from the result set by index.
+     * 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
@@ -90,7 +88,7 @@ public class QueryResultSet extends Abst
     }
 
     /**
-     * Get a columns from the result set by name.
+     * Gets a column from the result set by name.
      *
      * @param name QueryResultSetColumn name
      * @return The columns
@@ -202,5 +200,8 @@ public class QueryResultSet extends Abst
         }
     }
 
+    /**
+     * Internal implementation to clean the result set.
+     */
     private native void cleanupResultInternal(long resultPointer);
 }
--- a/src/main/java/nl/cwi/monetdb/embedded/resultset/QueryResultSetColumn.java
+++ b/src/main/java/nl/cwi/monetdb/embedded/resultset/QueryResultSetColumn.java
@@ -16,8 +16,7 @@ import java.util.Arrays;
 import java.util.ListIterator;
 
 /**
- *  Am abstract class for accessing, 
- *  materialised (Java-level) query result columns.
+ * An abstract class for accessing materialised (Java-level) query result columns.
  *
  * @param <T> A Java class mapped to a MonetDB data type
  * @author <a href="mailto:pedro.ferreira@monetdbsolutions.com">Pedro Ferreira</a>
@@ -199,8 +198,8 @@ public class QueryResultSetColumn<T> ext
      * @return The column values as a Java array
      * @throws MonetDBEmbeddedException If an error in the database occurred
      */
-    @SuppressWarnings("unchecked")
-    /*public T[] fetchColumnValuesAsync(int startIndex, int endIndex) throws MonetDBEmbeddedException {
+    /*@SuppressWarnings("unchecked")
+    public T[] fetchColumnValuesAsync(int startIndex, int endIndex) throws MonetDBEmbeddedException {
         return this.fetchColumnValuesAsync(startIndex, endIndex, (Class<T>) this.mapping.getJavaClass());
     }*/
 
@@ -255,6 +254,9 @@ public class QueryResultSetColumn<T> ext
         }
     }
 
+    /**
+     * Internal implementation to fetch values from the column.
+     */
     private native T[] fetchValuesInternal(long resultPointer, int resultSetIndex, Class<T> jclass, String className,
                                            int enumEntry, int first, int last) throws MonetDBEmbeddedException;
 }
--- a/src/main/java/nl/cwi/monetdb/embedded/resultset/QueryResultSetRows.java
+++ b/src/main/java/nl/cwi/monetdb/embedded/resultset/QueryResultSetRows.java
@@ -75,9 +75,7 @@ public class QueryResultSetRows implemen
          * @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 getColumn(int index, Class<T> javaClass) { return javaClass.cast(columns[index]); }
 
         /**
          * Gets a column value as a Java class using the default mapping.
@@ -92,9 +90,7 @@ public class QueryResultSetRows implemen
         }
 
         @Override
-        public ListIterator<Object> iterator() {
-            return Arrays.asList(this.columns).listIterator();
-        }
+        public ListIterator<Object> iterator() { return Arrays.asList(this.columns).listIterator(); }
     }
 
     /**
@@ -126,9 +122,7 @@ public class QueryResultSetRows implemen
      *
      * @return The original query result set this row set belongs
      */
-    public QueryResultSet getQueryResultSet() {
-        return queryResultSet;
-    }
+    public QueryResultSet getQueryResultSet() { return queryResultSet; }
 
     /**
      * Gets all rows of this set.
@@ -157,9 +151,7 @@ public class QueryResultSetRows implemen
      * @param row The index of the row to retrieve
      * @return A single row in this set
      */
-    public QueryResulSetRow getSingleRow(int row) {
-        return rows[row];
-    }
+    public QueryResulSetRow getSingleRow(int row) { return rows[row]; }
 
     /**
      * Gets a single value in this set as a Java class.
@@ -221,7 +213,5 @@ public class QueryResultSetRows implemen
     }
 
     @Override
-    public ListIterator<QueryResulSetRow> iterator() {
-        return Arrays.asList(this.rows).listIterator();
-    }
+    public ListIterator<QueryResulSetRow> iterator() { return Arrays.asList(this.rows).listIterator(); }
 }
--- a/src/main/java/nl/cwi/monetdb/embedded/resultset/UpdateResultSet.java
+++ b/src/main/java/nl/cwi/monetdb/embedded/resultset/UpdateResultSet.java
@@ -18,9 +18,10 @@ import nl.cwi.monetdb.embedded.env.Monet
  */
 public class UpdateResultSet extends AbstractConnectionResult {
 
-    protected UpdateResultSet(MonetDBEmbeddedConnection connection) {
-        super(connection);
-    }
+    protected UpdateResultSet(MonetDBEmbeddedConnection connection) { super(connection); }
 
+    /**
+     * Close this result set.
+     */
     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
@@ -1,11 +1,25 @@
 package nl.cwi.monetdb.embedded.tables;
 
 /**
- * Created by ferreira on 11/7/16.
+ * The base interface for iterating a MonetDB Table. The use can specify which rows to iterate in this interface.
+ *
+ * @author <a href="mailto:pedro.ferreira@monetdbsolutions.com">Pedro Ferreira</a>
  */
 public interface IMonetDBTableBaseIterator {
 
+    /**
+     * Specify the first row in the table to iterate. If a negative number is provided, then the iteration
+     * will start on the first row.
+     *
+     * @return The first row in the table to iterate
+     */
     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.
+     *
+     * @return The last row in the table to iterate
+     */
     int getLastRowToIterate();
 }
--- a/src/main/java/nl/cwi/monetdb/embedded/tables/IMonetDBTableIterator.java
+++ b/src/main/java/nl/cwi/monetdb/embedded/tables/IMonetDBTableIterator.java
@@ -1,9 +1,16 @@
 package nl.cwi.monetdb.embedded.tables;
 
 /**
- * Created by ferreira on 11/7/16.
+ * A row iterator for a MonetDB table.
+ *
+ * @author <a href="mailto:pedro.ferreira@monetdbsolutions.com">Pedro Ferreira</a>
  */
 public interface IMonetDBTableIterator extends IMonetDBTableBaseIterator {
 
+    /**
+     * The business logic for the iterator.
+     *
+     * @param nextRow The next row in the iteration.
+     */
     void nextRow(RowIterator nextRow);
 }
--- a/src/main/java/nl/cwi/monetdb/embedded/tables/IMonetDBTableRemover.java
+++ b/src/main/java/nl/cwi/monetdb/embedded/tables/IMonetDBTableRemover.java
@@ -1,9 +1,18 @@
 package nl.cwi.monetdb.embedded.tables;
 
 /**
- * Created by ferreira on 11/7/16.
+ * A row removal iterator for a MonetDB table.
+ *
+ * @author <a href="mailto:pedro.ferreira@monetdbsolutions.com">Pedro Ferreira</a>
  */
 public interface IMonetDBTableRemover extends IMonetDBTableBaseIterator {
 
-    void removeNextRow(RowRemover nextRow);
+    /**
+     * The business logic for the iterator. Use the
+     * {@link nl.cwi.monetdb.embedded.tables.RowRemover#setToRemove(boolean) setToRemove}
+     * method in <code>nextRow</code> to set the current row to remove.
+     *
+     * @param nextRow The next row in the iteration.
+     */
+    void nextRow(RowRemover nextRow);
 }
--- a/src/main/java/nl/cwi/monetdb/embedded/tables/IMonetDBTableUpdater.java
+++ b/src/main/java/nl/cwi/monetdb/embedded/tables/IMonetDBTableUpdater.java
@@ -1,9 +1,18 @@
 package nl.cwi.monetdb.embedded.tables;
 
 /**
- * Created by ferreira on 11/7/16.
+ * A row update iterator for a MonetDB table.
+ *
+ * @author <a href="mailto:pedro.ferreira@monetdbsolutions.com">Pedro Ferreira</a>
  */
 public interface IMonetDBTableUpdater extends IMonetDBTableBaseIterator {
 
-    void updateNextRow(RowUpdater nextRow);
+    /**
+     * The business logic for the iterator. Use the
+     * {@link nl.cwi.monetdb.embedded.tables.RowUpdater#setColumn(int, Object) setColumn}
+     * method in <code>nextRow</code> to update the current row.
+     *
+     * @param nextRow The next row in the iteration.
+     */
+    void nextRow(RowUpdater nextRow);
 }
--- a/src/main/java/nl/cwi/monetdb/embedded/tables/MonetDBTable.java
+++ b/src/main/java/nl/cwi/monetdb/embedded/tables/MonetDBTable.java
@@ -4,40 +4,41 @@ import nl.cwi.monetdb.embedded.env.Monet
 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.resultset.QueryResultSet;
+import nl.cwi.monetdb.embedded.resultset.QueryResultSetColumn;
+import nl.cwi.monetdb.embedded.utils.StringEscaper;
 
 /**
- * Java representation of a MonetDB table.
+ * Java representation of a MonetDB table. It's possible to perform several CRUD operations using the respective
+ * provided interfaces.
  *
  * @author <a href="mailto:pedro.ferreira@monetdbsolutions.com">Pedro Ferreira</a>
  */
 public class MonetDBTable extends AbstractResultTable {
 
     /**
-     * The table schema
+     * The table's schema.
      */
-    private final String tableSchema;
+    private final String schemaName;
 
     /**
-     * The table name
+     * The table's name.
      */
     private final String tableName;
 
     /**
-     * The table columns
+     * The table's columns.
      */
     private final MonetDBTableColumn<?>[] columns;
 
-    public MonetDBTable(MonetDBEmbeddedConnection connection, String tableSchema, String tableName,
+    public MonetDBTable(MonetDBEmbeddedConnection connection, String schemaName, String tableName,
                         MonetDBTableColumn<?>[] columns) {
         super(connection);
-        this.tableSchema = tableSchema;
+        this.schemaName = schemaName;
         this.tableName = tableName;
         this.columns = columns;
     }
 
-    /**
-     * Let's see...
-     */
     @Override
     protected void closeImplementation() {}
 
@@ -49,66 +50,141 @@ public class MonetDBTable extends Abstra
 
     @Override
     public int getNumberOfRows() {
-        return 0;
+        int res = -1;
+        try {
+            String qschemaName = StringEscaper.SQLStringEscape(this.schemaName);
+            String qtableName = StringEscaper.SQLStringEscape(this.tableName);
+            String query = "SELECT COUNT(*) FROM " + qschemaName + "." + qtableName + ";";
+            QueryResultSet eqr = this.getConnection().sendQuery(query);
+            QueryResultSetColumn<Integer> eqc = eqr.getColumn(0);
+            res = eqc.fetchFirstNColumnValues(1)[0];
+        } catch (MonetDBEmbeddedException ex) {
+        }
+        return res;
     }
 
     /**
-     * Get the table schema name
+     * Gets the table schema name.
      *
      * @return The table schema name
      */
-    public String getTableSchema() { return tableSchema; }
+    public String getSchemaName() { return schemaName; }
 
     /**
-     * Get the table name
+     * Gets the table name.
      *
      * @return The table name
      */
     public String getTableName() { return tableName; }
 
-    public void iterateTable(IMonetDBTableIterator iterator) throws MonetDBEmbeddedException {
-        RowIterator ri = new RowIterator(this, iterator.getFirstRowToIterate(), iterator.getLastRowToIterate());
-        while(this.getNextRow(ri)) {
-            iterator.nextRow(ri);
+    /**
+     * 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 int updateRows(IMonetDBTableUpdater updater) throws MonetDBEmbeddedException {
+    /**
+     * 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;
+    }
+
+    /**
+     * Iterate over the table using a {@link nl.cwi.monetdb.embedded.tables.IMonetDBTableIterator} instance.
+     *
+     * @param iterator The iterator with the business logic
+     * @return The number of rows iterated
+     */
+    public int iterateTable(IMonetDBTableIterator iterator) {
         int res = 0;
-        RowUpdater ru = new RowUpdater(this, updater.getFirstRowToIterate(), updater.getLastRowToIterate());
-        while(this.getNextRow(ru)) {
-            updater.updateNextRow(ru);
-            if(ru.toUpdate()) {
-                res++;
-                this.updateNextRow(ru);
-            }
-
+        RowIterator ri = new RowIterator(this, iterator.getFirstRowToIterate(), iterator.getLastRowToIterate());
+        while(ri.getNextTableRow()) {
+            iterator.nextRow(ri);
+            res++;
         }
         return res;
     }
 
-    public int removeRows(IMonetDBTableRemover remover) throws MonetDBEmbeddedException {
+    /**
+     * Perform an update iteration over the table using a {@link nl.cwi.monetdb.embedded.tables.IMonetDBTableUpdater}
+     * instance.
+     *
+     * @param updater The iterator with the business logic
+     * @return The number of rows updated
+     */
+    public int updateRows(IMonetDBTableUpdater updater) {
         int res = 0;
-        RowRemover rr = new RowRemover(this, remover.getFirstRowToIterate(), remover.getLastRowToIterate());
-        while(this.getNextRow(rr)) {
-            remover.removeNextRow(rr);
-            if(rr.isToRemove()) {
+        RowUpdater ru = new RowUpdater(this, updater.getFirstRowToIterate(), updater.getLastRowToIterate());
+        while(ru.getNextTableRow()) {
+            updater.nextRow(ru);
+            if(ru.tryUpdate()) {
                 res++;
-                this.removeNextRow(rr);
             }
         }
         return res;
     }
 
-    public native int truncate();
-
-    public int appendRows(Object[][] rows) {
-        return 0;
+    /**
+     * Perform a removal iteration over the table using a {@link nl.cwi.monetdb.embedded.tables.IMonetDBTableRemover}
+     * instance.
+     *
+     * @param remover The iterator with the business logic
+     * @return The number of rows removed
+     */
+    public int removeRows(IMonetDBTableRemover remover) {
+        int res = 0;
+        RowRemover rr = new RowRemover(this, remover.getFirstRowToIterate(), remover.getLastRowToIterate());
+        while(rr.getNextTableRow()) {
+            remover.nextRow(rr);
+            if(rr.tryRemove()) {
+                res++;
+            }
+        }
+        return res;
     }
 
-    private native boolean getNextRow(RowIterator ri) throws MonetDBEmbeddedException;
+    /**
+     * Deletes all rows in the table.
+     *
+     * @return The number of rows removed
+     */
+    public native int truncateTable();
 
-    private native boolean updateNextRow(RowUpdater ri) throws MonetDBEmbeddedException;
+    /**
+     * Appends new rows to the table.
+     *
+     * @param rows An array of rows to append
+     * @return The number of rows appended
+     */
+    public int appendRows(Object[][] rows) {
+        int i = 0;
+        for (Object[] row : rows) {
+            if (row.length != this.getNumberOfColumns()) {
+                throw new ArrayStoreException("The values array at row " + i + " differs from the number of columns!");
+            }
+            i++;
+        }
+        return this.appendRowsInternal(rows);
+    }
 
-    private native boolean removeNextRow(RowRemover rr) throws MonetDBEmbeddedException;
+    /**
+     * Internal implementation of rows insertion.
+     */
+    private native int appendRowsInternal(Object[][] rows);
 }
--- a/src/main/java/nl/cwi/monetdb/embedded/tables/MonetDBTableColumn.java
+++ b/src/main/java/nl/cwi/monetdb/embedded/tables/MonetDBTableColumn.java
@@ -9,9 +9,34 @@ import nl.cwi.monetdb.embedded.mapping.A
  */
 public class MonetDBTableColumn<T> extends AbstractColumn<T> {
 
+    /**
+     * A String representation of the default value if exists, otherwise is null.
+     */
+    private final String defaultValue;
+
+    /**
+     * A boolean indication if the column is nullable.
+     */
+    private final boolean isNullable;
+
     public MonetDBTableColumn(int resultSetIndex, String columnName, String columnType, int columnDigits,
-                              int columnScale) {
+                              int columnScale, String defaultValue, boolean isNullable) {
         super(resultSetIndex, columnName, columnType, columnDigits, columnScale);
+        this.defaultValue = defaultValue;
+        this.isNullable = isNullable;
     }
 
+    /**
+     * 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; }
+
+    /**
+     * Get the indication if the column is nullable.
+     *
+     * @return The indication if the column is nullable
+     */
+    public boolean isNullable() { return isNullable; }
 }
--- a/src/main/java/nl/cwi/monetdb/embedded/tables/RowIterator.java
+++ b/src/main/java/nl/cwi/monetdb/embedded/tables/RowIterator.java
@@ -3,7 +3,10 @@ package nl.cwi.monetdb.embedded.tables;
 import nl.cwi.monetdb.embedded.mapping.MonetDBToJavaMapping;
 
 /**
- * Created by ferreira on 11/7/16.
+ * The iterator class for a MonetDB table. It's possible to inspect the current currentColumns in the row as well
+ * their mappings.
+ *
+ * @author <a href="mailto:pedro.ferreira@monetdbsolutions.com">Pedro Ferreira</a>
  */
 public class RowIterator {
 
@@ -13,29 +16,36 @@ public class RowIterator {
     protected final MonetDBTable table;
 
     /**
-     * The mappings of the columns.
+     * The mappings of the currentColumns.
      */
     protected final MonetDBToJavaMapping[] mappings;
 
     /**
-     * The columns values as Java objects.
+     * The currentColumns values as Java objects.
      */
-    protected Object[] columns;
+    protected Object[] currentColumns;
 
     /**
      * The current row number.
      */
-    protected int rowNumber;
+    protected int currentRowNumber;
 
-    private final int firstIndex;
+    /**
+     * The first row in the table to iterate.
+     */
+    protected final int firstIndex;
 
-    private final int lastIndex;
+    /**
+     * The last row in the table to iterate.
+     */
+    protected final int lastIndex;
 
     public RowIterator(MonetDBTable table, int firstIndex, int lastIndex) {
         this.table = table;
         this.mappings = table.getMappings();
         this.firstIndex = Math.max(firstIndex, 0);
-        this.lastIndex = Math.min(lastIndex, table.getNumberOfRows());
+        this.lastIndex = Math.min(Math.min(lastIndex, table.getNumberOfRows()), 0);
+        this.currentRowNumber = this.firstIndex - 1; //starting on the row before the first index
     }
 
     /**
@@ -46,20 +56,39 @@ public class RowIterator {
     public MonetDBTable getTable() { return table; }
 
     /**
-     * Gets the columns values as Java objects.
+     * Gets the current row currentColumns values as Java objects.
      *
-     * @return The columns values as Java objects
+     * @return The current row currentColumns values as Java objects
      */
-    public Object[] getColumns() {
-        return columns;
-    }
+    public Object[] getCurrentColumns() { return currentColumns; }
 
     /**
      * Gets the current row number in the iteration.
      *
      * @return The current row number in the iteration
      */
-    public int getRowNumber() { return rowNumber; }
+    public int getCurrentRowNumber() { return currentRowNumber; }
+
+    /**
+     * Gets the first index used on this iteration.
+     *
+     * @return The first index used on this iteration
+     */
+    public int getFirstIndex() { return firstIndex; }
+
+    /**
+     * Gets the last index used on this iteration.
+     *
+     * @return The last index used on this iteration
+     */
+    public int getLastIndex() { return lastIndex; }
+
+    /**
+     * Checks if there are more rows to iterate after the current one.
+     *
+     * @return There are more rows to iterate
+     */
+    public boolean hasMore() { return currentRowNumber < lastIndex; }
 
     /**
      * Gets a column value as a Java class.
@@ -69,9 +98,7 @@ public class RowIterator {
      * @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 getColumn(int index, Class<T> javaClass) { return javaClass.cast(this.currentColumns[index]); }
 
     /**
      * Gets a column value as a Java class using the default mapping.
@@ -82,11 +109,23 @@ public class RowIterator {
      */
     public <T> T getColumn(int index) {
         Class<T> javaClass = this.mappings[index].getJavaClass();
-        return javaClass.cast(columns[index]);
+        return javaClass.cast(this.currentColumns[index]);
     }
 
-    protected void setNextIteration(Object[] columns, int rowNumber) {
-        this.columns = columns;
-        this.rowNumber = rowNumber;
+    /**
+     * Method used by JNI to set the next columns and increment the current row number.
+     *
+     * @param columns The next retrieved columns
+     */
+    protected void setNextIteration(Object[] columns) {
+        this.currentColumns = columns;
+        this.currentRowNumber++;
     }
+
+    /**
+     * Gets the next row in the iteration if there are more.
+     *
+     * @return A boolean indicating if a row was fetched
+     */
+    protected native boolean getNextTableRow();
 }
--- a/src/main/java/nl/cwi/monetdb/embedded/tables/RowRemover.java
+++ b/src/main/java/nl/cwi/monetdb/embedded/tables/RowRemover.java
@@ -1,10 +1,15 @@
 package nl.cwi.monetdb.embedded.tables;
 
 /**
- * Created by ferreira on 11/7/16.
+ * The removal iterator for a MonetDB table.
+ *
+ * @author <a href="mailto:pedro.ferreira@monetdbsolutions.com">Pedro Ferreira</a>
  */
 public class RowRemover extends RowIterator {
 
+    /**
+     * If the next row is going to be removed.
+     */
     private boolean toRemove;
 
     public RowRemover(MonetDBTable table, int firstIndex, int lastIndex) {
@@ -12,17 +17,42 @@ public class RowRemover extends RowItera
         this.toRemove = false;
     }
 
-    public boolean isToRemove() {
-        return toRemove;
+    /**
+     * Checks if the next row is going to be removed.
+     *
+     * @return If the next row is going to be removed
+     */
+    public boolean isToRemove() { return toRemove; }
+
+    /**
+     * Sets the current row to remove or not.
+     *
+     * @param toRemove A boolean indicating if the next row will be removed
+     */
+    public void setToRemove(boolean toRemove) { this.toRemove = toRemove; }
+
+    /**
+     * To be called by the JNI interface in every iteration.
+     *
+     * @param columns The next row's columns
+     */
+    @Override
+    protected void setNextIteration(Object[] columns) {
+        super.setNextIteration(columns);
+        this.toRemove = false;
     }
 
-    public void setToRemove(boolean toRemove) {
-        this.toRemove = toRemove;
-    }
+    /**
+     * Remove the current row if it was set for so.
+     *
+     * @return If the row was removed internally
+     */
+    protected boolean tryRemove() { return this.isToRemove() && this.removeNextTableRow(); }
 
-    @Override
-    protected void setNextIteration(Object[] columns, int rowNumber) {
-        super.setNextIteration(columns, rowNumber);
-        this.toRemove = false;
-    }
+    /**
+     * Removes the next row.
+     *
+     * @return If the row was removed internally
+     */
+    private native boolean removeNextTableRow();
 }
--- a/src/main/java/nl/cwi/monetdb/embedded/tables/RowUpdater.java
+++ b/src/main/java/nl/cwi/monetdb/embedded/tables/RowUpdater.java
@@ -3,10 +3,15 @@ package nl.cwi.monetdb.embedded.tables;
 import java.util.Arrays;
 
 /**
- * Created by ferreira on 11/7/16.
+ * The update iterator for a MonetDB table.
+ *
+ * @author <a href="mailto:pedro.ferreira@monetdbsolutions.com">Pedro Ferreira</a>
  */
 public class RowUpdater extends RowIterator {
 
+    /**
+     * A boolean array to check the columns to be updated.
+     */
     private final boolean[] updatedIndexes;
 
     public RowUpdater(MonetDBTable table, int firstIndex, int lastIndex) {
@@ -14,23 +19,57 @@ public class RowUpdater extends RowItera
         this.updatedIndexes = new boolean[table.getNumberOfColumns()];
     }
 
+    /**
+     * Sets a column value as a Java class.
+     *
+     * @param <T> A Java class mapped to a MonetDB data type
+     * @param index The index of the column
+     * @param value The value to set
+     */
     public <T> void setColumn(int index, T value) {
-        this.columns[index] = value;
+        this.currentColumns[index] = this.mappings[index].getJavaClass().cast(value);
+        this.updatedIndexes[index] = true;
+    }
+
+    /**
+     * Sets a column value as a Java class.
+     *
+     * @param <T> A Java class mapped to a MonetDB data type
+     * @param index The index of the column
+     * @param javaClass The Java class
+     * @param value The value to set
+     */
+    public <T> void setColumn(int index, Class<T> javaClass, T value) {
+        this.currentColumns[index] = javaClass.cast(value);
         this.updatedIndexes[index] = true;
     }
 
-    public <T> void setColumn(int index, Class<T> javaClass, T value) {
-        this.columns[index] = value;
-        this.updatedIndexes[index] = true;
-    }
-
+    /**
+     * Sets all column values as Java classes.
+     *
+     * @param values The values to set
+     */
     public void setAllColumns(Object[] values) {
-        this.columns = values;
+        if(values.length != this.currentColumns.length)
+            throw new ArrayStoreException("The values array and the columns length differ!");
+        this.currentColumns = values;
         Arrays.fill(this.updatedIndexes, true);
     }
 
+    /**
+     * Gets a boolean array of the columns indexes to be updated.
+     *
+     * @return A boolean array of the columns indexes to be updated
+     */
+    public boolean[] getUpdatedIndexes() { return Arrays.copyOf(this.updatedIndexes, this.updatedIndexes.length); }
+
+    /**
+     * Check if the current row is to be updated.
+     *
+     * @return A boolean indicating if the current row is to be updated
+     */
     public boolean toUpdate() {
-        for (boolean bol : updatedIndexes) {
+        for (boolean bol : this.updatedIndexes) {
             if(bol) {
                 return true;
             }
@@ -38,9 +77,28 @@ public class RowUpdater extends RowItera
         return false;
     }
 
+    /**
+     * To be called by the JNI interface in every iteration.
+     *
+     * @param columns The next row's columns
+     */
     @Override
-    protected void setNextIteration(Object[] columns, int rowNumber) {
-        super.setNextIteration(columns, rowNumber);
+    protected void setNextIteration(Object[] columns) {
+        super.setNextIteration(columns);
         Arrays.fill(this.updatedIndexes, false);
     }
+
+    /**
+     * Update the current row if there are changes.
+     *
+     * @return If the row was updated internally
+     */
+    protected boolean tryUpdate() { return this.toUpdate() && this.updateNextTableRow(); }
+
+    /**
+     * Updates the next row.
+     *
+     * @return If the row was updated internally
+     */
+    private native boolean updateNextTableRow();
 }
new file mode 100644
--- /dev/null
+++ b/src/main/java/nl/cwi/monetdb/embedded/utils/StringEscaper.java
@@ -0,0 +1,19 @@
+package nl.cwi.monetdb.embedded.utils;
+
+/**
+ * An util class to escape Java Strings to avoid SQL Injection and other problems with SQL queries.
+ *
+ * @author <a href="mailto:pedro.ferreira@monetdbsolutions.com">Pedro Ferreira</a>
+ */
+public class StringEscaper {
+
+    /**
+     * Escapes a Java String for usage in SQL queries.
+     *
+     * @param input The String to escape
+     * @return The input String escaped
+     */
+    public static String SQLStringEscape(String input) {
+        return "'" + input.replaceAll("\\\\", "\\\\\\\\").replaceAll("'", "\\\\'") + "'";
+    }
+}