0001: /*
0002:
0003: Derby - Class org.apache.derby.iapi.sql.dictionary.SPSDescriptor
0004:
0005: Licensed to the Apache Software Foundation (ASF) under one or more
0006: contributor license agreements. See the NOTICE file distributed with
0007: this work for additional information regarding copyright ownership.
0008: The ASF licenses this file to you under the Apache License, Version 2.0
0009: (the "License"); you may not use this file except in compliance with
0010: the License. You may obtain a copy of the License at
0011:
0012: http://www.apache.org/licenses/LICENSE-2.0
0013:
0014: Unless required by applicable law or agreed to in writing, software
0015: distributed under the License is distributed on an "AS IS" BASIS,
0016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0017: See the License for the specific language governing permissions and
0018: limitations under the License.
0019:
0020: */
0021:
0022: package org.apache.derby.iapi.sql.dictionary;
0023:
0024: import org.apache.derby.iapi.services.io.StoredFormatIds;
0025:
0026: import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
0027: import org.apache.derby.iapi.sql.conn.LanguageConnectionFactory;
0028: import org.apache.derby.iapi.sql.conn.StatementContext;
0029:
0030: import org.apache.derby.iapi.store.access.TransactionController;
0031:
0032: import org.apache.derby.iapi.sql.dictionary.DataDictionary;
0033: import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;
0034: import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
0035:
0036: import org.apache.derby.iapi.sql.execute.ConstantAction;
0037: import org.apache.derby.iapi.sql.execute.ExecutionContext;
0038:
0039: import org.apache.derby.iapi.sql.compile.CompilerContext;
0040:
0041: import org.apache.derby.iapi.types.DataTypeDescriptor;
0042: import org.apache.derby.iapi.sql.Statement;
0043: import org.apache.derby.iapi.sql.StorablePreparedStatement;
0044:
0045: import org.apache.derby.iapi.error.StandardException;
0046: import org.apache.derby.iapi.reference.SQLState;
0047:
0048: import org.apache.derby.iapi.services.context.ContextManager;
0049: import org.apache.derby.iapi.services.loader.ClassFactory;
0050: import org.apache.derby.iapi.services.context.ContextService;
0051: import org.apache.derby.iapi.services.monitor.Monitor;
0052:
0053: import org.apache.derby.iapi.sql.depend.DependencyManager;
0054: import org.apache.derby.iapi.sql.depend.Dependent;
0055: import org.apache.derby.iapi.sql.depend.Dependency;
0056: import org.apache.derby.iapi.sql.depend.Provider;
0057: import org.apache.derby.iapi.sql.depend.ProviderInfo;
0058:
0059: import org.apache.derby.iapi.types.DataValueFactory;
0060:
0061: import org.apache.derby.iapi.sql.execute.ExecPreparedStatement;
0062:
0063: import org.apache.derby.iapi.services.sanity.SanityManager;
0064: import org.apache.derby.iapi.services.loader.GeneratedClass;
0065:
0066: import org.apache.derby.catalog.UUID;
0067: import org.apache.derby.catalog.Dependable;
0068: import org.apache.derby.catalog.DependableFinder;
0069: import org.apache.derby.iapi.services.uuid.UUIDFactory;
0070:
0071: import java.util.Enumeration;
0072: import java.util.Vector;
0073: import java.sql.Timestamp;
0074:
0075: /**
0076: * A SPSDescriptor describes a Stored Prepared Statement.
0077: * It correlates to a row in SYS.SYSSTATEMENTS.
0078: *
0079: * <B>SYNCHRONIZATION</B>: Stored prepared statements
0080: * may be cached. Thus they may be shared by multiple
0081: * threads. It is very hard for two threads to try
0082: * to muck with an sps simultaeously because all ddl
0083: * (including sps recompilation) clears out the sps
0084: * cache and invalidates whatever statement held a
0085: * cached sps. But it is possible for two statements
0086: * to do a prepare execute statment <x> at the exact
0087: * same time, so both try to do an sps.prepare() at the
0088: * same time during code generation, so we synchronize
0089: * most everything except getters on immutable objects
0090: * just to be on the safe side.
0091: *
0092: *
0093: * @author jamie
0094: */
0095: public class SPSDescriptor extends TupleDescriptor implements
0096: UniqueSQLObjectDescriptor, Dependent, Provider {
0097: /**
0098: * Statement types.
0099: * <UL>
0100: * <LI> SPS_TYPE_TRIGGER - trigger (<B>NOT IMPLEMENTED</B>) </LI>
0101: * <LI> SPS_TYPE_EXPLAIN - explain (<B>NOT IMPLEMENTED</B>) </LI>
0102: * <LI> SPS_TYPE_REGULAR - catchall</LI>
0103: * </UL>
0104: */
0105: public static final char SPS_TYPE_TRIGGER = 'T';
0106: public static final char SPS_TYPE_REGULAR = 'S';
0107: public static final char SPS_TYPE_EXPLAIN = 'X';
0108:
0109: /**
0110: interface to this class is:
0111: <ol>
0112: <li>public void prepare() throws StandardException;
0113: <li>public void prepareAndRelease(LanguageConnectionContext lcc)
0114: throws StandardException;
0115: <li>public void prepareAndRelease(...);
0116: <li>public String getQualifiedName();
0117: <li>public char getType();
0118: <li>public String getTypeAsString();
0119: <li>public boolean isValid();
0120: <li>public boolean initiallyCompilable();
0121: <li>public java.sql.Timestamp getCompileTime();
0122: <li>public void setCompileTime();
0123: <li>public String getText();
0124: <li>public String getUsingText();
0125: <li>public void setUsingText(String usingText);
0126: <li>public void setUUID(UUID uuid);
0127: <li>public DataTypeDescriptor[] getParams() throws StandardException;
0128: <li>public void setParams(DataTypeDescriptor[] params);
0129: <li>Object[] getParameterDefaults() throws StandardException;
0130: <li>void setParameterDefaults(Object[] values);
0131: <li>public UUID getCompSchemaId();
0132: <li>public ExecPreparedStatement getPreparedStatement()
0133: throws StandardException;
0134: <li>public ExecPreparedStatement getPreparedStatement(boolean recompIfInvalid)
0135: throws StandardException;
0136: <li>public void revalidate(LanguageConnectionContext lcc)
0137: throws StandardException;
0138: </ol>
0139: */
0140:
0141: private static final int RECOMPILE = 1;
0142: private static final int INVALIDATE = 0;
0143:
0144: // Class contents
0145: private SchemaDescriptor sd;
0146: private String name;
0147: private UUID uuid;
0148: private UUID compSchemaId;
0149: private char type;
0150: private boolean valid;
0151: private String text;
0152: private String usingText;
0153: private ExecPreparedStatement preparedStatement;
0154: private DataTypeDescriptor params[];
0155: private Timestamp compileTime;
0156: /**
0157: * Old code - never used.
0158: */
0159: private Object paramDefaults[];
0160: private boolean initiallyCompilable;
0161: private boolean lookedUpParams;
0162:
0163: private UUIDFactory uuidFactory;
0164:
0165: // constructors
0166: /**
0167: * Constructor for a SPS Descriptor
0168: *
0169: * @param dataDictionary The data dictionary that this descriptor lives in
0170: * @param name the SPS name
0171: * @param uuid the UUID
0172: * @param suuid the schema UUID
0173: * @param compSchemaUUID the schema UUID at compilation time
0174: * @param type type
0175: * @param valid is the sps valid
0176: * @param text the text for this statement
0177: * @param initiallyCompilable is the statement initially compilable?
0178: *
0179: * @exception StandardException on error
0180: */
0181: public SPSDescriptor(DataDictionary dataDictionary, String name,
0182: UUID uuid, UUID suuid, UUID compSchemaUUID, char type,
0183: boolean valid, String text, boolean initiallyCompilable)
0184: throws StandardException {
0185: this (dataDictionary, name, uuid, suuid, compSchemaUUID, type,
0186: valid, text, (String) null, null, null,
0187: initiallyCompilable);
0188: }
0189:
0190: /**
0191: * Constructor for a SPS Descriptor. Used when
0192: * constructing an SPS descriptor from a row
0193: * in SYSSTATEMENTS.
0194: *
0195: * @param dataDictionary The data dictionary that this descriptor lives in
0196: * @param name the SPS name
0197: * @param uuid the UUID
0198: * @param suuid the schema UUID
0199: * @param compSchemaUUID the schema UUID at compilation time
0200: * @param type type
0201: * @param valid is the sps valid
0202: * @param text the text for this statement
0203: * @param usingText the text for the USING clause supplied to
0204: * CREATE or ALTER STATEMENT
0205: * @param compileTime the time this was compiled
0206: * @param preparedStatement the PreparedStatement
0207: * @param initiallyCompilable is the statement initially compilable?
0208: *
0209: * @exception StandardException on error
0210: */
0211: public SPSDescriptor(DataDictionary dataDictionary, String name,
0212: UUID uuid, UUID suuid, UUID compSchemaUUID, char type,
0213: boolean valid, String text, String usingText,
0214: Timestamp compileTime,
0215: ExecPreparedStatement preparedStatement,
0216: boolean initiallyCompilable) throws StandardException {
0217: super (dataDictionary);
0218:
0219: this .name = name;
0220: this .uuid = uuid;
0221: this .type = type;
0222: this .text = text;
0223: this .usingText = usingText;
0224: this .valid = valid;
0225: this .compileTime = compileTime;
0226: this .sd = dataDictionary.getSchemaDescriptor(suuid, null);
0227: this .preparedStatement = preparedStatement;
0228: this .compSchemaId = compSchemaUUID;
0229: this .initiallyCompilable = initiallyCompilable;
0230: }
0231:
0232: /**
0233: * FOR TRIGGERS ONLY
0234: * <p>
0235: * Generate the class for this SPS and immediately
0236: * release it. This is useful for cases where we
0237: * don't want to immediately execute the statement
0238: * corresponding to this sps (e.g. CREATE STATEMENT).
0239: * <p>
0240: * <I>SIDE EFFECTS</I>: will update and SYSDEPENDS
0241: * with the prepared statement dependency info.
0242: *
0243: * @param lcc the language connection context
0244: * @param triggerTable the table descriptor to bind against. Had
0245: * better be null if this isn't a trigger sps.
0246: * @param tc the transaction controller
0247: *
0248: * @exception StandardException on error
0249: */
0250: public final synchronized void prepareAndRelease(
0251: LanguageConnectionContext lcc,
0252: TableDescriptor triggerTable, TransactionController tc)
0253: throws StandardException {
0254: if (SanityManager.DEBUG) {
0255: if (triggerTable != null) {
0256: SanityManager
0257: .ASSERT(type == SPS_TYPE_TRIGGER,
0258: "only expect a table descriptor when we have a trigger");
0259: }
0260: }
0261:
0262: compileStatement(lcc, triggerTable, tc);
0263:
0264: preparedStatement.makeInvalid(
0265: DependencyManager.PREPARED_STATEMENT_RELEASE, lcc);
0266: }
0267:
0268: /**
0269: * FOR TRIGGERS ONLY
0270: * <p>
0271: * Generate the class for this SPS and immediately
0272: * release it. This is useful for cases where we
0273: * don't want to immediately execute the statement
0274: * corresponding to this sps (e.g. CREATE STATEMENT).
0275: * <p>
0276: * <I>SIDE EFFECTS</I>: will update and SYSDEPENDS
0277: * with the prepared statement dependency info.
0278: *
0279: * @param lcc the language connection context
0280: * @param triggerTable the table descriptor to bind against. Had
0281: * better be null if this isn't a trigger sps.
0282: *
0283: * @exception StandardException on error
0284: */
0285: public final synchronized void prepareAndRelease(
0286: LanguageConnectionContext lcc, TableDescriptor triggerTable)
0287: throws StandardException {
0288: prepareAndRelease(lcc, triggerTable,
0289: (TransactionController) null);
0290: }
0291:
0292: /**
0293: * Generate the class for this SPS and immediately
0294: * release it. This is useful for cases where we
0295: * don't want to immediately execute the statement
0296: * corresponding to this sps (e.g. CREATE STATEMENT).
0297: * <p>
0298: * <I>SIDE EFFECTS</I>: will update and SYSDEPENDS
0299: * with the prepared statement dependency info.
0300: *
0301: * @param lcc the language connection context
0302: *
0303: * @exception StandardException on error
0304: */
0305: public final synchronized void prepareAndRelease(
0306: LanguageConnectionContext lcc) throws StandardException {
0307: prepareAndRelease(lcc, (TableDescriptor) null,
0308: (TransactionController) null);
0309: }
0310:
0311: private void compileStatement(LanguageConnectionContext lcc,
0312: TableDescriptor triggerTable, TransactionController tc)
0313: throws StandardException {
0314: ContextManager cm = lcc.getContextManager();
0315: DependencyManager dm;
0316: ProviderInfo[] providerInfo;
0317:
0318: LanguageConnectionFactory lcf = lcc
0319: .getLanguageConnectionFactory();
0320:
0321: DataDictionary dd = getDataDictionary();
0322:
0323: /*
0324: ** If we are a trigger, then we have to go ahead
0325: ** and locate the trigger's table descriptor and
0326: ** push it on the lcc. This is expensive, but
0327: ** pretty atypical since trigger actions aren't
0328: ** likely to be invalidated too often. Also, when
0329: ** possible, we already have the triggerTable.
0330: */
0331: if (type == SPS_TYPE_TRIGGER && triggerTable == null) {
0332: String uuidStr = name.substring(49);
0333: triggerTable = dd.getTableDescriptor(recreateUUID(uuidStr));
0334: if (SanityManager.DEBUG) {
0335: if (triggerTable == null) {
0336: SanityManager
0337: .THROWASSERT("couldn't find trigger table for trigger sps "
0338: + name);
0339: }
0340: }
0341: }
0342:
0343: if (triggerTable != null) {
0344: lcc.pushTriggerTable(triggerTable);
0345: }
0346:
0347: // stored statements always stored as unicode.
0348: Statement stmt = lcf.getStatement(dd.getSchemaDescriptor(
0349: compSchemaId, null), text, true);
0350:
0351: try {
0352: preparedStatement = (ExecPreparedStatement) stmt
0353: .prepareStorable(lcc, preparedStatement,
0354: getParameterDefaults(),
0355: getSchemaDescriptor(),
0356: type == SPS_TYPE_TRIGGER);
0357: } finally {
0358: if (triggerTable != null) {
0359: lcc.popTriggerTable(triggerTable);
0360: }
0361: }
0362:
0363: //If this references a SESSION schema table (temporary or permanent), then throw an exception
0364: //This is if EXECUTE STATEMENT executing a statement that was created with NOCOMPILE. Because
0365: //of NOCOMPILE, we could not catch SESSION schema table reference by the statement at
0366: //CREATE STATEMENT time. And hence need to catch such statements at EXECUTE STATEMENT time
0367: //when the query is getting compiled.
0368: if (preparedStatement.referencesSessionSchema())
0369: throw StandardException
0370: .newException(SQLState.LANG_OPERATION_NOT_ALLOWED_ON_SESSION_SCHEMA_TABLES);
0371:
0372: setCompileTime();
0373: setParams(preparedStatement.getParameterTypes());
0374:
0375: if (!((org.apache.derby.impl.sql.catalog.DataDictionaryImpl) dd).readOnlyUpgrade) {
0376:
0377: /*
0378: ** Indicate that we are going to write the data
0379: ** dictionary. We have probably already done this
0380: ** but it is ok to call startWriting more than once.
0381: */
0382: dd.startWriting(lcc);
0383:
0384: dm = dd.getDependencyManager();
0385: /*
0386: ** Clear out all the dependencies that exist
0387: ** before we recreate them so we don't grow
0388: ** SYS.SYSDEPENDS forever.
0389: */
0390: dm.clearDependencies(lcc, this , tc);
0391:
0392: /*
0393: ** Copy over all the dependencies to me
0394: */
0395: dm.copyDependencies(preparedStatement, // from
0396: this , // to
0397: false, // persistent only
0398: cm, tc);
0399: }
0400:
0401: // mark it as valid
0402: valid = true;
0403: }
0404:
0405: /**
0406: * Gets the name of the sps.
0407: *
0408: * @return A String containing the name of the statement.
0409: */
0410: public final String getName() {
0411: return name;
0412: }
0413:
0414: /**
0415: * Gets the full, qualified name of the statement.
0416: *
0417: * @return A String containing the name of the statement.
0418: */
0419: public final String getQualifiedName() {
0420: return sd.getSchemaName() + "." + name;
0421: }
0422:
0423: /**
0424: * Gets the SchemaDescriptor for this SPS Descriptor.
0425: *
0426: * @return SchemaDescriptor The SchemaDescriptor.
0427: */
0428: public final SchemaDescriptor getSchemaDescriptor() {
0429: return sd;
0430: }
0431:
0432: /**
0433: * Gets an identifier telling what type of table this is.
0434: * Types match final ints in this interface. Currently
0435: * returns SPS_TYPE_REGULAR or SPS_TYPE_TRIGGER.
0436: *
0437: * @return An identifier telling what type of statement
0438: * we are.
0439: */
0440: public final char getType() {
0441: return type;
0442: }
0443:
0444: /**
0445: * Simple little helper function to convert your type
0446: * to a string, which is easier to use.
0447: *
0448: * @return type as a string
0449: */
0450: public final String getTypeAsString() {
0451: char[] charArray = new char[1];
0452: charArray[0] = type;
0453: return new String(charArray);
0454: }
0455:
0456: /**
0457: * Is the statement initially compilable?
0458: *
0459: * @return false if statement was created with the NOCOMPILE flag
0460: * true otherwise
0461: */
0462: public boolean initiallyCompilable() {
0463: return initiallyCompilable;
0464: }
0465:
0466: /**
0467: * Validate the type. <B>NOTE</B>: Only SPS_TYPE_REGULAR
0468: * and SPS_TYPE_TRIGGER are currently valid.
0469: *
0470: * @param type the type
0471: *
0472: * @return true/false
0473: */
0474: public final static boolean validType(char type) {
0475: return (type == SPSDescriptor.SPS_TYPE_REGULAR)
0476: || (type == SPSDescriptor.SPS_TYPE_TRIGGER);
0477: }
0478:
0479: /**
0480: * The time this prepared statement was compiled
0481: *
0482: * @return the time this class was last compiled
0483: */
0484: public final synchronized Timestamp getCompileTime() {
0485: return compileTime;
0486: }
0487:
0488: /**
0489: * Set the compile time to now
0490: *
0491: */
0492: public final synchronized void setCompileTime() {
0493: compileTime = new Timestamp(System.currentTimeMillis());
0494: }
0495:
0496: /**
0497: * Get the text used to create this statement.
0498: * Returns original text in a cleartext string.
0499: *
0500: * @return The text
0501: */
0502: public final String getText() {
0503: return text;
0504: }
0505:
0506: /**
0507: * Get the text of the USING clause used on CREATE
0508: * or ALTER statement.
0509: *
0510: * @return The text
0511: */
0512: public final synchronized String getUsingText() {
0513: return usingText;
0514: }
0515:
0516: /**
0517: * Sets the UUID of the SPS.
0518: *
0519: * @param uuid The UUID of the SPS to be set in the descriptor
0520: */
0521: public final synchronized void setUUID(UUID uuid) {
0522: this .uuid = uuid;
0523: }
0524:
0525: /**
0526: * Gets the UUID of the SPS.
0527: *
0528: * @return the uuid
0529: */
0530: public final UUID getUUID() {
0531: return uuid;
0532: }
0533:
0534: /**
0535: * Get the array of date type descriptors for
0536: * this statement. Currently, we do a lookup
0537: * if we don't already have the parameters saved.
0538: * When SPSes are cached, the parameters should
0539: * be set up when the sps is constructed.
0540: *
0541: * @return the array of data type descriptors
0542: *
0543: * @exception StandardException on error
0544: */
0545: public final synchronized DataTypeDescriptor[] getParams()
0546: throws StandardException {
0547: if (params == null && !lookedUpParams) {
0548: Vector v = new Vector();
0549: params = getDataDictionary().getSPSParams(this , v);
0550: paramDefaults = new Object[v.size()];
0551: Enumeration iterator = v.elements();
0552: for (int i = 0; iterator.hasMoreElements(); i++) {
0553: paramDefaults[i] = iterator.nextElement();
0554: }
0555:
0556: lookedUpParams = true;
0557: }
0558:
0559: return params;
0560: }
0561:
0562: /**
0563: * Set the list of parameters for this statement
0564: *
0565: * @param params the parameter list
0566: */
0567: public final synchronized void setParams(
0568: DataTypeDescriptor params[]) {
0569: this .params = params;
0570: }
0571:
0572: /**
0573: * Get the default parameter values for this
0574: * statement. Default parameter values are
0575: * supplied by a USING clause on either a
0576: * CREATE or ALTER STATEMENT statement.
0577: *
0578: * @return the default parameter values
0579: *
0580: * @exception StandardException on error
0581: */
0582: public final synchronized Object[] getParameterDefaults()
0583: throws StandardException {
0584: if (paramDefaults == null)
0585: getParams();
0586:
0587: return paramDefaults;
0588: }
0589:
0590: /**
0591: * Set the parameter defaults for this statement.
0592: *
0593: * @param values the parameter defaults
0594: */
0595: public final synchronized void setParameterDefaults(Object[] values) {
0596: this .paramDefaults = values;
0597: }
0598:
0599: /**
0600: * Get the constant action for this statement
0601: *
0602: * @return the constant action
0603: */
0604: //public final synchronized ConstantAction getConstantAction()
0605: //{
0606: // return preparedStatement.getConstantAction();
0607: //}
0608: /**
0609: * Get the preparedStatement for this statement.
0610: * If stmt is invalid or hasn't been compiled yet,
0611: * it will be recompiled.
0612: *
0613: * @return the preparedStatement
0614: *
0615: * @exception StandardException on error
0616: */
0617: public final ExecPreparedStatement getPreparedStatement()
0618: throws StandardException {
0619: return getPreparedStatement(true);
0620: }
0621:
0622: /**
0623: * Get the preparedStatement for this statement.
0624: * Expects the prepared statement to have already
0625: * been added to SYS.SYSSTATEMENTS.
0626: * <p>
0627: * Side Effects: will update SYS.SYSSTATEMENTS with
0628: * the new plan if it needs to be recompiled.
0629: *
0630: * @param recompIfInvalid if false, never recompile even
0631: * if statement is invalid
0632: *
0633: * @return the preparedStatement
0634: *
0635: * @exception StandardException on error
0636: */
0637: public final synchronized ExecPreparedStatement getPreparedStatement(
0638: boolean recompIfInvalid) throws StandardException {
0639: //System.out.println("preparedStatement = " + preparedStatement);
0640: /*
0641: ** Recompile if we are invalid, we don't have
0642: ** a prepared statement, or the statements activation
0643: ** has been cleared and cannot be reconstituted.
0644: */
0645: if (recompIfInvalid && (!valid || (preparedStatement == null))) {
0646: ContextManager cm = ContextService.getFactory()
0647: .getCurrentContextManager();
0648:
0649: /*
0650: ** Find the language connection context. Get
0651: ** it each time in case a connection is dropped.
0652: */
0653: LanguageConnectionContext lcc = (LanguageConnectionContext) cm
0654: .getContext(LanguageConnectionContext.CONTEXT_ID);
0655:
0656: if (!((org.apache.derby.impl.sql.catalog.DataDictionaryImpl) (lcc
0657: .getDataDictionary())).readOnlyUpgrade) {
0658:
0659: //bug 4821 - First try compiling on a nested transaction so we can release
0660: //the locks after the compilation. But if we get lock time out on the
0661: //nested transaction, then go ahead and do the compilation on the user
0662: //transaction. When doing the compilation on user transaction, the locks
0663: //acquired for recompilation will be released at the end of the user transaction.
0664: TransactionController nestedTC;
0665: try {
0666: nestedTC = lcc.getTransactionCompile()
0667: .startNestedUserTransaction(false);
0668: } catch (StandardException se) {
0669: // If I cannot start a Nested User Transaction use the parent
0670: // transaction to do all the work.
0671: nestedTC = null;
0672: }
0673:
0674: try {
0675: prepareAndRelease(lcc, null, nestedTC);
0676: updateSYSSTATEMENTS(lcc, RECOMPILE, nestedTC);
0677: } catch (StandardException se) {
0678: if (se.getMessageId().equals(SQLState.LOCK_TIMEOUT)) {
0679: if (nestedTC != null) {
0680: nestedTC.commit();
0681: nestedTC.destroy();
0682: nestedTC = null;
0683: }
0684: // if we couldn't do this with a nested xaction, retry with
0685: // parent-- we need to wait this time!
0686: prepareAndRelease(lcc, null, null);
0687: updateSYSSTATEMENTS(lcc, RECOMPILE, null);
0688: } else
0689: throw se;
0690: } finally {
0691: // no matter what, commit the nested transaction; if something
0692: // bad happened in the child xaction lets not abort the parent
0693: // here.
0694: if (nestedTC != null) {
0695: nestedTC.commit();
0696: nestedTC.destroy();
0697: }
0698: }
0699: }
0700: }
0701:
0702: return preparedStatement;
0703: }
0704:
0705: /**
0706: * Get the compilation type schema id when this view
0707: * was first bound.
0708: *
0709: * @return the schema UUID
0710: */
0711: public final UUID getCompSchemaId() {
0712: return compSchemaId;
0713: }
0714:
0715: /**
0716: * Prints the contents of the TableDescriptor
0717: *
0718: * @return The contents as a String
0719: */
0720: public final String toString() {
0721: if (SanityManager.DEBUG) {
0722: return "SPSDescriptor:\n" + "\tname: " + sd.getSchemaName()
0723: + "." + name + "\n" + "\tuuid: " + uuid + "\n"
0724: + "\ttext: " + text + "\n" + "\tvalid: "
0725: + ((valid) ? "TRUE" : "FALSE") + "\n"
0726: + "\tpreparedStatement: " + preparedStatement
0727: + "\n";
0728: } else {
0729: return "";
0730: }
0731: }
0732:
0733: //////////////////////////////////////////////////////
0734: //
0735: // PROVIDER INTERFACE
0736: //
0737: //////////////////////////////////////////////////////
0738:
0739: /**
0740: * Return the stored form of this provider
0741: *
0742: * @see Dependable#getDependableFinder
0743: */
0744: public final DependableFinder getDependableFinder() {
0745: return getDependableFinder(StoredFormatIds.SPS_DESCRIPTOR_FINDER_V01_ID);
0746: }
0747:
0748: /**
0749: * Return the name of this Provider. (Useful for errors.)
0750: *
0751: * @return String The name of this provider.
0752: */
0753: public final String getObjectName() {
0754: return name;
0755: }
0756:
0757: /**
0758: * Get the provider's UUID
0759: *
0760: * @return String The provider's UUID
0761: */
0762: public final UUID getObjectID() {
0763: return uuid;
0764: }
0765:
0766: /**
0767: * Get the provider's type.
0768: *
0769: * @return String The provider's type.
0770: */
0771: public final String getClassType() {
0772: return Dependable.STORED_PREPARED_STATEMENT;
0773: }
0774:
0775: //////////////////////////////////////////////////////
0776: //
0777: // DEPENDENT INTERFACE
0778: //
0779: //////////////////////////////////////////////////////
0780: /**
0781: * Check that all of the dependent's dependencies are valid.
0782: *
0783: * @return true if the dependent is currently valid
0784: */
0785: public final synchronized boolean isValid() {
0786: return valid;
0787: }
0788:
0789: /**
0790: * Prepare to mark the dependent as invalid (due to at least one of
0791: * its dependencies being invalid).
0792: *
0793: * @param action The action causing the invalidation
0794: * @param p the provider
0795: *
0796: * @exception StandardException thrown if unable to make it invalid
0797: */
0798: public final synchronized void prepareToInvalidate(Provider p,
0799: int action, LanguageConnectionContext lcc)
0800: throws StandardException {
0801: switch (action) {
0802: /*
0803: ** Things that don't affect us
0804: */
0805: case DependencyManager.CREATE_VIEW:
0806:
0807: /*
0808: ** Things that force a recompile, but are
0809: ** allowed.
0810: */
0811: case DependencyManager.CREATE_INDEX:
0812: case DependencyManager.CREATE_CONSTRAINT:
0813: case DependencyManager.DROP_CONSTRAINT:
0814: case DependencyManager.DROP_INDEX:
0815: case DependencyManager.DROP_TABLE:
0816: case DependencyManager.DROP_VIEW:
0817: case DependencyManager.DROP_METHOD_ALIAS:
0818: case DependencyManager.DROP_SYNONYM:
0819: case DependencyManager.ALTER_TABLE:
0820: case DependencyManager.RENAME:
0821: case DependencyManager.RENAME_INDEX:
0822: case DependencyManager.PREPARED_STATEMENT_RELEASE:
0823: case DependencyManager.USER_RECOMPILE_REQUEST:
0824: case DependencyManager.CHANGED_CURSOR:
0825: case DependencyManager.BULK_INSERT:
0826: case DependencyManager.COMPRESS_TABLE:
0827: case DependencyManager.SET_CONSTRAINTS_ENABLE:
0828: case DependencyManager.SET_CONSTRAINTS_DISABLE:
0829: case DependencyManager.SET_TRIGGERS_ENABLE:
0830: case DependencyManager.SET_TRIGGERS_DISABLE:
0831: case DependencyManager.ROLLBACK:
0832: case DependencyManager.INTERNAL_RECOMPILE_REQUEST:
0833: case DependencyManager.CREATE_TRIGGER:
0834: case DependencyManager.DROP_TRIGGER:
0835: case DependencyManager.DROP_COLUMN:
0836: case DependencyManager.UPDATE_STATISTICS:
0837: case DependencyManager.DROP_STATISTICS:
0838: case DependencyManager.TRUNCATE_TABLE:
0839: break;
0840:
0841: /*
0842: ** The rest are errors
0843: */
0844: default:
0845:
0846: DependencyManager dm;
0847:
0848: dm = getDataDictionary().getDependencyManager();
0849: throw StandardException.newException(
0850: SQLState.LANG_PROVIDER_HAS_DEPENDENT_S_P_S, dm
0851: .getActionString(action),
0852: p.getObjectName(), name);
0853:
0854: }
0855: }
0856:
0857: /**
0858: * Mark the dependent as invalid (due to at least one of
0859: * its dependencies being invalid).
0860: *
0861: * @param action The action causing the invalidation
0862: *
0863: * @exception StandardException thrown if unable to make it invalid
0864: */
0865: public final synchronized void makeInvalid(int action,
0866: LanguageConnectionContext lcc) throws StandardException {
0867: DependencyManager dm;
0868:
0869: dm = getDataDictionary().getDependencyManager();
0870:
0871: switch (action) {
0872: /*
0873: ** Some things that don't affect stored prepared
0874: ** statements.
0875: */
0876: case DependencyManager.PREPARED_STATEMENT_RELEASE:
0877: case DependencyManager.CREATE_VIEW:
0878: break;
0879:
0880: /*
0881: ** Things that can invalidate a stored
0882: ** prepared statement.
0883: */
0884: case DependencyManager.CREATE_INDEX:
0885: case DependencyManager.CREATE_CONSTRAINT:
0886: case DependencyManager.DROP_CONSTRAINT:
0887: case DependencyManager.DROP_TABLE:
0888: case DependencyManager.DROP_INDEX:
0889: case DependencyManager.DROP_VIEW:
0890: case DependencyManager.DROP_METHOD_ALIAS:
0891: case DependencyManager.DROP_SYNONYM:
0892: case DependencyManager.ALTER_TABLE:
0893: case DependencyManager.RENAME:
0894: case DependencyManager.RENAME_INDEX:
0895: case DependencyManager.USER_RECOMPILE_REQUEST:
0896: case DependencyManager.CHANGED_CURSOR:
0897: case DependencyManager.BULK_INSERT:
0898: case DependencyManager.COMPRESS_TABLE:
0899: case DependencyManager.SET_CONSTRAINTS_ENABLE:
0900: case DependencyManager.SET_CONSTRAINTS_DISABLE:
0901: case DependencyManager.SET_TRIGGERS_ENABLE:
0902: case DependencyManager.SET_TRIGGERS_DISABLE:
0903: case DependencyManager.ROLLBACK:
0904: case DependencyManager.INTERNAL_RECOMPILE_REQUEST:
0905: case DependencyManager.CREATE_TRIGGER:
0906: case DependencyManager.DROP_TRIGGER:
0907: case DependencyManager.DROP_COLUMN:
0908: case DependencyManager.UPDATE_STATISTICS:
0909: case DependencyManager.DROP_STATISTICS:
0910: case DependencyManager.TRUNCATE_TABLE:
0911: /*
0912: ** If we are already invalid, don't write ourselves
0913: ** out. Just to be safe, we'll send out an invalidate
0914: ** to our dependents either way.
0915: */
0916: if (valid == true) {
0917: valid = false;
0918: updateSYSSTATEMENTS(lcc, INVALIDATE, null);
0919: }
0920: dm.invalidateFor(this , dm.USER_RECOMPILE_REQUEST, lcc);
0921: break;
0922: case DependencyManager.DROP_SPS:
0923: //System.out.println("SPSD " + preparedStatement);
0924: dm.clearDependencies(lcc, this );
0925: break;
0926:
0927: default:
0928:
0929: /*
0930: ** We should never get here, since we can't have dangling references
0931: */
0932: if (SanityManager.DEBUG) {
0933: SanityManager
0934: .THROWASSERT("makeInvalid("
0935: + dm.getActionString(action)
0936: + ") not expected to get called; should have failed in "
0937: + "prepareToInvalidate()");
0938: }
0939: break;
0940:
0941: }
0942:
0943: }
0944:
0945: /**
0946: * Attempt to revalidate the dependent. For prepared statements,
0947: * this could go through its dependencies and check that they
0948: * are up to date; if not, it would recompile the statement.
0949: * Any failure during this attempt should throw
0950: * StandardException.unableToRevalidate().
0951: *
0952: * @exception StandardException thrown if unable to make it valid
0953: */
0954: public final synchronized void makeValid(
0955: LanguageConnectionContext lcc) throws StandardException {
0956: if (valid) {
0957: return;
0958: }
0959: prepareAndRelease(lcc);
0960:
0961: updateSYSSTATEMENTS(lcc, RECOMPILE, null);
0962:
0963: }
0964:
0965: /**
0966: * Invalidate and revalidate. The functional equivalent
0967: * of calling makeInvalid() and makeValid(), except it
0968: * is optimized.
0969: *
0970: * @exception StandardException on error
0971: */
0972: public final synchronized void revalidate(
0973: LanguageConnectionContext lcc) throws StandardException {
0974: /*
0975: ** Mark it as invalid first to ensure that
0976: ** we don't write SYSSTATEMENTS 2x.
0977: */
0978: valid = false;
0979: makeInvalid(DependencyManager.USER_RECOMPILE_REQUEST, lcc);
0980: prepareAndRelease(lcc);
0981: updateSYSSTATEMENTS(lcc, RECOMPILE, null);
0982: }
0983:
0984: /**
0985: * Load the underlying generatd class. This is not expected
0986: * to be used outside of the datadictionary package. It
0987: * is used for optimizing class loading for sps
0988: * cacheing.
0989: *
0990: * @exception StandardException on error
0991: */
0992: public void loadGeneratedClass() throws StandardException {
0993: /*
0994: ** On upgrade, we null out the statement body,
0995: ** so handle that here.
0996: */
0997: if (preparedStatement != null) {
0998: ((StorablePreparedStatement) preparedStatement)
0999: .loadGeneratedClass();
1000: }
1001: }
1002:
1003: /*
1004: ** Update SYSSTATEMENTS with the changed the descriptor.
1005: ** Always done in the user XACT.
1006: ** <p>
1007: ** Ideally, the changes to SYSSTATEMENTS would be made
1008: ** in a separate xact as the current user xact, but this
1009: ** is painful (you'ld need to get a new ContextManager
1010: ** and then push all of the usual langauge contexts
1011: ** onto it and THEN call AccessManager.getTransaction()),
1012: ** and it wont work, because the xact is in a different
1013: ** compatibility space and will self deadlock (e.g.
1014: ** in the process of call DependencyManager.makeInvalid()
1015: ** we first did a DDdependableFinder.getDependable()
1016: ** which called DataDictionaryImpl.getSPSDescriptor()
1017: ** so we hold a lock on SYS.SYSSTATEMENTS by the
1018: ** time we get a 2nd xact and try to drop the statement).
1019: */
1020: private void updateSYSSTATEMENTS(LanguageConnectionContext lcc,
1021: int mode, TransactionController tc)
1022: throws StandardException {
1023: int[] colsToUpdate;
1024: boolean updateSYSCOLUMNS, recompile;
1025: //bug 4821 - we want to wait for locks if updating sysstatements on parent transaction
1026: boolean wait = false;
1027: boolean firstCompilation = false;
1028: if (mode == RECOMPILE) {
1029: recompile = true;
1030: updateSYSCOLUMNS = true;
1031: if (!initiallyCompilable) {
1032: firstCompilation = true;
1033: initiallyCompilable = true;
1034: }
1035: } else {
1036: recompile = false;
1037: updateSYSCOLUMNS = false;
1038: }
1039:
1040: DataDictionary dd = getDataDictionary();
1041:
1042: if (((org.apache.derby.impl.sql.catalog.DataDictionaryImpl) dd).readOnlyUpgrade)
1043: return;
1044:
1045: /*
1046: ** Get busy time
1047: */
1048: dd.startWriting(lcc);
1049:
1050: if (tc == null) { //bug 4821 - tc will passed null if we want to use the user transaction
1051: tc = lcc.getTransactionExecute();
1052: wait = true;
1053: }
1054:
1055: dd.updateSPS(this , tc, recompile, updateSYSCOLUMNS, wait,
1056: firstCompilation);
1057: }
1058:
1059: /**
1060: * Get the UUID for the given string
1061: *
1062: * @param idString the string
1063: *
1064: * @return the UUID
1065: */
1066: private UUID recreateUUID(String idString) {
1067: if (uuidFactory == null) {
1068: uuidFactory = Monitor.getMonitor().getUUIDFactory();
1069: }
1070: return uuidFactory.recreateUUID(idString);
1071: }
1072:
1073: /** @see TupleDescriptor#getDescriptorType */
1074: public String getDescriptorType() {
1075: return "Statement";
1076: }
1077:
1078: /** @see TupleDescriptor#getDescriptorName */
1079: // RESOLVE: some descriptors have getName. some descriptors have
1080: // getTableName, getColumnName whatever! try and unify all of this to one
1081: // getDescriptorName!
1082: public String getDescriptorName() {
1083: return name;
1084: }
1085:
1086: }
|