0001: /*
0002:
0003: Derby - Class org.apache.derby.impl.sql.GenericPreparedStatement
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.impl.sql;
0023:
0024: import org.apache.derby.catalog.Dependable;
0025: import org.apache.derby.catalog.DependableFinder;
0026:
0027: import org.apache.derby.iapi.services.context.ContextService;
0028: import org.apache.derby.iapi.services.context.ContextManager;
0029:
0030: import org.apache.derby.iapi.services.monitor.Monitor;
0031:
0032: import org.apache.derby.iapi.services.sanity.SanityManager;
0033:
0034: import org.apache.derby.iapi.services.stream.HeaderPrintWriter;
0035: import org.apache.derby.iapi.services.cache.Cacheable;
0036:
0037: import org.apache.derby.catalog.UUID;
0038: import org.apache.derby.iapi.services.uuid.UUIDFactory;
0039: import org.apache.derby.iapi.util.ByteArray;
0040:
0041: import org.apache.derby.iapi.sql.dictionary.DataDictionary;
0042: import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;
0043: import org.apache.derby.iapi.sql.dictionary.SPSDescriptor;
0044:
0045: import org.apache.derby.iapi.sql.ParameterValueSet;
0046: import org.apache.derby.iapi.sql.PreparedStatement;
0047: import org.apache.derby.iapi.sql.Statement;
0048: import org.apache.derby.iapi.types.DataTypeDescriptor;
0049: import org.apache.derby.iapi.sql.ResultColumnDescriptor;
0050: import org.apache.derby.iapi.sql.ResultDescription;
0051: import org.apache.derby.iapi.sql.ResultSet;
0052: import org.apache.derby.iapi.sql.Activation;
0053:
0054: import org.apache.derby.iapi.sql.execute.ConstantAction;
0055: import org.apache.derby.iapi.sql.execute.ExecCursorTableReference;
0056: import org.apache.derby.iapi.sql.execute.ExecPreparedStatement;
0057:
0058: import org.apache.derby.iapi.sql.depend.DependencyManager;
0059: import org.apache.derby.iapi.sql.depend.Provider;
0060:
0061: import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
0062: import org.apache.derby.iapi.sql.conn.StatementContext;
0063:
0064: import org.apache.derby.impl.sql.compile.QueryTreeNode;
0065: import org.apache.derby.impl.sql.compile.CursorNode;
0066:
0067: import org.apache.derby.iapi.error.StandardException;
0068:
0069: import org.apache.derby.iapi.reference.SQLState;
0070:
0071: import org.apache.derby.iapi.services.loader.GeneratedClass;
0072:
0073: import java.sql.Timestamp;
0074: import java.sql.SQLWarning;
0075: import java.util.List;
0076:
0077: /**
0078: * Basic implementation of prepared statement.
0079: * relies on implementation of ResultDescription and Statement that
0080: * are also in this package.
0081: * <p>
0082: * These are both dependents (of the schema objects and prepared statements
0083: * they depend on) and providers. Prepared statements that are providers
0084: * are cursors that end up being used in positioned delete and update
0085: * statements (at present).
0086: * <p>
0087: * This is impl with the regular prepared statements; they will never
0088: * have the cursor info fields set.
0089: * <p>
0090: * Stored prepared statements extend this implementation
0091: *
0092: * @author ames
0093: */
0094: public class GenericPreparedStatement implements ExecPreparedStatement {
0095: ///////////////////////////////////////////////
0096: //
0097: // WARNING: when adding members to this class, be
0098: // sure to do the right thing in getClone(): if
0099: // it is PreparedStatement specific like finished,
0100: // then it shouldn't be copied, but stuff like parameters
0101: // must be copied.
0102: //
0103: ////////////////////////////////////////////////
0104:
0105: ////////////////////////////////////////////////
0106: // STATE that is copied by getClone()
0107: ////////////////////////////////////////////////
0108: public Statement statement;
0109: protected GeneratedClass activationClass; // satisfies Activation
0110: protected ResultDescription resultDesc;
0111: protected DataTypeDescriptor[] paramTypeDescriptors;
0112: private String spsName;
0113: private SQLWarning warnings;
0114:
0115: //If the query node for this statement references SESSION schema tables, mark it so in the boolean below
0116: //This information will be used by EXECUTE STATEMENT if it is executing a statement that was created with NOCOMPILE. Because
0117: //of NOCOMPILE, we could not catch SESSION schema table reference by the statement at CREATE STATEMENT time. Need to catch
0118: //such statements at EXECUTE STATEMENT time when the query is getting compiled.
0119: //This information will also be used to decide if the statement should be cached or not. Any statement referencing SESSION
0120: //schema tables will not be cached.
0121: private boolean referencesSessionSchema;
0122:
0123: // fields used for cursors
0124: protected ExecCursorTableReference targetTable;
0125: protected ResultColumnDescriptor[] targetColumns;
0126: protected String[] updateColumns;
0127: protected int updateMode;
0128:
0129: protected ConstantAction executionConstants;
0130: protected Object[] savedObjects;
0131: protected List requiredPermissionsList;
0132:
0133: // fields for dependency tracking
0134: protected String UUIDString;
0135: protected UUID UUIDValue;
0136:
0137: private boolean needsSavepoint;
0138:
0139: private String execStmtName;
0140: private String execSchemaName;
0141: protected boolean isAtomic;
0142: protected String sourceTxt;
0143:
0144: private int inUseCount;
0145:
0146: // true if the statement is being compiled.
0147: boolean compilingStatement;
0148:
0149: ////////////////////////////////////////////////
0150: // STATE that is not copied by getClone()
0151: ////////////////////////////////////////////////
0152: // fields for run time stats
0153: protected long parseTime;
0154: protected long bindTime;
0155: protected long optimizeTime;
0156: protected long generateTime;
0157: protected long compileTime;
0158: protected Timestamp beginCompileTimestamp;
0159: protected Timestamp endCompileTimestamp;
0160:
0161: //private boolean finished;
0162: protected boolean isValid;
0163: protected boolean spsAction;
0164:
0165: // state for caching.
0166: /**
0167: If non-null then this object is the cacheable
0168: that holds us in the cache.
0169: */
0170: private Cacheable cacheHolder;
0171:
0172: //
0173: // constructors
0174: //
0175:
0176: GenericPreparedStatement() {
0177: /* Get the UUID for this prepared statement */
0178: UUIDFactory uuidFactory = Monitor.getMonitor().getUUIDFactory();
0179:
0180: UUIDValue = uuidFactory.createUUID();
0181: UUIDString = UUIDValue.toString();
0182: spsAction = false;
0183: }
0184:
0185: /**
0186: */
0187: public GenericPreparedStatement(Statement st) {
0188: this ();
0189:
0190: statement = st;
0191: }
0192:
0193: //
0194: // PreparedStatement interface
0195: //
0196: public synchronized boolean upToDate() throws StandardException {
0197: return isValid && (activationClass != null)
0198: && !compilingStatement;
0199: }
0200:
0201: public void rePrepare(LanguageConnectionContext lcc)
0202: throws StandardException {
0203: if (!upToDate())
0204: makeValid(lcc);
0205: }
0206:
0207: /**
0208: * Get a new activation instance.
0209: *
0210: * @exception StandardException thrown if finished.
0211: */
0212: public synchronized Activation getActivation(
0213: LanguageConnectionContext lcc, boolean scrollable)
0214: throws StandardException {
0215: GeneratedClass gc = getActivationClass();
0216:
0217: if (gc == null) {
0218: rePrepare(lcc);
0219: gc = getActivationClass();
0220: }
0221:
0222: Activation ac = new GenericActivationHolder(lcc, gc, this ,
0223: scrollable);
0224:
0225: inUseCount++;
0226:
0227: return ac;
0228: }
0229:
0230: public ResultSet execute(LanguageConnectionContext lcc,
0231: boolean rollbackParentContext, long timeoutMillis)
0232: throws StandardException {
0233: Activation a = getActivation(lcc, false);
0234: a.setSingleExecution();
0235: return execute(a, rollbackParentContext, timeoutMillis);
0236: }
0237:
0238: /**
0239: * The guts of execution.
0240: *
0241: * @param activation the activation to run.
0242: * @param rollbackParentContext True if 1) the statement context is
0243: * NOT a top-level context, AND 2) in the event of a statement-level
0244: * exception, the parent context needs to be rolled back, too.
0245: * @param timeoutMillis timeout value in milliseconds.
0246: * @return the result set to be pawed through
0247: *
0248: * @exception StandardException thrown on error
0249: */
0250:
0251: public ResultSet execute(Activation activation,
0252: boolean rollbackParentContext, long timeoutMillis)
0253: throws StandardException {
0254: boolean needToClearSavePoint = false;
0255:
0256: if (activation == null
0257: || activation.getPreparedStatement() != this ) {
0258: throw StandardException.newException(
0259: SQLState.LANG_WRONG_ACTIVATION, "execute");
0260: }
0261:
0262: recompileOutOfDatePlan: while (true) {
0263: // verify the activation is for me--somehow. NOTE: This is
0264: // different from the above check for whether the activation is
0265: // associated with the right PreparedStatement - it's conceivable
0266: // that someone could construct an activation of the wrong type
0267: // that points to the right PreparedStatement.
0268: //
0269: //SanityManager.ASSERT(activation instanceof activationClass, "executing wrong activation");
0270:
0271: /* This is where we set and clear savepoints around each individual
0272: * statement which needs one. We don't set savepoints for cursors because
0273: * they're not needed and they wouldn't work in a read only database.
0274: * We can't set savepoints for commit/rollback because they'll get
0275: * blown away before we try to clear them.
0276: */
0277:
0278: LanguageConnectionContext lccToUse = activation
0279: .getLanguageConnectionContext();
0280:
0281: if (lccToUse.getLogStatementText()) {
0282: HeaderPrintWriter istream = Monitor.getStream();
0283: String xactId = lccToUse.getTransactionExecute()
0284: .getActiveStateTxIdString();
0285: String pvsString = "";
0286: ParameterValueSet pvs = activation
0287: .getParameterValueSet();
0288: if (pvs != null && pvs.getParameterCount() > 0) {
0289: pvsString = " with " + pvs.getParameterCount()
0290: + " parameters " + pvs.toString();
0291: }
0292: istream
0293: .printlnWithHeader(LanguageConnectionContext.xidStr
0294: + xactId
0295: + "), "
0296: + LanguageConnectionContext.lccStr
0297: + lccToUse.getInstanceNumber()
0298: + "), "
0299: + LanguageConnectionContext.dbnameStr
0300: + lccToUse.getDbname()
0301: + "), "
0302: + LanguageConnectionContext.drdaStr
0303: + lccToUse.getDrdaID()
0304: + "), Executing prepared statement: "
0305: + getSource()
0306: + " :End prepared statement"
0307: + pvsString);
0308: }
0309:
0310: ParameterValueSet pvs = activation.getParameterValueSet();
0311:
0312: /* put it in try block to unlock the PS in any case
0313: */
0314: if (!spsAction) {
0315: // only re-prepare if this isn't an SPS for a trigger-action;
0316: // if it _is_ an SPS for a trigger action, then we can't just
0317: // do a regular prepare because the statement might contain
0318: // internal SQL that isn't allowed in other statements (such as a
0319: // static method call to get the trigger context for retrieval
0320: // of "new row" or "old row" values). So in that case we
0321: // skip the call to 'rePrepare' and if the statement is out
0322: // of date, we'll get a NEEDS_COMPILE exception when we try
0323: // to execute. That exception will be caught by the executeSPS()
0324: // method of the GenericTriggerExecutor class, and at that time
0325: // the SPS action will be recompiled correctly.
0326: rePrepare(lccToUse);
0327: }
0328:
0329: StatementContext statementContext = lccToUse
0330: .pushStatementContext(isAtomic,
0331: updateMode == CursorNode.READ_ONLY,
0332: getSource(), pvs, rollbackParentContext,
0333: timeoutMillis);
0334:
0335: if (needsSavepoint()) {
0336: /* Mark this position in the log so that a statement
0337: * rollback will undo any changes.
0338: */
0339: statementContext.setSavePoint();
0340: needToClearSavePoint = true;
0341: }
0342:
0343: if (executionConstants != null) {
0344: lccToUse.validateStmtExecution(executionConstants);
0345: }
0346:
0347: ResultSet resultSet = null;
0348: try {
0349:
0350: resultSet = activation.execute();
0351:
0352: resultSet.open();
0353: } catch (StandardException se) {
0354: /* Cann't handle recompiling SPS action recompile here */
0355: if (!se.getMessageId().equals(
0356: SQLState.LANG_STATEMENT_NEEDS_RECOMPILE)
0357: || spsAction)
0358: throw se;
0359: statementContext.cleanupOnError(se);
0360: continue recompileOutOfDatePlan;
0361:
0362: }
0363:
0364: if (needToClearSavePoint) {
0365: /* We're done with our updates */
0366: statementContext.clearSavePoint();
0367: }
0368:
0369: lccToUse.popStatementContext(statementContext, null);
0370:
0371: if (activation.isSingleExecution() && resultSet.isClosed()) {
0372: // if the result set is 'done', i.e. not openable,
0373: // then we can also release the activation.
0374: // Note that a result set with output parameters
0375: // or rows to return is explicitly finished
0376: // by the user.
0377: activation.close();
0378: }
0379:
0380: return resultSet;
0381:
0382: }
0383: }
0384:
0385: public ResultDescription getResultDescription() {
0386: return resultDesc;
0387: }
0388:
0389: public DataTypeDescriptor[] getParameterTypes() {
0390: return paramTypeDescriptors;
0391: }
0392:
0393: public String getSource() {
0394: return (sourceTxt != null) ? sourceTxt
0395: : (statement == null) ? "null" : statement.getSource();
0396: }
0397:
0398: public void setSource(String text) {
0399: sourceTxt = text;
0400: }
0401:
0402: public final void setSPSName(String name) {
0403: spsName = name;
0404: }
0405:
0406: public String getSPSName() {
0407: return spsName;
0408: }
0409:
0410: /**
0411: * Get the total compile time for the associated query in milliseconds.
0412: * Compile time can be divided into parse, bind, optimize and generate times.
0413: *
0414: * @return long The total compile time for the associated query in milliseconds.
0415: */
0416: public long getCompileTimeInMillis() {
0417: return compileTime;
0418: }
0419:
0420: /**
0421: * Get the parse time for the associated query in milliseconds.
0422: *
0423: * @return long The parse time for the associated query in milliseconds.
0424: */
0425: public long getParseTimeInMillis() {
0426: return parseTime;
0427: }
0428:
0429: /**
0430: * Get the bind time for the associated query in milliseconds.
0431: *
0432: * @return long The bind time for the associated query in milliseconds.
0433: */
0434: public long getBindTimeInMillis() {
0435: return bindTime;
0436: }
0437:
0438: /**
0439: * Get the optimize time for the associated query in milliseconds.
0440: *
0441: * @return long The optimize time for the associated query in milliseconds.
0442: */
0443: public long getOptimizeTimeInMillis() {
0444: return optimizeTime;
0445: }
0446:
0447: /**
0448: * Get the generate time for the associated query in milliseconds.
0449: *
0450: * @return long The generate time for the associated query in milliseconds.
0451: */
0452: public long getGenerateTimeInMillis() {
0453: return generateTime;
0454: }
0455:
0456: /**
0457: * Get the timestamp for the beginning of compilation
0458: *
0459: * @return Timestamp The timestamp for the beginning of compilation.
0460: */
0461: public Timestamp getBeginCompileTimestamp() {
0462: return beginCompileTimestamp;
0463: }
0464:
0465: /**
0466: * Get the timestamp for the end of compilation
0467: *
0468: * @return Timestamp The timestamp for the end of compilation.
0469: */
0470: public Timestamp getEndCompileTimestamp() {
0471: return endCompileTimestamp;
0472: }
0473:
0474: void setCompileTimeWarnings(SQLWarning warnings) {
0475: this .warnings = warnings;
0476: }
0477:
0478: public final SQLWarning getCompileTimeWarnings() {
0479: return warnings;
0480: }
0481:
0482: /**
0483: * Set the compile time for this prepared statement.
0484: *
0485: * @param compileTime The compile time
0486: */
0487: protected void setCompileTimeMillis(long parseTime, long bindTime,
0488: long optimizeTime, long generateTime, long compileTime,
0489: Timestamp beginCompileTimestamp,
0490: Timestamp endCompileTimestamp) {
0491: this .parseTime = parseTime;
0492: this .bindTime = bindTime;
0493: this .optimizeTime = optimizeTime;
0494: this .generateTime = generateTime;
0495: this .compileTime = compileTime;
0496: this .beginCompileTimestamp = beginCompileTimestamp;
0497: this .endCompileTimestamp = endCompileTimestamp;
0498: }
0499:
0500: /**
0501: Finish marks a statement as totally unusable.
0502: */
0503: public void finish(LanguageConnectionContext lcc) {
0504:
0505: synchronized (this ) {
0506: inUseCount--;
0507:
0508: if (cacheHolder != null)
0509: return;
0510:
0511: if (inUseCount != 0) {
0512: //if (SanityManager.DEBUG) {
0513: // if (inUseCount < 0)
0514: // SanityManager.THROWASSERT("inUseCount is negative " + inUseCount + " for " + this);
0515: //}
0516: return;
0517: }
0518: }
0519:
0520: // invalidate any prepared statements that
0521: // depended on this statement (including this one)
0522: // prepareToInvalidate(this, DependencyManager.PREPARED_STATEMENT_INVALID);
0523: try {
0524: /* NOTE: Since we are non-persistent, we "know" that no exception
0525: * will be thrown under us.
0526: */
0527: makeInvalid(DependencyManager.PREPARED_STATEMENT_RELEASE,
0528: lcc);
0529: } catch (StandardException se) {
0530: if (SanityManager.DEBUG) {
0531: se.printStackTrace(System.out);
0532: SanityManager.THROWASSERT("Unexpected exception - "
0533: + se);
0534: }
0535: }
0536: }
0537:
0538: /**
0539: * Set the Execution constants. This routine is called as we Prepare the
0540: * statement.
0541: *
0542: * @param constantAction The big structure enclosing the Execution constants.
0543: */
0544: final void setConstantAction(ConstantAction constantAction) {
0545: executionConstants = constantAction;
0546: }
0547:
0548: /**
0549: * Get the Execution constants. This routine is called at Execution time.
0550: *
0551: * @return ConstantAction The big structure enclosing the Execution constants.
0552: */
0553: public final ConstantAction getConstantAction() {
0554: return executionConstants;
0555: }
0556:
0557: /**
0558: * Set the saved objects. Called when compilation completes.
0559: *
0560: * @param objects The objects to save from compilation
0561: */
0562: final void setSavedObjects(Object[] objects) {
0563: savedObjects = objects;
0564: }
0565:
0566: /**
0567: * Get the specified saved object.
0568: *
0569: * @param objectNum The object to get.
0570: * @return the requested saved object.
0571: */
0572: public final Object getSavedObject(int objectNum) {
0573: if (SanityManager.DEBUG) {
0574: if (!(objectNum >= 0 && objectNum < savedObjects.length))
0575: SanityManager
0576: .THROWASSERT("request for savedObject entry "
0577: + objectNum + " invalid; "
0578: + "savedObjects has "
0579: + savedObjects.length + " entries");
0580: }
0581: return savedObjects[objectNum];
0582: }
0583:
0584: /**
0585: * Get the saved objects.
0586: *
0587: * @return all the saved objects
0588: */
0589: public final Object[] getSavedObjects() {
0590: return savedObjects;
0591: }
0592:
0593: //
0594: // Dependent interface
0595: //
0596: /**
0597: Check that all of the dependent's dependencies are valid.
0598:
0599: @return true if the dependent is currently valid
0600: */
0601: public boolean isValid() {
0602: return isValid;
0603: }
0604:
0605: /**
0606: * set this prepared statement to be valid, currently used by
0607: * GenericTriggerExecutor.
0608: */
0609: public void setValid() {
0610: isValid = true;
0611: }
0612:
0613: /**
0614: * Indicate this prepared statement is an SPS action, currently used
0615: * by GenericTriggerExecutor.
0616: */
0617: public void setSPSAction() {
0618: spsAction = true;
0619: }
0620:
0621: /**
0622: Prepare to mark the dependent as invalid (due to at least one of
0623: its dependencies being invalid).
0624:
0625: @param action The action causing the invalidation
0626: @param p the provider
0627:
0628: @exception StandardException thrown if unable to make it invalid
0629: */
0630: public void prepareToInvalidate(Provider p, int action,
0631: LanguageConnectionContext lcc) throws StandardException {
0632:
0633: /*
0634: this statement can have other open result sets
0635: if another one is closing without any problems.
0636:
0637: It is not a problem to create an index when there is an open
0638: result set, since it doesn't invalidate the access path that was
0639: chosen for the result set.
0640: */
0641: switch (action) {
0642: case DependencyManager.CHANGED_CURSOR:
0643: case DependencyManager.CREATE_INDEX:
0644: return;
0645: }
0646:
0647: /* Verify that there are no activations with open result sets
0648: * on this prepared statement.
0649: */
0650: lcc.verifyNoOpenResultSets(this , p, action);
0651: }
0652:
0653: /**
0654: Mark the dependent as invalid (due to at least one of
0655: its dependencies being invalid).
0656:
0657: @param action The action causing the invalidation
0658:
0659: @exception StandardException Standard Cloudscape error policy.
0660: */
0661: public void makeInvalid(int action, LanguageConnectionContext lcc)
0662: throws StandardException {
0663:
0664: boolean alreadyInvalid;
0665:
0666: synchronized (this ) {
0667:
0668: if (compilingStatement)
0669: return;
0670:
0671: alreadyInvalid = !isValid;
0672:
0673: // make ourseleves invalid
0674: isValid = false;
0675:
0676: // block compiles while we are invalidating
0677: compilingStatement = true;
0678: }
0679:
0680: try {
0681:
0682: DependencyManager dm = lcc.getDataDictionary()
0683: .getDependencyManager();
0684:
0685: if (!alreadyInvalid) {
0686: dm.invalidateFor(this , action, lcc);
0687: }
0688:
0689: /* Clear out the old dependencies on this statement as we
0690: * will build the new set during the reprepare in makeValid().
0691: */
0692: dm.clearDependencies(lcc, this );
0693:
0694: /*
0695: ** If we are invalidating an EXECUTE STATEMENT because of a stale
0696: ** plan, we also need to invalidate the stored prepared statement.
0697: */
0698: if (execStmtName != null) {
0699: switch (action) {
0700: case DependencyManager.INTERNAL_RECOMPILE_REQUEST:
0701: case DependencyManager.CHANGED_CURSOR: {
0702: /*
0703: ** Get the DataDictionary, so we can get the descriptor for
0704: ** the SPP to invalidate it.
0705: */
0706: DataDictionary dd = lcc.getDataDictionary();
0707:
0708: SchemaDescriptor sd = dd.getSchemaDescriptor(
0709: execSchemaName,
0710: lcc.getTransactionCompile(), true);
0711: SPSDescriptor spsd = dd.getSPSDescriptor(
0712: execStmtName, sd);
0713: spsd.makeInvalid(action, lcc);
0714: break;
0715: }
0716: }
0717: }
0718: } finally {
0719: synchronized (this ) {
0720: compilingStatement = false;
0721: notifyAll();
0722: }
0723: }
0724: }
0725:
0726: /**
0727: Attempt to revalidate the dependent. For prepared statements,
0728: this could go through its dependencies and check that they
0729: are up to date; if not, it would recompile the statement.
0730: Any failure during this attempt should throw
0731: StandardException.unableToRevalidate().
0732:
0733: @exception StandardException thrown if unable to make it valid
0734: */
0735: public void makeValid(LanguageConnectionContext lcc)
0736: throws StandardException {
0737: PreparedStatement ps;
0738:
0739: // REMIND: will want to go through dependency list
0740: // and check if we can make it valid just on faith,
0741: // i.e. when it was marked 'possibly invalid' due
0742: // to a rollback or some similar action.
0743:
0744: // this ends up calling makeValid(qt, ac) below:
0745: ps = statement.prepare(lcc);
0746: if (SanityManager.DEBUG)
0747: SanityManager.ASSERT(ps == this , "ps != this");
0748: }
0749:
0750: /**
0751: * Is this dependent persistent? A stored dependency will be required
0752: * if both the dependent and provider are persistent.
0753: *
0754: * @return boolean Whether or not this dependent is persistent.
0755: */
0756: public boolean isPersistent() {
0757: /* Non-stored prepared statements are not persistent */
0758: return false;
0759: }
0760:
0761: //
0762: // Dependable interface
0763: //
0764:
0765: /**
0766: @return the stored form of this Dependable
0767:
0768: @see Dependable#getDependableFinder
0769: */
0770: public DependableFinder getDependableFinder() {
0771: return null;
0772: }
0773:
0774: /**
0775: * Return the name of this Dependable. (Useful for errors.)
0776: *
0777: * @return String The name of this Dependable..
0778: */
0779: public String getObjectName() {
0780: return UUIDString;
0781: }
0782:
0783: /**
0784: * Get the Dependable's UUID String.
0785: *
0786: * @return String The Dependable's UUID String.
0787: */
0788: public UUID getObjectID() {
0789: return UUIDValue;
0790: }
0791:
0792: /**
0793: * Get the Dependable's class type.
0794: *
0795: * @return String Classname that this Dependable belongs to.
0796: */
0797: public String getClassType() {
0798: return Dependable.PREPARED_STATEMENT;
0799: }
0800:
0801: /**
0802: * Return true if the query node for this statement references SESSION schema
0803: * tables/views.
0804: * This method gets called at the very beginning of the compile phase of any statement.
0805: * If the statement which needs to be compiled is already found in cache, then there is
0806: * no need to compile it again except the case when the statement is referencing SESSION
0807: * schema objects. There is a small window where such a statement might get cached
0808: * temporarily (a statement referencing SESSION schema object will be removed from the
0809: * cache after the bind phase is over because that is when we know for sure that the
0810: * statement is referencing SESSION schema objects.)
0811: *
0812: * @return true if references SESSION schema tables, else false
0813: */
0814: public boolean referencesSessionSchema() {
0815: return referencesSessionSchema;
0816: }
0817:
0818: /**
0819: * Return true if the QueryTreeNode references SESSION schema tables/views.
0820: * The return value is also saved in the local field because it will be
0821: * used by referencesSessionSchema() method.
0822: * This method gets called when the statement is not found in cache and
0823: * hence it is getting compiled.
0824: * At the beginning of compilation for any statement, first we check if
0825: * the statement's plan already exist in the cache. If not, then we add
0826: * the statement to the cache and continue with the parsing and binding.
0827: * At the end of the binding, this method gets called to see if the
0828: * QueryTreeNode references a SESSION schema object. If it does, then
0829: * we want to remove it from the cache, since any statements referencing
0830: * SESSION schema objects should never get cached.
0831: *
0832: * @return true if references SESSION schema tables/views, else false
0833: */
0834: public boolean referencesSessionSchema(QueryTreeNode qt)
0835: throws StandardException {
0836: //If the query references a SESSION schema table (temporary or permanent), then
0837: // mark so in this statement
0838: referencesSessionSchema = qt.referencesSessionSchema();
0839: return (referencesSessionSchema);
0840: }
0841:
0842: //
0843: // class interface
0844: //
0845:
0846: /**
0847: Makes the prepared statement valid, assigning
0848: values for its query tree, generated class,
0849: and associated information.
0850:
0851: @param qt the query tree for this statement
0852:
0853: @exception StandardException thrown on failure.
0854: */
0855: void completeCompile(QueryTreeNode qt) throws StandardException {
0856: //if (finished)
0857: // throw StandardException.newException(SQLState.LANG_STATEMENT_CLOSED, "completeCompile()");
0858:
0859: paramTypeDescriptors = qt.getParameterTypes();
0860:
0861: // erase cursor info in case statement text changed
0862: if (targetTable != null) {
0863: targetTable = null;
0864: updateMode = 0;
0865: updateColumns = null;
0866: targetColumns = null;
0867: }
0868:
0869: // get the result description (null for non-cursor statements)
0870: // would we want to reuse an old resultDesc?
0871: // or do we need to always replace in case this was select *?
0872: resultDesc = qt.makeResultDescription();
0873:
0874: // would look at resultDesc.getStatementType() but it
0875: // doesn't call out cursors as such, so we check
0876: // the root node type instead.
0877:
0878: if (resultDesc != null) {
0879: /*
0880: For cursors, we carry around some extra information.
0881: */
0882: CursorInfo cursorInfo = (CursorInfo) qt.getCursorInfo();
0883: if (cursorInfo != null) {
0884: targetTable = cursorInfo.targetTable;
0885: targetColumns = cursorInfo.targetColumns;
0886: updateColumns = cursorInfo.updateColumns;
0887: updateMode = cursorInfo.updateMode;
0888: }
0889: }
0890: isValid = true;
0891:
0892: return;
0893: }
0894:
0895: public GeneratedClass getActivationClass() throws StandardException {
0896: return activationClass;
0897: }
0898:
0899: void setActivationClass(GeneratedClass ac) {
0900: activationClass = ac;
0901: }
0902:
0903: //
0904: // ExecPreparedStatement
0905: //
0906:
0907: /**
0908: * the update mode of the cursor
0909: *
0910: * @return The update mode of the cursor
0911: */
0912: public int getUpdateMode() {
0913: return updateMode;
0914: }
0915:
0916: /**
0917: * the target table of the cursor
0918: *
0919: * @return target table of the cursor
0920: */
0921: public ExecCursorTableReference getTargetTable() {
0922: if (SanityManager.DEBUG) {
0923: SanityManager.ASSERT(targetTable != null,
0924: "Not a cursor, no target table");
0925: }
0926: return targetTable;
0927: }
0928:
0929: /**
0930: * the target columns of the cursor as a result column list
0931: *
0932: * @return target columns of the cursor as a result column list
0933: */
0934: public ResultColumnDescriptor[] getTargetColumns() {
0935: return targetColumns;
0936: }
0937:
0938: /**
0939: * the update columns of the cursor as a update column list
0940: *
0941: * @return update columns of the cursor as a array of strings
0942: */
0943: public String[] getUpdateColumns() {
0944: return updateColumns;
0945: }
0946:
0947: /**
0948: * Return the cursor info in a single chunk. Used
0949: * by StrorablePreparedStatement
0950: */
0951: public Object getCursorInfo() {
0952: return new CursorInfo(updateMode, targetTable, targetColumns,
0953: updateColumns);
0954: }
0955:
0956: void setCursorInfo(CursorInfo cursorInfo) {
0957: if (cursorInfo != null) {
0958: updateMode = cursorInfo.updateMode;
0959: targetTable = cursorInfo.targetTable;
0960: targetColumns = cursorInfo.targetColumns;
0961: updateColumns = cursorInfo.updateColumns;
0962: }
0963: }
0964:
0965: //
0966: // class implementation
0967: //
0968:
0969: /**
0970: * Get the byte code saver for this statement.
0971: * Overridden for StorablePreparedStatement. We
0972: * don't want to save anything
0973: *
0974: * @return a byte code saver (null for us)
0975: */
0976: ByteArray getByteCodeSaver() {
0977: return null;
0978: }
0979:
0980: /**
0981: * Does this statement need a savepoint?
0982: *
0983: * @return true if this statement needs a savepoint.
0984: */
0985: public boolean needsSavepoint() {
0986: return needsSavepoint;
0987: }
0988:
0989: /**
0990: * Set the stmts 'needsSavepoint' state. Used
0991: * by an SPS to convey whether the underlying stmt
0992: * needs a savepoint or not.
0993: *
0994: * @param needsSavepoint true if this statement needs a savepoint.
0995: */
0996: void setNeedsSavepoint(boolean needsSavepoint) {
0997: this .needsSavepoint = needsSavepoint;
0998: }
0999:
1000: /**
1001: * Set the stmts 'isAtomic' state.
1002: *
1003: * @param isAtomic true if this statement must be atomic
1004: * (i.e. it is not ok to do a commit/rollback in the middle)
1005: */
1006: void setIsAtomic(boolean isAtomic) {
1007: this .isAtomic = isAtomic;
1008: }
1009:
1010: /**
1011: * Returns whether or not this Statement requires should
1012: * behave atomically -- i.e. whether a user is permitted
1013: * to do a commit/rollback during the execution of this
1014: * statement.
1015: *
1016: * @return boolean Whether or not this Statement is atomic
1017: */
1018: public boolean isAtomic() {
1019: return isAtomic;
1020: }
1021:
1022: /**
1023: * Set the name of the statement and schema for an "execute statement"
1024: * command.
1025: */
1026: void setExecuteStatementNameAndSchema(String execStmtName,
1027: String execSchemaName) {
1028: this .execStmtName = execStmtName;
1029: this .execSchemaName = execSchemaName;
1030: }
1031:
1032: /**
1033: * Get a new prepared statement that is a shallow copy
1034: * of the current one.
1035: *
1036: * @return a new prepared statement
1037: *
1038: * @exception StandardException on error
1039: */
1040: public ExecPreparedStatement getClone() throws StandardException {
1041:
1042: GenericPreparedStatement clone = new GenericPreparedStatement(
1043: statement);
1044:
1045: clone.activationClass = getActivationClass();
1046: clone.resultDesc = resultDesc;
1047: clone.paramTypeDescriptors = paramTypeDescriptors;
1048: clone.executionConstants = executionConstants;
1049: clone.UUIDString = UUIDString;
1050: clone.UUIDValue = UUIDValue;
1051: clone.savedObjects = savedObjects;
1052: clone.execStmtName = execStmtName;
1053: clone.execSchemaName = execSchemaName;
1054: clone.isAtomic = isAtomic;
1055: clone.sourceTxt = sourceTxt;
1056: clone.targetTable = targetTable;
1057: clone.targetColumns = targetColumns;
1058: clone.updateColumns = updateColumns;
1059: clone.updateMode = updateMode;
1060: clone.needsSavepoint = needsSavepoint;
1061:
1062: return clone;
1063: }
1064:
1065: // cache holder stuff.
1066: public void setCacheHolder(Cacheable cacheHolder) {
1067:
1068: this .cacheHolder = cacheHolder;
1069:
1070: if (cacheHolder == null) {
1071:
1072: // need to invalidate the statement
1073: if (!isValid || (inUseCount != 0))
1074: return;
1075:
1076: ContextManager cm = ContextService.getFactory()
1077: .getCurrentContextManager();
1078: LanguageConnectionContext lcc = (LanguageConnectionContext) (cm
1079: .getContext(LanguageConnectionContext.CONTEXT_ID));
1080:
1081: // invalidate any prepared statements that
1082: // depended on this statement (including this one)
1083: // prepareToInvalidate(this, DependencyManager.PREPARED_STATEMENT_INVALID);
1084: try {
1085: /* NOTE: Since we are non-persistent, we "know" that no exception
1086: * will be thrown under us.
1087: */
1088: makeInvalid(
1089: DependencyManager.PREPARED_STATEMENT_RELEASE,
1090: lcc);
1091: } catch (StandardException se) {
1092: if (SanityManager.DEBUG) {
1093: se.printStackTrace(System.out);
1094: SanityManager.THROWASSERT("Unexpected exception - "
1095: + se);
1096: }
1097: }
1098: }
1099: }
1100:
1101: public String toString() {
1102: return getObjectName();
1103: }
1104:
1105: public boolean isStorable() {
1106: return false;
1107: }
1108:
1109: public void setRequiredPermissionsList(List requiredPermissionsList) {
1110: this .requiredPermissionsList = requiredPermissionsList;
1111: }
1112:
1113: public List getRequiredPermissionsList() {
1114: return requiredPermissionsList;
1115: }
1116: }
|