--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.iapi.sql.dictionary.SPSDescriptor\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.iapi.sql.dictionary;\r
+\r
+import java.sql.Timestamp;\r
+import java.util.Enumeration;\r
+import java.util.Vector;\r
+\r
+import org.apache.derby.catalog.Dependable;\r
+import org.apache.derby.catalog.DependableFinder;\r
+import org.apache.derby.catalog.UUID;\r
+import org.apache.derby.iapi.error.StandardException;\r
+import org.apache.derby.iapi.reference.SQLState;\r
+import org.apache.derby.iapi.services.context.ContextManager;\r
+import org.apache.derby.iapi.services.context.ContextService;\r
+import org.apache.derby.iapi.services.io.StoredFormatIds;\r
+import org.apache.derby.iapi.services.monitor.Monitor;\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+import org.apache.derby.iapi.services.uuid.UUIDFactory;\r
+import org.apache.derby.iapi.sql.Statement;\r
+import org.apache.derby.iapi.sql.StorablePreparedStatement;\r
+import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;\r
+import org.apache.derby.iapi.sql.conn.LanguageConnectionFactory;\r
+import org.apache.derby.iapi.sql.depend.DependencyManager;\r
+import org.apache.derby.iapi.sql.depend.Dependent;\r
+import org.apache.derby.iapi.sql.depend.Provider;\r
+import org.apache.derby.iapi.sql.depend.ProviderInfo;\r
+import org.apache.derby.iapi.sql.execute.ExecPreparedStatement;\r
+import org.apache.derby.iapi.store.access.TransactionController;\r
+import org.apache.derby.iapi.types.DataTypeDescriptor;\r
+\r
+/**\r
+ * A SPSDescriptor describes a Stored Prepared Statement.\r
+ * It correlates to a row in SYS.SYSSTATEMENTS.\r
+ *\r
+ * <B>SYNCHRONIZATION</B>: Stored prepared statements\r
+ * may be cached. Thus they may be shared by multiple\r
+ * threads. It is very hard for two threads to try\r
+ * to muck with an sps simultaeously because all ddl\r
+ * (including sps recompilation) clears out the sps\r
+ * cache and invalidates whatever statement held a\r
+ * cached sps. But it is possible for two statements\r
+ * to do a prepare execute statment <x> at the exact\r
+ * same time, so both try to do an sps.prepare() at the \r
+ * same time during code generation, so we synchronize\r
+ * most everything except getters on immutable objects\r
+ * just to be on the safe side.\r
+ *\r
+ *\r
+ */\r
+public class SPSDescriptor extends TupleDescriptor\r
+ implements UniqueSQLObjectDescriptor, Dependent, Provider\r
+{\r
+ /**\r
+ * Statement types. \r
+ * <UL>\r
+ * <LI> SPS_TYPE_TRIGGER - trigger (<B>NOT IMPLEMENTED</B>) </LI>\r
+ * <LI> SPS_TYPE_EXPLAIN - explain (<B>NOT IMPLEMENTED</B>) </LI>\r
+ * <LI> SPS_TYPE_REGULAR - catchall</LI>\r
+ * </UL>\r
+ */\r
+ public static final char SPS_TYPE_TRIGGER = 'T';\r
+ public static final char SPS_TYPE_REGULAR = 'S';\r
+ public static final char SPS_TYPE_EXPLAIN = 'X';\r
+\r
+ /**\r
+ interface to this class is:\r
+ <ol>\r
+ <li>public void prepare() throws StandardException;\r
+ <li>public void prepareAndRelease(LanguageConnectionContext lcc) \r
+ throws StandardException;\r
+ <li>public void prepareAndRelease(...);\r
+ <li>public String getQualifiedName();\r
+ <li>public char getType();\r
+ <li>public String getTypeAsString();\r
+ <li>public boolean isValid();\r
+ <li>public boolean initiallyCompilable();\r
+ <li>public java.sql.Timestamp getCompileTime();\r
+ <li>public void setCompileTime();\r
+ <li>public String getText();\r
+ <li>public String getUsingText();\r
+ <li>public void setUsingText(String usingText);\r
+ <li>public void setUUID(UUID uuid);\r
+ <li>public DataTypeDescriptor[] getParams() throws StandardException;\r
+ <li>public void setParams(DataTypeDescriptor[] params);\r
+ <li>Object[] getParameterDefaults() throws StandardException;\r
+ <li>void setParameterDefaults(Object[] values);\r
+ <li>public UUID getCompSchemaId();\r
+ <li>public ExecPreparedStatement getPreparedStatement()\r
+ throws StandardException;\r
+ <li>public ExecPreparedStatement getPreparedStatement(boolean recompIfInvalid)\r
+ throws StandardException;\r
+ <li>public void revalidate(LanguageConnectionContext lcc)\r
+ throws StandardException;\r
+ </ol>\r
+ */\r
+\r
+ private static final int RECOMPILE = 1;\r
+ private static final int INVALIDATE = 0;\r
+\r
+ \r
+ // Class contents\r
+ private SchemaDescriptor sd;\r
+ private String name;\r
+ private UUID uuid;\r
+ private UUID compSchemaId;\r
+ private char type;\r
+ private boolean valid;\r
+ private String text;\r
+ private String usingText;\r
+ private ExecPreparedStatement preparedStatement;\r
+ private DataTypeDescriptor params[];\r
+ private Timestamp compileTime;\r
+ /**\r
+ * Old code - never used.\r
+ */\r
+ private Object paramDefaults[];\r
+ private boolean initiallyCompilable;\r
+ private boolean lookedUpParams;\r
+ \r
+ private UUIDFactory uuidFactory;\r
+\r
+\r
+ // constructors\r
+ /**\r
+ * Constructor for a SPS Descriptor\r
+ *\r
+ * @param dataDictionary The data dictionary that this descriptor lives in\r
+ * @param name the SPS name\r
+ * @param uuid the UUID\r
+ * @param suuid the schema UUID\r
+ * @param compSchemaUUID the schema UUID at compilation time\r
+ * @param type type\r
+ * @param valid is the sps valid\r
+ * @param text the text for this statement\r
+ * @param initiallyCompilable is the statement initially compilable?\r
+ *\r
+ * @exception StandardException on error\r
+ */\r
+ public SPSDescriptor\r
+ (DataDictionary dataDictionary,\r
+ String name,\r
+ UUID uuid,\r
+ UUID suuid,\r
+ UUID compSchemaUUID,\r
+ char type,\r
+ boolean valid,\r
+ String text,\r
+ boolean initiallyCompilable ) throws StandardException\r
+ {\r
+ this( dataDictionary, name, uuid, suuid, compSchemaUUID,\r
+ type, valid, text, (String) null, null, null, initiallyCompilable );\r
+ }\r
+\r
+ /**\r
+ * Constructor for a SPS Descriptor. Used when\r
+ * constructing an SPS descriptor from a row\r
+ * in SYSSTATEMENTS.\r
+ *\r
+ * @param dataDictionary The data dictionary that this descriptor lives in\r
+ * @param name the SPS name\r
+ * @param uuid the UUID\r
+ * @param suuid the schema UUID\r
+ * @param compSchemaUUID the schema UUID at compilation time\r
+ * @param type type\r
+ * @param valid is the sps valid\r
+ * @param text the text for this statement\r
+ * @param usingText the text for the USING clause supplied to\r
+ * CREATE or ALTER STATEMENT\r
+ * @param compileTime the time this was compiled\r
+ * @param preparedStatement the PreparedStatement\r
+ * @param initiallyCompilable is the statement initially compilable?\r
+ *\r
+ * @exception StandardException on error\r
+ */\r
+ public SPSDescriptor\r
+ (DataDictionary dataDictionary,\r
+ String name,\r
+ UUID uuid,\r
+ UUID suuid,\r
+ UUID compSchemaUUID,\r
+ char type,\r
+ boolean valid,\r
+ String text,\r
+ String usingText,\r
+ Timestamp compileTime,\r
+ ExecPreparedStatement preparedStatement,\r
+ boolean initiallyCompilable ) throws StandardException\r
+ {\r
+ super( dataDictionary );\r
+\r
+ this.name = name;\r
+ this.uuid = uuid; \r
+ this.type = type;\r
+ this.text = text;\r
+ this.usingText = usingText;\r
+ this.valid = valid;\r
+ this.compileTime = compileTime;\r
+ this.sd = dataDictionary.getSchemaDescriptor(suuid, null);\r
+ this.preparedStatement = preparedStatement;\r
+ this.compSchemaId = compSchemaUUID;\r
+ this.initiallyCompilable = initiallyCompilable;\r
+ }\r
+\r
+ /**\r
+ * FOR TRIGGERS ONLY\r
+ * <p>\r
+ * Generate the class for this SPS and immediately\r
+ * release it. This is useful for cases where we\r
+ * don't want to immediately execute the statement \r
+ * corresponding to this sps (e.g. CREATE STATEMENT).\r
+ * <p>\r
+ * <I>SIDE EFFECTS</I>: will update and SYSDEPENDS \r
+ * with the prepared statement dependency info.\r
+ * \r
+ * @param lcc the language connection context\r
+ * @param triggerTable the table descriptor to bind against. Had\r
+ * better be null if this isn't a trigger sps.\r
+ * @param tc the transaction controller\r
+ *\r
+ * @exception StandardException on error\r
+ */\r
+ public final synchronized void prepareAndRelease\r
+ (\r
+ LanguageConnectionContext lcc, \r
+ TableDescriptor triggerTable,\r
+ TransactionController tc\r
+ ) throws StandardException\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ if (triggerTable != null)\r
+ {\r
+ SanityManager.ASSERT(type == SPS_TYPE_TRIGGER, "only expect a table descriptor when we have a trigger");\r
+ }\r
+ }\r
+ \r
+ compileStatement(lcc, triggerTable, tc);\r
+ \r
+ preparedStatement.makeInvalid(DependencyManager.PREPARED_STATEMENT_RELEASE, lcc);\r
+ }\r
+ \r
+ /**\r
+ * FOR TRIGGERS ONLY\r
+ * <p>\r
+ * Generate the class for this SPS and immediately\r
+ * release it. This is useful for cases where we\r
+ * don't want to immediately execute the statement \r
+ * corresponding to this sps (e.g. CREATE STATEMENT).\r
+ * <p>\r
+ * <I>SIDE EFFECTS</I>: will update and SYSDEPENDS \r
+ * with the prepared statement dependency info.\r
+ * \r
+ * @param lcc the language connection context\r
+ * @param triggerTable the table descriptor to bind against. Had\r
+ * better be null if this isn't a trigger sps.\r
+ *\r
+ * @exception StandardException on error\r
+ */\r
+ public final synchronized void prepareAndRelease\r
+ (\r
+ LanguageConnectionContext lcc, \r
+ TableDescriptor triggerTable\r
+ ) throws StandardException\r
+ {\r
+ prepareAndRelease(lcc, triggerTable, (TransactionController)null);\r
+ }\r
+\r
+ /**\r
+ * Generate the class for this SPS and immediately\r
+ * release it. This is useful for cases where we\r
+ * don't want to immediately execute the statement \r
+ * corresponding to this sps (e.g. CREATE STATEMENT).\r
+ * <p>\r
+ * <I>SIDE EFFECTS</I>: will update and SYSDEPENDS \r
+ * with the prepared statement dependency info.\r
+ *\r
+ * @param lcc the language connection context\r
+ * \r
+ * @exception StandardException on error\r
+ */\r
+ public final synchronized void prepareAndRelease(LanguageConnectionContext lcc) throws StandardException\r
+ {\r
+ prepareAndRelease(lcc, (TableDescriptor)null, (TransactionController)null);\r
+ }\r
+\r
+ private void compileStatement\r
+ (\r
+ LanguageConnectionContext lcc,\r
+ TableDescriptor triggerTable,\r
+ TransactionController tc\r
+ )\r
+ throws StandardException\r
+ {\r
+ ContextManager cm = lcc.getContextManager();\r
+ DependencyManager dm;\r
+ ProviderInfo[] providerInfo;\r
+\r
+ LanguageConnectionFactory lcf = lcc.getLanguageConnectionFactory();\r
+\r
+ DataDictionary dd = getDataDictionary();\r
+\r
+\r
+ /*\r
+ ** If we are a trigger, then we have to go ahead\r
+ ** and locate the trigger's table descriptor and\r
+ ** push it on the lcc. This is expensive, but\r
+ ** pretty atypical since trigger actions aren't\r
+ ** likely to be invalidated too often. Also, when\r
+ ** possible, we already have the triggerTable.\r
+ */\r
+ if (type == SPS_TYPE_TRIGGER && triggerTable == null)\r
+ {\r
+ String uuidStr = name.substring(49);\r
+ triggerTable = dd.getTableDescriptor(recreateUUID(uuidStr));\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ if (triggerTable == null)\r
+ {\r
+ SanityManager.THROWASSERT("couldn't find trigger table for trigger sps "+name);\r
+ }\r
+ }\r
+ }\r
+\r
+ if (triggerTable != null)\r
+ {\r
+ lcc.pushTriggerTable(triggerTable);\r
+ }\r
+\r
+ // stored statements always stored as unicode.\r
+ Statement stmt = lcf.getStatement(dd.getSchemaDescriptor(compSchemaId, null), text, true);\r
+\r
+ try\r
+ {\r
+ preparedStatement = (ExecPreparedStatement) stmt.prepareStorable(\r
+ lcc,\r
+ preparedStatement, \r
+ getParameterDefaults(),\r
+ getSchemaDescriptor(),\r
+ type == SPS_TYPE_TRIGGER);\r
+ }\r
+ finally\r
+ {\r
+ if (triggerTable != null)\r
+ {\r
+ lcc.popTriggerTable(triggerTable);\r
+ }\r
+ }\r
+\r
+ //If this references a SESSION schema table (temporary or permanent), then throw an exception\r
+ //This is if EXECUTE STATEMENT executing a statement that was created with NOCOMPILE. Because\r
+ //of NOCOMPILE, we could not catch SESSION schema table reference by the statement at\r
+ //CREATE STATEMENT time. And hence need to catch such statements at EXECUTE STATEMENT time\r
+ //when the query is getting compiled.\r
+ if (preparedStatement.referencesSessionSchema())\r
+ throw StandardException.newException(SQLState.LANG_OPERATION_NOT_ALLOWED_ON_SESSION_SCHEMA_TABLES);\r
+ \r
+ setCompileTime();\r
+ setParams(preparedStatement.getParameterTypes());\r
+\r
+ if (!((org.apache.derby.impl.sql.catalog.DataDictionaryImpl) dd).readOnlyUpgrade) {\r
+\r
+ /*\r
+ ** Indicate that we are going to write the data\r
+ ** dictionary. We have probably already done this\r
+ ** but it is ok to call startWriting more than once.\r
+ */\r
+ dd.startWriting(lcc);\r
+\r
+ dm = dd.getDependencyManager();\r
+ /*\r
+ ** Clear out all the dependencies that exist\r
+ ** before we recreate them so we don't grow\r
+ ** SYS.SYSDEPENDS forever.\r
+ */\r
+ dm.clearDependencies(lcc, this, tc);\r
+\r
+ /*\r
+ ** Copy over all the dependencies to me\r
+ */\r
+ dm.copyDependencies(preparedStatement, // from\r
+ this, // to\r
+ false, // persistent only\r
+ cm,\r
+ tc);\r
+ }\r
+\r
+ // mark it as valid\r
+ valid = true;\r
+ }\r
+\r
+ /**\r
+ * Gets the name of the sps.\r
+ *\r
+ * @return A String containing the name of the statement.\r
+ */\r
+ public final String getName()\r
+ {\r
+ return name;\r
+ }\r
+\r
+ /**\r
+ * Gets the full, qualified name of the statement.\r
+ *\r
+ * @return A String containing the name of the statement.\r
+ */\r
+ public final String getQualifiedName()\r
+ {\r
+ return sd.getSchemaName() + "." + name;\r
+ }\r
+\r
+ /**\r
+ * Gets the SchemaDescriptor for this SPS Descriptor.\r
+ *\r
+ * @return SchemaDescriptor The SchemaDescriptor.\r
+ */\r
+ public final SchemaDescriptor getSchemaDescriptor()\r
+ {\r
+ return sd;\r
+ }\r
+\r
+ /**\r
+ * Gets an identifier telling what type of table this is.\r
+ * Types match final ints in this interface. Currently\r
+ * returns SPS_TYPE_REGULAR or SPS_TYPE_TRIGGER.\r
+ *\r
+ * @return An identifier telling what type of statement\r
+ * we are.\r
+ */\r
+ public final char getType()\r
+ {\r
+ return type;\r
+ } \r
+\r
+ /**\r
+ * Simple little helper function to convert your type\r
+ * to a string, which is easier to use.\r
+ *\r
+ * @return type as a string\r
+ */ \r
+ public final String getTypeAsString()\r
+ {\r
+ char[] charArray = new char[1];\r
+ charArray[0] = type;\r
+ return new String(charArray);\r
+ }\r
+\r
+ /**\r
+ * Is the statement initially compilable? \r
+ *\r
+ * @return false if statement was created with the NOCOMPILE flag\r
+ * true otherwise\r
+ */\r
+ public boolean initiallyCompilable() { return initiallyCompilable; }\r
+ \r
+ /**\r
+ * Validate the type. <B>NOTE</B>: Only SPS_TYPE_REGULAR\r
+ * and SPS_TYPE_TRIGGER are currently valid.\r
+ *\r
+ * @param type the type\r
+ *\r
+ * @return true/false \r
+ */\r
+ public final static boolean validType(char type)\r
+ {\r
+ return (type == SPSDescriptor.SPS_TYPE_REGULAR) || \r
+ (type == SPSDescriptor.SPS_TYPE_TRIGGER);\r
+ }\r
+\r
+ /**\r
+ * The time this prepared statement was compiled\r
+ *\r
+ * @return the time this class was last compiled\r
+ */\r
+ public final synchronized Timestamp getCompileTime()\r
+ {\r
+ return compileTime;\r
+ }\r
+\r
+ /**\r
+ * Set the compile time to now\r
+ *\r
+ */\r
+ public final synchronized void setCompileTime()\r
+ {\r
+ compileTime = new Timestamp(System.currentTimeMillis());\r
+ }\r
+ \r
+ /**\r
+ * Get the text used to create this statement.\r
+ * Returns original text in a cleartext string.\r
+ *\r
+ * @return The text\r
+ */\r
+ public final String getText()\r
+ {\r
+ return text;\r
+ }\r
+\r
+ /**\r
+ * Get the text of the USING clause used on CREATE\r
+ * or ALTER statement.\r
+ *\r
+ * @return The text\r
+ */\r
+ public final synchronized String getUsingText()\r
+ {\r
+ return usingText;\r
+ }\r
+\r
+ /**\r
+ * Sets the UUID of the SPS.\r
+ *\r
+ * @param uuid The UUID of the SPS to be set in the descriptor\r
+ */\r
+ public final synchronized void setUUID(UUID uuid)\r
+ {\r
+ this.uuid = uuid;\r
+ }\r
+\r
+ /**\r
+ * Gets the UUID of the SPS.\r
+ *\r
+ * @return the uuid\r
+ */\r
+ public final UUID getUUID()\r
+ {\r
+ return uuid;\r
+ }\r
+ \r
+ /**\r
+ * Get the array of date type descriptors for\r
+ * this statement. Currently, we do a lookup\r
+ * if we don't already have the parameters saved.\r
+ * When SPSes are cached, the parameters should\r
+ * be set up when the sps is constructed.\r
+ *\r
+ * @return the array of data type descriptors\r
+ *\r
+ * @exception StandardException on error\r
+ */\r
+ public final synchronized DataTypeDescriptor[] getParams()\r
+ throws StandardException\r
+ {\r
+ if (params == null && !lookedUpParams)\r
+ {\r
+ Vector v = new Vector();\r
+ params = getDataDictionary().getSPSParams(this, v);\r
+ paramDefaults = new Object[v.size()]; \r
+ Enumeration iterator = v.elements();\r
+ for (int i = 0; iterator.hasMoreElements(); i++)\r
+ {\r
+ paramDefaults[i] = iterator.nextElement();\r
+ }\r
+\r
+ lookedUpParams = true;\r
+ }\r
+\r
+ return params;\r
+ }\r
+\r
+ /**\r
+ * Set the list of parameters for this statement\r
+ *\r
+ * @param params the parameter list\r
+ */\r
+ public final synchronized void setParams(DataTypeDescriptor params[])\r
+ {\r
+ this.params = params;\r
+ }\r
+\r
+ /**\r
+ * Get the default parameter values for this \r
+ * statement. Default parameter values are\r
+ * supplied by a USING clause on either a\r
+ * CREATE or ALTER STATEMENT statement.\r
+ *\r
+ * @return the default parameter values\r
+ *\r
+ * @exception StandardException on error\r
+ */\r
+ public final synchronized Object[] getParameterDefaults()\r
+ throws StandardException\r
+ {\r
+ if (paramDefaults == null)\r
+ getParams();\r
+\r
+ return paramDefaults;\r
+ }\r
+\r
+ /**\r
+ * Set the parameter defaults for this statement.\r
+ *\r
+ * @param values the parameter defaults\r
+ */\r
+ public final synchronized void setParameterDefaults(Object[] values)\r
+ {\r
+ this.paramDefaults = values;\r
+ }\r
+ \r
+ /**\r
+ * Get the constant action for this statement\r
+ *\r
+ * @return the constant action\r
+ */\r
+ //public final synchronized ConstantAction getConstantAction()\r
+ //{\r
+ // return preparedStatement.getConstantAction();\r
+ //}\r
+ \r
+ /**\r
+ * Get the preparedStatement for this statement.\r
+ * If stmt is invalid or hasn't been compiled yet,\r
+ * it will be recompiled.\r
+ *\r
+ * @return the preparedStatement\r
+ *\r
+ * @exception StandardException on error\r
+ */\r
+ public final ExecPreparedStatement getPreparedStatement()\r
+ throws StandardException\r
+ {\r
+ return getPreparedStatement(true);\r
+ }\r
+\r
+ /**\r
+ * Get the preparedStatement for this statement.\r
+ * Expects the prepared statement to have already\r
+ * been added to SYS.SYSSTATEMENTS.\r
+ * <p>\r
+ * Side Effects: will update SYS.SYSSTATEMENTS with\r
+ * the new plan if it needs to be recompiled.\r
+ *\r
+ * @param recompIfInvalid if false, never recompile even\r
+ * if statement is invalid\r
+ *\r
+ * @return the preparedStatement\r
+ *\r
+ * @exception StandardException on error\r
+ */\r
+ public final synchronized ExecPreparedStatement getPreparedStatement(boolean recompIfInvalid)\r
+ throws StandardException\r
+ {\r
+ //System.out.println("preparedStatement = " + preparedStatement);\r
+ /*\r
+ ** Recompile if we are invalid, we don't have\r
+ ** a prepared statement, or the statements activation\r
+ ** has been cleared and cannot be reconstituted.\r
+ */\r
+ if (recompIfInvalid &&\r
+ (!valid ||\r
+ (preparedStatement == null)))\r
+ {\r
+ ContextManager cm = ContextService.getFactory().getCurrentContextManager();\r
+\r
+ /*\r
+ ** Find the language connection context. Get\r
+ ** it each time in case a connection is dropped.\r
+ */\r
+ LanguageConnectionContext lcc = (LanguageConnectionContext)\r
+ cm.getContext(LanguageConnectionContext.CONTEXT_ID);\r
+ \r
+\r
+\r
+ if (!((org.apache.derby.impl.sql.catalog.DataDictionaryImpl) (lcc.getDataDictionary())).readOnlyUpgrade) {\r
+\r
+ //bug 4821 - First try compiling on a nested transaction so we can release\r
+ //the locks after the compilation. But if we get lock time out on the\r
+ //nested transaction, then go ahead and do the compilation on the user\r
+ //transaction. When doing the compilation on user transaction, the locks\r
+ //acquired for recompilation will be released at the end of the user transaction.\r
+ TransactionController nestedTC;\r
+ try\r
+ {\r
+ nestedTC = lcc.getTransactionCompile().startNestedUserTransaction(false);\r
+ }\r
+ catch (StandardException se)\r
+ {\r
+ // If I cannot start a Nested User Transaction use the parent\r
+ // transaction to do all the work.\r
+ nestedTC = null;\r
+ }\r
+\r
+ // DERBY-2584: If the first attempt to compile the query fails,\r
+ // we need to reset initiallyCompilable to make sure the\r
+ // prepared plan is fully stored to disk. Save the initial\r
+ // value here.\r
+ final boolean compilable = initiallyCompilable;\r
+\r
+ try\r
+ {\r
+ prepareAndRelease(lcc, null, nestedTC);\r
+ updateSYSSTATEMENTS(lcc, RECOMPILE, nestedTC);\r
+ }\r
+ catch (StandardException se)\r
+ {\r
+ if (se.getMessageId().equals(SQLState.LOCK_TIMEOUT))\r
+ {\r
+ if (nestedTC != null)\r
+ {\r
+ nestedTC.commit();\r
+ nestedTC.destroy();\r
+ nestedTC = null;\r
+ }\r
+ // if we couldn't do this with a nested xaction, retry with\r
+ // parent-- we need to wait this time!\r
+ initiallyCompilable = compilable;\r
+ prepareAndRelease(lcc, null, null);\r
+ updateSYSSTATEMENTS(lcc, RECOMPILE, null);\r
+ }\r
+ else throw se;\r
+ }\r
+ finally\r
+ {\r
+ // no matter what, commit the nested transaction; if something\r
+ // bad happened in the child xaction lets not abort the parent\r
+ // here.\r
+ if (nestedTC != null)\r
+ {\r
+ nestedTC.commit();\r
+ nestedTC.destroy();\r
+ }\r
+ } \r
+ }\r
+ }\r
+\r
+ return preparedStatement;\r
+ }\r
+\r
+ /**\r
+ * Get the compilation type schema id when this view\r
+ * was first bound.\r
+ *\r
+ * @return the schema UUID\r
+ */\r
+ public final UUID getCompSchemaId()\r
+ {\r
+ return compSchemaId;\r
+ }\r
+\r
+ /**\r
+ * Prints the contents of the TableDescriptor\r
+ *\r
+ * @return The contents as a String\r
+ */\r
+ public final String toString()\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ return "SPSDescriptor:\n"+\r
+ "\tname: "+sd.getSchemaName()+"."+name+"\n"+\r
+ "\tuuid: "+uuid+"\n"+\r
+ "\ttext: "+text+"\n"+\r
+ "\tvalid: "+((valid) ? "TRUE" : "FALSE")+"\n" +\r
+ "\tpreparedStatement: "+preparedStatement+"\n";\r
+ }\r
+ else\r
+ {\r
+ return "";\r
+ }\r
+ }\r
+\r
+ //////////////////////////////////////////////////////\r
+ //\r
+ // PROVIDER INTERFACE\r
+ //\r
+ //////////////////////////////////////////////////////\r
+\r
+ /** \r
+ * Return the stored form of this provider\r
+ *\r
+ * @see Dependable#getDependableFinder\r
+ */\r
+ public final DependableFinder getDependableFinder()\r
+ {\r
+ return getDependableFinder(StoredFormatIds.SPS_DESCRIPTOR_FINDER_V01_ID);\r
+ }\r
+\r
+ /**\r
+ * Return the name of this Provider. (Useful for errors.)\r
+ *\r
+ * @return String The name of this provider.\r
+ */\r
+ public final String getObjectName()\r
+ {\r
+ return name;\r
+ }\r
+\r
+ /**\r
+ * Get the provider's UUID \r
+ *\r
+ * @return String The provider's UUID\r
+ */\r
+ public final UUID getObjectID()\r
+ {\r
+ return uuid;\r
+ }\r
+\r
+ /**\r
+ * Get the provider's type.\r
+ *\r
+ * @return String The provider's type.\r
+ */\r
+ public final String getClassType()\r
+ {\r
+ return Dependable.STORED_PREPARED_STATEMENT;\r
+ }\r
+\r
+ //////////////////////////////////////////////////////\r
+ //\r
+ // DEPENDENT INTERFACE\r
+ //\r
+ //////////////////////////////////////////////////////\r
+ /**\r
+ * Check that all of the dependent's dependencies are valid.\r
+ *\r
+ * @return true if the dependent is currently valid\r
+ */\r
+ public final synchronized boolean isValid()\r
+ {\r
+ return valid;\r
+ }\r
+\r
+ /**\r
+ * Prepare to mark the dependent as invalid (due to at least one of\r
+ * its dependencies being invalid).\r
+ *\r
+ * @param action The action causing the invalidation\r
+ * @param p the provider\r
+ *\r
+ * @exception StandardException thrown if unable to make it invalid\r
+ */\r
+ public final synchronized void prepareToInvalidate(\r
+ Provider p, int action,\r
+ LanguageConnectionContext lcc) \r
+ throws StandardException\r
+ {\r
+ switch (action)\r
+ {\r
+ /*\r
+ ** Things that don't affect us\r
+ */\r
+ case DependencyManager.CREATE_VIEW:\r
+ \r
+ /*\r
+ ** Things that force a recompile, but are\r
+ ** allowed.\r
+ */\r
+ case DependencyManager.CREATE_INDEX:\r
+ case DependencyManager.CREATE_CONSTRAINT:\r
+ case DependencyManager.DROP_CONSTRAINT:\r
+ case DependencyManager.DROP_INDEX:\r
+ case DependencyManager.DROP_TABLE:\r
+ case DependencyManager.DROP_VIEW: \r
+ case DependencyManager.DROP_METHOD_ALIAS:\r
+ case DependencyManager.DROP_SYNONYM:\r
+ case DependencyManager.ALTER_TABLE:\r
+ case DependencyManager.RENAME:\r
+ case DependencyManager.RENAME_INDEX:\r
+ case DependencyManager.PREPARED_STATEMENT_RELEASE:\r
+ case DependencyManager.USER_RECOMPILE_REQUEST:\r
+ case DependencyManager.CHANGED_CURSOR:\r
+ case DependencyManager.BULK_INSERT:\r
+ case DependencyManager.COMPRESS_TABLE:\r
+ case DependencyManager.SET_CONSTRAINTS_ENABLE:\r
+ case DependencyManager.SET_CONSTRAINTS_DISABLE:\r
+ case DependencyManager.SET_TRIGGERS_ENABLE:\r
+ case DependencyManager.SET_TRIGGERS_DISABLE:\r
+ case DependencyManager.ROLLBACK:\r
+ case DependencyManager.INTERNAL_RECOMPILE_REQUEST:\r
+ case DependencyManager.CREATE_TRIGGER:\r
+ case DependencyManager.DROP_TRIGGER:\r
+ case DependencyManager.DROP_COLUMN:\r
+ case DependencyManager.DROP_COLUMN_RESTRICT:\r
+ case DependencyManager.UPDATE_STATISTICS:\r
+ case DependencyManager.DROP_STATISTICS:\r
+ case DependencyManager.TRUNCATE_TABLE:\r
+ break;\r
+\r
+ /*\r
+ ** The rest are errors\r
+ */\r
+ default:\r
+\r
+ DependencyManager dm;\r
+\r
+ dm = getDataDictionary().getDependencyManager();\r
+ throw StandardException.newException(SQLState.LANG_PROVIDER_HAS_DEPENDENT_S_P_S, \r
+ dm.getActionString(action), \r
+ p.getObjectName(), name);\r
+\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Mark the dependent as invalid (due to at least one of\r
+ * its dependencies being invalid).\r
+ *\r
+ * @param action The action causing the invalidation\r
+ *\r
+ * @exception StandardException thrown if unable to make it invalid\r
+ */\r
+ public final synchronized void makeInvalid(int action,\r
+ LanguageConnectionContext lcc) \r
+ throws StandardException\r
+ {\r
+ DependencyManager dm;\r
+\r
+ dm = getDataDictionary().getDependencyManager();\r
+\r
+ switch (action)\r
+ {\r
+ /*\r
+ ** Some things that don't affect stored prepared\r
+ ** statements.\r
+ */\r
+ case DependencyManager.PREPARED_STATEMENT_RELEASE:\r
+ case DependencyManager.CREATE_VIEW:\r
+ break;\r
+\r
+ /*\r
+ ** Things that can invalidate a stored\r
+ ** prepared statement.\r
+ */\r
+ case DependencyManager.CREATE_INDEX:\r
+ case DependencyManager.CREATE_CONSTRAINT:\r
+ case DependencyManager.DROP_CONSTRAINT:\r
+ case DependencyManager.DROP_TABLE:\r
+ case DependencyManager.DROP_INDEX:\r
+ case DependencyManager.DROP_VIEW: \r
+ case DependencyManager.DROP_METHOD_ALIAS:\r
+ case DependencyManager.DROP_SYNONYM:\r
+ case DependencyManager.ALTER_TABLE:\r
+ case DependencyManager.RENAME:\r
+ case DependencyManager.RENAME_INDEX:\r
+ case DependencyManager.USER_RECOMPILE_REQUEST:\r
+ case DependencyManager.CHANGED_CURSOR:\r
+ case DependencyManager.BULK_INSERT:\r
+ case DependencyManager.COMPRESS_TABLE:\r
+ case DependencyManager.SET_CONSTRAINTS_ENABLE:\r
+ case DependencyManager.SET_CONSTRAINTS_DISABLE:\r
+ case DependencyManager.SET_TRIGGERS_ENABLE:\r
+ case DependencyManager.SET_TRIGGERS_DISABLE:\r
+ case DependencyManager.ROLLBACK:\r
+ case DependencyManager.INTERNAL_RECOMPILE_REQUEST:\r
+ case DependencyManager.CREATE_TRIGGER:\r
+ case DependencyManager.DROP_TRIGGER:\r
+ case DependencyManager.DROP_COLUMN:\r
+ case DependencyManager.DROP_COLUMN_RESTRICT:\r
+ case DependencyManager.UPDATE_STATISTICS:\r
+ case DependencyManager.DROP_STATISTICS:\r
+ case DependencyManager.TRUNCATE_TABLE:\r
+ /*\r
+ ** If we are already invalid, don't write ourselves\r
+ ** out. Just to be safe, we'll send out an invalidate\r
+ ** to our dependents either way.\r
+ */\r
+ if (valid == true)\r
+ {\r
+ valid = false;\r
+ updateSYSSTATEMENTS(lcc, INVALIDATE, null);\r
+ }\r
+ dm.invalidateFor(this, dm.USER_RECOMPILE_REQUEST, lcc);\r
+ break;\r
+ case DependencyManager.DROP_SPS:\r
+ //System.out.println("SPSD " + preparedStatement);\r
+ dm.clearDependencies(lcc, this);\r
+ break;\r
+ \r
+ default:\r
+\r
+ /* \r
+ ** We should never get here, since we can't have dangling references \r
+ */\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ SanityManager.THROWASSERT("makeInvalid("+\r
+ dm.getActionString(action)+\r
+ ") not expected to get called; should have failed in "+\r
+ "prepareToInvalidate()");\r
+ }\r
+ break;\r
+\r
+ }\r
+\r
+ }\r
+\r
+ /**\r
+ * Invalidate and revalidate. The functional equivalent\r
+ * of calling makeInvalid() and makeValid(), except it\r
+ * is optimized.\r
+ *\r
+ * @exception StandardException on error\r
+ */\r
+ public final synchronized void revalidate(LanguageConnectionContext lcc)\r
+ throws StandardException\r
+ {\r
+ /*\r
+ ** Mark it as invalid first to ensure that\r
+ ** we don't write SYSSTATEMENTS 2x.\r
+ */\r
+ valid = false;\r
+ makeInvalid(DependencyManager.USER_RECOMPILE_REQUEST, lcc);\r
+ prepareAndRelease(lcc);\r
+ updateSYSSTATEMENTS(lcc, RECOMPILE, null);\r
+ }\r
+\r
+ /**\r
+ * Load the underlying generatd class. This is not expected\r
+ * to be used outside of the datadictionary package. It\r
+ * is used for optimizing class loading for sps\r
+ * cacheing.\r
+ *\r
+ * @exception StandardException on error\r
+ */\r
+ public void loadGeneratedClass() throws StandardException\r
+ {\r
+ /*\r
+ ** On upgrade, we null out the statement body,\r
+ ** so handle that here.\r
+ */\r
+ if (preparedStatement != null)\r
+ {\r
+ ((StorablePreparedStatement)preparedStatement).loadGeneratedClass();\r
+ }\r
+ }\r
+\r
+ /*\r
+ ** Update SYSSTATEMENTS with the changed the descriptor. \r
+ ** Always done in the user XACT.\r
+ ** <p>\r
+ ** Ideally, the changes to SYSSTATEMENTS would be made \r
+ ** in a separate xact as the current user xact, but this\r
+ ** is painful (you'ld need to get a new ContextManager\r
+ ** and then push all of the usual langauge contexts\r
+ ** onto it and THEN call AccessManager.getTransaction()),\r
+ ** and it wont work, because the xact is in a different\r
+ ** compatibility space and will self deadlock (e.g.\r
+ ** in the process of call DependencyManager.makeInvalid() \r
+ ** we first did a DDdependableFinder.getDependable()\r
+ ** which called DataDictionaryImpl.getSPSDescriptor()\r
+ ** so we hold a lock on SYS.SYSSTATEMENTS by the\r
+ ** time we get a 2nd xact and try to drop the statement).\r
+ */\r
+ private void updateSYSSTATEMENTS(LanguageConnectionContext lcc, int mode, TransactionController tc)\r
+ throws StandardException\r
+ {\r
+ int[] colsToUpdate;\r
+ boolean updateSYSCOLUMNS, recompile;\r
+ //bug 4821 - we want to wait for locks if updating sysstatements on parent transaction\r
+ boolean wait = false;\r
+ boolean firstCompilation = false;\r
+ if (mode == RECOMPILE)\r
+ {\r
+ recompile = true;\r
+ updateSYSCOLUMNS = true;\r
+ if(!initiallyCompilable)\r
+ {\r
+ firstCompilation = true;\r
+ initiallyCompilable = true;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ recompile = false;\r
+ updateSYSCOLUMNS = false;\r
+ }\r
+\r
+ DataDictionary dd = getDataDictionary();\r
+\r
+ if (((org.apache.derby.impl.sql.catalog.DataDictionaryImpl) dd).readOnlyUpgrade)\r
+ return;\r
+\r
+\r
+ /*\r
+ ** Get busy time\r
+ */\r
+ dd.startWriting(lcc); \r
+\r
+ if (tc == null) { //bug 4821 - tc will passed null if we want to use the user transaction\r
+ tc = lcc.getTransactionExecute();\r
+ wait = true;\r
+ }\r
+\r
+ dd.updateSPS(this,\r
+ tc, \r
+ recompile,\r
+ updateSYSCOLUMNS,\r
+ wait,\r
+ firstCompilation);\r
+ }\r
+\r
+ /**\r
+ * Get the UUID for the given string\r
+ *\r
+ * @param idString the string\r
+ *\r
+ * @return the UUID\r
+ */\r
+ private UUID recreateUUID(String idString)\r
+ {\r
+ if (uuidFactory == null)\r
+ {\r
+ uuidFactory = Monitor.getMonitor().getUUIDFactory();\r
+ }\r
+ return uuidFactory.recreateUUID(idString);\r
+ }\r
+\r
+ /** @see TupleDescriptor#getDescriptorType */\r
+ public String getDescriptorType() { return "Statement"; }\r
+\r
+ /** @see TupleDescriptor#getDescriptorName */\r
+ // RESOLVE: some descriptors have getName. some descriptors have\r
+ // getTableName, getColumnName whatever! try and unify all of this to one\r
+ // getDescriptorName! \r
+ public String getDescriptorName() { return name; }\r
+ \r
+}\r
+\r