Package org.voltdb.jdbc

Source Code of org.voltdb.jdbc.JDBC4Statement$VoltSQL

/* This file is part of VoltDB.
* Copyright (C) 2008-2014 VoltDB Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with VoltDB.  If not, see <http://www.gnu.org/licenses/>.
*/

package org.voltdb.jdbc;

import java.io.IOException;
import java.sql.BatchUpdateException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.voltdb.VoltTable;
import org.voltdb.VoltType;
import org.voltdb.client.ClientResponse;
import org.voltdb.client.ProcCallException;

public class JDBC4Statement implements java.sql.Statement
{

    //Timeout for statement. This is used for execute* methods. batch add dont have timeout.
    private int m_timeout = 0;
    static class VoltSQL
    {
        public static final byte TYPE_SELECT = 1;
        public static final byte TYPE_INSERT = 2;
        public static final byte TYPE_UPDATE = 3;
        public static final byte TYPE_DELETE = 4;
        public static final byte TYPE_EXEC = 5;

        private final String[] sql;
        private final int parameterCount;
        private final byte type;
        private final byte queryType;   // Type of query EXEC'd by @AdHoc
        private final Object[] parameters;

        private VoltSQL(String[] sql, int parameterCount, byte type)
        {
            this.sql = sql;
            this.parameterCount = parameterCount;
            this.type = this.queryType = type;
            this.parameters = null;
        }

        private VoltSQL(String[] sql, int parameterCount, byte type, Object[] parameters)
        {
            this(sql, parameterCount, type, type, parameters);
        }

        private VoltSQL(String[] sql, int parameterCount, byte type, byte queryType, Object[] parameters)
        {
            this.sql = sql;
            this.parameterCount = parameterCount;
            this.type = type;
            this.queryType = queryType;
            this.parameters = parameters;
        }

        public boolean hasParameters()
        {
            return this.parameterCount > 0;
        }

        public Object[] getParameterArray() throws SQLException
        {
            return new Object[this.parameterCount];
        }

        public int getParameterCount()
        {
            return this.parameterCount;
        }

        public boolean isOfType(int... types)
        {
            for(int i=0;i<types.length;i++)
                if (this.type == types[i])
                    return true;
            return false;
        }

        public boolean isQueryOfType(int... types)
        {
            for(int i=0;i<types.length;i++)
                if (this.queryType == types[i])
                    return true;
            return false;
        }

        protected VoltTable[] execute(JDBC4ClientConnection connection, long timeout) throws SQLException {
            try
            {
                if (this.type == TYPE_EXEC)
                    return connection.execute(this.sql[0], timeout, this.parameters).getResults();
                else
                    return connection.execute("@AdHoc", timeout, this.sql[0]).getResults();
            }
            catch(ProcCallException e)
            {
                ClientResponse response = e.getClientResponse();
                if (response != null) {
                    // Map response status to specific JDBC exception, mostly GENERAL_ERROR except
                    // for connection problems.
                    switch (response.getStatus()) {
                    case ClientResponse.CONNECTION_LOST:
                        throw SQLError.get(e, SQLError.CONNECTION_CLOSED, "CONNECTION_LOST", e.getMessage());
                    case ClientResponse.CONNECTION_TIMEOUT:
                        throw SQLError.get(e, SQLError.CONNECTION_FAILURE, "CONNECTION_TIMEOUT", e.getMessage());
                    case ClientResponse.SERVER_UNAVAILABLE:
                        throw SQLError.get(e, SQLError.CONNECTION_FAILURE, "CONNECTION_UNAVAILABLE", e.getMessage());
                    case ClientResponse.USER_ABORT:
                        throw SQLError.get(e, SQLError.GENERAL_ERROR, "USER_ABORT", e.getMessage());
                    case ClientResponse.UNEXPECTED_FAILURE:
                        throw SQLError.get(e, SQLError.GENERAL_ERROR, "UNEXPECTED_FAILURE", e.getMessage());
                    case ClientResponse.GRACEFUL_FAILURE:
                        throw SQLError.get(e, SQLError.GENERAL_ERROR, "GRACEFUL_FAILURE", e.getMessage());
                    default:
                        throw SQLError.get(e, SQLError.GENERAL_ERROR, String.format("status=%d", (int)response.getStatus()), e.getMessage());
                    }
                } else {
                    throw SQLError.get(e, SQLError.GENERAL_ERROR, e.getMessage());
                }
            }
            catch(IOException e)
            {
                throw SQLError.get(e, SQLError.CONNECTION_FAILURE, e.getMessage());
            }
        }

