view src/main/java/nl/cwi/monetdb/embedded/tables/MonetDBTable.java @ 50:3b97ec05f6b1 embedded

Java classes to tables import working!!!
author Pedro Ferreira <pedro.ferreira@monetdbsolutions.com>
date Tue, 15 Nov 2016 13:18:35 +0100 (2016-11-15)
parents 8217f77fcf6b
children c592d8a72627
line wrap: on
line source
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.resultset.QueryResultSet;
import nl.cwi.monetdb.embedded.resultset.QueryResultSetColumn;

/**
 * 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's schema.
     */
    private final String schemaName;

    /**
     * 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) {
        super(connection);
        this.connectionPointer = connectionPointer;
        this.schemaName = schemaName;
        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; }

    /**
     * Gets the current number of rows in the table, or -1 if an error in the database has ocurred.
     *
     * @return The number of rows in the table.
     */
    @Override
    public int getNumberOfRows() {
        int res;
        try {
            String query = "SELECT COUNT(*) FROM " + this.schemaName + "." + this.tableName + ";";
            QueryResultSet eqr = this.getConnection().sendQuery(query);
            QueryResultSetColumn<Long> eqc = eqr.getColumn(0);
            res = eqc.fetchFirstNColumnValues(1)[0].intValue();
            eqr.close();
        } catch (MonetDBEmbeddedException ex) {
            res = -1;
        }
        return res;
    }

    /**
     * Gets the table schema name.
     *
     * @return The table schema name
     */
    public String getSchemaName() { return schemaName; }

    /**
     * Gets the table name.
     *
     * @return The table name
     */
    public String getTableName() { return 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;
    }

    /**
     * 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;
    }

    /**
     * Private method to check the limits of iteration.
     *
     * @param iterator The iterator to check
     * @return An integer array with the limits fixed
     */
    private int[] checkIterator(IMonetDBTableBaseIterator iterator) {
        int[] res = {iterator.getFirstRowToIterate(), iterator.getLastRowToIterate()};
        if(res[1] < res[0]) {
            int aux = res[0];
            res[0] = res[1];
            res[0] = aux;
        }
        if (res[0] < 1) {
            res[0] = 1;
        }
        int numberOfRows = this.getNumberOfRows();
        if (res[1] >= numberOfRows) {
            res[1] = numberOfRows;
        }
        return res;
    }

    /**
     * Iterate over the table using a {@link IMonetDBTableCursor} instance.
     *
     * @param cursor The iterator with the business logic
     * @return The number of rows iterated
     * @throws MonetDBEmbeddedException If an error in the database occurred
     */
    public int iterateTable(IMonetDBTableCursor cursor) throws MonetDBEmbeddedException {
        int[] limits = this.checkIterator(cursor);
        int res = 0, total = limits[1] - limits[0] + 1;
        String query = new StringBuffer("SELECT * FROM ").append(this.schemaName).append(".").append(this.tableName)
                .append(" LIMIT ").append(total).append(" OFFSET ").append(limits[0] - 1).append(";").toString();

        QueryResultSet eqr = this.getConnection().sendQuery(query);
        MonetDBRow[] array = eqr.fetchAllRowValues().getAllRows();
        eqr.close();
        Object[][] data = new Object[eqr.getNumberOfRows()][this.getNumberOfColumns()];
        for(int i = 0 ; i < eqr.getNumberOfRows() ; i++) {
            data[i] = array[i].getAllColumns();
        }

        RowIterator ri = new RowIterator(this, data, limits[0], limits[1]);
        while(ri.tryContinueIteration()) {
            cursor.processNextRow(ri);
            res++;
        }
        return res;
    }

    /**
     * Iterate over the table using a {@link IMonetDBTableCursor}
     * instance asynchronously.
     *
     * @param iterator The iterator with the business logic
     * @return The number of rows iterated
     * @throws MonetDBEmbeddedException If an error in the database occurred
     */
    /*public CompletableFuture<Integer> iterateTable(IMonetDBTableCursor iterator) throws MonetDBEmbeddedException {
        return CompletableFuture.supplyAsync(() -> this.iterateTable(iterator));
    }*/

    /**
     * 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
     * @throws MonetDBEmbeddedException If an error in the database occurred
     */
    /*public int updateRows(IMonetDBTableUpdater updater) throws MonetDBEmbeddedException {
        int[] limits = this.checkIterator(updater);
        RowUpdater ru = this.getRowUpdaterInternal(this.connectionPointer, this.schemaName, this.tableName,
                limits[0], limits[1]);
        while(ru.tryContinueIteration()) {
            updater.processNextRow(ru);
        }
        return ru.submitUpdates();
    }*/

    /**
     * Perform an update iteration over the table using a {@link nl.cwi.monetdb.embedded.tables.IMonetDBTableUpdater}
     * instance asynchronously.
     *
     * @param updater The iterator with the business logic
     * @return The number of rows updated
     * @throws MonetDBEmbeddedException If an error in the database occurred
     */
    /*public CompletableFuture<Integer> updateRowsAsync(IMonetDBTableUpdater updater) throws MonetDBEmbeddedException {
        return CompletableFuture.supplyAsync(() -> this.updateRows(updater));
    }*/

    /**
     * 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
     * @throws MonetDBEmbeddedException If an error in the database occurred
     */
    /*public int removeRows(IMonetDBTableRemover remover) throws MonetDBEmbeddedException {
        int[] limits = this.checkIterator(remover);
        RowRemover rr = this.getRowRemoverInternal(this.connectionPointer, this.schemaName, this.tableName,
                limits[0], limits[1]);
        while(rr.tryContinueIteration()) {
            remover.processNextRow(rr);
        }
        return rr.submitDeletes();
    }*/

    /**
     * Perform a removal iteration over the table using a {@link nl.cwi.monetdb.embedded.tables.IMonetDBTableRemover}
     * instance asynchronously.
     *
     * @param remover The iterator with the business logic
     * @return The number of rows removed
     * @throws MonetDBEmbeddedException If an error in the database occurred
     */
    /*public CompletableFuture<Integer> removeRowsAsync(IMonetDBTableRemover remover) throws MonetDBEmbeddedException {
        return CompletableFuture.supplyAsync(() -> this.removeRows(remover));
    }*/

    /**
     * Deletes all rows in the table.
     *
     * @return The number of rows removed
     * @throws MonetDBEmbeddedException If an error in the database occurred
     */
    /*public int truncateTable() throws MonetDBEmbeddedException {
        return this.truncateTableInternal(this.connectionPointer, this.schemaName, this.tableName);
    }*/

    /**
     * Deletes all rows in the table asynchronously.
     *
     * @return The number of rows removed
     * @throws MonetDBEmbeddedException If an error in the database occurred
     */
    /*public CompletableFuture<Integer> truncateTableAsync() throws MonetDBEmbeddedException {
        return CompletableFuture.supplyAsync(() -> this.truncateTable());
    }*/

    /**
     * Appends new rows to the table. As MonetDB's storage is column-wise, the method
     * {@link nl.cwi.monetdb.embedded.tables.MonetDBTable#appendColumns(Object[][]) appendColumns} is preferable
     * over this one.
     *
     * @param rows 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();
        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) {
                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];
            }
        }
        return this.appendColumns(transposed);
    }

    /**
     * Appends new rows to the table asynchronously.
     *
     * @param rows An array of rows to append
     * @return The number of rows appended
     * @throws MonetDBEmbeddedException If an error in the database occurred
     */
    /*public CompletableFuture<Integer> appendRowsAsync(Object[][] rows) throws MonetDBEmbeddedException {
        return CompletableFuture.supplyAsync(() -> this.appendRows(schemaName, tableName));
    }*/

    /**
     * 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
     * @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) {
            throw new ArrayStoreException("The number of columns differs from the table's number of columns!");
        }
        if(numberOfRows == 0) {
            throw new ArrayStoreException("Appending 0 rows?");
        }
        for (int i = 0; i < numberOfColumns; i++) {
            if(columns[i].length != numberOfRows) {
                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);
    }

    /**
     * Appends new rows to the table column-wise and asynchronously.
     *
     * @param columns An array of columns to append
     * @return The number of rows appended
     * @throws MonetDBEmbeddedException If an error in the database occurred
     */
    /*public CompletableFuture<Integer> appendColumnsAsync(Object[][] columns) throws MonetDBEmbeddedException {
        return CompletableFuture.supplyAsync(() -> this.appendColumns(schemaName, tableName));
    }*/

    /**
     * Internal implementation of table truncation.
     */
    /*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)
            throws MonetDBEmbeddedException;
}