alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

HSQLDB example source code file (Session.java)

This example HSQLDB source code file (Session.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - HSQLDB tags/keywords

autocommit, compiledstatement, hsqlexception, hsqlexception, hsqlname, hsqlname, jdbc, node, object, result, result, set, sql, string, string, throwable

The HSQLDB Session.java source code

/*
 * For work developed by the HSQL Development Group:
 *
 * Copyright (c) 2001-2010, The HSQL Development Group
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * Neither the name of the HSQL Development Group nor the names of its
 * contributors may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *
 *
 * For work originally developed by the Hypersonic SQL Group:
 *
 * Copyright (c) 1995-2000, The Hypersonic SQL Group.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * Neither the name of the Hypersonic SQL Group nor the names of its
 * contributors may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE HYPERSONIC SQL GROUP,
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * This software consists of voluntary contributions made by many individuals
 * on behalf of the Hypersonic SQL Group.
 */


package org.hsqldb;

import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;

import org.hsqldb.HsqlNameManager.HsqlName;
import org.hsqldb.jdbc.jdbcConnection;
import org.hsqldb.lib.ArrayUtil;
import org.hsqldb.lib.HashMappedList;
import org.hsqldb.lib.HsqlArrayList;
import org.hsqldb.lib.IntKeyHashMap;
import org.hsqldb.lib.SimpleLog;
import org.hsqldb.lib.java.JavaSystem;
import org.hsqldb.store.ValuePool;

// fredt@users 20020320 - doc 1.7.0 - update
// fredt@users 20020315 - patch 1.7.0 - switch for scripting
// fredt@users 20020130 - patch 476694 by velichko - transaction savepoints
// additions in different parts to support savepoint transactions
// fredt@users 20020910 - patch 1.7.1 by fredt - database readonly enforcement
// fredt@users 20020912 - patch 1.7.1 by fredt - permanent internal connection
// boucherb@users 20030512 - patch 1.7.2 - compiled statements
//                                       - session becomes execution hub
// boucherb@users 20050510 - patch 1.7.2 - generalized Result packet passing
//                                         based command execution
//                                       - batch execution handling
// fredt@users 20030628 - patch 1.7.2 - session proxy support
// fredt@users 20040509 - patch 1.7.2 - SQL conformance for CURRENT_TIMESTAMP and other datetime functions

/**
 *  Implementation of a user session with the database. In 1.7.2 Session
 *  becomes the public interface to an HSQLDB database, accessed locally or
 *  remotely via SessionInterface.
 *
 *  When as Session is closed, all references to internal engine objects are
 *  set to null. But the session id and scripting mode may still be used for
 *  scripting
 *
 * New class based based on original Hypersonic code.
 * Extensively rewritten and extended in successive versions of HSQLDB.
 *
 * @author Thomas Mueller (Hypersonic SQL Group)
 * @version 1.8.0
 * @since 1.7.0
 */
public class Session implements SessionInterface {

    //
    private volatile boolean isAutoCommit;
    private volatile boolean isReadOnly;
    private volatile boolean isClosed;

    //
    Database          database;
    private User      user;
    HsqlArrayList     rowActionList;
    private boolean   isNestedTransaction;
    private int       nestedOldTransIndex;
    int               isolationMode = SessionInterface.TX_READ_COMMITTED;
    long              actionTimestamp;
    long              transactionTimestamp;
    private int       currentMaxRows;
    private int       sessionMaxRows;
    private Number    lastIdentity = ValuePool.getInt(0);
    private final int sessionId;
    HashMappedList    savepoints;
    private boolean   script;
    private Tokenizer tokenizer;
    private Parser    parser;
    static final Result emptyUpdateCount =
        new Result(ResultConstants.UPDATECOUNT);

    //
    private jdbcConnection intConnection;

    // schema
    public HsqlName  currentSchema;
    public HsqlName  loggedSchema;
    private HsqlName oldSchema;

    // query processing
    boolean isProcessingScript;
    boolean isProcessingLog;

    // two types of temp tables
    private IntKeyHashMap indexArrayMap;
    private IntKeyHashMap indexArrayKeepMap;

    /** @todo fredt - clarify in which circumstances Session has to disconnect */
    Session getSession() {
        return this;
    }

    /**
     * Constructs a new Session object.
     *
     * @param  db the database to which this represents a connection
     * @param  user the initial user
     * @param  autocommit the initial autocommit value
     * @param  readonly the initial readonly value
     * @param  id the session identifier, as known to the database
     */
    Session(Database db, User user, boolean autocommit, boolean readonly,
            int id) {

        sessionId                 = id;
        database                  = db;
        this.user                 = user;
        rowActionList             = new HsqlArrayList(true);
        savepoints                = new HashMappedList(4);
        isAutoCommit              = autocommit;
        isReadOnly                = readonly;
        dbCommandInterpreter      = new DatabaseCommandInterpreter(this);
        compiledStatementExecutor = new CompiledStatementExecutor(this);
        compiledStatementManager  = db.compiledStatementManager;
        tokenizer                 = new Tokenizer();
        parser                    = new Parser(this, database, tokenizer);

        resetSchema();
    }

    void resetSchema() {

        HsqlName initialSchema = user.getInitialSchema();

        currentSchema = ((initialSchema == null)
                         ? database.schemaManager.getDefaultSchemaHsqlName()
                         : initialSchema);
    }

    /**
     *  Retrieves the session identifier for this Session.
     *
     * @return the session identifier for this Session
     */
    public int getId() {
        return sessionId;
    }

    /**
     * Closes this Session.
     */
    public void close() {

        if (isClosed) {
            return;
        }

        synchronized (database) {

            // test again inside block
            if (isClosed) {
                return;
            }

            database.sessionManager.removeSession(this);
            rollback();

            try {
                database.logger.writeToLog(this, Token.T_DISCONNECT);
            } catch (HsqlException e) {}

            clearIndexRoots();
            clearIndexRootsKeep();
            compiledStatementManager.removeSession(sessionId);
            database.closeIfLast();

            database                  = null;
            user                      = null;
            rowActionList             = null;
            savepoints                = null;
            intConnection             = null;
            compiledStatementExecutor = null;
            compiledStatementManager  = null;
            dbCommandInterpreter      = null;
            lastIdentity              = null;
            isClosed                  = true;
        }
    }

    /**
     * Retrieves whether this Session is closed.
     *
     * @return true if this Session is closed
     */
    public boolean isClosed() {
        return isClosed;
    }

    public void setIsolation(int level) throws HsqlException {
        isolationMode = level;
    }

    public int getIsolation() throws HsqlException {
        return isolationMode;
    }

    /**
     * Setter for iLastIdentity attribute.
     *
     * @param  i the new value
     */
    void setLastIdentity(Number i) {
        lastIdentity = i;
    }

    /**
     * Getter for iLastIdentity attribute.
     *
     * @return the current value
     */
    Number getLastIdentity() {
        return lastIdentity;
    }

    /**
     * Retrieves the Database instance to which this
     * Session represents a connection.
     *
     * @return the Database object to which this Session is connected
     */
    Database getDatabase() {
        return database;
    }

    /**
     * Retrieves the name, as known to the database, of the
     * user currently controlling this Session.
     *
     * @return the name of the user currently connected within this Session
     */
    String getUsername() {
        return user.getName();
    }

    /**
     * Retrieves the User object representing the user currently controlling
     * this Session.
     *
     * @return this Session's User object
     */
    public User getUser() {
        return user;
    }

    /**
     * Sets this Session's User object to the one specified by the
     * user argument.
     *
     * @param  user the new User object for this session
     */
    void setUser(User user) {
        this.user = user;
    }

    int getMaxRows() {
        return currentMaxRows;
    }

    int getSQLMaxRows() {
        return sessionMaxRows;
    }

    /**
     * The SQL command SET MAXROWS n will override the Statement.setMaxRows(n)
     * until SET MAXROWS 0 is issued.
     *
     * NB this is dedicated to the SET MAXROWS sql statement and should not
     * otherwise be called. (fredt@users)
     */
    void setSQLMaxRows(int rows) {
        currentMaxRows = sessionMaxRows = rows;
    }

    /**
     * Checks whether this Session's current User has the privileges of
     * the ADMIN role.
     *
     * @throws HsqlException if this Session's User does not have the
     *      privileges of the ADMIN role.
     */
    void checkAdmin() throws HsqlException {
        user.checkAdmin();
    }

    /**
     * Checks whether this Session's current User has the set of rights
     * specified by the right argument, in relation to the database
     * object identifier specified by the object argument.
     *
     * @param  object the database object to check
     * @param  right the rights to check for
     * @throws  HsqlException if the Session User does not have such rights
     */
    void check(HsqlName object, int right) throws HsqlException {
        user.check(object, right);
    }

    /**
     * Checks the rights on a function
     *
     * @param  object the function
     * @throws  HsqlException if the Session User does not have such rights
     */
    void check(String object) throws HsqlException {
        user.check(object);
    }

    /**
     * This is used for reading - writing to existing tables.
     * @throws  HsqlException
     */
    void checkReadWrite() throws HsqlException {

        if (isReadOnly) {
            throw Trace.error(Trace.DATABASE_IS_READONLY);
        }
    }

    /**
     * This is used for creating new database objects such as tables.
     * @throws  HsqlException
     */
    void checkDDLWrite() throws HsqlException {

        if (database.isFilesReadOnly() && !user.isSys()) {
            throw Trace.error(Trace.DATABASE_IS_READONLY);
        }

        checkReadWrite();
    }

    /**
     *  Adds a single-row deletion step to the transaction UNDO buffer.
     *
     * @param  table the table from which the row was deleted
     * @param  row the deleted row
     * @throws  HsqlException
     */
    boolean addDeleteAction(Table table, Row row) throws HsqlException {

        if (!isAutoCommit || isNestedTransaction) {
            Transaction t = new Transaction(true, table, row, actionTimestamp);

            rowActionList.add(t);
            database.txManager.addTransaction(this, t);

            return true;
        } else {
            table.removeRowFromStore(row);
        }

        return false;
    }

    /**
     *  Adds a single-row insertion step to the transaction UNDO buffer.
     *
     * @param  table the table into which the row was inserted
     * @param  row the inserted row
     * @throws  HsqlException
     */
    boolean addInsertAction(Table table, Row row) throws HsqlException {

        if (!isAutoCommit || isNestedTransaction) {
            Transaction t = new Transaction(false, table, row,
                                            actionTimestamp);

            rowActionList.add(t);
            database.txManager.addTransaction(this, t);

            return true;
        } else {
            table.commitRowToStore(row);
        }

        return false;
    }

    /**
     *  Setter for the autocommit attribute.
     *
     * @param  autocommit the new value
     * @throws  HsqlException
     */
    public void setAutoCommit(boolean autocommit) {

        if (isClosed) {
            return;
        }

        synchronized (database) {
            if (autocommit != isAutoCommit) {
                commit();

                isAutoCommit = autocommit;

                try {
                    database.logger.writeToLog(this, getAutoCommitStatement());
                } catch (HsqlException e) {}
            }
        }
    }

    public void startPhasedTransaction() throws HsqlException {}

    public void prepareCommit() throws HsqlException {}

    /**
     * Commits any uncommited transaction this Session may have open
     *
     * @throws  HsqlException
     */
    public void commit() {

        if (isClosed) {
            return;
        }

        synchronized (database) {
            if (!rowActionList.isEmpty()) {
                try {
                    database.logger.writeCommitStatement(this);
                } catch (HsqlException e) {}
            }

            database.txManager.commit(this);
            clearIndexRoots();
        }
    }

    /**
     * Rolls back any uncommited transaction this Session may have open.
     *
     * @throws  HsqlException
     */
    public void rollback() {

        if (isClosed) {
            return;
        }

        synchronized (database) {
            if (rowActionList.size() != 0) {
                try {
                    database.logger.writeToLog(this, Token.T_ROLLBACK);
                } catch (HsqlException e) {}
            }

            database.txManager.rollback(this);
            clearIndexRoots();
        }
    }

    /**
     * No-op in this implementation
     */
    public void resetSession() throws HsqlException {
        throw new HsqlException("", "", 0);
    }

    /**
     *  Implements a transaction SAVEPOINT. A new SAVEPOINT with the
     *  name of an existing one replaces the old SAVEPOINT.
     *
     * @param  name of the savepoint
     * @throws  HsqlException if there is no current transaction
     */
    void savepoint(String name) throws HsqlException {

        savepoints.remove(name);
        savepoints.add(name, ValuePool.getInt(rowActionList.size()));

        try {
            database.logger.writeToLog(this, Token.T_SAVEPOINT + " " + name);
        } catch (HsqlException e) {}
    }

    /**
     *  Implements a partial transaction ROLLBACK.
     *
     * @param  name Name of savepoint that was marked before by savepoint()
     *      call
     * @throws  HsqlException
     */
    void rollbackToSavepoint(String name) throws HsqlException {

        if (isClosed) {
            return;
        }

        try {
            database.logger.writeToLog(this,
                                       Token.T_ROLLBACK + " " + Token.T_TO
                                       + " " + Token.T_SAVEPOINT + " " + name);
        } catch (HsqlException e) {}

        database.txManager.rollbackSavepoint(this, name);
    }

    /**
     * Implements release of named SAVEPOINT.
     *
     * @param  name Name of savepoint that was marked before by savepoint()
     *      call
     * @throws  HsqlException if name does not correspond to a savepoint
     */
    void releaseSavepoint(String name) throws HsqlException {

        // remove this and all later savepoints
        int index = savepoints.getIndex(name);

        Trace.check(index >= 0, Trace.SAVEPOINT_NOT_FOUND, name);

        while (savepoints.size() > index) {
            savepoints.remove(savepoints.size() - 1);
        }
    }

    /**
     * Starts a nested transaction.
     *
     * @throws  HsqlException
     */
    void beginNestedTransaction() throws HsqlException {

        if (isNestedTransaction) {
            Trace.doAssert(false, "beginNestedTransaction");
        }

        nestedOldTransIndex = rowActionList.size();
        isNestedTransaction = true;

        if (isAutoCommit) {
            try {
                database.logger.writeToLog(this, "SET AUTOCOMMIT FALSE");
            } catch (HsqlException e) {}
        }
    }

    /**
     * @todo -- fredt 20050604 - if this method is called after an out of memory
     * error during update, the next block might throw out of memory too and as
     * a result inNestedTransaction remains true and no further update
     * is possible. The session must be closed at that point by the user
     * application.
     */

    /**
     * Ends a nested transaction.
     *
     * @param  rollback true to roll back or false to commit the nested transaction
     * @throws  HsqlException
     */
    void endNestedTransaction(boolean rollback) throws HsqlException {

        if (!isNestedTransaction) {
            Trace.doAssert(false, "endNestedTransaction");
        }

        if (rollback) {
            database.txManager.rollbackTransactions(this, nestedOldTransIndex,
                    true);
        }

        // reset after the rollback
        isNestedTransaction = false;

        if (isAutoCommit) {
            database.txManager.commit(this);

            try {
                database.logger.writeToLog(this, "SET AUTOCOMMIT TRUE");
            } catch (HsqlException e) {}
        }
    }

    /**
     * Setter for readonly attribute.
     *
     * @param  readonly the new value
     */
    public void setReadOnly(boolean readonly) throws HsqlException {

        if (!readonly && database.databaseReadOnly) {
            throw Trace.error(Trace.DATABASE_IS_READONLY);
        }

        isReadOnly = readonly;
    }

    /**
     *  Getter for readonly attribute.
     *
     * @return the current value
     */
    public boolean isReadOnly() {
        return isReadOnly;
    }

    /**
     *  Getter for nestedTransaction attribute.
     *
     * @return the current value
     */
    boolean isNestedTransaction() {
        return isNestedTransaction;
    }

    /**
     *  Getter for autoCommit attribute.
     *
     * @return the current value
     */
    public boolean isAutoCommit() {
        return isAutoCommit;
    }

    /**
     *  A switch to set scripting on the basis of type of statement executed.
     *  A method in DatabaseCommandInterpreter.java sets this value to false
     *  before other  methods are called to act on an SQL statement, which may
     *  set this to true. Afterwards the method reponsible for logging uses
     *  getScripting() to determine if logging is required for the executed
     *  statement. (fredt@users)
     *
     * @param  script The new scripting value
     */
    void setScripting(boolean script) {
        this.script = script;
    }

    /**
     * Getter for scripting attribute.
     *
     * @return  scripting for the last statement.
     */
    boolean getScripting() {
        return script;
    }

    public String getAutoCommitStatement() {
        return isAutoCommit ? "SET AUTOCOMMIT TRUE"
                            : "SET AUTOCOMMIT FALSE";
    }

    /**
     * Retrieves an internal Connection object equivalent to the one
     * that created this Session.
     *
     * @return  internal connection.
     */
    jdbcConnection getInternalConnection() throws HsqlException {

        if (intConnection == null) {
            intConnection = new jdbcConnection(this);
        }

        return intConnection;
    }

// boucherb@users 20020810 metadata 1.7.2
//----------------------------------------------------------------
    private final long connectTime = System.currentTimeMillis();

// more effecient for MetaData concerns than checkAdmin

    /**
     * Getter for admin attribute.
     *
     * @ return the current value
     */
    boolean isAdmin() {
        return user.isAdmin();
    }

    /**
     * Getter for connectTime attribute.
     *
     * @return the value
     */
    long getConnectTime() {
        return connectTime;
    }

    /**
     * Getter for transactionSise attribute.
     *
     * @return the current value
     */
    int getTransactionSize() {
        return rowActionList.size();
    }

    /**
     * Retrieves whether the database object identifier by the dbobject
     * argument is accessible by the current Session User.
     *
     * @return true if so, else false
     */
    boolean isAccessible(String dbobject) throws HsqlException {
        return user.isAccessible(dbobject);
    }

    boolean isAccessible(HsqlName dbobject) throws HsqlException {
        return user.isAccessible(dbobject);
    }

// boucherb@users 20030417 - patch 1.7.2 - compiled statement support
//-------------------------------------------------------------------
    DatabaseCommandInterpreter dbCommandInterpreter;
    CompiledStatementExecutor  compiledStatementExecutor;
    CompiledStatementManager   compiledStatementManager;

    CompiledStatement sqlCompileStatement(String sql) throws HsqlException {

        parser.reset(sql);

        CompiledStatement cs;
        int               brackets = 0;
        String            token    = tokenizer.getString();
        int               cmd      = Token.get(token);

        switch (cmd) {

            case Token.OPENBRACKET : {
                brackets = parser.parseOpenBracketsSelect() + 1;
            }
            case Token.SELECT : {
                cs = parser.compileSelectStatement(brackets);

                break;
            }
            case Token.INSERT : {
                cs = parser.compileInsertStatement();

                break;
            }
            case Token.UPDATE : {
                cs = parser.compileUpdateStatement();

                break;
            }
            case Token.DELETE : {
                cs = parser.compileDeleteStatement();

                break;
            }
            case Token.CALL : {
                cs = parser.compileCallStatement();

                break;
            }
            default : {

                // DDL statements
                cs = new CompiledStatement(currentSchema);

                break;
            }
        }

        // In addition to requiring that the compilation was successful,
        // we also require that the submitted sql represents a _single_
        // valid DML or DDL statement. We do not check the DDL yet.
        // fredt - now accepts semicolon and whitespace at the end of statement
        // fredt - investigate if it should or not for prepared statements
        if (cs.type != CompiledStatement.DDL) {
            while (tokenizer.getPosition() < tokenizer.getLength()) {
                token = tokenizer.getString();

                if (token.length() != 0 && !token.equals(Token.T_SEMICOLON)) {
                    throw Trace.error(Trace.UNEXPECTED_TOKEN, token);
                }
            }
        }

        // - need to be able to key cs against its sql in statement pool
        // - also need to be able to revalidate its sql occasionally
        cs.sql = sql;

        return cs;
    }

    /**
     * Executes the command encapsulated by the cmd argument.
     *
     * @param cmd the command to execute
     * @return the result of executing the command
     */
    public Result execute(Result cmd) {

        try {
            if (isClosed) {
                Trace.check(false, Trace.ACCESS_IS_DENIED,
                            Trace.getMessage(Trace.Session_execute));
            }
        } catch (Throwable t) {
            return new Result(t, null);
        }

        synchronized (database) {
            int type = cmd.mode;

            if (sessionMaxRows == 0) {
                currentMaxRows = cmd.updateCount;
            }

            // we simply get the next system change number - no matter what type of query
            actionTimestamp = database.txManager.nextActionTimestamp();

            JavaSystem.gc();

            switch (type) {

                case ResultConstants.SQLEXECUTE : {
                    Result resultout = sqlExecute(cmd);

                    resultout = performPostExecute(resultout);

                    return resultout;
                }
                case ResultConstants.BATCHEXECUTE : {
                    Result resultout = sqlExecuteBatch(cmd);

                    resultout = performPostExecute(resultout);

                    return resultout;
                }
                case ResultConstants.SQLEXECDIRECT : {
                    Result resultout =
                        sqlExecuteDirectNoPreChecks(cmd.getMainString());

                    resultout = performPostExecute(resultout);

                    return resultout;
                }
                case ResultConstants.BATCHEXECDIRECT : {
                    Result resultout = sqlExecuteBatchDirect(cmd);

                    resultout = performPostExecute(resultout);

                    return resultout;
                }
                case ResultConstants.SQLPREPARE : {
                    CompiledStatement cs;

                    try {
                        cs = compiledStatementManager.compile(
                            this, cmd.getMainString());
                    } catch (Throwable t) {
                        return new Result(t, cmd.getMainString());
                    }

                    Result rmd = cs.describeResult();
                    Result pmd = cs.describeParameters();

                    return Result.newPrepareResponse(cs.id, rmd, pmd);
                }
                case ResultConstants.SQLFREESTMT : {
                    compiledStatementManager.freeStatement(
                        cmd.getStatementID(), sessionId, false);

                    return emptyUpdateCount;
                }
                case ResultConstants.GETSESSIONATTR : {
                    return getAttributes();
                }
                case ResultConstants.SETSESSIONATTR : {
                    return setAttributes(cmd);
                }
                case ResultConstants.SQLENDTRAN : {
                    switch (cmd.getEndTranType()) {

                        case ResultConstants.COMMIT :
                            commit();
                            break;

                        case ResultConstants.ROLLBACK :
                            rollback();
                            break;

                        case ResultConstants.SAVEPOINT_NAME_RELEASE :
                            try {
                                String name = cmd.getMainString();

                                releaseSavepoint(name);
                            } catch (Throwable t) {
                                return new Result(t, null);
                            }
                            break;

                        case ResultConstants.SAVEPOINT_NAME_ROLLBACK :
                            try {
                                rollbackToSavepoint(cmd.getMainString());
                            } catch (Throwable t) {
                                return new Result(t, null);
                            }
                            break;

                        // not yet
                        // case ResultConstants.COMMIT_AND_CHAIN :
                        // case ResultConstants.ROLLBACK_AND_CHAIN :
                    }

                    return emptyUpdateCount;
                }
                case ResultConstants.SQLSETCONNECTATTR : {
                    switch (cmd.getConnectionAttrType()) {

                        case ResultConstants.SQL_ATTR_SAVEPOINT_NAME :
                            try {
                                savepoint(cmd.getMainString());
                            } catch (Throwable t) {
                                return new Result(t, null);
                            }

                        // case ResultConstants.SQL_ATTR_AUTO_IPD
                        //   - always true
                        // default: throw - case never happens
                    }

                    return emptyUpdateCount;
                }
                case ResultConstants.SQLDISCONNECT : {
                    close();

                    return emptyUpdateCount;
                }
                default : {
                    return new Result(
                        Trace.runtimeError(
                            Trace.UNSUPPORTED_INTERNAL_OPERATION,
                            "Session.execute()"), null);
                }
            }
        }
    }

    private Result performPostExecute(Result r) {

        try {
            if (database != null) {
                database.schemaManager.logSequences(this, database.logger);

                if (isAutoCommit) {
                    clearIndexRoots();
                    database.logger.synchLog();
                }
            }

            return r;
        } catch (Exception e) {
            return new Result(e, null);
        } finally {
            if (database != null && database.logger.needsCheckpoint()) {
                try {
                    database.logger.checkpoint(false);
                } catch (HsqlException e) {
                    database.logger.appLog.logContext(
                        SimpleLog.LOG_ERROR, "checkpoint did not complete");
                }
            }
        }
    }

    public Result sqlExecuteDirectNoPreChecks(String sql) {

        synchronized (database) {
            return dbCommandInterpreter.execute(sql);
        }
    }

    Result sqlExecuteCompiledNoPreChecks(CompiledStatement cs,
                                         Object[] pvals) {
        return compiledStatementExecutor.execute(cs, pvals);
    }

    private Result sqlExecuteBatch(Result cmd) {

        int               csid;
        Record            record;
        Result            out;
        CompiledStatement cs;
        Expression[]      parameters;
        int[]             updateCounts;
        int               count;

        csid = cmd.getStatementID();
        cs   = database.compiledStatementManager.getStatement(this, csid);

        if (cs == null) {

            // invalid sql has been removed already
            return new Result(
                Trace.runtimeError(Trace.INVALID_PREPARED_STATEMENT, null),
                null);
        }

        parameters   = cs.parameters;
        count        = 0;
        updateCounts = new int[cmd.getSize()];
        record       = cmd.rRoot;

        while (record != null) {
            Result   in;
            Object[] pvals = record.data;

            in = sqlExecuteCompiledNoPreChecks(cs, pvals);

            // On the client side, iterate over the vals and throw
            // a BatchUpdateException if a batch status value of
            // esultConstants.EXECUTE_FAILED is encountered in the result
            if (in.mode == ResultConstants.UPDATECOUNT) {
                updateCounts[count++] = in.updateCount;
            } else if (in.isData()) {

                // FIXME:  we don't have what it takes yet
                // to differentiate between things like
                // stored procedure calls to methods with
                // void return type and select statements with
                // a single row/column containg null
                updateCounts[count++] = ResultConstants.SUCCESS_NO_INFO;
            } else {
                updateCounts = ArrayUtil.arraySlice(updateCounts, 0, count);

                break;
            }

            record = record.next;
        }

        out = new Result(ResultConstants.SQLEXECUTE, updateCounts, 0);

        return out;
    }

    private Result sqlExecuteBatchDirect(Result cmd) {

        Record record;
        Result out;
        int[]  updateCounts;
        int    count;

        count        = 0;
        updateCounts = new int[cmd.getSize()];
        record       = cmd.rRoot;

        while (record != null) {
            Result in;
            String sql = (String) record.data[0];

            try {
                in = dbCommandInterpreter.execute(sql);
            } catch (Throwable t) {
                in = new Result(ResultConstants.ERROR);

                // if (t instanceof OutOfMemoryError) {
                // System.gc();
                // }
                // "in" alread equals "err"
                // maybe test for OOME and do a gc() ?
                // t.printStackTrace();
            }

            // On the client side, iterate over the colType vals and throw
            // a BatchUpdateException if a batch status value of
            // ResultConstants.EXECUTE_FAILED is encountered
            if (in.mode == ResultConstants.UPDATECOUNT) {
                updateCounts[count++] = in.updateCount;
            } else if (in.isData()) {

                // FIXME:  we don't have what it takes yet
                // to differentiate between things like
                // stored procedure calls to methods with
                // void return type and select statements with
                // a single row/column containg null
                updateCounts[count++] = ResultConstants.SUCCESS_NO_INFO;
            } else {
                updateCounts = ArrayUtil.arraySlice(updateCounts, 0, count);

                break;
            }

            record = record.next;
        }

        out = new Result(ResultConstants.SQLEXECUTE, updateCounts, 0);

        return out;
    }

    /**
     * Retrieves the result of executing the prepared statement whose csid
     * and parameter values/types are encapsulated by the cmd argument.
     *
     * @return the result of executing the statement
     */
    private Result sqlExecute(Result cmd) {

        int csid = cmd.getStatementID();
        CompiledStatement cs = compiledStatementManager.getStatement(this,
            csid);

        if (cs == null) {

            // invalid sql has been removed already
            return new Result(
                Trace.runtimeError(Trace.INVALID_PREPARED_STATEMENT, null),
                null);
        }

        Object[] pvals = cmd.getParameterData();

        return sqlExecute(cs, pvals);
    }

    private Result sqlExecute(CompiledStatement cs, Object[] pvals) {
        return sqlExecuteCompiledNoPreChecks(cs, pvals);
    }

// session DATETIME functions
    long      currentDateTimeSCN;
    long      currentMillis;
    Date      currentDate;
    Time      currentTime;
    Timestamp currentTimestamp;

    /**
     * Returns the current date, unchanged for the duration of the current
     * execution unit (statement).<p>
     *
     * SQL standards require that CURRENT_DATE, CURRENT_TIME and
     * CURRENT_TIMESTAMP are all evaluated at the same point of
     * time in the duration of each SQL statement, no matter how long the
     * SQL statement takes to complete.<p>
     *
     * When this method or a corresponding method for CURRENT_TIME or
     * CURRENT_TIMESTAMP is first called in the scope of a system change
     * number, currentMillis is set to the current system time. All further
     * CURRENT_XXXX calls in this scope will use this millisecond value.
     * (fredt@users)
     */
    Date getCurrentDate() {

        if (currentDateTimeSCN != actionTimestamp) {
            currentDateTimeSCN = actionTimestamp;
            currentMillis      = System.currentTimeMillis();
            currentDate        = HsqlDateTime.getCurrentDate(currentMillis);
            currentTime        = null;
            currentTimestamp   = null;
        } else if (currentDate == null) {
            currentDate = HsqlDateTime.getCurrentDate(currentMillis);
        }

        return currentDate;
    }

    /**
     * Returns the current time, unchanged for the duration of the current
     * execution unit (statement)
     */
    Time getCurrentTime() {

        if (currentDateTimeSCN != actionTimestamp) {
            currentDateTimeSCN = actionTimestamp;
            currentMillis      = System.currentTimeMillis();
            currentDate        = null;
            currentTime =
                new Time(HsqlDateTime.getNormalisedTime(currentMillis));
            currentTimestamp = null;
        } else if (currentTime == null) {
            currentTime =
                new Time(HsqlDateTime.getNormalisedTime(currentMillis));
        }

        return currentTime;
    }

    /**
     * Returns the current timestamp, unchanged for the duration of the current
     * execution unit (statement)
     */
    Timestamp getCurrentTimestamp() {

        if (currentDateTimeSCN != actionTimestamp) {
            currentDateTimeSCN = actionTimestamp;
            currentMillis      = System.currentTimeMillis();
            currentDate        = null;
            currentTime        = null;
            currentTimestamp   = HsqlDateTime.getTimestamp(currentMillis);
        } else if (currentTimestamp == null) {
            currentTimestamp = HsqlDateTime.getTimestamp(currentMillis);
        }

        return currentTimestamp;
    }

    Result getAttributes() {

        Result   r   = Result.newSessionAttributesResult();
        Object[] row = new Object[] {
            database.getURI(), getUsername(), ValuePool.getInt(sessionId),
            ValuePool.getInt(isolationMode),
            ValuePool.getBoolean(isAutoCommit),
            ValuePool.getBoolean(database.databaseReadOnly),
            ValuePool.getBoolean(isReadOnly)
        };

        r.add(row);

        return r;
    }

    Result setAttributes(Result r) {

        Object[] row = r.rRoot.data;

        for (int i = 0; i < row.length; i++) {
            Object value = row[i];

            if (value == null) {
                continue;
            }

            try {
                switch (i) {

                    case SessionInterface.INFO_AUTOCOMMIT : {
                        this.setAutoCommit(((Boolean) value).booleanValue());

                        break;
                    }
                    case SessionInterface.INFO_CONNECTION_READONLY :
                        this.setReadOnly(((Boolean) value).booleanValue());
                        break;
                }
            } catch (HsqlException e) {
                return new Result(e, null);
            }
        }

        return emptyUpdateCount;
    }

    // DatabaseMetaData.getURL should work as specified for
    // internal connections too.
    public String getInternalConnectionURL() {
        return DatabaseURL.S_URL_PREFIX + database.getURI();
    }

    boolean isProcessingScript() {
        return isProcessingScript;
    }

    boolean isProcessingLog() {
        return isProcessingLog;
    }

    boolean isSchemaDefintion() {
        return oldSchema != null;
    }

    void startSchemaDefinition(String schema) throws HsqlException {

        if (isProcessingScript) {
            setSchema(schema);

            return;
        }

        oldSchema = currentSchema;

        setSchema(schema);
    }

    void endSchemaDefinition() throws HsqlException {

        if (oldSchema == null) {
            return;
        }

        currentSchema = oldSchema;
        oldSchema     = null;

        database.logger.writeToLog(this,
                                   "SET SCHEMA "
                                   + currentSchema.statementName);
    }

    // schema object methods
    public void setSchema(String schema) throws HsqlException {
        currentSchema = database.schemaManager.getSchemaHsqlName(schema);
    }

    /**
     * If schemaName is null, return the current schema name, else return
     * the HsqlName object for the schema. If schemaName does not exist,
     * throw.
     */
    HsqlName getSchemaHsqlName(String name) throws HsqlException {
        return name == null ? currentSchema
                            : database.schemaManager.getSchemaHsqlName(name);
    }

    /**
     * Same as above, but return string
     */
    public String getSchemaName(String name) throws HsqlException {
        return name == null ? currentSchema.name
                            : database.schemaManager.getSchemaName(name);
    }

    /**
     * If schemaName is null, return the current schema name, else return
     * the HsqlName object for the schema. If schemaName does not exist, or
     * schema readonly, throw.
     */
    HsqlName getSchemaHsqlNameForWrite(String name) throws HsqlException {

        HsqlName schema = getSchemaHsqlName(name);

        if (database.schemaManager.isSystemSchema(schema)) {
            throw Trace.error(Trace.INVALID_SCHEMA_NAME_NO_SUBCLASS);
        }

        return schema;
    }

    /**
     * Same as above, but return string
     */
    public String getSchemaNameForWrite(String name) throws HsqlException {

        HsqlName schema = getSchemaHsqlNameForWrite(name);

        return schema.name;
    }

    /**
     * get the root for a temp table index
     */
    Node getIndexRoot(HsqlName index, boolean preserve) {

        if (preserve) {
            if (indexArrayKeepMap == null) {
                return null;
            }

            return (Node) indexArrayKeepMap.get(index.hashCode());
        } else {
            if (indexArrayMap == null) {
                return null;
            }

            return (Node) indexArrayMap.get(index.hashCode());
        }
    }

    /**
     * set the root for a temp table index
     */
    void setIndexRoot(HsqlName index, boolean preserve, Node root) {

        if (preserve) {
            if (indexArrayKeepMap == null) {
                if (root == null) {
                    return;
                }

                indexArrayKeepMap = new IntKeyHashMap();
            }

            indexArrayKeepMap.put(index.hashCode(), root);
        } else {
            if (indexArrayMap == null) {
                if (root == null) {
                    return;
                }

                indexArrayMap = new IntKeyHashMap();
            }

            indexArrayMap.put(index.hashCode(), root);
        }
    }

    void dropIndex(HsqlName index, boolean preserve) {

        if (preserve) {
            if (indexArrayKeepMap != null) {
                indexArrayKeepMap.remove(index.hashCode());
            }
        } else {
            if (indexArrayMap != null) {
                indexArrayMap.remove(index.hashCode());
            }
        }
    }

    /**
     * clear default temp table contents for this session
     */
    void clearIndexRoots() {

        if (indexArrayMap != null) {
            indexArrayMap.clear();
        }
    }

    /**
     * clear ON COMMIT PRESERVE temp table contents for this session
     */
    void clearIndexRootsKeep() {

        if (indexArrayKeepMap != null) {
            indexArrayKeepMap.clear();
        }
    }

    // warnings
    HsqlArrayList sqlWarnings;

    public void addWarning(HsqlException warning) {

        if (sqlWarnings == null) {
            sqlWarnings = new HsqlArrayList(true);
        }

        sqlWarnings.add(warning);
    }

    public HsqlException[] getAndClearWarnings() {

        if (sqlWarnings == null) {
            return new HsqlException[0];
        }

        HsqlException[] array = new HsqlException[sqlWarnings.size()];

        sqlWarnings.toArray(array);
        sqlWarnings.clear();

        return array;
    }
}

Other HSQLDB examples (source code examples)

Here is a short list of links related to this HSQLDB Session.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.