        public static boolean isUpdateResult(VoltTable table)
        {
            return ((table.getColumnName(0).length() == 0 || table.getColumnName(0).equals("modified_tuples"))&& table.getRowCount() == 1 && table.getColumnCount() == 1 && table.getColumnType(0) == VoltType.BIGINT);
        }

        public String toSqlString()
        {
            return this.sql[0];
        }

        public VoltSQL getExecutableQuery(Object... params) throws SQLException
        {
            if (params.length != this.parameterCount)
                throw SQLError.get(SQLError.ILLEGAL_ARGUMENT);

            if (this.type == TYPE_EXEC)
                return new VoltSQL(this.sql, this.parameterCount, this.type, params);
            else
            {
                Object[] paramsOut = new Object[params.length+1];
                paramsOut[0] = this.sql[0];
                for (int i = 0; i < params.length; ++i) {
                    paramsOut[i+1] = params[i];
                }
                return new VoltSQL(new String[] {"@AdHoc"}, this.parameterCount, TYPE_EXEC, this.type, paramsOut);
            }
        }

        // SQL Parsing
        private static final Pattern ExtractParameterizedCall = Pattern.compile("^\\s*\\{\\s*call\\s+([^\\s()]+)\\s*\\(([?,\\s]+)\\)\\s*\\}\\s*$", Pattern.CASE_INSENSITIVE);
        private static final Pattern ExtractNoParameterCall = Pattern.compile("^\\s*\\{\\s*call\\s+([^\\s()]+)\\s*\\}\\s*$", Pattern.CASE_INSENSITIVE);
        private static final Pattern CleanCallParameters = Pattern.compile("[\\s,]+");
        public static VoltSQL parseCall(String jdbcCall) throws SQLException        {
            Matcher m = ExtractParameterizedCall.matcher(jdbcCall);
            if (m.matches())
                return new VoltSQL(new String[]{m.group(1)},
                        CleanCallParameters.matcher(m.group(2)).replaceAll("").length(), TYPE_EXEC);
            else
            {
                m = ExtractNoParameterCall.matcher(jdbcCall);
                if (m.matches())
                    return new VoltSQL(new String[]{m.group(1)}, 0, TYPE_EXEC);
            }
            throw SQLError.get(SQLError.ILLEGAL_STATEMENT);
        }

