cc.setCurrentDependent(preparedStmt);
//Only top level statements go through here, nested statement
//will invoke this method from other places
StatementNode qt = 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);
}
}
//Derby424 - In order to avoid caching select statements referencing
// any SESSION schema objects (including statements referencing views
// in SESSION schema), we need to do the SESSION schema object check
// here.
//a specific eg for statement referencing a view in SESSION schema
//CREATE TABLE t28A (c28 int)
//INSERT INTO t28A VALUES (280),(281)
//CREATE VIEW SESSION.t28v1 as select * from t28A
//SELECT * from SESSION.t28v1 should show contents of view and we
// should not cache this statement because a user can later define
// a global temporary table with the same name as the view name.
//Following demonstrates that
//DECLARE GLOBAL TEMPORARY TABLE SESSION.t28v1(c21 int, c22 int) not
// logged
//INSERT INTO SESSION.t28v1 VALUES (280,1),(281,2)
//SELECT * from SESSION.t28v1 should show contents of global temporary
//table and not the view. Since this select statement was not cached
// earlier, it will be compiled again and will go to global temporary
// table to fetch data. This plan will not be cached either because
// select statement is using SESSION schema object.
//
//Following if statement makes sure that if the statement is
// referencing SESSION schema objects, then we do not want to cache it.
// We will remove the entry that was made into the cache for
//this statement at the beginning of the compile phase.
//The reason we do this check here rather than later in the compile
// phase is because for a view, later on, we loose the information that
// it was referencing SESSION schema because the reference
//view gets replaced with the actual view definition. Right after
// binding, we still have the information on the view and that is why
// we do the check here.
if (preparedStmt.referencesSessionSchema(qt)) {
if (foundInCache)
((GenericLanguageConnectionContext)lcc).removeStatement(this);
}
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.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++) {