net.starschema.clouddb.jdbc.BQStatementRoot.java Source code

Java tutorial

Introduction

Here is the source code for net.starschema.clouddb.jdbc.BQStatementRoot.java

Source

/**
 * Starschema Big Query JDBC Driver
 * Copyright (C) 2012, Starschema Ltd.
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 * 
 * This class is the parent of BQStatement and BQPreparedStatement
 */

package net.starschema.clouddb.jdbc;

import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.sql.SQLWarning;
import java.sql.Statement;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.google.api.services.bigquery.model.Job;

// import net.starschema.clouddb.bqjdbc.logging.Logger;

/**
 * This class partially implements java.sql.Statement, and
 * java.sql.PreparedStatement
 * 
 * @author Horvth Attila
 * @author Balazs Gunics
 * 
 */
public abstract class BQStatementRoot implements java.sql.Statement {

    /** Reference to store the ran Query run by Executequery or Execute */
    ResultSet resset = null;

    /** String containing the context of the Project */
    String ProjectId = null;

    protected final Log logger = LogFactory.getLog(BQStatementRoot.class);

    /** Variable that stores the closed state of the statement */
    boolean closed = false;

    /** Reference for the Connection that created this Statement object */
    BQConnection connection;

    /** Variable that stores the set query timeout */
    int querytimeout = Integer.MAX_VALUE;
    /** Instance of log4j.Logger */
    /**
     * Variable stores the time an execute is made
     */
    long starttime = 0;

    /**
     * Maximum number of rows (pure, as specified by the user of the statement)
     */
    int maxRows = 0;

    /**
     * Variable that stores the max row number which can be stored in the
     * resultset (like maxRows but tweaked - why ?)
     */
    int resultMaxRowCount = Integer.MAX_VALUE - 1;

    /** Variable to Store EscapeProc state */
    boolean EscapeProc = false;

    /**
     * These Variables contain information about the type of resultset this
     * statement creates
     */
    int resultSetType;
    int resultSetConcurrency;

    /**
     * to be used with setMaxFieldSize
     */
    private int maxFieldSize = 0;

    /**
     * <p>
     * <h1>Implementation Details:</h1><br>
     * Not implemented yet.
     * </p>
     * 
     * @throws BQSQLException
     */

    public void addBatch(String arg0) throws SQLException {
        throw new BQSQLException("Not implemented." + "addBatch(string)");
    }

    /**
     * <p>
     * <h1>Implementation Details:</h1><br>
     * Not implemented yet.
     * </p>
     * 
     * @throws BQSQLFeatureNotSupportedException
     */

    public void cancel() throws SQLException {
        throw new BQSQLFeatureNotSupportedException("cancel()");
    }

    /**
     * <p>
     * <h1>Implementation Details:</h1><br>
     * Not implemented yet.
     * </p>
     * 
     * @throws BQSQLException
     */

    public void clearBatch() throws SQLException {
        throw new BQSQLException("Not implemented." + "clearBatch()");
    }

    /**
     * <p>
     * <h1>Implementation Details:</h1><br>
     * Not implemented yet.
     * </p>
     * 
     * @throws BQSQLException
     */

    public void clearWarnings() throws SQLException {
        throw new BQSQLException("Not implemented." + "clearWarnings()");
    }

    /**
     * <p>
     * <h1>Implementation Details:</h1><br>
     * Only sets closed boolean to true
     * </p>
     */
    public void close() throws SQLException {
        this.closed = true;
        if (this.resset != null) {
            this.resset.close();
        }
    }

    /**
     * <p>
     * <h1>Implementation Details:</h1><br>
     * Executes the given SQL statement on BigQuery (note: it returns only 1
     * resultset). This function directly uses executeQuery function
     * </p>
     */