        private static final Pattern EscapedSingleQuote = Pattern.compile("''", Pattern.MULTILINE);
        private static final Pattern SingleLineComments = Pattern.compile("^\\s*(\\/\\/|--).*$", Pattern.MULTILINE);
        private static final Pattern Extract = Pattern.compile("'[^']*'", Pattern.MULTILINE);
        private static final Pattern AutoSplit = Pattern.compile("\\s(select|insert|update|delete)\\s", Pattern.MULTILINE + Pattern.CASE_INSENSITIVE);
        private static final Pattern SpaceCleaner = Pattern.compile("[\\s]+", Pattern.MULTILINE);
        private static final Pattern IsSelect = Pattern.compile("^select\\s.+", Pattern.CASE_INSENSITIVE);
        private static final Pattern IsInsert = Pattern.compile("^insert\\s.+", Pattern.CASE_INSENSITIVE);
        private static final Pattern IsUpdate = Pattern.compile("^update\\s.+", Pattern.CASE_INSENSITIVE);
        private static final Pattern IsDelete = Pattern.compile("^delete\\s.+", Pattern.CASE_INSENSITIVE);
        public static VoltSQL parseSQL(String queryIn) throws SQLException
        {
            if (queryIn == null || queryIn.length() == 0)
                throw SQLError.get(SQLError.ILLEGAL_STATEMENT);

            String query = SingleLineComments.matcher(queryIn).replaceAll("");
            query = EscapedSingleQuote.matcher(query).replaceAll("#(SQL_PARSER_ESCAPE_SINGLE_QUOTE)");
            Matcher stringFragmentMatcher = Extract.matcher(query);
            ArrayList<String> stringFragments = new ArrayList<String>();
            int i = 0;
            while(stringFragmentMatcher.find())
            {
                stringFragments.add(stringFragmentMatcher.group());
                query = stringFragmentMatcher.replaceFirst("#(SQL_PARSER_STRING_FRAGMENT#" + i + ")");
                stringFragmentMatcher = Extract.matcher(query);
                i++;
            }
            query = AutoSplit.matcher(query.trim()).replaceAll(";$1 ");
            String[] sqlFragments = query.split("\\s*;+\\s*");
            if (sqlFragments.length > 1)
                throw SQLError.get(SQLError.QUERY_PARSING_ERROR);
            query = SpaceCleaner.matcher(sqlFragments[0]).replaceAll(" ").trim();

            if (query.length() == 0)
                throw SQLError.get(SQLError.ILLEGAL_STATEMENT);

            byte type = 0;
            if (IsSelect.matcher(query).matches())
                type = TYPE_SELECT;
            else if (IsInsert.matcher(query).matches())
                type = TYPE_INSERT;
            else if (IsUpdate.matcher(query).matches())
                type = TYPE_UPDATE;
            else if (IsDelete.matcher(query).matches())
                type = TYPE_DELETE;

            if (type == 0)
                throw SQLError.get(SQLError.INVALID_QUERY_TYPE);

            if (query.indexOf("'") > -1)
                throw SQLError.get(SQLError.UNTERMINATED_STRING);

            // Make sure there's a ';' terminator;
            if (!query.endsWith(";")) {
                query += ";";
            }
            // Count substitution parameters.
            int parameterCount = 0;
            if(query.indexOf("?") > -1)
            {
                String[] queryParts = (query + ";").split("\\?");
                parameterCount = queryParts.length-1;
            }

            if(stringFragments.size() > 0)
            {
                for(int k = 0;k<stringFragments.size();k++) {
                    query = query.replace("#(SQL_PARSER_STRING_FRAGMENT#" + k + ")", stringFragments.get(k));
                }
            }
            query = query.replace("#(SQL_PARSER_ESCAPE_SINGLE_QUOTE)", "''");

            // Welcome to volt... cannot accept \r or \n in inline SQL...
            if (query.indexOf("\r") > -1 || query.indexOf("\n") > -1)
                throw SQLError.get(SQLError.QUERY_PARSING_ERROR);

            return new VoltSQL(new String[] {query}, parameterCount, type);
        }
    }

    private ArrayList<VoltSQL> batch = null;
    protected boolean isClosed = false;
    private int fetchDirection = ResultSet.FETCH_FORWARD;
    private int fetchSize = 0;
    private final int maxFieldSize = VoltType.MAX_VALUE_LENGTH;
    private int maxRows = VoltTable.MAX_SERIALIZED_TABLE_LENGTH/2; // Not exactly true, but best type of estimate we can give...
    protected JDBC4Connection sourceConnection;
    private boolean isPoolable = false;

    protected VoltTable[] tableResults = null;
    protected int tableResultIndex = -1;
    protected int lastUpdateCount = -1;
    protected Set<JDBC4ResultSet> openResults = new HashSet<JDBC4ResultSet>();
    protected JDBC4ResultSet result = null;

    public JDBC4Statement(JDBC4Connection connection)
    {
        sourceConnection = connection;
    }

    protected void checkClosed() throws SQLException
    {
        if (this.isClosed())
            throw SQLError.get(SQLError.CONNECTION_CLOSED);
    }

    private void closeCurrentResult() throws SQLException
    {
        this.lastUpdateCount = -1;
        if (this.result != null)
            this.result.close();
        this.result = null;
    }

