use of org.apache.derby.iapi.sql.conn.StatementContext in project derby by apache.
the class GenericStatement method prepMinion.
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;
// if it is invalid, we will recompile now.
if (preparedStmt != null) {
if (preparedStmt.upToDate())
return preparedStmt;
}
// Start a new optimizer trace for this statement
if (lcc.optimizerTracingIsOn()) {
lcc.getOptimizerTracer().traceStartStatement(getSource());
}
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 isolation 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 Derby 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;
}
}
// 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.isCompiling()) {
break;
}
try {
preparedStmt.wait();
} catch (InterruptedException ie) {
InterruptStatus.setInterrupted();
}
}
preparedStmt.beginCompiling();
}
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 and timeout param to 0
statementContext = lcc.pushStatementContext(true, isForReadOnly, getSource(), null, false, 0L);
}
/*
** 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 != TransactionControl.UNSPECIFIED_ISOLATION_LEVEL) {
cc.setScanIsolationLevel(prepareIsolationLevel);
}
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
StatementNode qt = (StatementNode) p.parseStatement(statementText, paramDefaults);
parseTime = getCurrentTimeMillis(lcc);
// Call user-written tree-printer if it exists
walkAST(lcc, qt, ASTVisitor.AFTER_PARSE);
if (SanityManager.DEBUG) {
if (SanityManager.DEBUG_ON("DumpParseTree")) {
SanityManager.GET_DEBUG_STREAM().print("\n\n============PARSE===========\n\n");
qt.treePrint();
lcc.getPrintedObjectsMap().clear();
}
if (SanityManager.DEBUG_ON("StopAfterParsing")) {
lcc.setLastQueryTree(qt);
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.bindStatement();
bindTime = getCurrentTimeMillis(lcc);
// Call user-written tree-printer if it exists
walkAST(lcc, qt, ASTVisitor.AFTER_BIND);
if (SanityManager.DEBUG) {
if (SanityManager.DEBUG_ON("DumpBindTree")) {
SanityManager.GET_DEBUG_STREAM().print("\n\n============BIND===========\n\n");
qt.treePrint();
lcc.getPrintedObjectsMap().clear();
}
if (SanityManager.DEBUG_ON("StopAfterBinding")) {
throw StandardException.newException(SQLState.LANG_STOP_AFTER_BINDING);
}
}
// we do the check here.
if (preparedStmt.referencesSessionSchema(qt)) {
if (foundInCache)
((GenericLanguageConnectionContext) lcc).removeStatement(this);
}
// stop adding privileges for user-defined types
cc.skipTypePrivileges(true);
qt.optimizeStatement();
optimizeTime = getCurrentTimeMillis(lcc);
// Call user-written tree-printer if it exists
walkAST(lcc, qt, ASTVisitor.AFTER_OPTIMIZE);
// 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();
// 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")) {
SanityManager.GET_DEBUG_STREAM().print("\n\n============OPT===========\n\n");
qt.treePrint();
lcc.getPrintedObjectsMap().clear();
}
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.setRequiredPermissionsList(cc.getRequiredPermissionsList());
preparedStmt.incrementVersionCounter();
preparedStmt.setActivationClass(ac);
preparedStmt.setNeedsSavepoint(qt.needsSavepoint());
preparedStmt.setCursorInfo((CursorInfo) cc.getCursorInfo());
preparedStmt.setIsAtomic(qt.isAtomic());
preparedStmt.setExecuteStatementNameAndSchema(qt.executeStatementName(), qt.executeSchemaName());
preparedStmt.setSPSName(qt.getSPSName());
preparedStmt.completeCompile(qt);
preparedStmt.setCompileTimeWarnings(cc.getWarnings());
// Schedule updates of any stale index statistics we may
// have detected when creating the plan.
TableDescriptor[] tds = qt.updateIndexStatisticsFor();
if (tds.length > 0) {
IndexStatisticsDaemon isd = lcc.getDataDictionary().getIndexStatsRefresher(true);
if (isd != null) {
for (int i = 0; i < tds.length; i++) {
isd.schedule(tds[i]);
}
}
}
} catch (// hold it, throw it
StandardException e) {
lcc.commitNestedTransaction();
throw e;
}
if (lcc.getRunTimeStatisticsMode()) {
preparedStmt.setCompileTimeMillis(// parse time
parseTime - beginTime, // bind time
bindTime - parseTime, // optimize time
optimizeTime - bindTime, // generate time
generateTime - optimizeTime, // total compile time
generateTime - beginTime, beginTimestamp, endTimestamp);
}
} finally // for block introduced by pushCompilerContext()
{
lcc.popCompilerContext(cc);
}
} catch (StandardException se) {
if (foundInCache)
((GenericLanguageConnectionContext) lcc).removeStatement(this);
throw se;
} finally {
preparedStmt.endCompiling();
}
lcc.commitNestedTransaction();
if (statementContext != null)
lcc.popStatementContext(statementContext, null);
return preparedStmt;
}
Aggregations