    public boolean execute(String arg0) throws SQLException {
        if (this.isClosed()) {
            throw new BQSQLException("This Statement is Closed");
        }
        this.resset = this.executeQuery(arg0);
        this.logger.info("Executing Query: " + arg0);
        if (this.resset != null) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * <p>
     * <h1>Implementation Details:</h1><br>
     * Not implemented yet.
     * </p>
     * 
     * @throws BQSQLFeatureNotSupportedException
     */

    public boolean execute(String arg0, int arg1) throws SQLException {
        throw new BQSQLFeatureNotSupportedException("execute(String, int)");
    }

    /**
     * <p>
     * <h1>Implementation Details:</h1><br>
     * Not implemented yet.
     * </p>
     * 
     * @throws BQSQLFeatureNotSupportedException
     */

    public boolean execute(String arg0, int[] arg1) throws SQLException {
        throw new BQSQLFeatureNotSupportedException("execute(string,int[])");
    }

    /**
     * <p>
     * <h1>Implementation Details:</h1><br>
     * Not implemented yet.
     * </p>
     * 
     * @throws BQSQLFeatureNotSupportedException
     */

    public boolean execute(String arg0, String[] arg1) throws SQLException {
        throw new BQSQLFeatureNotSupportedException("execute(string,string[])");
    }

    /**
     * <p>
     * <h1>Implementation Details:</h1><br>
     * Not implemented yet.
     * </p>
     * 
     * @throws BQSQLException
     */

    public int[] executeBatch() throws SQLException {
        throw new BQSQLException("Not implemented." + "executeBatch()");
    }

    /** {@inheritDoc} */

    public ResultSet executeQuery(String querySql) throws SQLException {
        if (this.isClosed()) {
            throw new BQSQLException("This Statement is Closed");
        }
        this.starttime = System.currentTimeMillis();
        Job referencedJob;
        // ANTLR Parsing
        BQQueryParser parser = new BQQueryParser(querySql, this.connection);
        querySql = parser.parse();

        try {
            // Gets the Job reference of the completed job with give Query
            referencedJob = BQSupportFuncts.startQuery(this.connection.getBigquery(), this.ProjectId, querySql);
            this.logger.info("Executing Query: " + querySql);
        } catch (IOException e) {
            throw new BQSQLException("Something went wrong with the query: " + querySql, e);
        }
        try {
            do {
                if (BQSupportFuncts.getQueryState(referencedJob, this.connection.getBigquery(), this.ProjectId)
                        .equals("DONE")) {
                    if (resultSetType == ResultSet.TYPE_SCROLL_INSENSITIVE) {
                        return new BQScrollableResultSet(BQSupportFuncts.getQueryResults(
                                this.connection.getBigquery(), this.ProjectId, referencedJob), this);
                    } else {
                        return new BQForwardOnlyResultSet(this.connection.getBigquery(),
                                this.ProjectId.replace("__", ":").replace("_", "."), referencedJob, this);
                    }
                }
                // Pause execution for half second before polling job status
                // again, to
                // reduce unnecessary calls to the BigQUery API and lower
                // overall
                // application bandwidth.
                Thread.sleep(500);
                this.logger.debug("slept for 500" + "ms, querytimeout is: " + this.querytimeout + "s");
            } while (System.currentTimeMillis() - this.starttime <= (long) this.querytimeout * 1000);
            // it runs for a minimum of 1 time
        } catch (IOException e) {
            throw new BQSQLException("Something went wrong with the query: " + querySql, e);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // here we should kill/stop the running job, but bigquery doesn't
        // support that :(
        throw new BQSQLException("Query run took more than the specified timeout");
    }

    /**
     * <p>
     * <h1>Implementation Details:</h1><br>
     * Not implemented yet.
     * </p>
     * 
     * @throws BQSQLException
     */

    public int executeUpdate(String arg0) throws SQLException {
        throw new BQSQLFeatureNotSupportedException("executeUpdate(string)");
    }

    /**
     * <p>
     * <h1>Implementation Details:</h1><br>
     * Not implemented yet.
     * </p>
     * 
     * @throws BQSQLFeatureNotSupportedException
     */

    public int executeUpdate(String arg0, int arg1) throws SQLException {
        throw new BQSQLFeatureNotSupportedException("executeUpdate(String,int)");
    }

    /**
     * <p>
     * <h1>Implementation Details:</h1><br>
     * Not implemented yet.
     * </p>
     * 
     * @throws BQSQLFeatureNotSupportedException
     */

    public int executeUpdate(String arg0, int[] arg1) throws SQLException {
        throw new BQSQLFeatureNotSupportedException("executeUpdate(string,int[])");
    }

    /**
     * <p>
     * <h1>Implementation Details:</h1><br>
     * Not implemented yet.
     * </p>
     * 
     * @throws BQSQLFeatureNotSupportedException
     */

    public int executeUpdate(String arg0, String[] arg1) throws SQLException {
        throw new BQSQLFeatureNotSupportedException("execute(update(string,string[])");
    }

    /**
     * <p>
     * <h1>Implementation Details:</h1><br>
     * Returns the connection that made the object.
     * </p>
     * 
     * @returns connection
     */
    public Connection getConnection() throws SQLException {
        return this.connection;
    }

    /**
     * <p>
     * <h1>Implementation Details:</h1><br>
     * Fetch direction is unknown.
     * </p>
     * 
     * @return FETCH_UNKNOWN
     */

    public int getFetchDirection() throws SQLException {
        return ResultSet.FETCH_UNKNOWN;
    }

    /**
     * <p>
     * <h1>Implementation Details:</h1><br>
     * Not implemented yet.
     * </p>
     * 
     * @throws BQSQLException
     */

    public int getFetchSize() throws SQLException {
        throw new BQSQLException("Not implemented." + "getFetchSize()");
    }

    /**
     * <p>
     * <h1>Implementation Details:</h1><br>
     * Not implemented yet.
     * </p>
     * 
     * @throws BQSQLException
     */

    public ResultSet getGeneratedKeys() throws SQLException {
        throw new BQSQLFeatureNotSupportedException("getGeneratedKeys()");
    }

    /**
     * <p>
     * <h1>Implementation Details:</h1><br>
     * Not implemented yet.
     * </p>
     * 
     * @throws BQSQLException
     */

    public int getMaxFieldSize() throws SQLException {
        return maxFieldSize;
    }

    /**
     * <p>
     * <h1>Implementation Details:</h1><br>
     * We store it in an array which indexed through, int
     * </p>
     * We could return Integer.MAX_VALUE too, but i don't think we could get
     * that much row.
     * 
     * @return 0 -
     */

    public int getResultMaxRowCount() throws SQLException {
        return this.resultMaxRowCount;
    }

    @Override
    public int getMaxRows() throws SQLException {
        return this.maxRows;
    }

    /**
     * <p>
     * <h1>Implementation Details:</h1><br>
     * Not implemented yet, since Bigquery Does not support precompiled sql
     * </p>
     * 
     * @throws BQSQLException
     */
    public ResultSetMetaData getMetaData() throws SQLException {
        throw new BQSQLException(new SQLFeatureNotSupportedException("getMetaData()"));
    }

    /**
     * <p>
     * <h1>Implementation Details:</h1><br>
     * Multiple result sets are not supported currently.
     * </p>
     * 
     * @return false;
     */

    public boolean getMoreResults() throws SQLException {
        return false;
    }

    /**
     * <p>
     * <h1>Implementation Details:</h1><br>
     * Multiple result sets are not supported currently. we check that the
     * result set is open, the parameter is acceptable, and close our current
     * resultset or throw a FeatureNotSupportedException
     * </p>
     * 
     * @param current
     *            - one of the following Statement constants indicating what
     *            should happen to current ResultSet objects obtained using the
     *            method getResultSet: Statement.CLOSE_CURRENT_RESULT,
     *            Statement.KEEP_CURRENT_RESULT, or Statement.CLOSE_ALL_RESULTS
     * @throws BQSQLException
     */

    public boolean getMoreResults(int current) throws SQLException {
        if (this.closed) {
            throw new BQSQLException("Statement is closed.");
        }
        if (current == Statement.CLOSE_CURRENT_RESULT || current == Statement.KEEP_CURRENT_RESULT
                || current == Statement.CLOSE_ALL_RESULTS) {

            if (BQDatabaseMetadata.multipleOpenResultsSupported
                    && (current == Statement.KEEP_CURRENT_RESULT || current == Statement.CLOSE_ALL_RESULTS)) {
                throw new BQSQLFeatureNotSupportedException();
            }
            // Statement.CLOSE_CURRENT_RESULT
            this.close();
            return false;
        } else {
            throw new BQSQLException("Wrong parameter.");
        }
    }

    /** {@inheritDoc} */

    public int getQueryTimeout() throws SQLException {
        if (this.isClosed()) {
            throw new BQSQLException("This Statement is Closed");
        }
        if (this.starttime == 0) {
            return 0;
        }
        if (this.querytimeout == Integer.MAX_VALUE) {
            return 0;
        } else {
            if (System.currentTimeMillis() - this.starttime > this.querytimeout) {
                throw new BQSQLException("Time is over");
            }
            return this.querytimeout;
        }
    }

    /**
     * <p>
     * <h1>Implementation Details:</h1><br>
     * Gives back reultset stored in resset
     * </p>
     */

    public ResultSet getResultSet() throws SQLException {
        if (this.isClosed()) {
            throw new BQSQLException("This Statement is Closed");
        }
        if (this.resset != null) {
            return this.resset;
        } else {
            return null;
        }
    }

    /**
     * <p>
     * <h1>Implementation Details:</h1><br>
     * The driver is read only currently.
     * </p>
     * 
     * @return CONCUR_READ_ONLY
     */

    public int getResultSetConcurrency() throws SQLException {
        return ResultSet.CONCUR_READ_ONLY;
    }

    /**
     * <p>
     * <h1>Implementation Details:</h1><br>
     * Read only mode, no commit.
     * </p>
     * 
     * @return CLOSE_CURSORS_AT_COMMIT
     */

    public int getResultSetHoldability() throws SQLException {
        return ResultSet.CLOSE_CURSORS_AT_COMMIT;
        // TODO
    }

    /**
     * <p>
     * <h1>Implementation Details:</h1><br>
     * Updates and deletes not supported.
     * </p>
     * 
     * @return TYPE_SCROLL_INSENSITIVE
     */

    public int getResultSetType() throws SQLException {
        return ResultSet.TYPE_SCROLL_INSENSITIVE;
    }

    /**
     * <p>
     * <h1>Implementation Details:</h1><br>
     * Result will be a ResultSet object.
     * </p>
     * 
     * @return -1
     */

    public int getUpdateCount() throws SQLException {
        return -1;
    }

    /**
     * <p>
     * <h1>Implementation Details:</h1><br>
     * returns null
     * </p>
     * 
     * @return null
     */

    public SQLWarning getWarnings() throws SQLException {
        return null;
        // TODO Implement Warning Handling
    }

    /**
     * <p>
     * <h1>Implementation Details:</h1><br>
     * Returns the value of boolean closed
     * </p>
     */
    public boolean isClosed() throws SQLException {
        return this.closed;
    }

    /**
     * <p>
     * <h1>Implementation Details:</h1><br>
     * Not implemented yet.
     * </p>
     * 
     * @throws BQSQLException
     */

    public boolean isPoolable() throws SQLException {
        throw new BQSQLException("Not implemented." + "isPoolable()");
    }

    /**
     * <p>
     * <h1>Implementation Details:</h1><br>
     * Not implemented yet.
     * </p>
     * 
     * @return false
     */
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return false;
    }

    /**
     * <p>
     * <h1>Implementation Details:</h1><br>
     * FeatureNotSupportedExceptionjpg
     * </p>
     * 
     * @throws BQSQLFeatureNotSupportedException
     */

    public void setCursorName(String arg0) throws SQLException {
        throw new BQSQLFeatureNotSupportedException("setCursorName(string)");
    }

    /**
     * <p>
     * <h1>Implementation Details:</h1><br>
     * Now Only setf this.EscapeProc to arg0
     * </p>
     */

    public void setEscapeProcessing(boolean arg0) throws SQLException {
        if (this.isClosed()) {
            throw new BQSQLException("This Statement is Closed");
        }
        this.EscapeProc = arg0;
    }

    /**
     * <p>
     * <h1>Implementation Details:</h1><br>
     * Not implemented yet.
     * </p>
     * 
     * @throws BQSQLException
     */

    public void setFetchDirection(int arg0) throws SQLException {
        throw new BQSQLException("Not implemented." + "setFetchDirection(int)");
    }

    /**
     * <p>
     * <h1>Implementation Details:</h1><br>
     * Does nothing
     * </p>
     * 
     * @throws BQSQLException
     */
    public void setFetchSize(int arg0) throws SQLException {
        if (this.isClosed()) {
            throw new BQSQLException("Statement closed");
        }
    }

    /**
     * <p>
     * Sets the limit for the maximum number of bytes in a ResultSet column storing 
     * character or binary values to the given number of bytes. This limit applies only 
     * to BINARY, VARBINARY, LONGVARBINARY, CHAR, VARCHAR, and LONGVARCHAR fields. 
     * If the limit is exceeded, the excess data is silently discarded. For maximum 
     * portability, use values greater than 256.
     * </p>
     * 
     * @throws BQSQLException
     */
    public void setMaxFieldSize(int arg0) throws SQLException {
        this.maxFieldSize = arg0;
    }

    @Override
    public void setMaxRows(int arg0) throws SQLException {
        this.maxRows = arg0;
        this.resultMaxRowCount = arg0 == 0 ? arg0 : Integer.MAX_VALUE - 1;
    }

    /**
     * <p>
     * <h1>Implementation Details:</h1><br>
     * Not implemented yet.
     * </p>
     * 
     * @throws BQSQLException
     */
    public void setPoolable(boolean arg0) throws SQLException {
        throw new BQSQLException("Not implemented." + "setPoolable(bool)");
    }

    /** {@inheritDoc} */
    public void setQueryTimeout(int arg0) throws SQLException {
        if (this.isClosed()) {
            throw new BQSQLException("This Statement is Closed");
        }
        if (arg0 == 0) {
            this.querytimeout = Integer.MAX_VALUE;
        } else {
            this.querytimeout = arg0;
        }
    }

    /**
     * <p>
     * <h1>Implementation Details:</h1><br>
     * Always throws SQLException
     * </p>
     * 
     * @throws SQLException
     */
    public <T> T unwrap(Class<T> iface) throws SQLException {
        throw new BQSQLException("not found");
    }
}