    private JDBC4ResultSet createTrimmedResultSet(VoltTable input) throws SQLException
    {
        VoltTable result = input;
        if (maxRows > 0 && input.getRowCount() > maxRows) {
            VoltTable trimmed = new VoltTable(input.getTableSchema());
            input.resetRowPosition();
            for (int i = 0; i < maxRows; i++) {
                input.advanceRow();
                trimmed.add(input.cloneRow());
            }
            result = trimmed;
        }
        return new JDBC4ResultSet(this, result);
    }

    private void setCurrentResult(VoltTable[] tables, int updateCount) throws SQLException
    {
        this.tableResults = tables;
        this.tableResultIndex = -1;
        this.lastUpdateCount = updateCount;
        if (this.result != null)
            this.result.close();
        if (this.tableResults == null || this.tableResults.length == 0)
            return;
        this.tableResultIndex = 0;
        this.result = createTrimmedResultSet(this.tableResults[this.tableResultIndex]);
    }

    private void closeAllOpenResults() throws SQLException
    {
        if (this.openResults != null)
        {
            for (Iterator<JDBC4ResultSet> iter = this.openResults.iterator(); iter.hasNext();)
            {
                JDBC4ResultSet element = iter.next();

                try
                {
                    element.close();
                }
                catch (SQLException x) {} // Will simply never happen, by design
            }
            this.openResults.clear();
        }
    }

    protected void addBatch(VoltSQL query) throws SQLException
    {
        if (batch == null)
            batch = new ArrayList<VoltSQL>();
        batch.add(query);
    }

    // Adds the given SQL command to the current list of commmands for this Statement object.
    @Override
    public void addBatch(String sql) throws SQLException
    {
        checkClosed();
        VoltSQL query = VoltSQL.parseSQL(sql);
        if (!query.isOfType(VoltSQL.TYPE_INSERT,VoltSQL.TYPE_UPDATE,VoltSQL.TYPE_DELETE))
            throw SQLError.get(SQLError.ILLEGAL_STATEMENT, sql);
        this.addBatch(query);
    }

    // Cancels this Statement object if both the DBMS and driver support aborting an SQL statement.
    @Override
    public void cancel() throws SQLException
    {
        checkClosed();
        throw SQLError.noSupport();
    }

    // Empties this Statement object's current list of SQL commands.
    @Override
    public void clearBatch() throws SQLException
    {
        checkClosed();
        batch = null;
    }

    // Clears all the warnings reported on this Statement object.
    @Override
    public void clearWarnings() throws SQLException
    {
        checkClosed();
    }

    // Releases this Statement object's database and JDBC resources immediately instead of waiting for this to happen when it is automatically closed.
    @Override
    public void close() throws SQLException
    {
        // close resultset too
        this.isClosed = true;
    }

    protected boolean execute(VoltSQL query) throws SQLException
    {
        checkClosed();
        if (query.isQueryOfType(VoltSQL.TYPE_SELECT,VoltSQL.TYPE_EXEC))
        {
            setCurrentResult(query.execute(this.sourceConnection.NativeConnection, this.m_timeout), -1);
            return true;
        }
        else
        {
            setCurrentResult(null, (int) query.execute(this.sourceConnection.NativeConnection, this.m_timeout)[0].fetchRow(0).getLong(0));
            return false;
        }
    }

    // Executes the given SQL statement, which may return multiple results.
    @Override
    public boolean execute(String sql) throws SQLException
    {
        checkClosed();
        VoltSQL query = VoltSQL.parseSQL(sql);
        if (!query.isOfType(VoltSQL.TYPE_SELECT,VoltSQL.TYPE_INSERT,VoltSQL.TYPE_UPDATE,VoltSQL.TYPE_DELETE))
            throw SQLError.get(SQLError.ILLEGAL_STATEMENT, sql);

        return this.execute(query);
    }

    // Executes the given SQL statement, which may return multiple results, and signals the driver that any auto-generated keys should be made available for retrieval.
    @Override
    public boolean execute(String sql, int autoGeneratedKeys) throws SQLException
    {
        checkClosed();
        throw SQLError.noSupport();
    }

