Package org.apache.derby.impl.sql

Source Code of org.apache.derby.impl.sql.GenericStatement

/*

   Derby - Class org.apache.derby.impl.sql.GenericStatement

   Copyright 1997, 2004 The Apache Software Foundation or its licensors, as applicable.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

*/

package org.apache.derby.impl.sql;

import org.apache.derby.iapi.services.stream.HeaderPrintWriter;

import org.apache.derby.iapi.reference.JDBC20Translation;
import org.apache.derby.iapi.reference.JDBC30Translation;
import org.apache.derby.iapi.reference.SQLState;

import org.apache.derby.iapi.sql.Activation;
import org.apache.derby.iapi.types.DataTypeDescriptor;
import org.apache.derby.iapi.sql.ResultSet;
import org.apache.derby.iapi.sql.Statement;
import org.apache.derby.iapi.sql.PreparedStatement;
import org.apache.derby.iapi.sql.execute.ConstantAction;
import org.apache.derby.iapi.sql.execute.ExecutionContext;
import org.apache.derby.iapi.sql.execute.ExecPreparedStatement;
import org.apache.derby.iapi.sql.ParameterValueSet;

import org.apache.derby.iapi.sql.conn.LanguageConnectionFactory;
import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
import org.apache.derby.iapi.sql.conn.StatementContext;

import org.apache.derby.iapi.sql.depend.Dependent;

import org.apache.derby.iapi.sql.compile.CompilerContext;
import org.apache.derby.iapi.sql.compile.NodeFactory;
import org.apache.derby.iapi.sql.compile.Parser;

import org.apache.derby.impl.sql.compile.QueryTreeNode;
import org.apache.derby.impl.sql.conn.GenericLanguageConnectionContext;

import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;
import org.apache.derby.iapi.sql.dictionary.DataDictionaryContext;
import org.apache.derby.iapi.sql.dictionary.DataDictionary;

import org.apache.derby.iapi.services.compiler.JavaFactory;
import org.apache.derby.iapi.services.uuid.UUIDFactory;
import org.apache.derby.iapi.util.ByteArray;

import org.apache.derby.iapi.error.StandardException;

import org.apache.derby.iapi.services.monitor.Monitor;

import org.apache.derby.iapi.services.context.Context;
import org.apache.derby.iapi.services.context.ContextService;
import org.apache.derby.iapi.services.context.ContextManager;
import org.apache.derby.iapi.services.sanity.SanityManager;

import org.apache.derby.iapi.services.loader.GeneratedClass;

import java.sql.Timestamp;
import java.sql.SQLWarning;

