--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.sql.conn.GenericStatementContext\r
+\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to you under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+\r
+ */\r
+\r
+package org.apache.derby.impl.sql.conn;\r
+\r
+import org.apache.derby.iapi.services.context.Context;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+\r
+import org.apache.derby.iapi.services.monitor.Monitor;\r
+\r
+import org.apache.derby.iapi.services.timer.TimerFactory;\r
+\r
+import org.apache.derby.iapi.error.StandardException;\r
+\r
+import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;\r
+import org.apache.derby.iapi.sql.conn.StatementContext;\r
+\r
+import org.apache.derby.iapi.sql.depend.Dependency;\r
+import org.apache.derby.iapi.sql.depend.DependencyManager;\r
+\r
+import org.apache.derby.iapi.sql.execute.NoPutResultSet;\r
+\r
+import org.apache.derby.iapi.sql.ResultSet;\r
+import org.apache.derby.iapi.sql.ParameterValueSet;\r
+\r
+import org.apache.derby.iapi.store.access.TransactionController;\r
+\r
+import org.apache.derby.iapi.services.context.ContextImpl;\r
+\r
+import org.apache.derby.iapi.error.ExceptionSeverity;\r
+import org.apache.derby.iapi.reference.SQLState;\r
+import java.util.ArrayList;\r
+import java.util.Iterator;\r
+import java.util.Timer;\r
+import java.util.TimerTask;\r
+import java.sql.SQLException;\r
+\r
+/**\r
+ * GenericStatementContext is pushed/popped around a statement prepare and execute\r
+ * so that any statement specific clean up can be performed.\r
+ *\r
+ *\r
+ */\r
+final class GenericStatementContext \r
+ extends ContextImpl implements StatementContext\r
+{\r
+ private boolean setSavePoint;\r
+ private String internalSavePointName;\r
+ private ResultSet topResultSet;\r
+ private ArrayList dependencies;\r
+ private NoPutResultSet[] subqueryTrackingArray;\r
+ private NoPutResultSet[] materializedSubqueries;\r
+ private final LanguageConnectionContext lcc;\r
+ private boolean inUse = true;\r
+\r
+ // This flag satisfies all the conditions\r
+ // for using volatile instead of synchronized.\r
+ // (Source: Doug Lea, Concurrent Programming in Java, Second Edition,\r
+ // section 2.2.7.4, page 97)\r
+ // true if statement has been cancelled\r
+ private volatile boolean cancellationFlag = false;\r
+\r
+ // Reference to the TimerTask that will time out this statement.\r
+ // Needed for stopping the task when execution completes before timeout.\r
+ private CancelQueryTask cancelTask = null;\r
+ \r
+ private boolean parentInTrigger; // whetherparent started with a trigger on stack\r
+ private boolean isForReadOnly = false; \r
+ private boolean isAtomic; \r
+ private boolean isSystemCode;\r
+ private boolean rollbackParentContext;\r
+ private String stmtText;\r
+ private ParameterValueSet pvs;\r
+\r
+ /**\r
+ Set to one of RoutineAliasInfo.{MODIFIES_SQL_DATA, READS_SQL_DATA, CONTAINS_SQL, NO_SQL}\r
+ */\r
+ private short sqlAllowed = -1;\r
+\r
+ /*\r
+ constructor\r
+ @param tc transaction\r
+ */\r
+ GenericStatementContext(LanguageConnectionContext lcc) \r
+ {\r
+ super(lcc.getContextManager(), org.apache.derby.iapi.reference.ContextId.LANG_STATEMENT);\r
+ this.lcc = lcc;\r
+\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ SanityManager.ASSERT((lcc != null),\r
+ "Failed to get language connection context");\r
+ }\r
+\r
+ internalSavePointName = lcc.getUniqueSavepointName();\r
+ }\r
+\r
+ /**\r
+ * This is a TimerTask that is responsible for timing out statements,\r
+ * typically when an application has called Statement.setQueryTimeout().\r
+ *\r
+ * When the application invokes execute() on a statement object, or\r
+ * fetches data on a ResultSet, a StatementContext object is allocated\r
+ * for the duration of the execution in the engine (until control is\r
+ * returned to the application).\r
+ *\r
+ * When the StatementContext object is assigned with setInUse(),\r
+ * a CancelQueryTask is scheduled if a timeout > 0 has been set.\r
+ */\r
+ private static class CancelQueryTask\r
+ extends\r
+ TimerTask\r
+ {\r
+ /**\r
+ * Reference to the StatementContext for the executing statement\r
+ * which might time out.\r
+ */\r
+ private StatementContext statementContext;\r
+\r
+ /**\r
+ * Initializes a new task for timing out a statement's execution.\r
+ * This does not schedule it for execution, the caller is\r
+ * responsible for calling Timer.schedule() with this object\r
+ * as parameter.\r
+ */\r
+ public CancelQueryTask(StatementContext ctx)\r
+ {\r
+ statementContext = ctx;\r
+ }\r
+\r
+ /**\r
+ * Invoked by a Timer class to cancel an executing statement.\r
+ * This method just sets a volatile flag in the associated\r
+ * StatementContext object by calling StatementContext.cancel();\r
+ * it is the responsibility of the thread executing the statement\r
+ * to check this flag regularly.\r
+ */\r
+ public void run()\r
+ {\r
+ synchronized (this) {\r
+ if (statementContext != null) {\r
+ statementContext.cancel();\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Stops this task and prevents it from cancelling a statement.\r
+ * Guarantees that after this method returns, the associated\r
+ * StatementContext object will not be tampered with by this task.\r
+ * Thus, the StatementContext object may safely be allocated to\r
+ * other executing statements.\r
+ */\r
+ public void forgetContext() {\r
+ boolean mayStillRun = !cancel();\r
+ if (mayStillRun) {\r
+ synchronized (this) {\r
+ statementContext = null;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ // StatementContext Interface\r
+\r
+ public void setInUse\r
+ ( \r
+ boolean parentInTrigger,\r
+ boolean isAtomic, \r
+ boolean isForReadOnly,\r
+ String stmtText,\r
+ ParameterValueSet pvs,\r
+ long timeoutMillis\r
+ ) \r
+ {\r
+ inUse = true;\r
+\r
+ this.parentInTrigger = parentInTrigger;\r
+ this.isForReadOnly = isForReadOnly;\r
+ this.isAtomic = isAtomic;\r
+ this.stmtText = stmtText;\r
+ this.pvs = pvs;\r
+ rollbackParentContext = false;\r
+ if (timeoutMillis > 0) {\r
+ TimerFactory factory = Monitor.getMonitor().getTimerFactory();\r
+ Timer timer = factory.getCancellationTimer();\r
+ cancelTask = new CancelQueryTask(this);\r
+ timer.schedule(cancelTask, timeoutMillis);\r
+ }\r
+ }\r
+\r
+ public void clearInUse() {\r
+ /* We must clear out the current top ResultSet to prepare for\r
+ * reusing a StatementContext.\r
+ */\r
+ stuffTopResultSet( null, null );\r
+ inUse = false;\r
+\r
+ parentInTrigger = false;\r
+ isAtomic = false;\r
+ isForReadOnly = false;\r
+ this.stmtText = null;\r
+ sqlAllowed = -1;\r
+ isSystemCode = false;\r
+ rollbackParentContext = false;\r
+\r
+ if (cancelTask != null) {\r
+ cancelTask.forgetContext();\r
+ cancelTask = null;\r
+ }\r
+ cancellationFlag = false;\r
+ }\r
+\r
+ /**\r
+ * @see StatementContext#setSavePoint\r
+ * @exception StandardException Thrown on error\r
+ */\r
+ public void setSavePoint() throws StandardException {\r
+ \r
+ if (SanityManager.DEBUG)\r
+ {\r
+ if (SanityManager.DEBUG_ON("traceSavepoints"))\r
+ {\r
+ SanityManager.DEBUG_PRINT(\r
+ "GenericStatementContext.setSavePoint()",\r
+ internalSavePointName);\r
+ }\r
+ }\r
+ \r
+ pleaseBeOnStack();\r
+ \r
+\r
+ lcc.getTransactionExecute().setSavePoint(internalSavePointName, null);\r
+ setSavePoint = true;\r
+ }\r
+\r
+ /**\r
+ * Resets the savepoint to the current spot if it is\r
+ * set, otherwise, noop. Used when a commit is\r
+ * done on a nested connection.\r
+ *\r
+ * @see StatementContext#resetSavePoint\r
+ * @exception StandardException Thrown on error\r
+ */\r
+ public void resetSavePoint() throws StandardException {\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ if (SanityManager.DEBUG_ON("traceSavepoints"))\r
+ {\r
+ SanityManager.DEBUG_PRINT(\r
+ "GenericStatementContext.resetSavePoint()",\r
+ internalSavePointName);\r
+ }\r
+ }\r
+ \r
+ if (inUse && setSavePoint)\r
+ { \r
+ // RESOLVE PLUGIN ???. For the plugin, there will be no transaction controller\r
+ lcc.getTransactionExecute().setSavePoint(internalSavePointName, null);\r
+ // stage buffer management\r
+ }\r
+ }\r
+\r
+ /**\r
+ * @see StatementContext#clearSavePoint\r
+ * @exception StandardException Thrown on error\r
+ */\r
+ public void clearSavePoint() throws StandardException {\r
+\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ if (SanityManager.DEBUG_ON("traceSavepoints"))\r
+ {\r
+ SanityManager.DEBUG_PRINT("GenericStatementContext.clearSavePoint()",\r
+ internalSavePointName);\r
+ }\r
+ }\r
+\r
+ pleaseBeOnStack();\r
+\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ SanityManager.ASSERT(setSavePoint, "setSavePoint is expected to be true");\r
+ }\r
+\r
+ // RESOLVE PLUGIN ???. For the plugin, there will be no transaction controller\r
+ lcc.getTransactionExecute().releaseSavePoint(internalSavePointName, null);\r
+ setSavePoint = false;\r
+ }\r
+\r
+ /**\r
+ * Set the top ResultSet in the ResultSet tree for close down on\r
+ * an error.\r
+ *\r
+ * @exception StandardException thrown on error.\r
+ */\r
+ public void setTopResultSet(ResultSet topResultSet, \r
+ NoPutResultSet[] subqueryTrackingArray)\r
+ throws StandardException\r
+ {\r
+ pleaseBeOnStack();\r
+\r
+ /* We have to handle both materialize and non-materialized subqueries.\r
+ * Materialized subqueries are attached before the top result set is \r
+ * set. If there are any, then we must copy them into the new\r
+ * subqueryTrackingArray.\r
+ */\r
+ if (materializedSubqueries != null)\r
+ {\r
+ // Do the merging into the passed in array.\r
+ if (subqueryTrackingArray != null)\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ if (this.materializedSubqueries.length != subqueryTrackingArray.length)\r
+ {\r
+ SanityManager.THROWASSERT(\r
+ "this.ms.length (" + this.materializedSubqueries.length +\r
+ ") expected to = sta.length(" + subqueryTrackingArray.length +\r
+ ")");\r
+ }\r
+ }\r
+ for (int index = 0; index < subqueryTrackingArray.length; index++)\r
+ {\r
+ if (this.subqueryTrackingArray[index] != null)\r
+ {\r
+ subqueryTrackingArray[index] = this.materializedSubqueries[index];\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ subqueryTrackingArray = this.materializedSubqueries;\r
+ }\r
+ materializedSubqueries = null;\r
+ }\r
+\r
+ stuffTopResultSet( topResultSet, subqueryTrackingArray );\r
+ }\r
+\r
+ /**\r
+ * Private minion of setTopResultSet() and clearInUse()\r
+ *\r
+ * @param topResultSet make this the top result set\r
+ * @param subqueryTrackingArray where to keep track of subqueries in this statement\r
+ */\r
+ private void stuffTopResultSet(ResultSet topResultSet, \r
+ NoPutResultSet[] subqueryTrackingArray)\r
+ {\r
+ this.topResultSet = topResultSet;\r
+ this.subqueryTrackingArray = subqueryTrackingArray;\r
+ dependencies = null;\r
+ }\r
+\r
+\r
+ /**\r
+ * Set the appropriate entry in the subquery tracking array for\r
+ * the specified subquery.\r
+ * Useful for closing down open subqueries on an exception.\r
+ *\r
+ * @param subqueryNumber The subquery # for this subquery\r
+ * @param subqueryResultSet The ResultSet at the top of the subquery\r
+ * @param numSubqueries The total # of subqueries in the entire query\r
+ *\r
+ * @exception StandardException thrown on error.\r
+ */\r
+ public void setSubqueryResultSet(int subqueryNumber,\r
+ NoPutResultSet subqueryResultSet,\r
+ int numSubqueries)\r
+ throws StandardException\r
+ {\r
+ pleaseBeOnStack();\r
+ \r
+ /* NOTE: In degenerate cases, it is possible that there is no top\r
+ * result set. For example:\r
+ * call (select 1 from systables).valueOf('111');\r
+ * In that case, we allocate our own subquery tracking array on\r
+ * each call. (Gross!)\r
+ * (Trust me, this is only done in degenerate cases. The tests passed,\r
+ * except for the degenerate cases, before making this change, so we\r
+ * know that the top result set and array reuse is working for\r
+ * the non-degenerate cases.)\r
+ */\r
+ if (subqueryTrackingArray == null)\r
+ {\r
+ if (topResultSet == null)\r
+ {\r
+ subqueryTrackingArray = new NoPutResultSet[numSubqueries];\r
+ materializedSubqueries = new NoPutResultSet[numSubqueries];\r
+ }\r
+ else\r
+ {\r
+ subqueryTrackingArray = \r
+ topResultSet.getSubqueryTrackingArray(numSubqueries);\r
+ }\r
+ }\r
+ subqueryTrackingArray[subqueryNumber] = subqueryResultSet;\r
+ if (materializedSubqueries != null)\r
+ {\r
+ materializedSubqueries[subqueryNumber] = subqueryResultSet;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Get the subquery tracking array for this query.\r
+ * (Useful for runtime statistics.)\r
+ *\r
+ * @return NoPutResultSet[] The (sparse) array of tops of subquery ResultSet trees\r
+ * @exception StandardException thrown on error.\r
+ */\r
+ public NoPutResultSet[] getSubqueryTrackingArray()\r
+ throws StandardException\r
+ {\r
+ pleaseBeOnStack();\r
+ \r
+ return subqueryTrackingArray;\r
+ }\r
+\r
+ /**\r
+ * Track a Dependency within this StatementContext.\r
+ * (We need to clear any dependencies added within this\r
+ * context on an error.\r
+ *\r
+ * @param dy The dependency to track.\r
+ *\r
+ * @exception StandardException thrown on error.\r
+ */\r
+ public void addDependency(Dependency dy)\r
+ throws StandardException\r
+ {\r
+ pleaseBeOnStack();\r
+ \r
+ if (dependencies == null)\r
+ {\r
+ dependencies = new ArrayList();\r
+ }\r
+ dependencies.add(dy);\r
+ }\r
+\r
+ /**\r
+ * Returns whether we started from within the context of a trigger\r
+ * or not.\r
+ *\r
+ * @return true if we are in a trigger context\r
+ */\r
+ public boolean inTrigger()\r
+ {\r
+ return parentInTrigger;\r
+ }\r
+\r
+ //\r
+ // Context interface\r
+ //\r
+ /**\r
+ * Close down the top ResultSet, if relevant, and rollback to the\r
+ * internal savepoint, if one was set.\r
+ *\r
+ * @exception StandardException thrown on error. REVISIT: don't want\r
+ * cleanupOnError's to throw exceptions.\r
+ */\r
+ public void cleanupOnError(Throwable error) throws StandardException\r
+ {\r
+\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ if (SanityManager.DEBUG_ON("traceSavepoints"))\r
+ {\r
+ SanityManager.DEBUG_PRINT(\r
+ "GenericStatementContext.cleanupOnError()",\r
+ String.valueOf( hashCode() ) );\r
+ }\r
+ }\r
+\r
+ /*\r
+ ** If it isn't a StandardException, then assume\r
+ ** session severity. It is probably an unexpected\r
+ ** java error somewhere in the language.\r
+ ** Store layer treats JVM error as session severity, \r
+ ** hence to be consistent and to avoid getting rawstore\r
+ ** protocol violation errors, we treat java errors here\r
+ ** to be of session severity. \r
+ */\r
+ int severity = (error instanceof StandardException) ?\r
+ ((StandardException) error).getSeverity() :\r
+ ExceptionSeverity.SESSION_SEVERITY;\r
+\r
+\r
+ /**\r
+ * Don't clean up this statement context if it's not in use.\r
+ * This can happen if you get an error while calling one of\r
+ * the JDBC getxxxx() methods on a ResultSet, since no statement\r
+ * context is pushed when those calls occur.\r
+ */\r
+ if (! inUse)\r
+ {\r
+ return;\r
+ }\r
+\r
+ /* Clean up the ResultSet, if one exists */\r
+ if (topResultSet != null)\r
+ {\r
+ topResultSet.cleanUp();\r
+ }\r
+\r
+ /* Close down any open subqueries */\r
+ if (subqueryTrackingArray != null)\r
+ {\r
+ for (int index = 0; index < subqueryTrackingArray.length; index++)\r
+ {\r
+ /* Remember, the array is sparse, so only check\r
+ * non-null entries.\r
+ */\r
+ if (subqueryTrackingArray[index] != null)\r
+ {\r
+ subqueryTrackingArray[index].cleanUp();\r
+ }\r
+ }\r
+ }\r
+\r
+ /* Clean up any dependencies */\r
+ if (dependencies != null)\r
+ {\r
+ DependencyManager dmgr = lcc.getDataDictionary().getDependencyManager();\r
+\r
+ for (Iterator iterator = dependencies.iterator(); iterator.hasNext(); ) \r
+ {\r
+ Dependency dy = (Dependency) iterator.next();\r
+ dmgr.clearInMemoryDependency(dy);\r
+ }\r
+\r
+ dependencies = null;\r
+ }\r
+\r
+ if (severity <= ExceptionSeverity.STATEMENT_SEVERITY\r
+ && setSavePoint)\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ if (SanityManager.DEBUG_ON("traceSavepoints"))\r
+ {\r
+ SanityManager.DEBUG_PRINT(\r
+ "GenericStatementContext.cleanupOnError",\r
+ "rolling back to: " + internalSavePointName);\r
+ }\r
+ }\r
+\r
+ lcc.internalRollbackToSavepoint( internalSavePointName, false, null);\r
+\r
+ clearSavePoint();\r
+ }\r
+\r
+ if (severity >= ExceptionSeverity.TRANSACTION_SEVERITY )\r
+ {\r
+ // transaction severity errors roll back the transaction.\r
+\r
+ /*\r
+ ** We call clearSavePoint() above only for statement errors.\r
+ ** We don't call clearSavePoint() for transaction errors because\r
+ ** the savepoint will be rolled back anyway. So in this case,\r
+ ** we need to indicate that the savepoint is not set.\r
+ */\r
+ setSavePoint = false;\r
+ }\r
+\r
+ /* Pop the context */\r
+ lcc.popStatementContext(this, error);\r
+ }\r
+\r
+ /**\r
+ * @see Context#isLastHandler\r
+ */\r
+ public boolean isLastHandler(int severity)\r
+ {\r
+ // For JVM errors, severity gets mapped to \r
+ // ExceptionSeverity.NO_APPLICABLE_SEVERITY\r
+ // in ContextManager.cleanupOnError. It is necessary to \r
+ // let outer contexts take corrective action for jvm errors, so \r
+ // return false as this will not be the last handler for such \r
+ // errors.\r
+ return inUse && !rollbackParentContext && \r
+ ( severity == ExceptionSeverity.STATEMENT_SEVERITY );\r
+ }\r
+\r
+ /**\r
+ * Reports whether this StatementContext is on the context stack.\r
+ *\r
+ * @return true if this StatementContext is on the context stack. false otherwise.\r
+ */\r
+ public boolean onStack() { return inUse; }\r
+\r
+ /**\r
+ * Indicates whether the statement needs to be executed atomically\r
+ * or not, i.e., whether a commit/rollback is permitted by a\r
+ * connection nested in this statement.\r
+ *\r
+ * @return true if needs to be atomic\r
+ */\r
+ public boolean isAtomic()\r
+ {\r
+ return isAtomic;\r
+ }\r
+\r
+ /**\r
+ * Return the text of the current statement.\r
+ * Note that this may be null. It is currently\r
+ * not set up correctly for ResultSets that aren't\r
+ * single row result sets (e.g SELECT), replication,\r
+ * and setXXXX/getXXXX jdbc methods.\r
+ *\r
+ * @return the statement text\r
+ */\r
+ public String getStatementText()\r
+ {\r
+ return stmtText;\r
+ }\r
+\r
+ //\r
+ // class implementation\r
+ //\r
+\r
+ /**\r
+ * Raise an exception if this Context is not in use, that is, on the\r
+ * Context Stack.\r
+ *\r
+ * @exception StandardException thrown on error.\r
+ */\r
+ private void pleaseBeOnStack() throws StandardException\r
+ {\r
+ if ( !inUse ) { throw StandardException.newException(SQLState.LANG_DEAD_STATEMENT); }\r
+ }\r
+\r
+ public boolean inUse()\r
+ {\r
+ return inUse;\r
+ }\r
+ public boolean isForReadOnly()\r
+ {\r
+ return isForReadOnly;\r
+ }\r
+ \r
+ /**\r
+ * Tests whether the statement which has allocated this StatementContext\r
+ * object has been cancelled. This method is typically called from the\r
+ * thread which is executing the statement, to test whether execution\r
+ * should continue or stop.\r
+ *\r
+ * @return whether the statement which has allocated this StatementContext\r
+ * object has been cancelled.\r
+ */\r
+ public boolean isCancelled()\r
+ {\r
+ return cancellationFlag;\r
+ }\r
+\r
+ /**\r
+ * Cancels the statement which has allocated this StatementContext object.\r
+ * This is done by setting a flag in the StatementContext object. For\r
+ * this to have any effect, it is the responsibility of the executing\r
+ * statement to check this flag regularly.\r
+ */\r
+ public void cancel()\r
+ {\r
+ cancellationFlag = true;\r
+ }\r
+\r
+ public void setSQLAllowed(short allow, boolean force) {\r
+\r
+ // cannot override a stricter setting.\r
+ // -1 is no routine restriction in place\r
+ // 0 is least restrictive\r
+ // 4 is most\r
+ if (force || (allow > sqlAllowed))\r
+ sqlAllowed = allow;\r
+\r
+ }\r
+ public short getSQLAllowed() {\r
+ if (!inUse)\r
+ return org.apache.derby.catalog.types.RoutineAliasInfo.NO_SQL;\r
+\r
+ return sqlAllowed;\r
+ }\r
+\r
+ /**\r
+ * Indicate that, in the event of a statement-level exception,\r
+ * this context is NOT the last one that needs to be rolled\r
+ * back--rather, it is nested within some other statement\r
+ * context, and that other context needs to be rolled back,\r
+ * too.\r
+ */\r
+ public void setParentRollback() {\r
+ rollbackParentContext = true;\r
+ }\r
+\r
+ /**\r
+ Set to indicate statement is system code.\r
+ For example a system procedure, view, function etc.\r
+ */\r
+ public void setSystemCode() {\r
+ isSystemCode = true;\r
+ }\r
+\r
+ /**\r
+ Return true if this statement is system code.\r
+ */\r
+ public boolean getSystemCode() {\r
+ return isSystemCode;\r
+ }\r
+\r
+ public StringBuffer appendErrorInfo() {\r
+\r
+ StringBuffer sb = ((ContextImpl) lcc).appendErrorInfo();\r
+ if (sb != null) {\r
+\r
+ sb.append("Failed Statement is: ");\r
+\r
+ sb.append(getStatementText());\r
+\r
+ if ((pvs != null) && pvs.getParameterCount() > 0)\r
+ {\r
+ String pvsString = " with " + pvs.getParameterCount() +\r
+ " parameters " + pvs.toString();\r
+ sb.append(pvsString);\r
+ }\r
+ }\r
+ return sb;\r
+\r
+ }\r
+}\r