    // Executes the given SQL statement, which may return multiple results, and signals the driver that the auto-generated keys indicated in the given array should be made available for retrieval.
    @Override
    public boolean execute(String sql, int[] columnIndexes) throws SQLException
    {
        checkClosed();
        throw SQLError.noSupport();
    }

    // Executes the given SQL statement, which may return multiple results, and signals the driver that the auto-generated keys indicated in the given array should be made available for retrieval.
    @Override
    public boolean execute(String sql, String[] columnNames) throws SQLException
    {
        checkClosed();
        throw SQLError.noSupport();
    }

    // Submits a batch of commands to the database for execution and if all commands execute successfully, returns an array of update counts.
    @Override
    public int[] executeBatch() throws SQLException
    {
        checkClosed();
        closeCurrentResult();
        if (batch == null || batch.size() == 0) {
            return new int[0];
        }

        int[] updateCounts = new int[batch.size()];
        // keep a running total of update counts
        int runningUpdateCount = 0;

        for(int i = 0; i < batch.size(); i++)
        {
            try
            {
                setCurrentResult(null, (int) batch.get(i).execute(sourceConnection.NativeConnection,
                        this.m_timeout)[0].fetchRow(0).getLong(0));
                updateCounts[i] = this.lastUpdateCount;
                runningUpdateCount += this.lastUpdateCount;
            }
            catch(SQLException x)
            {
                updateCounts[i] = EXECUTE_FAILED;
                throw new BatchUpdateException(Arrays.copyOf(updateCounts, i+1), x);
            }
        }

        // replace the update count from the last statement with the update count
        // from the last batch.
        this.lastUpdateCount = runningUpdateCount;

        return updateCounts;
    }

    protected ResultSet executeQuery(VoltSQL query) throws SQLException
    {
        setCurrentResult(query.execute(this.sourceConnection.NativeConnection, this.m_timeout), -1);
        return this.result;
    }

    // Executes the given SQL statement, which returns a single ResultSet object.
    @Override
    public ResultSet executeQuery(String sql) throws SQLException
    {
        checkClosed();
        VoltSQL query = VoltSQL.parseSQL(sql);
        if (!query.isOfType(VoltSQL.TYPE_SELECT))
            throw SQLError.get(SQLError.ILLEGAL_STATEMENT, sql);
        return this.executeQuery(query);
    }

    protected int executeUpdate(VoltSQL query) throws SQLException
    {
        setCurrentResult(null, (int) query.execute(this.sourceConnection.NativeConnection, this.m_timeout)[0].fetchRow(0).getLong(0));
        return this.lastUpdateCount;
    }

    // Executes the given SQL statement, which may be an INSERT, UPDATE, or DELETE statement or an SQL statement that returns nothing, such as an SQL DDL statement.
    @Override
    public int executeUpdate(String sql) throws SQLException
    {
        checkClosed();
        VoltSQL query = VoltSQL.parseSQL(sql);
        if (!query.isOfType(VoltSQL.TYPE_INSERT,VoltSQL.TYPE_UPDATE,VoltSQL.TYPE_DELETE))
            throw SQLError.get(SQLError.ILLEGAL_STATEMENT, sql);
        return this.executeUpdate(query);
    }

    // Executes the given SQL statement and signals the driver with the given flag about whether the auto-generated keys produced by this Statement object should be made available for retrieval.
    @Override
    public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException
    {
        checkClosed();
        throw SQLError.noSupport(); // AutoGeneratedKeys not supported by provider
    }

    // Executes the given SQL statement and signals the driver that the auto-generated keys indicated in the given array should be made available for retrieval.
    @Override
    public int executeUpdate(String sql, int[] columnIndexes) throws SQLException
    {
        checkClosed();
        throw SQLError.noSupport(); // AutoGeneratedKeys not supported by provider
    }

    // Executes the given SQL statement and signals the driver that the auto-generated keys indicated in the given array should be made available for retrieval.
    @Override
    public int executeUpdate(String sql, String[] columnNames) throws SQLException
    {
        checkClosed();
        throw SQLError.noSupport(); // AutoGeneratedKeys not supported by provider
    }

    // Retrieves the Connection object that produced this Statement object.
    @Override
    public Connection getConnection() throws SQLException
    {
        checkClosed();
        return sourceConnection;
    }