public class GenericStatement
  implements Statement {

  // these fields define the identity of the statement
  private final SchemaDescriptor compilationSchema;
  private final String      statementText;
  private int                      prepareIsolationLevel;
  private GenericPreparedStatement preparedStmt;

  /**
   * Constructor for a Statement given the text of the statement in a String
   *
   * @param statementText  The text of the statement
   */

  public GenericStatement(SchemaDescriptor compilationSchema, String statementText)
  {
    this.compilationSchema = compilationSchema;
    this.statementText = statementText;
  }

  /*
   * Statement interface
   */


  /* RESOLVE: may need error checking, debugging code here */
  public PreparedStatement prepare(LanguageConnectionContext lcc) throws StandardException
  {
    /*
    ** Note: don't reset state since this might be
    ** a recompilation of an already prepared statement.
    */
    return prepMinion(lcc, true, (Object[]) null, (SchemaDescriptor) null, false);
  }

  private PreparedStatement prepMinion(LanguageConnectionContext lcc, boolean cacheMe, Object[] paramDefaults,
    SchemaDescriptor spsSchema, boolean internalSQL)
    throws StandardException
  {
             
    long        beginTime = 0;
    long        parseTime = 0;
    long        bindTime = 0;
    long        optimizeTime = 0;
    long        generateTime = 0;
    Timestamp      beginTimestamp = null;
    Timestamp      endTimestamp = null;
    StatementContext  statementContext = null;

    // verify it isn't already prepared...
    // if it is, and is valid, simply return that tree.
    // if it is invalid, we will recompile now.
    if (preparedStmt != null) {
      if (preparedStmt.upToDate())
        return preparedStmt;
    }

    // Clear the optimizer trace from the last statement
    if (lcc.getOptimizerTrace())
      lcc.setOptimizerTraceOutput(getSource() + "\n");

    beginTime = getCurrentTimeMillis(lcc);
    /* beginTimestamp only meaningful if beginTime is meaningful.
     * beginTime is meaningful if STATISTICS TIMING is ON.
     */
    if (beginTime != 0)
    {
      beginTimestamp = new Timestamp(beginTime);
    }

    /** set the prepare Isolaton from the LanguageConnectionContext now as
     * we need to consider it in caching decisions
     */
    prepareIsolationLevel = lcc.getPrepareIsolationLevel();

    /* a note on statement caching:
     *
     * A GenericPreparedStatement (GPS) is only added it to the cache if the
     * parameter cacheMe is set to TRUE when the GPS is created.
     *
     * Earlier only CacheStatement (CS) looked in the statement cache for a
     * prepared statement when prepare was called. Now the functionality
     * of CS has been folded into GenericStatement (GS). So we search the
     * cache for an existing PreparedStatement only when cacheMe is TRUE.
     * i.e if the user calls prepare with cacheMe set to TRUE:
     * then we
     *         a) look for the prepared statement in the cache.
     *         b) add the prepared statement to the cache.
     *
     * In cases where the statement cache has been disabled (by setting the
     * relevant cloudscape property) then the value of cacheMe is irrelevant.
     */
    boolean foundInCache = false;
    if (preparedStmt == null)
    {
      if (cacheMe)
        preparedStmt = (GenericPreparedStatement)((GenericLanguageConnectionContext)lcc).lookupStatement(this);

      if (preparedStmt == null)
      {
        preparedStmt = new GenericPreparedStatement(this);
      }
      else
      {
        foundInCache = true;
      }
    }

    // if anyone else also has this prepared statement,
    // we don't want them trying to compile with it while
    // we are.  So, we synchronize on it and re-check
    // its validity first.
    // this is a no-op if and until there is a central
    // cache of prepared statement objects...
    synchronized (preparedStmt)
    {

      for (;;) {

        if (foundInCache) {
          if (preparedStmt.referencesSessionSchema()) {
            // cannot use this state since it is private to a connection.
            // switch to a new statement.
            foundInCache = false;
            preparedStmt = new GenericPreparedStatement(this);
            break;
          }
        }

        // did it get updated while we waited for the lock on it?
        if (preparedStmt.upToDate()) {
          return preparedStmt;
        }

        if (!preparedStmt.compilingStatement) {
          break;
        }

        try {
          preparedStmt.wait();
        } catch (InterruptedException ie) {
          throw StandardException.interrupt(ie);
        }
      }

      preparedStmt.compilingStatement = true;
      preparedStmt.setActivationClass(null);
    }

    try {

      HeaderPrintWriter istream = lcc.getLogStatementText() ? Monitor.getStream() : null;

      /*
      ** For stored prepared statements, we want all
      ** errors, etc in the context of the underlying
      ** EXECUTE STATEMENT statement, so don't push/pop
      ** another statement context unless we don't have
      ** one.  We won't have one if it is an internal
      ** SPS (e.g. jdbcmetadata).
      */
      if (!preparedStmt.isStorable() || lcc.getStatementDepth() == 0)
      {
        // since this is for compilation only, set atomic
        // param to true
        statementContext = lcc.pushStatementContext(true, getSource(), null, false);
      }



      /*
      ** RESOLVE: we may ultimately wish to pass in
      ** whether we are a jdbc metadata query or not to
      ** get the CompilerContext to make the createDependency()
      ** call a noop.
      */
      CompilerContext cc = lcc.pushCompilerContext(compilationSchema);
     
      if (prepareIsolationLevel !=
        ExecutionContext.UNSPECIFIED_ISOLATION_LEVEL)
      {
        cc.setScanIsolationLevel(prepareIsolationLevel);
      }


      // Look for stored statements that are in a system schema
      // and with a match compilation schema. If so, allow them
      // to compile using internal SQL constructs.

      if (internalSQL ||
        (spsSchema != null) && (spsSchema.isSystemSchema()) &&
          (spsSchema.equals(compilationSchema))) {
            cc.setReliability(CompilerContext.INTERNAL_SQL_LEGAL);
      }

      try
      {
        // Statement logging if lcc.getLogStatementText() is true
        if (istream != null)
        {
          String xactId = lcc.getTransactionExecute().getActiveStateTxIdString();
          istream.printlnWithHeader(LanguageConnectionContext.xidStr +
                        xactId +
                        "), " +
                        LanguageConnectionContext.lccStr +
                          lcc.getInstanceNumber() +
                        "), " +
                        LanguageConnectionContext.dbnameStr +
                          lcc.getDbname() +
                        "), " +
                        LanguageConnectionContext.drdaStr +
                          lcc.getDrdaID() +
                        "), Begin compiling prepared statement: " +
                        getSource() +
                        " :End prepared statement");
        }

        Parser p = cc.getParser();

        cc.setCurrentDependent(preparedStmt);

        //Only top level statements go through here, nested statement
        //will invoke this method from other places
        QueryTreeNode qt = p.parseStatement(statementText, paramDefaults);

        parseTime = getCurrentTimeMillis(lcc);

        if (SanityManager.DEBUG)
        {
          if (SanityManager.DEBUG_ON("DumpParseTree"))
          {
            qt.treePrint();
          }

          if (SanityManager.DEBUG_ON("StopAfterParsing"))
          {
            throw StandardException.newException(SQLState.LANG_STOP_AFTER_PARSING);
          }
        }

        /*
        ** Tell the data dictionary that we are about to do
        ** a bunch of "get" operations that must be consistent with
        ** each other.
        */
       
        DataDictionary dataDictionary = lcc.getDataDictionary();

        int ddMode = dataDictionary == null ? 0 : dataDictionary.startReading(lcc);

        try
        {
          // start a nested transaction -- all locks acquired by bind
          // and optimize will be released when we end the nested
          // transaction.
          lcc.beginNestedTransaction(true);

          qt = qt.bind();
          bindTime = getCurrentTimeMillis(lcc);

          if (SanityManager.DEBUG)
          {
            if (SanityManager.DEBUG_ON("DumpBindTree"))
            {
              qt.treePrint();
            }

            if (SanityManager.DEBUG_ON("StopAfterBinding")) {
              throw StandardException.newException(SQLState.LANG_STOP_AFTER_BINDING);
            }
          }

          qt = qt.optimize();

          optimizeTime = getCurrentTimeMillis(lcc);

          // Statement logging if lcc.getLogStatementText() is true
          if (istream != null)
          {
            String xactId = lcc.getTransactionExecute().getActiveStateTxIdString();
            istream.printlnWithHeader(LanguageConnectionContext.xidStr +
                          xactId +
                          "), " +
                          LanguageConnectionContext.lccStr +
                          lcc.getInstanceNumber() +
                          "), " +
                          LanguageConnectionContext.dbnameStr +
                          lcc.getDbname() +
                          "), " +
                          LanguageConnectionContext.drdaStr +
                          lcc.getDrdaID() +
                          "), End compiling prepared statement: " +
                          getSource() +
                          " :End prepared statement");
          }
        }

        catch (StandardException se)
        {
          lcc.commitNestedTransaction();
          if (foundInCache)
            ((GenericLanguageConnectionContext)lcc).removeStatement(this);


          // Statement logging if lcc.getLogStatementText() is true
          if (istream != null)
          {
            String xactId = lcc.getTransactionExecute().getActiveStateTxIdString();
            istream.printlnWithHeader(LanguageConnectionContext.xidStr +
                          xactId +
                          "), " +
                          LanguageConnectionContext.lccStr +
                          lcc.getInstanceNumber() +
                          "), " +
                          LanguageConnectionContext.dbnameStr +
                          lcc.getDbname() +
                          "), " +
                          LanguageConnectionContext.drdaStr +
                          lcc.getDrdaID() +
                          "), Error compiling prepared statement: " +
                          getSource() +
                          " :End prepared statement");
          }
          throw se;
        }

        finally
        {
          /* Tell the data dictionary that we are done reading */
          if (dataDictionary != null)
          dataDictionary.doneReading(ddMode, lcc);
        }

        /* we need to move the commit of nested sub-transaction
         * after we mark PS valid, during compilation, we might need
         * to get some lock to synchronize with another thread's DDL
         * execution, in particular, the compilation of insert/update/
         * delete vs. create index/constraint (see Beetle 3976).  We
         * can't release such lock until after we mark the PS valid.
         * Otherwise we would just erase the DDL's invalidation when
         * we mark it valid.
         */
        try    // put in try block, commit sub-transaction if bad
        {
          if (SanityManager.DEBUG)
          {
            if (SanityManager.DEBUG_ON("DumpOptimizedTree"))
            {
              qt.treePrint();
            }

            if (SanityManager.DEBUG_ON("StopAfterOptimizing"))
            {
              throw StandardException.newException(SQLState.LANG_STOP_AFTER_OPTIMIZING);
            }
          }

          GeneratedClass ac = qt.generate(preparedStmt.getByteCodeSaver());

          generateTime = getCurrentTimeMillis(lcc);
          /* endTimestamp only meaningful if generateTime is meaningful.
           * generateTime is meaningful if STATISTICS TIMING is ON.
           */
          if (generateTime != 0)
          {
            endTimestamp = new Timestamp(generateTime);
          }

          if (SanityManager.DEBUG)
          {
            if (SanityManager.DEBUG_ON("StopAfterGenerating"))
            {
              throw StandardException.newException(SQLState.LANG_STOP_AFTER_GENERATING);
            }
          }

          /*
            copy over the compile-time created objects
            to the prepared statement.  This always happens
            at the end of a compile, so there is no need
            to erase the previous entries on a re-compile --
            this erases as it replaces.  Set the activation
            class in case it came from a StorablePreparedStatement
          */
          preparedStmt.setConstantAction( qt.makeConstantAction() );
          preparedStmt.setSavedObjects( cc.getSavedObjects() );
          preparedStmt.setActivationClass(ac);
          preparedStmt.setParams(cc.getParams());
          preparedStmt.setNeedsSavepoint(qt.needsSavepoint());
          preparedStmt.setCursorInfo((CursorInfo)cc.getCursorInfo());
          preparedStmt.setIsAtomic(qt.isAtomic());
          preparedStmt.setExecuteStatementNameAndSchema(
                        qt.executeStatementName(),
                        qt.executeSchemaName()
                        );
          preparedStmt.setSPSName(qt.getSPSName());

          //if this statement is referencing session schema tables, then we do not want cache it. Following will remove the
          //entry that was made into the cache for this statement at the beginning of the compile phase
          if (preparedStmt.completeCompile(qt)) {
            if (foundInCache)
              ((GenericLanguageConnectionContext)lcc).removeStatement(this);
          }

          preparedStmt.setCompileTimeWarnings(cc.getWarnings());
        }
        catch (StandardException e)   // hold it, throw it
        {
          lcc.commitNestedTransaction();
          if (foundInCache)
            ((GenericLanguageConnectionContext)lcc).removeStatement(this);
          throw e;
        }

        if (lcc.getRunTimeStatisticsMode())
        {
          preparedStmt.setCompileTimeMillis(
            parseTime - beginTime, //parse time
            bindTime - parseTime, //bind time
            optimizeTime - bindTime, //optimize time
            generateTime - optimizeTime, //generate time
            getElapsedTimeMillis(beginTime),
            beginTimestamp,
            endTimestamp);
        }

      }
      finally // for block introduced by pushCompilerContext()
      {
        lcc.popCompilerContext( cc );
      }
    }
    finally
    {
      synchronized (preparedStmt) {
        preparedStmt.compilingStatement = false;
        preparedStmt.notifyAll();
      }
    }

    lcc.commitNestedTransaction();

    if (statementContext != null)
      lcc.popStatementContext(statementContext, null);

    return preparedStmt;
  }

  /**
   * Generates an execution plan given a set of named parameters.
   * Does so for a storable prepared statement.
   *
   * @param   compilationSchema  the schema to compile against
   * @param  paramDefaults    Parameter defaults
   *
   * @return A PreparedStatement that allows execution of the execution
   *     plan.
   * @exception StandardException  Thrown if this is an
   *     execution-only version of the module (the prepare() method
   *     relies on compilation).
   */
  public  PreparedStatement prepareStorable(
        LanguageConnectionContext lcc,
        PreparedStatement ps,
        Object[]      paramDefaults,
        SchemaDescriptor  spsSchema,
        boolean internalSQL)
    throws StandardException
  {
    if (ps == null)
      ps = new GenericStorablePreparedStatement(this);
    else
      ((GenericPreparedStatement) ps).statement = this;

    this.preparedStmt = (GenericPreparedStatement) ps;
    return prepMinion(lcc, false, paramDefaults, spsSchema, internalSQL);
  }

  public String getSource() {
    return statementText;
  }

  public boolean getUnicode() {
    return true;
  }

  public String getCompilationSchema() {
    return compilationSchema.getDescriptorName();
  }

  private static long getCurrentTimeMillis(LanguageConnectionContext lcc)
  {
    if (lcc.getStatisticsTiming())
    {
      return System.currentTimeMillis();
    }
    else
    {
      return 0;
    }
  }

  private static long getElapsedTimeMillis(long beginTime)
  {
    if (beginTime != 0)
    {
      return System.currentTimeMillis() - beginTime;
    }
    else
    {
      return 0;
    }
  }

  /*
  ** Identity
  */

  public boolean equals(Object other) {

    if (other instanceof GenericStatement) {

      GenericStatement os = (GenericStatement) other;

      return statementText.equals(os.statementText)
        && compilationSchema.equals(os.compilationSchema) &&
        (prepareIsolationLevel == os.prepareIsolationLevel);
    }

    return false;
  }

  public int hashCode() {

    return statementText.hashCode();
  }
}
TOP

Related Classes of org.apache.derby.impl.sql.GenericStatement

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.