--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.sql.GenericActivationHolder\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;\r
+\r
+import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;\r
+\r
+import org.apache.derby.iapi.types.DataValueFactory;\r
+\r
+import org.apache.derby.iapi.sql.execute.ExecPreparedStatement;\r
+import org.apache.derby.iapi.sql.execute.ExecRow;\r
+import org.apache.derby.iapi.sql.execute.ExecutionFactory;\r
+import org.apache.derby.iapi.sql.execute.NoPutResultSet;\r
+import org.apache.derby.iapi.sql.execute.ConstantAction;\r
+\r
+import org.apache.derby.impl.sql.execute.BaseActivation;\r
+\r
+import org.apache.derby.iapi.types.DataTypeDescriptor;\r
+import org.apache.derby.iapi.sql.ParameterValueSet;\r
+import org.apache.derby.iapi.sql.ResultSet;\r
+import org.apache.derby.iapi.sql.ResultDescription;\r
+import org.apache.derby.iapi.sql.Activation;\r
+import org.apache.derby.iapi.sql.execute.CursorResultSet;\r
+import org.apache.derby.iapi.sql.execute.TemporaryRowHolder;\r
+\r
+import org.apache.derby.iapi.sql.dictionary.IndexRowGenerator;\r
+import org.apache.derby.iapi.sql.dictionary.TableDescriptor;\r
+\r
+import org.apache.derby.iapi.reference.SQLState;\r
+\r
+import org.apache.derby.iapi.error.StandardException;\r
+\r
+import org.apache.derby.iapi.services.loader.GeneratedClass;\r
+import org.apache.derby.iapi.services.context.Context;\r
+\r
+import org.apache.derby.iapi.store.access.ConglomerateController;\r
+import org.apache.derby.iapi.store.access.ScanController;\r
+\r
+import org.apache.derby.iapi.types.RowLocation;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+\r
+import org.apache.derby.iapi.store.access.TransactionController;\r
+\r
+import java.sql.SQLWarning;\r
+import java.util.Enumeration;\r
+import java.util.Vector;\r
+import java.util.Hashtable;\r
+\r
+/**\r
+ * This class holds an Activation, and passes through most of the calls\r
+ * to the activation. The purpose of this class is to allow a PreparedStatement\r
+ * to be recompiled without the caller having to detect this and get a new\r
+ * activation.\r
+ *\r
+ * In addition to the Activation, this class holds a reference to the\r
+ * PreparedStatement that created it, along with a reference to the\r
+ * GeneratedClass that was associated with the PreparedStatement at the time\r
+ * this holder was created. These references are used to validate the\r
+ * Activation, to ensure that an activation is used only with the\r
+ * PreparedStatement that created it, and to detect when recompilation has\r
+ * happened.\r
+ *\r
+ * We detect recompilation by checking whether the GeneratedClass has changed.\r
+ * If it has, we try to let the caller continue to use this ActivationHolder.\r
+ * We create a new instance of the new GeneratedClass (that is, we create a\r
+ * new Activation), and we compare the number and type of parameters. If these\r
+ * are compatible, we copy the parameters from the old to the new Activation.\r
+ * If they are not compatible, we throw an exception telling the user that\r
+ * the Activation is out of date, and they need to get a new one.\r
+ *\r
+ */\r
+\r
+final class GenericActivationHolder implements Activation\r
+{\r
+ BaseActivation ac;\r
+ ExecPreparedStatement ps;\r
+ GeneratedClass gc;\r
+ DataTypeDescriptor[] paramTypes;\r
+ private final LanguageConnectionContext lcc;\r
+\r
+ /**\r
+ * Constructor for an ActivationHolder\r
+ *\r
+ * @param gc The GeneratedClass of the Activation\r
+ * @param ps The PreparedStatement this ActivationHolder is associated\r
+ * with\r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+ GenericActivationHolder(LanguageConnectionContext lcc, GeneratedClass gc, ExecPreparedStatement ps, boolean scrollable)\r
+ throws StandardException\r
+ {\r
+ this.lcc = lcc;\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ SanityManager.ASSERT(gc != null, "generated class is null , ps is a " + ps.getClass());\r
+ }\r
+\r
+ this.gc = gc;\r
+ this.ps = ps;\r
+\r
+ ac = (BaseActivation) gc.newInstance(lcc);\r
+ ac.setupActivation(ps, scrollable);\r
+ paramTypes = ps.getParameterTypes();\r
+ }\r
+\r
+ /* Activation interface */\r
+\r
+ /**\r
+ * @see Activation#reset\r
+ *\r
+ * @exception StandardException thrown on failure\r
+ */\r
+ public void reset() throws StandardException\r
+ {\r
+ ac.reset();\r
+ }\r
+\r
+ /**\r
+ * Temporary tables can be declared with ON COMMIT DELETE ROWS. But if the table has a held curosr open at\r
+ * commit time, data should not be deleted from the table. This method, (gets called at commit time) checks if this\r
+ * activation held cursor and if so, does that cursor reference the passed temp table name.\r
+ *\r
+ * @return true if this activation has held cursor and if it references the passed temp table name\r
+ */\r
+ public boolean checkIfThisActivationHasHoldCursor(String tableName)\r
+ {\r
+ return ac.checkIfThisActivationHasHoldCursor(tableName);\r
+ }\r
+\r
+ /**\r
+ * @see Activation#setCursorName\r
+ *\r
+ */\r
+ public void setCursorName(String cursorName)\r
+ {\r
+ ac.setCursorName(cursorName);\r
+ }\r
+\r
+ /**\r
+ * @see Activation#getCursorName\r
+ */\r
+ public String getCursorName()\r
+ {\r
+ return ac.getCursorName();\r
+ }\r
+\r
+ /**\r
+ * @see Activation#setResultSetHoldability\r
+ *\r
+ */\r
+ public void setResultSetHoldability(boolean resultSetHoldability)\r
+ {\r
+ ac.setResultSetHoldability(resultSetHoldability);\r
+ }\r
+\r
+ /**\r
+ * @see Activation#getResultSetHoldability\r
+ */\r
+ public boolean getResultSetHoldability()\r
+ {\r
+ return ac.getResultSetHoldability();\r
+ }\r
+\r
+ /** @see Activation#setAutoGeneratedKeysResultsetInfo */\r
+ public void setAutoGeneratedKeysResultsetInfo(int[] columnIndexes, String[] columnNames)\r
+ {\r
+ ac.setAutoGeneratedKeysResultsetInfo(columnIndexes, columnNames);\r
+ }\r
+\r
+ /** @see Activation#getAutoGeneratedKeysResultsetMode */\r
+ public boolean getAutoGeneratedKeysResultsetMode()\r
+ {\r
+ return ac.getAutoGeneratedKeysResultsetMode();\r
+ }\r
+\r
+ /** @see Activation#getAutoGeneratedKeysColumnIndexes */\r
+ public int[] getAutoGeneratedKeysColumnIndexes()\r
+ {\r
+ return ac.getAutoGeneratedKeysColumnIndexes();\r
+ }\r
+\r
+ /** @see Activation#getAutoGeneratedKeysColumnNames */\r
+ public String[] getAutoGeneratedKeysColumnNames()\r
+ {\r
+ return ac.getAutoGeneratedKeysColumnNames();\r
+ }\r
+\r
+ /** @see org.apache.derby.iapi.sql.Activation#getLanguageConnectionContext */\r
+ public LanguageConnectionContext getLanguageConnectionContext()\r
+ {\r
+ return lcc;\r
+ }\r
+\r
+ public TransactionController getTransactionController()\r
+ {\r
+ return ac.getTransactionController();\r
+ }\r
+\r
+ /** @see Activation#getExecutionFactory */\r
+ public ExecutionFactory getExecutionFactory()\r
+ {\r
+ return ac.getExecutionFactory();\r
+ }\r
+\r
+ /**\r
+ * @see Activation#getParameterValueSet\r
+ */\r
+ public ParameterValueSet getParameterValueSet()\r
+ {\r
+ return ac.getParameterValueSet();\r
+ }\r
+\r
+ /**\r
+ * @see Activation#setParameters\r
+ */\r
+ public void setParameters(ParameterValueSet parameterValues, DataTypeDescriptor[] parameterTypes) throws StandardException\r
+ {\r
+ ac.setParameters(parameterValues, parameterTypes);\r
+ }\r
+\r
+ /** \r
+ * @see Activation#execute\r
+ *\r
+ * @exception StandardException Thrown on failure\r
+ */\r
+ public ResultSet execute() throws StandardException\r
+ {\r
+ /*\r
+ ** Synchronize to avoid problems if another thread is preparing\r
+ ** the statement at the same time we're trying to execute it.\r
+ */\r
+ // synchronized (ps)\r
+ {\r
+ /* Has the activation class changed? */\r
+ if (gc != ps.getActivationClass())\r
+ {\r
+\r
+ GeneratedClass newGC;\r
+\r
+ // ensure the statement is valid by rePreparing it.\r
+ // DERBY-3260: If someone else reprepares the statement at the\r
+ // same time as we do, there's a window between the calls to\r
+ // rePrepare() and getActivationClass() when the activation\r
+ // class can be set to null, leading to NullPointerException\r
+ // being thrown later. Therefore, synchronize on ps to close\r
+ // the window.\r
+ synchronized (ps) {\r
+ ps.rePrepare(getLanguageConnectionContext());\r
+ newGC = ps.getActivationClass();\r
+ }\r
+\r
+ /*\r
+ ** If we get here, it means the PreparedStatement has been\r
+ ** recompiled. Get a new Activation and check whether the\r
+ ** parameters are compatible. If so, transfer the parameters\r
+ ** from the old Activation to the new one, and make that the\r
+ ** current Activation. If not, throw an exception.\r
+ */\r
+ BaseActivation newAC = (BaseActivation) newGC.newInstance(lcc);\r
+\r
+ DataTypeDescriptor[] newParamTypes = ps.getParameterTypes();\r
+\r
+ /*\r
+ ** Link the new activation to the prepared statement.\r
+ */\r
+ newAC.setupActivation(ps, ac.getScrollable());\r
+\r
+ newAC.setParameters(ac.getParameterValueSet(), paramTypes);\r
+\r
+\r
+ /*\r
+ ** IMPORTANT\r
+ **\r
+ ** Copy any essential state from the old activation\r
+ ** to the new activation. This must match the state\r
+ ** setup in EmbedStatement.\r
+ ** singleExecution, cursorName, holdability, maxRows.\r
+ */\r
+\r
+ if (ac.isSingleExecution())\r
+ newAC.setSingleExecution();\r
+\r
+ newAC.setCursorName(ac.getCursorName());\r
+\r
+ newAC.setResultSetHoldability(ac.getResultSetHoldability());\r
+ if (ac.getAutoGeneratedKeysResultsetMode()) //Need to do copy only if auto generated mode is on\r
+ newAC.setAutoGeneratedKeysResultsetInfo(ac.getAutoGeneratedKeysColumnIndexes(),\r
+ ac.getAutoGeneratedKeysColumnNames());\r
+ newAC.setMaxRows(ac.getMaxRows());\r
+\r
+ // break the link with the prepared statement\r
+ ac.setupActivation(null, false);\r
+ ac.close();\r
+\r
+ /* Remember the new class information */\r
+ ac = newAC;\r
+ gc = newGC;\r
+ paramTypes = newParamTypes;\r
+ }\r
+ }\r
+\r
+ String cursorName = ac.getCursorName();\r
+ if (cursorName != null)\r
+ {\r
+ // have to see if another activation is open\r
+ // with the same cursor name. If so we can't use this name\r
+\r
+ Activation activeCursor = lcc.lookupCursorActivation(cursorName);\r
+\r
+ if ((activeCursor != null) && (activeCursor != ac)) {\r
+ throw StandardException.newException(SQLState.LANG_CURSOR_ALREADY_EXISTS, cursorName);\r
+ }\r
+ }\r
+\r
+ return ac.execute();\r
+ }\r
+\r
+ /**\r
+ * @see Activation#getResultSet\r
+ *\r
+ * @return the current ResultSet of this activation.\r
+ */\r
+ public ResultSet getResultSet()\r
+ {\r
+ return ac.getResultSet();\r
+ }\r
+\r
+ /**\r
+ * @see Activation#setCurrentRow\r
+ *\r
+ */\r
+ public void setCurrentRow(ExecRow currentRow, int resultSetNumber) \r
+ {\r
+ ac.setCurrentRow(currentRow, resultSetNumber);\r
+ }\r
+\r
+ /**\r
+ * @see Activation#clearCurrentRow\r
+ */\r
+ public void clearCurrentRow(int resultSetNumber) \r
+ {\r
+ ac.clearCurrentRow(resultSetNumber);\r
+ }\r
+\r
+ /**\r
+ * @see Activation#getPreparedStatement\r
+ */\r
+ public ExecPreparedStatement getPreparedStatement()\r
+ {\r
+ return ps;\r
+ }\r
+\r
+ public void checkStatementValidity() throws StandardException {\r
+ ac.checkStatementValidity();\r
+ }\r
+\r
+ /**\r
+ * @see Activation#getResultDescription\r
+ */\r
+ public ResultDescription getResultDescription()\r
+ {\r
+ return ac.getResultDescription();\r
+ }\r
+\r
+ /**\r
+ * @see Activation#getDataValueFactory\r
+ */\r
+ public DataValueFactory getDataValueFactory()\r
+ {\r
+ return ac.getDataValueFactory();\r
+ }\r
+\r
+ /**\r
+ * @see Activation#getRowLocationTemplate\r
+ */\r
+ public RowLocation getRowLocationTemplate(int itemNumber)\r
+ {\r
+ return ac.getRowLocationTemplate(itemNumber);\r
+ }\r
+\r
+ /**\r
+ * @see Activation#getHeapConglomerateController\r
+ */\r
+ public ConglomerateController getHeapConglomerateController()\r
+ {\r
+ return ac.getHeapConglomerateController();\r
+ }\r
+\r
+ /**\r
+ * @see Activation#setHeapConglomerateController\r
+ */\r
+ public void setHeapConglomerateController(ConglomerateController updateHeapCC)\r
+ {\r
+ ac.setHeapConglomerateController(updateHeapCC);\r
+ }\r
+\r
+ /**\r
+ * @see Activation#clearHeapConglomerateController\r
+ */\r
+ public void clearHeapConglomerateController()\r
+ {\r
+ ac.clearHeapConglomerateController();\r
+ }\r
+\r
+ /**\r
+ * @see Activation#getIndexScanController\r
+ */\r
+ public ScanController getIndexScanController()\r
+ {\r
+ return ac.getIndexScanController();\r
+ }\r
+\r
+ /**\r
+ * @see Activation#setIndexScanController\r
+ */\r
+ public void setIndexScanController(ScanController indexSC)\r
+ {\r
+ ac.setIndexScanController(indexSC);\r
+ }\r
+\r
+ /**\r
+ * @see Activation#getIndexConglomerateNumber\r
+ */\r
+ public long getIndexConglomerateNumber()\r
+ {\r
+ return ac.getIndexConglomerateNumber();\r
+ }\r
+\r
+ /**\r
+ * @see Activation#setIndexConglomerateNumber\r
+ */\r
+ public void setIndexConglomerateNumber(long indexConglomerateNumber)\r
+ {\r
+ ac.setIndexConglomerateNumber(indexConglomerateNumber);\r
+ }\r
+\r
+ /**\r
+ * @see Activation#clearIndexScanInfo\r
+ */\r
+ public void clearIndexScanInfo()\r
+ {\r
+ ac.clearIndexScanInfo();\r
+ }\r
+\r
+ /**\r
+ * @see Activation#close\r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+ public void close() throws StandardException\r
+ {\r
+ ac.close();\r
+ }\r
+\r
+ /**\r
+ * @see Activation#isClosed\r
+ */\r
+ public boolean isClosed()\r
+ {\r
+ return ac.isClosed();\r
+ }\r
+\r
+ /**\r
+ Set the activation for a single execution.\r
+\r
+ @see Activation#setSingleExecution\r
+ */\r
+ public void setSingleExecution() {\r
+ ac.setSingleExecution();\r
+ }\r
+\r
+ /**\r
+ Is the activation set up for a single execution.\r
+\r
+ @see Activation#isSingleExecution\r
+ */\r
+ public boolean isSingleExecution() {\r
+ return ac.isSingleExecution();\r
+ }\r
+\r
+ /**\r
+ Get the number of subqueries in the entire query.\r
+ @return int The number of subqueries in the entire query.\r
+ */\r
+ public int getNumSubqueries() {\r
+ return ac.getNumSubqueries();\r
+ }\r
+\r
+ /**\r
+ * @see Activation#setForCreateTable()\r
+ */\r
+ public void setForCreateTable()\r
+ {\r
+ ac.setForCreateTable();\r
+ }\r
+\r
+ /**\r
+ * @see Activation#getForCreateTable()\r
+ */\r
+ public boolean getForCreateTable()\r
+ {\r
+ return ac.getForCreateTable();\r
+ }\r
+\r
+ /**\r
+ * @see Activation#setDDLTableDescriptor\r
+ */\r
+ public void setDDLTableDescriptor(TableDescriptor td)\r
+ {\r
+ ac.setDDLTableDescriptor(td);\r
+ }\r
+\r
+ /**\r
+ * @see Activation#getDDLTableDescriptor\r
+ */\r
+ public TableDescriptor getDDLTableDescriptor()\r
+ {\r
+ return ac.getDDLTableDescriptor();\r
+ }\r
+\r
+ /**\r
+ * @see Activation#setMaxRows\r
+ */\r
+ public void setMaxRows(int maxRows)\r
+ {\r
+ ac.setMaxRows(maxRows);\r
+ }\r
+\r
+ /**\r
+ * @see Activation#getMaxRows\r
+ */\r
+ public int getMaxRows()\r
+ {\r
+ return ac.getMaxRows();\r
+ }\r
+\r
+ public void setTargetVTI(java.sql.ResultSet targetVTI)\r
+ {\r
+ ac.setTargetVTI(targetVTI);\r
+ }\r
+\r
+ public java.sql.ResultSet getTargetVTI()\r
+ {\r
+ return ac.getTargetVTI();\r
+ }\r
+\r
+ /* Class implementation */\r
+\r
+\r
+ /**\r
+ * Mark the activation as unused. \r
+ */\r
+ public void markUnused()\r
+ {\r
+ ac.markUnused();\r
+ }\r
+\r
+ /**\r
+ * Is the activation in use?\r
+ *\r
+ * @return true/false\r
+ */\r
+ public boolean isInUse()\r
+ {\r
+ return ac.isInUse();\r
+ }\r
+ /**\r
+ @see org.apache.derby.iapi.sql.Activation#addWarning\r
+ */\r
+ public void addWarning(SQLWarning w)\r
+ {\r
+ ac.addWarning(w);\r
+ }\r
+\r
+ /**\r
+ @see org.apache.derby.iapi.sql.Activation#getWarnings\r
+ */\r
+ public SQLWarning getWarnings()\r
+ {\r
+ return ac.getWarnings();\r
+ }\r
+\r
+ /**\r
+ @see org.apache.derby.iapi.sql.Activation#clearWarnings\r
+ */\r
+ public void clearWarnings()\r
+ {\r
+ ac.clearWarnings();\r
+ }\r
+\r
+ /**\r
+ @see Activation#informOfRowCount\r
+ @exception StandardException Thrown on error\r
+ */\r
+ public void informOfRowCount(NoPutResultSet resultSet, long rowCount)\r
+ throws StandardException\r
+ {\r
+ ac.informOfRowCount(resultSet, rowCount);\r
+ }\r
+\r
+ /**\r
+ * @see Activation#isCursorActivation\r
+ */\r
+ public boolean isCursorActivation()\r
+ {\r
+ return ac.isCursorActivation();\r
+ }\r
+\r
+ public ConstantAction getConstantAction() {\r
+ return ac.getConstantAction();\r
+ }\r
+\r
+ public void setParentResultSet(TemporaryRowHolder rs, String resultSetId)\r
+ {\r
+ ac.setParentResultSet(rs, resultSetId);\r
+ }\r
+\r
+\r
+ public Vector getParentResultSet(String resultSetId)\r
+ {\r
+ return ac.getParentResultSet(resultSetId);\r
+ }\r
+\r
+ public void clearParentResultSets()\r
+ {\r
+ ac.clearParentResultSets();\r
+ }\r
+\r
+ public Hashtable getParentResultSets()\r
+ {\r
+ return ac.getParentResultSets();\r
+ }\r
+\r
+ public void setForUpdateIndexScan(CursorResultSet forUpdateResultSet)\r
+ {\r
+ ac.setForUpdateIndexScan(forUpdateResultSet);\r
+ }\r
+\r
+ public CursorResultSet getForUpdateIndexScan()\r
+ {\r
+ return ac.getForUpdateIndexScan();\r
+ }\r
+\r
+ public java.sql.ResultSet[][] getDynamicResults() {\r
+ return ac.getDynamicResults();\r
+ }\r
+ public int getMaxDynamicResults() {\r
+ return ac.getMaxDynamicResults();\r
+ }\r
+\r
+}\r