    // Retrieves the direction for fetching rows from database tables that is the default for result sets generated from this Statement object.
    @Override
    public int getFetchDirection() throws SQLException
    {
        checkClosed();
        return this.fetchDirection;
    }

    // Retrieves the number of result set rows that is the default fetch size for ResultSet objects generated from this Statement object.
    @Override
    public int getFetchSize() throws SQLException
    {
        checkClosed();
        return this.fetchSize;
    }

    // Retrieves any auto-generated keys created as a result of executing this Statement object.
    @Override
    public ResultSet getGeneratedKeys() throws SQLException
    {
        checkClosed();
        throw SQLError.noSupport();
    }

    // Retrieves the maximum number of bytes that can be returned for character and binary column values in a ResultSet object produced by this Statement object.
    @Override
    public int getMaxFieldSize() throws SQLException
    {
        checkClosed();
        return this.maxFieldSize;
    }

    // Retrieves the maximum number of rows that a ResultSet object produced by this Statement object can contain.
    @Override
    public int getMaxRows() throws SQLException
    {
        checkClosed();
        return this.maxRows;
    }

    // Moves to this Statement object's next result, returns true if it is a ResultSet object, and implicitly closes any current ResultSet object(s) throws SQLException { throw SQLError.noSupport(); } obtained with the method getResultSet.
    @Override
    public boolean getMoreResults() throws SQLException
    {
        return this.getMoreResults(Statement.CLOSE_CURRENT_RESULT);
    }

    // Moves to this Statement object's next result, deals with any current ResultSet object(s) throws SQLException { throw SQLError.noSupport(); } according to the instructions specified by the given flag, and returns true if the next result is a ResultSet object.
    @Override
    public boolean getMoreResults(int current) throws SQLException
    {
        checkClosed();
        switch(current)
        {
            case Statement.KEEP_CURRENT_RESULT:
                this.openResults.add(this.result);
                this.result = null;
                this.lastUpdateCount = -1;
                break;
            case Statement.CLOSE_CURRENT_RESULT:
                closeCurrentResult();
                break;
            case Statement.CLOSE_ALL_RESULTS:
                closeCurrentResult();
                closeAllOpenResults();
                break;
            default:
                throw SQLError.get(SQLError.ILLEGAL_ARGUMENT, current);
        }
        if (current != Statement.CLOSE_ALL_RESULTS)
        {
            this.tableResultIndex++;
            if (this.tableResultIndex < this.tableResults.length)
            {
                VoltTable table = this.tableResults[this.tableResultIndex];
                if (VoltSQL.isUpdateResult(table))
                    this.lastUpdateCount = (int)table.fetchRow(0).getLong(0);
                else
                {
                    this.result = createTrimmedResultSet(table);
                    return true;
                }
            }
        }
        return false;
    }

    // Retrieves the number of seconds the driver will wait for a Statement object to execute.
    @Override
    public int getQueryTimeout() throws SQLException
    {
        checkClosed();
        return this.m_timeout;
    }

    // Retrieves the current result as a ResultSet object.
    @Override
    public ResultSet getResultSet() throws SQLException
    {
        checkClosed();
        return this.result;
    }

    // Retrieves the result set concurrency for ResultSet objects generated by this Statement object.
    @Override
    public int getResultSetConcurrency() throws SQLException
    {
        checkClosed();
        return ResultSet.CONCUR_READ_ONLY;
    }

    // Retrieves the result set holdability for ResultSet objects generated by this Statement object.
    @Override
    public int getResultSetHoldability() throws SQLException
    {
        checkClosed();
        throw SQLError.noSupport();
    }

    // Retrieves the result set type for ResultSet objects generated by this Statement object.
    @Override
    public int getResultSetType() throws SQLException
    {
        checkClosed();
        return ResultSet.TYPE_SCROLL_INSENSITIVE;
    }

    // Retrieves the current result as an update count; if the result is a ResultSet object or there are no more results, -1 is returned.
    @Override
    public int getUpdateCount() throws SQLException
    {
        checkClosed();
        return this.lastUpdateCount;
    }

    // Retrieves the first warning reported by calls on this Statement object.
    @Override
    public SQLWarning getWarnings() throws SQLException
    {
        checkClosed();
        throw SQLError.noSupport();
    }

    // Retrieves whether this Statement object has been closed.
    @Override
    public boolean isClosed() throws SQLException
    {
        return this.isClosed;
    }

    // Returns a value indicating whether the Statement is poolable or not.
    @Override
    public boolean isPoolable() throws SQLException
    {
        checkClosed();
        return this.isPoolable;
    }

    // Sets the SQL cursor name to the given String, which will be used by subsequent Statement object execute methods.
    @Override
    public void setCursorName(String name) throws SQLException
    {
        checkClosed();
        throw SQLError.noSupport();
    }

    // Sets escape processing on or off.
    @Override
    public void setEscapeProcessing(boolean enable) throws SQLException
    {
        checkClosed();
        // Do nothing / not applicable?
    }

    // Gives the driver a hint as to the direction in which rows will be processed in ResultSet objects created using this Statement object.
    @Override
    public void setFetchDirection(int direction) throws SQLException
    {
        checkClosed();
        if ((direction != ResultSet.FETCH_FORWARD) && (direction != ResultSet.FETCH_REVERSE) && (direction != ResultSet.FETCH_UNKNOWN))
            throw SQLError.get(SQLError.ILLEGAL_ARGUMENT, direction);
        this.fetchDirection = direction;
    }

    // Gives the JDBC driver a hint as to the number of rows that should be fetched from the database when more rows are needed for ResultSet objects genrated by this Statement.
    @Override
    public void setFetchSize(int rows) throws SQLException
    {
        checkClosed();
        if (rows < 0)
            throw SQLError.get(SQLError.ILLEGAL_ARGUMENT, rows);
        this.fetchSize = rows;
    }

    // Sets the limit for the maximum number of bytes that can be returned for character and binary column values in a ResultSet object produced by this Statement object.
    @Override
    public void setMaxFieldSize(int max) throws SQLException
    {
        checkClosed();
        if (max < 0)
            throw SQLError.get(SQLError.ILLEGAL_ARGUMENT, max);
        throw SQLError.noSupport(); // Not supported by provider - no point trashing data we received from the server just to simulate the feature while not getting any gains!
    }

    // Sets the limit for the maximum number of rows that any ResultSet object generated by this Statement object can contain to the given number.
    @Override
    public void setMaxRows(int max) throws SQLException
    {
        checkClosed();
        if (max < 0)
            throw SQLError.get(SQLError.ILLEGAL_ARGUMENT, max);
        this.maxRows = max;
    }

    // Requests that a Statement be pooled or not pooled.
    @Override
    public void setPoolable(boolean poolable) throws SQLException
    {
        checkClosed();
        this.isPoolable = poolable;
    }

    // Sets the number of seconds the driver will wait for a Statement object to execute to the given number of seconds.
    @Override
    public void setQueryTimeout(int seconds) throws SQLException
    {
        checkClosed();
        if (seconds < 0)
            throw SQLError.get(SQLError.ILLEGAL_ARGUMENT, seconds);
        this.m_timeout = seconds;
    }

    // Returns true if this either implements the interface argument or is directly or indirectly a wrapper for an object that does.
    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException
    {
        return iface.isInstance(this);
    }

    // Returns an object that implements the given interface to allow access to non-standard methods, or standard methods not exposed by the proxy.
    @Override
    public <T> T unwrap(Class<T> iface)    throws SQLException
    {
        try
        {
            return iface.cast(this);
        }
         catch (ClassCastException cce)
         {
            throw SQLError.get(SQLError.ILLEGAL_ARGUMENT, iface.toString());
        }
    }

    @Override
    public void closeOnCompletion() throws SQLException {
        throw SQLError.noSupport();
    }

    @Override
    public boolean isCloseOnCompletion() throws SQLException {
        throw SQLError.noSupport();
    }
}
TOP

Related Classes of org.voltdb.jdbc.JDBC4Statement$VoltSQL

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.