0001: /*
0002:
0003: Derby - Class org.apache.derby.impl.sql.execute.BaseActivation
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.execute;
0023:
0024: import org.apache.derby.iapi.services.context.ContextManager;
0025: import org.apache.derby.iapi.services.context.Context;
0026:
0027: import org.apache.derby.iapi.jdbc.ConnectionContext;
0028:
0029: import org.apache.derby.iapi.sql.Activation;
0030:
0031: import org.apache.derby.iapi.sql.execute.CursorResultSet;
0032: import org.apache.derby.iapi.sql.execute.ExecPreparedStatement;
0033: import org.apache.derby.iapi.sql.execute.CursorActivation;
0034: import org.apache.derby.iapi.sql.ResultSet;
0035: import org.apache.derby.iapi.sql.execute.ExecRow;
0036: import org.apache.derby.iapi.sql.execute.NoPutResultSet;
0037: import org.apache.derby.iapi.sql.ParameterValueSet;
0038: import org.apache.derby.iapi.sql.ResultDescription;
0039:
0040: import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
0041:
0042: import org.apache.derby.iapi.reference.SQLState;
0043: import org.apache.derby.iapi.error.StandardException;
0044:
0045: import org.apache.derby.iapi.sql.execute.ExecutionContext;
0046: import org.apache.derby.iapi.sql.execute.ExecutionFactory;
0047: import org.apache.derby.iapi.sql.execute.ResultSetFactory;
0048: import org.apache.derby.iapi.sql.execute.ConstantAction;
0049:
0050: import org.apache.derby.iapi.types.DataValueFactory;
0051: import org.apache.derby.iapi.types.DataValueDescriptor;
0052: import org.apache.derby.iapi.types.NumberDataValue;
0053: import org.apache.derby.iapi.types.RowLocation;
0054:
0055: import org.apache.derby.iapi.sql.dictionary.IndexRowGenerator;
0056: import org.apache.derby.iapi.sql.dictionary.DataDescriptorGenerator;
0057: import org.apache.derby.iapi.sql.dictionary.DataDictionaryContext;
0058: import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
0059:
0060: import org.apache.derby.iapi.sql.depend.DependencyManager;
0061:
0062: import org.apache.derby.iapi.store.access.Qualifier;
0063: import org.apache.derby.iapi.store.access.ConglomerateController;
0064: import org.apache.derby.iapi.store.access.ScanController;
0065: import org.apache.derby.iapi.store.access.TransactionController;
0066: import org.apache.derby.iapi.types.DataTypeDescriptor;
0067:
0068: import org.apache.derby.iapi.services.sanity.SanityManager;
0069:
0070: import org.apache.derby.iapi.services.context.ContextService;
0071:
0072: import org.apache.derby.iapi.services.loader.GeneratedClass;
0073: import org.apache.derby.iapi.services.loader.GeneratedByteCode;
0074: import org.apache.derby.iapi.services.loader.GeneratedMethod;
0075:
0076: import org.apache.derby.iapi.services.loader.ClassFactory;
0077: import org.apache.derby.iapi.services.monitor.Monitor;
0078:
0079: import org.apache.derby.iapi.services.property.PropertyUtil;
0080: import org.apache.derby.iapi.sql.compile.Optimizer;
0081:
0082: import org.apache.derby.iapi.reference.Property;
0083: import org.apache.derby.iapi.services.io.FormatableBitSet;
0084:
0085: import org.apache.derby.iapi.sql.execute.RunTimeStatistics;
0086:
0087: import java.sql.Connection;
0088: import java.sql.SQLException;
0089: import java.sql.SQLWarning;
0090:
0091: import java.util.ArrayList;
0092: import java.util.Enumeration;
0093: import java.util.Vector;
0094: import java.util.Hashtable;
0095: import java.util.HashSet;
0096: import org.apache.derby.iapi.util.ReuseFactory;
0097: import org.apache.derby.iapi.sql.execute.TemporaryRowHolder;
0098:
0099: /**
0100: * BaseActivation
0101: * provides the fundamental support we expect all activations to have.
0102: * Doesn't actually implement any of the activation interface,
0103: * expects the subclasses to do that.
0104: */
0105: public abstract class BaseActivation implements CursorActivation,
0106: GeneratedByteCode
0107:
0108: {
0109:
0110: protected ResultSetFactory rsFactory;
0111: protected ExecutionFactory exFactory;
0112: protected DataValueFactory dvFactory;
0113: protected LanguageConnectionContext lcc;
0114: protected ContextManager cm;
0115: protected/*private*/ExecutionContext ec;
0116:
0117: protected ExecPreparedStatement preStmt;
0118: protected ResultSet resultSet;
0119: protected ResultDescription resultDescription;
0120: protected boolean closed;
0121: private String cursorName;
0122:
0123: protected int numSubqueries;
0124:
0125: private boolean singleExecution;
0126:
0127: // This flag is declared volatile to ensure it is
0128: // visible when it has been modified by the finalizer thread.
0129: private volatile boolean inUse;
0130:
0131: private java.sql.ResultSet targetVTI;
0132: private SQLWarning warnings;
0133:
0134: private GeneratedClass gc; // my Generated class object.
0135:
0136: private boolean checkRowCounts;
0137: private HashSet rowCountsCheckedThisExecution = new HashSet(4, 0.9f);
0138:
0139: private static final long MAX_SQRT = (long) Math
0140: .sqrt(Long.MAX_VALUE);
0141:
0142: // When the row count exceeds this number, we should recompile if
0143: // the difference in row counts is greater than 10%. If it's less
0144: // than this number, we use an entirely different technique to check
0145: // for recompilation. See comments below, in informOfRowCount()
0146: private static final int TEN_PERCENT_THRESHOLD = 400;
0147:
0148: /* Performance optimization for update/delete - only
0149: * open heap ConglomerateController once when doing
0150: * index row to base row on search
0151: */
0152: private ConglomerateController updateHeapCC;
0153: private ScanController indexSC;
0154: private long indexConglomerateNumber = -1;
0155:
0156: private TableDescriptor ddlTableDescriptor;
0157:
0158: private int maxRows = -1;
0159: private boolean forCreateTable;
0160:
0161: private boolean scrollable;
0162:
0163: private boolean resultSetHoldability;
0164:
0165: //beetle 3865: updateable cursor using index. A way of communication
0166: //between cursor activation and update activation.
0167: private CursorResultSet forUpdateIndexScan;
0168:
0169: //Following three are used for JDBC3.0 auto-generated keys feature.
0170: //autoGeneratedKeysResultSetMode will be set true if at the time of statement execution,
0171: //either Statement.RETURN_GENERATED_KEYS was passed or an array of (column positions or
0172: //column names) was passed
0173: private boolean autoGeneratedKeysResultSetMode;
0174: private int[] autoGeneratedKeysColumnIndexes;
0175: private String[] autoGeneratedKeysColumnNames;
0176:
0177: //Following is the position of the session table names list in savedObjects in compiler context
0178: //This is updated to be the correct value at cursor generate time if the cursor references any session table names.
0179: //If the cursor does not reference any session table names, this will stay negative
0180: protected int indexOfSessionTableNamesInSavedObjects = -1;
0181:
0182: // WARNING: these fields are accessed by code generated in the
0183: // ExpressionClassBuilder: don't change them unless you
0184: // make the appropriate changes there.
0185: protected ExecRow[] row;
0186: protected ParameterValueSet pvs;
0187:
0188: //
0189: // constructors
0190: //
0191:
0192: protected BaseActivation() {
0193: super ();
0194: }
0195:
0196: public final void initFromContext(Context context)
0197: throws StandardException {
0198:
0199: if (SanityManager.DEBUG) {
0200: SanityManager
0201: .ASSERT(context != null,
0202: "NULL context passed to BaseActivation.initFromContext");
0203: }
0204: this .cm = context.getContextManager();
0205:
0206: lcc = (LanguageConnectionContext) cm
0207: .getContext(LanguageConnectionContext.CONTEXT_ID);
0208:
0209: if (SanityManager.DEBUG) {
0210: if (lcc == null)
0211: SanityManager
0212: .THROWASSERT("lcc is null in activation type "
0213: + getClass());
0214: }
0215:
0216: dvFactory = lcc.getDataValueFactory();
0217: if (SanityManager.DEBUG) {
0218: SanityManager.ASSERT(dvFactory != null,
0219: "No data value factory in getDataValueFactory");
0220: }
0221:
0222: ec = lcc.getExecutionContext();
0223:
0224: // look for the execution context and
0225: // get our result set factory from it.
0226: rsFactory = ec.getResultSetFactory();
0227: if (SanityManager.DEBUG) {
0228: SanityManager.ASSERT(rsFactory != null,
0229: "Unable to find ResultSetFactory");
0230: }
0231:
0232: exFactory = ec.getExecutionFactory();
0233: if (SanityManager.DEBUG) {
0234: SanityManager.ASSERT(exFactory != null,
0235: "Unable to find ExecutionFactory");
0236: }
0237:
0238: // mark in use
0239: inUse = true;
0240:
0241: // add this activation to the pool for the connection.
0242: lcc.addActivation(this );
0243: }
0244:
0245: //
0246: // Activation interface
0247: //
0248:
0249: public final ExecPreparedStatement getPreparedStatement() {
0250: return preStmt;
0251: }
0252:
0253: public ConstantAction getConstantAction() {
0254: return preStmt.getConstantAction();
0255: }
0256:
0257: public final void checkStatementValidity() throws StandardException {
0258:
0259: if (preStmt == null)
0260: return;
0261:
0262: synchronized (preStmt) {
0263:
0264: if ((gc == preStmt.getActivationClass())
0265: && preStmt.upToDate())
0266: return;
0267: }
0268:
0269: StandardException se = StandardException
0270: .newException(SQLState.LANG_STATEMENT_NEEDS_RECOMPILE);
0271: se.setReport(StandardException.REPORT_NEVER);
0272: throw se;
0273: }
0274:
0275: /**
0276: Link this activation with its PreparedStatement.
0277: It can be called with null to break the link with the
0278: PreparedStatement.
0279:
0280: */
0281: public final void setupActivation(ExecPreparedStatement ps,
0282: boolean scrollable) {
0283: preStmt = ps;
0284:
0285: if (ps != null) {
0286: // get the result set description
0287: resultDescription = ps.getResultDescription();
0288: this .scrollable = scrollable;
0289:
0290: // Initialize the parameter set to have allocated
0291: // DataValueDescriptor objects for each parameter.
0292: if (pvs != null && pvs.getParameterCount() != 0)
0293: pvs.initialize(ps.getParameterTypes());
0294:
0295: } else {
0296: resultDescription = null;
0297: this .scrollable = false;
0298: }
0299: }
0300:
0301: public ResultSet getResultSet() {
0302: return resultSet;
0303: }
0304:
0305: public void clearResultSet() {
0306: resultSet = null;
0307: }
0308:
0309: /**
0310: Get the saved RowLocation.
0311:
0312: @param itemNumber The saved item number.
0313:
0314: @return A RowLocation template for the conglomerate
0315: */
0316: public RowLocation getRowLocationTemplate(int itemNumber) {
0317: if (SanityManager.DEBUG) {
0318: SanityManager.ASSERT(itemNumber >= 0,
0319: "itemNumber expected to be >= 0");
0320: if (!(getPreparedStatement().getSavedObject(itemNumber) instanceof RowLocation)) {
0321: SanityManager
0322: .THROWASSERT("getPreparedStatement().getSavedObject(itemNumber) expected to be "
0323: + "instance of RowLocation, not "
0324: + getPreparedStatement()
0325: .getSavedObject(itemNumber)
0326: .getClass().getName()
0327: + ", query is "
0328: + getPreparedStatement().getSource());
0329: }
0330: RowLocation rl = (RowLocation) getPreparedStatement()
0331: .getSavedObject(itemNumber);
0332: if (!(rl.cloneObject() instanceof RowLocation)) {
0333: SanityManager
0334: .THROWASSERT("rl.cloneObject() expected to be "
0335: + "instance of RowLocation, not "
0336: + rl.getClass().getName()
0337: + ", query is "
0338: + getPreparedStatement().getSource());
0339: }
0340: }
0341: /* We have to return a clone of the saved RowLocation due
0342: * to the shared cache of SPSs.
0343: */
0344: return (RowLocation) ((RowLocation) (getPreparedStatement()
0345: .getSavedObject(itemNumber))).cloneObject();
0346: }
0347:
0348: /*
0349: */
0350: public ResultDescription getResultDescription() {
0351: if (SanityManager.DEBUG)
0352: SanityManager.ASSERT(resultDescription != null,
0353: "Must have a result description");
0354: return resultDescription;
0355: }
0356:
0357: /**
0358: This is a partial implementation of reset.
0359: Subclasses will want to reset information
0360: they are aware of, such as parameters.
0361: <p>
0362: All subclasses must call super.reset() and
0363: then do their cleanup.
0364: <p>
0365: The execute call must set the resultSet field
0366: to be the resultSet that it has returned.
0367:
0368: @exception StandardException on error
0369: */
0370: public void reset() throws StandardException {
0371: // if resultset holdability after commit is false, close it
0372: if (resultSet != null) {
0373: if (!resultSetHoldability || !resultSet.returnsRows()) {
0374: // would really like to check if it is open,
0375: // this is as close as we can approximate that.
0376: resultSet.close();
0377: resultSet = null; // forget about it, prepare for next exec.
0378: } else if (resultSet.returnsRows()) {
0379: resultSet.clearCurrentRow();
0380: }
0381: }
0382: updateHeapCC = null;
0383: // REMIND: do we need to get them to stop input as well?
0384:
0385: if (!isSingleExecution())
0386: clearWarnings();
0387: }
0388:
0389: /**
0390: Closing an activation marks it as unusable. Any other
0391: requests made on it will fail. An activation should be
0392: marked closed when it is expected to not be used any longer,
0393: i.e. when the connection for it is closed, or it has suffered some
0394: sort of severe error.
0395:
0396: This should also remove it from the language connection context.
0397:
0398: @exception StandardException on error
0399: */
0400: public final void close() throws StandardException {
0401: if (!closed) {
0402:
0403: // markUnused();
0404:
0405: // we finish the result set before we call reset
0406: // because reset will set it to null.
0407: if (resultSet != null) {
0408: resultSet.finish();
0409: resultSet = null;
0410: }
0411:
0412: // we call reset so that if the actual type of "this"
0413: // is a subclass of BaseActivation, its cleanup will
0414: // also happen -- reset in the actual type is called,
0415: // not reset in BaseActivation. Subclass reset's
0416: // are supposed to call super.reset() as well.
0417: reset(); // get everything related to executing released
0418:
0419: closed = true;
0420:
0421: LanguageConnectionContext lcc = getLanguageConnectionContext();
0422:
0423: lcc.removeActivation(this );
0424: if (preStmt != null) {
0425: preStmt.finish(lcc);
0426: preStmt = null;
0427: }
0428:
0429: try {
0430: closeActivationAction();
0431: } catch (Throwable e) {
0432: throw StandardException.plainWrapException(e);
0433: }
0434:
0435: }
0436:
0437: }
0438:
0439: /**
0440: A generated class can create its own closeActivationAction
0441: method to invoke special logic when the activation is closed.
0442: */
0443: protected void closeActivationAction() throws Exception {
0444: // no code to be added here as generated code
0445: // will not call super.closeActivationAction()
0446: }
0447:
0448: /**
0449: Find out if the activation closed or not.
0450: @return true if the prepared statement has been closed.
0451: */
0452: public boolean isClosed() {
0453: return closed;
0454: }
0455:
0456: /**
0457: Set this Activation for a single execution.
0458:
0459: @see Activation#setSingleExecution
0460: */
0461: public void setSingleExecution() {
0462: singleExecution = true;
0463: }
0464:
0465: /**
0466: Returns true if this Activation is only going to be used for
0467: one execution.
0468:
0469: @see Activation#isSingleExecution
0470: */
0471: public boolean isSingleExecution() {
0472: return singleExecution;
0473: }
0474:
0475: /**
0476: Get the number of subqueries in the entire query.
0477: @return int The number of subqueries in the entire query.
0478: */
0479: public int getNumSubqueries() {
0480: return numSubqueries;
0481: }
0482:
0483: /**
0484: * @see Activation#isCursorActivation
0485: */
0486: public boolean isCursorActivation() {
0487: return false;
0488: }
0489:
0490: //
0491: // GeneratedByteCode interface
0492: //
0493:
0494: public final void setGC(GeneratedClass gc) {
0495: this .gc = gc;
0496: }
0497:
0498: public final GeneratedClass getGC() {
0499:
0500: if (SanityManager.DEBUG) {
0501: if (gc == null)
0502: SanityManager
0503: .THROWASSERT("move code requiring GC to postConstructor() method!!");
0504: }
0505: return gc;
0506: }
0507:
0508: public final GeneratedMethod getMethod(String methodName)
0509: throws StandardException {
0510:
0511: return getGC().getMethod(methodName);
0512: }
0513:
0514: public Object e0() throws StandardException {
0515: return null;
0516: }
0517:
0518: public Object e1() throws StandardException {
0519: return null;
0520: }
0521:
0522: public Object e2() throws StandardException {
0523: return null;
0524: }
0525:
0526: public Object e3() throws StandardException {
0527: return null;
0528: }
0529:
0530: public Object e4() throws StandardException {
0531: return null;
0532: }
0533:
0534: public Object e5() throws StandardException {
0535: return null;
0536: }
0537:
0538: public Object e6() throws StandardException {
0539: return null;
0540: }
0541:
0542: public Object e7() throws StandardException {
0543: return null;
0544: }
0545:
0546: public Object e8() throws StandardException {
0547: return null;
0548: }
0549:
0550: public Object e9() throws StandardException {
0551: return null;
0552: }
0553:
0554: //
0555: // class interface
0556: //
0557:
0558: /**
0559: * Temporary tables can be declared with ON COMMIT DELETE ROWS. But if the table has a held curosr open at
0560: * commit time, data should not be deleted from the table. This method, (gets called at commit time) checks if this
0561: * activation held cursor and if so, does that cursor reference the passed temp table name.
0562: *
0563: * @return true if this activation has held cursor and if it references the passed temp table name
0564: */
0565: public boolean checkIfThisActivationHasHoldCursor(String tableName) {
0566: if (!inUse)
0567: return false;
0568:
0569: if (resultSetHoldability == false) //if this activation is not held over commit, do not need to worry about it
0570: return false;
0571:
0572: if (indexOfSessionTableNamesInSavedObjects == -1) //if this activation does not refer to session schema tables, do not need to worry about it
0573: return false;
0574:
0575: /* is there an open result set? */
0576: if ((resultSet != null) && !resultSet.isClosed()
0577: && resultSet.returnsRows()) {
0578: //If we came here, it means this activation is held over commit and it reference session table names
0579: //Now let's check if it referneces the passed temporary table name which has ON COMMIT DELETE ROWS defined on it.
0580: return ((ArrayList) getPreparedStatement().getSavedObject(
0581: indexOfSessionTableNamesInSavedObjects))
0582: .contains(tableName);
0583: }
0584:
0585: return false;
0586: }
0587:
0588: /**
0589: remember the cursor name
0590: */
0591:
0592: public void setCursorName(String cursorName) {
0593: if (isCursorActivation())
0594: this .cursorName = cursorName;
0595: }
0596:
0597: /**
0598: get the cursor name. For something that isn't
0599: a cursor, this is used as a string name of the
0600: result set for messages from things like the
0601: dependency manager.
0602: <p>
0603: Activations that do support cursors will override
0604: this.
0605: */
0606: public String getCursorName() {
0607:
0608: return isCursorActivation() ? cursorName : null;
0609: }
0610:
0611: public void setResultSetHoldability(boolean resultSetHoldability) {
0612: this .resultSetHoldability = resultSetHoldability;
0613: }
0614:
0615: public boolean getResultSetHoldability() {
0616: return resultSetHoldability;
0617: }
0618:
0619: /** @see Activation#setAutoGeneratedKeysResultsetInfo */
0620: public void setAutoGeneratedKeysResultsetInfo(int[] columnIndexes,
0621: String[] columnNames) {
0622: autoGeneratedKeysResultSetMode = true;
0623: autoGeneratedKeysColumnIndexes = columnIndexes;
0624: autoGeneratedKeysColumnNames = columnNames;
0625: }
0626:
0627: /** @see Activation#getAutoGeneratedKeysResultsetMode */
0628: public boolean getAutoGeneratedKeysResultsetMode() {
0629: return autoGeneratedKeysResultSetMode;
0630: }
0631:
0632: /** @see Activation#getAutoGeneratedKeysColumnIndexes */
0633: public int[] getAutoGeneratedKeysColumnIndexes() {
0634: return autoGeneratedKeysColumnIndexes;
0635: }
0636:
0637: /** @see Activation#getAutoGeneratedKeysColumnNames */
0638: public String[] getAutoGeneratedKeysColumnNames() {
0639: return autoGeneratedKeysColumnNames;
0640: }
0641:
0642: //
0643: // class implementation
0644: //
0645:
0646: /**
0647: Used in the execute method of activations for
0648: generating the result sets that they concatenate together.
0649: */
0650: public ResultSetFactory getResultSetFactory() {
0651: return rsFactory;
0652: }
0653:
0654: /**
0655: Used in activations for generating rows.
0656: */
0657: public ExecutionFactory getExecutionFactory() {
0658: return exFactory;
0659: }
0660:
0661: /**
0662: Used in CurrentOfResultSet to get to the target result set
0663: for a cursor. Overridden by activations generated for
0664: updatable cursors. Those activations capture the target
0665: result set in a field in their execute() method, and then
0666: return the value of that field in their version of this method.
0667:
0668: @return null.
0669: */
0670: public CursorResultSet getTargetResultSet() {
0671: if (SanityManager.DEBUG)
0672: SanityManager.THROWASSERT("Must be overridden to be used.");
0673: return null;
0674: }
0675:
0676: /*
0677: * Called by generated code to compute the next autoincrement value.
0678: *
0679: * @return The next autoincrement value which should be inserted.
0680: * returns the correct number datatype.
0681: */
0682: protected DataValueDescriptor getSetAutoincrementValue(
0683: int columnPosition, long increment)
0684: throws StandardException {
0685: DataValueDescriptor l = ((InsertResultSet) resultSet)
0686: .getSetAutoincrementValue(columnPosition, increment);
0687: return l;
0688:
0689: }
0690:
0691: /**
0692: Used in CurrentOfResultSet to get to the cursor result set
0693: for a cursor. Overridden by activations generated for
0694: updatable cursors. Those activations capture the cursor
0695: result set in a field in their execute() method, and then
0696: return the value of that field in their version of this method.
0697:
0698: @return null
0699: */
0700: public CursorResultSet getCursorResultSet() {
0701: if (SanityManager.DEBUG)
0702: SanityManager.THROWASSERT("Must be overridden to be used.");
0703: return null;
0704: }
0705:
0706: /**
0707: Various activation methods need to disallow their
0708: invocation if the activation is closed. This lets them
0709: check and throw without generating alot of code.
0710: <p>
0711: The code to write to generate the call to this is approximately:
0712: <verbatim>
0713: // jf is a JavaFactory
0714: CallableExpression ce = jf.newMethodCall(
0715: jf.thisExpression(),
0716: BaseActivation.CLASS_NAME,
0717: "throwIfClosed",
0718: "void",
0719: acb.exprArray(jf.newStringLiteral(...some literal here...)));
0720:
0721: //mb is a MethodBuilder
0722: mb.addStatement(jf.newStatement(ce));
0723: </verbatim>
0724: The java code to write to call this is:
0725: <verbatim>
0726: this.throwIfClosed(...some literal here...);
0727: </verbatim>
0728: In both cases, "...some literal here..." gets replaced with
0729: an expression of type String that evaluates to the name
0730: of the operation that is being checked, like "execute" or
0731: "reset".
0732:
0733: @exception StandardException thrown if closed
0734: */
0735: public void throwIfClosed(String op) throws StandardException {
0736: if (closed)
0737: throw StandardException.newException(
0738: SQLState.LANG_ACTIVATION_CLOSED, op);
0739: }
0740:
0741: /**
0742: * Set a column position in an array of column positions.
0743: *
0744: * @param columnPositions The array of column positions
0745: * @param positionToSet The place to put the column position
0746: * @param column The column position
0747: */
0748: public static void setColumnPosition(int[] columnPositions,
0749: int positionToSet, int column) {
0750: columnPositions[positionToSet] = column;
0751: }
0752:
0753: /**
0754: * Allocate an array of qualifiers and initialize in Qualifier[][]
0755: *
0756: * @param qualifiers The array of Qualifier arrays.
0757: * @param position The position in the array to set
0758: * @param length The array length of the qualifier array to allocate.
0759: */
0760: public static void allocateQualArray(Qualifier[][] qualifiers,
0761: int position, int length) {
0762: qualifiers[position] = new Qualifier[length];
0763: }
0764:
0765: /**
0766: * Set a Qualifier in a 2 dimensional array of Qualifiers.
0767: *
0768: * Set a single Qualifier into one slot of a 2 dimensional array of
0769: * Qualifiers. @see Qualifier for detailed description of layout of
0770: * the 2-d array.
0771: *
0772: * @param qualifiers The array of Qualifiers
0773: * @param qualifier The Qualifier
0774: * @param position_1 The Nth array index into qualifiers[N][M]
0775: * @param position_2 The Nth array index into qualifiers[N][M]
0776: */
0777: public static void setQualifier(Qualifier[][] qualifiers,
0778: Qualifier qualifier, int position_1, int position_2) {
0779: qualifiers[position_1][position_2] = qualifier;
0780: }
0781:
0782: /**
0783: * Reinitialize all Qualifiers in an array of Qualifiers.
0784: *
0785: * @param qualifiers The array of Qualifiers
0786: */
0787: public static void reinitializeQualifiers(Qualifier[][] qualifiers) {
0788: if (qualifiers != null) {
0789: for (int term = 0; term < qualifiers.length; term++) {
0790: for (int i = 0; i < qualifiers[term].length; i++) {
0791: qualifiers[term][i].reinitialize();
0792: }
0793: }
0794: }
0795: }
0796:
0797: /**
0798: * Mark the activation as unused.
0799: */
0800: public final void markUnused() {
0801: if (isInUse()) {
0802: inUse = false;
0803: lcc.notifyUnusedActivation();
0804: }
0805: }
0806:
0807: /**
0808: * Is the activation in use?
0809: *
0810: * @return true/false
0811: */
0812: public final boolean isInUse() {
0813: return inUse;
0814: }
0815:
0816: /**
0817: @see org.apache.derby.iapi.sql.Activation#addWarning
0818: */
0819: public void addWarning(SQLWarning w) {
0820: if (warnings == null)
0821: warnings = w;
0822: else
0823: warnings.setNextWarning(w);
0824: }
0825:
0826: /**
0827: @see org.apache.derby.iapi.sql.Activation#getWarnings
0828: */
0829: public SQLWarning getWarnings() {
0830: return warnings;
0831: }
0832:
0833: /**
0834: @see org.apache.derby.iapi.sql.Activation#clearWarnings
0835: */
0836: public void clearWarnings() {
0837: warnings = null;
0838: }
0839:
0840: /**
0841: * @exception StandardException on error
0842: */
0843: protected static void nullToPrimitiveTest(DataValueDescriptor dvd,
0844: String primitiveType) throws StandardException {
0845: if (dvd.isNull()) {
0846: throw StandardException.newException(
0847: SQLState.LANG_NULL_TO_PRIMITIVE_PARAMETER,
0848: primitiveType);
0849: }
0850: }
0851:
0852: /**
0853: @see Activation#informOfRowCount
0854: @exception StandardException Thrown on error
0855: */
0856: public void informOfRowCount(NoPutResultSet resultSet,
0857: long currentRowCount) throws StandardException {
0858:
0859: /* Do we want to check the row counts during this execution? */
0860: if (checkRowCounts) {
0861: boolean significantChange = false;
0862:
0863: int resultSetNumber = resultSet.resultSetNumber();
0864: Integer rsn = ReuseFactory.getInteger(resultSetNumber);
0865:
0866: /* Check each result set only once per execution */
0867: if (rowCountsCheckedThisExecution.add(rsn)) {
0868: synchronized (getPreparedStatement()) {
0869: Vector rowCountCheckVector = getRowCountCheckVector();
0870:
0871: if (rowCountCheckVector == null) {
0872: rowCountCheckVector = new Vector();
0873: setRowCountCheckVector(rowCountCheckVector);
0874: }
0875:
0876: Long firstRowCount = null;
0877:
0878: /*
0879: ** Check whether this resultSet has been seen yet.
0880: */
0881: if (resultSetNumber < rowCountCheckVector.size()) {
0882: firstRowCount = (Long) rowCountCheckVector
0883: .elementAt(resultSetNumber);
0884: } else {
0885: rowCountCheckVector
0886: .setSize(resultSetNumber + 1);
0887: }
0888:
0889: if (firstRowCount != null) {
0890: /*
0891: ** This ResultSet has been seen - has the row count
0892: ** changed significantly?
0893: */
0894: long n1 = firstRowCount.longValue();
0895:
0896: if (currentRowCount != n1) {
0897: if (n1 >= TEN_PERCENT_THRESHOLD) {
0898: /*
0899: ** For tables with more than
0900: ** TEN_PERCENT_THRESHOLD rows, the
0901: ** threshold is 10% of the size of the table.
0902: */
0903: long changeFactor = n1
0904: / (currentRowCount - n1);
0905: if (Math.abs(changeFactor) <= 10)
0906: significantChange = true;
0907: } else {
0908: /*
0909: ** For tables with less than
0910: ** TEN_PERCENT_THRESHOLD rows, the threshold
0911: ** is non-linear. This is because we want
0912: ** recompilation to happen sooner for small
0913: ** tables that change size. This formula
0914: ** is for a second-order equation (a parabola).
0915: ** The derivation is:
0916: **
0917: ** c * n1 = (difference in row counts) ** 2
0918: ** - or -
0919: ** c * n1 = (currentRowCount - n1) ** 2
0920: **
0921: ** Solving this for currentRowCount, we get:
0922: **
0923: ** currentRowCount = n1 + sqrt(c * n1)
0924: **
0925: ** - or -
0926: **
0927: ** difference in row counts = sqrt(c * n1)
0928: **
0929: ** - or -
0930: **
0931: ** (difference in row counts) ** 2 =
0932: ** c * n1
0933: **
0934: ** Which means that we should recompile when
0935: ** the current row count exceeds n1 (the first
0936: ** row count) by sqrt(c * n1), or when the
0937: ** square of the difference exceeds c * n1.
0938: ** A good value for c seems to be 4.
0939: **
0940: ** We don't use this formula when c is greater
0941: ** than TEN_PERCENT_THRESHOLD because we never
0942: ** want to recompile unless the number of rows
0943: ** changes by more than 10%, and this formula
0944: ** is more sensitive than that for values of
0945: ** n1 greater than TEN_PERCENT_THRESHOLD.
0946: */
0947: long changediff = currentRowCount - n1;
0948:
0949: /*
0950: ** Square changediff rather than take the square
0951: ** root of (4 * n1), because multiplying is
0952: ** faster than taking a square root. Also,
0953: ** check to be sure that squaring changediff
0954: ** will not cause an overflow by comparing it
0955: ** with the square root of the maximum value
0956: ** for a long (this square root is taken only
0957: ** once, when the class is loaded, or during
0958: ** compilation if the compiler is smart enough).
0959: */
0960: if (Math.abs(changediff) <= MAX_SQRT) {
0961: if ((changediff * changediff) > Math
0962: .abs(4 * n1)) {
0963: significantChange = true;
0964: }
0965: }
0966: }
0967: }
0968: } else {
0969: firstRowCount = new Long(currentRowCount);
0970: rowCountCheckVector.setElementAt(firstRowCount,
0971: resultSetNumber);
0972:
0973: }
0974: }
0975: }
0976:
0977: /* Invalidate outside of the critical section */
0978: if (significantChange) {
0979: preStmt.makeInvalid(
0980: DependencyManager.INTERNAL_RECOMPILE_REQUEST,
0981: lcc);
0982: }
0983: }
0984:
0985: }
0986:
0987: /**
0988: * The subclass calls this method when it begins an execution.
0989: *
0990: * @exception StandardException Thrown on error
0991: */
0992: public void startExecution() throws StandardException {
0993: // determine if we should check row counts during this execution
0994: shouldWeCheckRowCounts();
0995:
0996: // If we are to check row counts, clear the hash table of row counts
0997: // we have checked.
0998: if (checkRowCounts)
0999: rowCountsCheckedThisExecution.clear();
1000: }
1001:
1002: /**
1003: * @see Activation#getHeapConglomerateController
1004: */
1005: public ConglomerateController getHeapConglomerateController() {
1006: return updateHeapCC;
1007: }
1008:
1009: /**
1010: * @see Activation#setHeapConglomerateController
1011: */
1012: public void setHeapConglomerateController(
1013: ConglomerateController updateHeapCC) {
1014: this .updateHeapCC = updateHeapCC;
1015: }
1016:
1017: /**
1018: * @see Activation#clearHeapConglomerateController
1019: */
1020: public void clearHeapConglomerateController() {
1021: updateHeapCC = null;
1022: }
1023:
1024: /**
1025: * @see Activation#getIndexScanController
1026: */
1027: public ScanController getIndexScanController() {
1028: return indexSC;
1029: }
1030:
1031: /**
1032: * @see Activation#setIndexScanController
1033: */
1034: public void setIndexScanController(ScanController indexSC) {
1035: this .indexSC = indexSC;
1036: }
1037:
1038: /**
1039: * @see Activation#getIndexConglomerateNumber
1040: */
1041: public long getIndexConglomerateNumber() {
1042: return indexConglomerateNumber;
1043: }
1044:
1045: /**
1046: * @see Activation#setIndexConglomerateNumber
1047: */
1048: public void setIndexConglomerateNumber(long indexConglomerateNumber) {
1049: this .indexConglomerateNumber = indexConglomerateNumber;
1050: }
1051:
1052: /**
1053: * @see Activation#clearIndexScanInfo
1054: */
1055: public void clearIndexScanInfo() {
1056: indexSC = null;
1057: indexConglomerateNumber = -1;
1058: }
1059:
1060: /**
1061: * @see Activation#setForCreateTable()
1062: */
1063: public void setForCreateTable() {
1064: forCreateTable = true;
1065: }
1066:
1067: /**
1068: * @see Activation#getForCreateTable()
1069: */
1070: public boolean getForCreateTable() {
1071: return forCreateTable;
1072: }
1073:
1074: /**
1075: * @see Activation#setDDLTableDescriptor
1076: */
1077: public void setDDLTableDescriptor(TableDescriptor td) {
1078: ddlTableDescriptor = td;
1079: }
1080:
1081: /**
1082: * @see Activation#getDDLTableDescriptor
1083: */
1084: public TableDescriptor getDDLTableDescriptor() {
1085: return ddlTableDescriptor;
1086: }
1087:
1088: /**
1089: * @see Activation#setMaxRows
1090: */
1091: public void setMaxRows(int maxRows) {
1092: this .maxRows = maxRows;
1093: }
1094:
1095: /**
1096: * @see Activation#getMaxRows
1097: */
1098: public int getMaxRows() {
1099: return maxRows;
1100: }
1101:
1102: public void setTargetVTI(java.sql.ResultSet targetVTI) {
1103: this .targetVTI = targetVTI;
1104: }
1105:
1106: public java.sql.ResultSet getTargetVTI() {
1107: return targetVTI;
1108: }
1109:
1110: private void shouldWeCheckRowCounts() throws StandardException {
1111: /*
1112: ** Check the row count only every N executions. OK to check this
1113: ** without synchronization, since the value of this number is not
1114: ** critical. The value of N is determined by the property
1115: ** derby.language.stalePlanCheckInterval.
1116: */
1117: int executionCount = getExecutionCount() + 1;
1118:
1119: /*
1120: ** Always check row counts the first time, to establish the
1121: ** row counts for each result set. After that, don't check
1122: ** if the execution count is below the minimum row count check
1123: ** interval. This saves us from checking a database property
1124: ** when we don't have to (checking involves querying the store,
1125: ** which can be expensive).
1126: */
1127:
1128: if (executionCount == 1) {
1129: checkRowCounts = true;
1130: } else if (executionCount < Property.MIN_LANGUAGE_STALE_PLAN_CHECK_INTERVAL) {
1131: checkRowCounts = false;
1132: } else {
1133: int stalePlanCheckInterval = getStalePlanCheckInterval();
1134:
1135: /*
1136: ** Only query the database property once. We can tell because
1137: ** the minimum value of the property is greater than zero.
1138: */
1139: if (stalePlanCheckInterval == 0) {
1140: TransactionController tc = getTransactionController();
1141:
1142: stalePlanCheckInterval = PropertyUtil
1143: .getServiceInt(
1144: tc,
1145: Property.LANGUAGE_STALE_PLAN_CHECK_INTERVAL,
1146: Property.MIN_LANGUAGE_STALE_PLAN_CHECK_INTERVAL,
1147: Integer.MAX_VALUE,
1148: Property.DEFAULT_LANGUAGE_STALE_PLAN_CHECK_INTERVAL);
1149: setStalePlanCheckInterval(stalePlanCheckInterval);
1150: }
1151:
1152: checkRowCounts = (executionCount % stalePlanCheckInterval) == 1;
1153:
1154: }
1155:
1156: setExecutionCount(executionCount);
1157: }
1158:
1159: /*
1160: ** These accessor methods are provided by the sub-class to help figure
1161: ** out whether to check row counts during this execution.
1162: */
1163: abstract protected int getExecutionCount();
1164:
1165: abstract protected void setExecutionCount(int newValue);
1166:
1167: /*
1168: ** These accessor methods are provided by the sub-class to help figure
1169: ** out whether the row count for a particular result set has changed
1170: ** enough to force recompilation.
1171: */
1172: abstract protected Vector getRowCountCheckVector();
1173:
1174: abstract protected void setRowCountCheckVector(Vector newValue);
1175:
1176: /*
1177: ** These accessor methods are provided by the sub-class to remember the
1178: ** value of the stale plan check interval property, so that we only
1179: ** have to query the database properties once (there is heavyweight
1180: ** synchronization around the database properties).
1181: */
1182: abstract protected int getStalePlanCheckInterval();
1183:
1184: abstract protected void setStalePlanCheckInterval(int newValue);
1185:
1186: public final boolean getScrollable() {
1187: return scrollable;
1188: }
1189:
1190: protected final void setParameterValueSet(int paramCount,
1191: boolean hasReturnParam) {
1192:
1193: pvs = lcc.getLanguageFactory().newParameterValueSet(
1194: lcc.getLanguageConnectionFactory().getClassFactory()
1195: .getClassInspector(), paramCount,
1196: hasReturnParam);
1197: }
1198:
1199: /**
1200: * This method can help reduce the amount of generated code by changing
1201: * instances of this.pvs.getParameter(position) to this.getParameter(position)
1202: * @param position
1203: * @throws StandardException
1204: */
1205: protected final DataValueDescriptor getParameter(int position)
1206: throws StandardException {
1207: return pvs.getParameter(position);
1208: }
1209:
1210: /**
1211: return the parameters.
1212: */
1213: public ParameterValueSet getParameterValueSet() {
1214: if (pvs == null)
1215: setParameterValueSet(0, false);
1216: return pvs;
1217: }
1218:
1219: // how do we do/do we want any sanity checking for
1220: // the number of parameters expected?
1221: public void setParameters(ParameterValueSet parameterValues,
1222: DataTypeDescriptor[] parameterTypes)
1223: throws StandardException {
1224: if (!isClosed()) {
1225:
1226: if (this .pvs == null || parameterTypes == null) {
1227: pvs = parameterValues;
1228: return;
1229:
1230: }
1231:
1232: DataTypeDescriptor[] newParamTypes = preStmt
1233: .getParameterTypes();
1234:
1235: /*
1236: ** If there are old parameters but not new ones,
1237: ** they aren't compatible.
1238: */
1239: boolean match = false;
1240: if (newParamTypes != null) {
1241:
1242: if (newParamTypes.length == parameterTypes.length) {
1243:
1244: /* Check each parameter */
1245: match = true;
1246: for (int i = 0; i < parameterTypes.length; i++) {
1247: DataTypeDescriptor oldType = parameterTypes[i];
1248: DataTypeDescriptor newType = newParamTypes[i];
1249:
1250: if (!oldType.isExactTypeAndLengthMatch(newType)) {
1251: match = false;
1252: break;
1253: }
1254: /*
1255: ** We could probably get away without checking nullability,
1256: ** since parameters are always nullable.
1257: */
1258: if (oldType.isNullable() != newType
1259: .isNullable()) {
1260: match = false;
1261: break;
1262: }
1263: }
1264: }
1265:
1266: }
1267:
1268: if (!match)
1269: throw StandardException
1270: .newException(SQLState.LANG_OBSOLETE_PARAMETERS);
1271:
1272: parameterValues.transferDataValues(pvs);
1273:
1274: } else if (SanityManager.DEBUG) {
1275: SanityManager
1276: .THROWASSERT("isClosed() is expected to return false");
1277: }
1278: }
1279:
1280: /**
1281: Throw an exception if any parameters are uninitialized.
1282:
1283: @exception StandardException Thrown if any parameters
1284: are unitialized
1285: */
1286:
1287: public void throwIfMissingParms() throws StandardException {
1288: if (pvs != null && !pvs.allAreSet()) {
1289: throw StandardException
1290: .newException(SQLState.LANG_MISSING_PARMS);
1291: }
1292: }
1293:
1294: /**
1295: * Remember the row for the specified ResultSet.
1296: */
1297: public void setCurrentRow(ExecRow currentRow, int resultSetNumber) {
1298: if (SanityManager.DEBUG) {
1299: SanityManager.ASSERT(!isClosed(), "closed");
1300: if (row != null) {
1301: if (!(resultSetNumber >= 0 && resultSetNumber < row.length)) {
1302: SanityManager.THROWASSERT("resultSetNumber = "
1303: + resultSetNumber
1304: + ", expected to be between 0 and "
1305: + row.length);
1306: }
1307: }
1308: }
1309: if (row != null) {
1310: row[resultSetNumber] = currentRow;
1311: }
1312: }
1313:
1314: /**
1315: * Clear the current row for the specified ResultSet.
1316: */
1317: public void clearCurrentRow(int resultSetNumber) {
1318: if (SanityManager.DEBUG) {
1319: if (row != null) {
1320: if (!(resultSetNumber >= 0 && resultSetNumber < row.length)) {
1321: SanityManager.THROWASSERT("resultSetNumber = "
1322: + resultSetNumber
1323: + ", expected to be between 0 and "
1324: + row.length);
1325: }
1326: }
1327: }
1328: if (row != null) {
1329: row[resultSetNumber] = null;
1330: }
1331: }
1332:
1333: protected final DataValueDescriptor getColumnFromRow(int rsNumber,
1334: int colId) throws StandardException {
1335:
1336: if (row[rsNumber] == null) {
1337: /* This actually happens. NoPutResultSetImpl.clearOrderableCache attempts to prefetch invariant values
1338: * into a cache. This fails in some deeply nested joins. See Beetle 4736 and 4880.
1339: */
1340: return null;
1341: }
1342: return row[rsNumber].getColumn(colId);
1343: }
1344:
1345: protected void checkPositionedStatement(String cursorName,
1346: String psName) throws StandardException {
1347:
1348: ExecPreparedStatement ps = getPreparedStatement();
1349: if (ps == null)
1350: return;
1351:
1352: LanguageConnectionContext lcc = getLanguageConnectionContext();
1353:
1354: CursorActivation cursorActivation = lcc
1355: .lookupCursorActivation(cursorName);
1356:
1357: if (cursorActivation != null) {
1358: // check we are compiled against the correct cursor
1359: if (!psName.equals(cursorActivation.getPreparedStatement()
1360: .getObjectName())) {
1361:
1362: // our prepared statement is now invalid since there
1363: // exists another cursor with the same name but a different
1364: // statement.
1365: ps.makeInvalid(DependencyManager.CHANGED_CURSOR, lcc);
1366: }
1367: }
1368: }
1369:
1370: /* This method is used to materialize a resultset if can actually fit in the memory
1371: * specified by "maxMemoryPerTable" system property. It converts the result set into
1372: * union(union(union...(union(row, row), row), ...row), row). It returns this
1373: * in-memory converted resultset, or the original result set if not converted.
1374: * See beetle 4373 for details.
1375: *
1376: * Optimization implemented as part of Beetle: 4373 can cause severe stack overflow
1377: * problems. See JIRA entry DERBY-634. With default MAX_MEMORY_PER_TABLE of 1MG, it is
1378: * possible that this optimization could attempt to cache upto 250K rows as nested
1379: * union results. At runtime, this would cause stack overflow.
1380: *
1381: * As Jeff mentioned in DERBY-634, right way to optimize original problem would have been
1382: * to address subquery materialization during optimization phase, through hash joins.
1383: * Recent Army's optimizer work through DEBRY-781 and related work introduced a way to
1384: * materialize subquery results correctly and needs to be extended to cover this case.
1385: * While his optimization needs to be made more generic and stable, I propose to avoid
1386: * this regression by limiting size of the materialized resultset created here to be
1387: * less than MAX_MEMORY_PER_TABLE and MAX_DYNAMIC_MATERIALIZED_ROWS.
1388: *
1389: * @param rs input result set
1390: * @return materialized resultset, or original rs if it can't be materialized
1391: */
1392: public NoPutResultSet materializeResultSetIfPossible(
1393: NoPutResultSet rs) throws StandardException {
1394: rs.openCore();
1395: Vector rowCache = new Vector();
1396: ExecRow aRow;
1397: int cacheSize = 0;
1398: FormatableBitSet toClone = null;
1399:
1400: int maxMemoryPerTable = getLanguageConnectionContext()
1401: .getOptimizerFactory().getMaxMemoryPerTable();
1402:
1403: aRow = rs.getNextRowCore();
1404: if (aRow != null) {
1405: toClone = new FormatableBitSet(aRow.nColumns() + 1);
1406: toClone.set(1);
1407: }
1408: while (aRow != null) {
1409: cacheSize += aRow.getColumn(1).getLength();
1410: if (cacheSize > maxMemoryPerTable
1411: || rowCache.size() > Optimizer.MAX_DYNAMIC_MATERIALIZED_ROWS)
1412: break;
1413: rowCache.addElement(aRow.getClone(toClone));
1414: aRow = rs.getNextRowCore();
1415: }
1416: rs.close();
1417:
1418: if (aRow == null) {
1419: int rsNum = rs.resultSetNumber();
1420:
1421: int numRows = rowCache.size();
1422: if (numRows == 0) {
1423: return new RowResultSet(this , (ExecRow) null, true,
1424: rsNum, 0, 0);
1425: }
1426: RowResultSet[] rrs = new RowResultSet[numRows];
1427: UnionResultSet[] urs = new UnionResultSet[numRows - 1];
1428:
1429: for (int i = 0; i < numRows; i++) {
1430: rrs[i] = new RowResultSet(this , (ExecRow) rowCache
1431: .elementAt(i), true, rsNum, 1, 0);
1432: if (i > 0) {
1433: urs[i - 1] = new UnionResultSet(
1434: (i > 1) ? (NoPutResultSet) urs[i - 2]
1435: : (NoPutResultSet) rrs[0], rrs[i],
1436: this , rsNum, i + 1, 0);
1437: }
1438: }
1439:
1440: rs.finish();
1441:
1442: if (numRows == 1)
1443: return rrs[0];
1444: else
1445: return urs[urs.length - 1];
1446: }
1447: return rs;
1448: }
1449:
1450: //WARNING : this field name is referred in the DeleteNode generate routines.
1451: protected CursorResultSet[] raParentResultSets;
1452:
1453: // maintain hash table of parent result set vector
1454: // a table can have more than one parent source.
1455: protected Hashtable parentResultSets;
1456:
1457: public void setParentResultSet(TemporaryRowHolder rs,
1458: String resultSetId) {
1459: Vector rsVector;
1460: if (parentResultSets == null)
1461: parentResultSets = new Hashtable();
1462: rsVector = (Vector) parentResultSets.get(resultSetId);
1463: if (rsVector == null) {
1464: rsVector = new Vector();
1465: rsVector.addElement(rs);
1466: } else {
1467: rsVector.addElement(rs);
1468: }
1469: parentResultSets.put(resultSetId, rsVector);
1470: }
1471:
1472: /**
1473: * get the reference to parent table ResultSets, that will be needed by the
1474: * referential action dependent table scans.
1475: */
1476: public Vector getParentResultSet(String resultSetId) {
1477: return (Vector) parentResultSets.get(resultSetId);
1478: }
1479:
1480: public Hashtable getParentResultSets() {
1481: return parentResultSets;
1482: }
1483:
1484: /**
1485: ** prepared statement use the same activation for
1486: ** multiple execution. For each excution we create new
1487: ** set of temporary resultsets, we should clear this hash table.
1488: ** otherwise we will refer to the released resources.
1489: */
1490: public void clearParentResultSets() {
1491: if (parentResultSets != null)
1492: parentResultSets.clear();
1493: }
1494:
1495: /**
1496: * beetle 3865: updateable cursor using index. A way of communication
1497: * between cursor activation and update activation.
1498: */
1499: public void setForUpdateIndexScan(CursorResultSet forUpdateIndexScan) {
1500: this .forUpdateIndexScan = forUpdateIndexScan;
1501: }
1502:
1503: public CursorResultSet getForUpdateIndexScan() {
1504: return forUpdateIndexScan;
1505: }
1506:
1507: private java.util.Calendar cal;
1508:
1509: /**
1510: Return a calendar for use by this activation.
1511: Calendar objects are not thread safe, the one returned
1512: is purely for use by this activation and it is assumed
1513: that is it single threded through the single active
1514: thread in a connection model.
1515: */
1516: protected java.util.Calendar getCalendar() {
1517: if (cal == null)
1518: cal = new java.util.GregorianCalendar();
1519: return cal;
1520:
1521: }
1522:
1523: /*
1524: ** Code originally in the parent class BaseExpressionActivation
1525: */
1526: /**
1527: Get the language connection factory associated with this connection
1528: */
1529: public final LanguageConnectionContext getLanguageConnectionContext() {
1530: return lcc;
1531: }
1532:
1533: public final TransactionController getTransactionController() {
1534: return lcc.getTransactionExecute();
1535: }
1536:
1537: /**
1538: * Get the ExecutionContext.
1539: */
1540: ExecutionContext getExecutionContext() {
1541: return ec;
1542: }
1543:
1544: /**
1545: * Get the Current ContextManager.
1546: *
1547: * @return Current ContextManager
1548: */
1549: public ContextManager getContextManager() {
1550: return cm;
1551: }
1552:
1553: /**
1554: Used by activations to generate data values. Most DML statements
1555: will use this method. Possibly some DDL statements will, as well.
1556: */
1557: public DataValueFactory getDataValueFactory() {
1558: return dvFactory;
1559: }
1560:
1561: /**
1562: * Used to get a proxy for the current connection.
1563: *
1564: * @exception SQLException Thrown on failure to get connection
1565: */
1566: public Connection getCurrentConnection() throws SQLException {
1567:
1568: ConnectionContext cc = (ConnectionContext) cm
1569: .getContext(ConnectionContext.CONTEXT_ID);
1570:
1571: return cc.getNestedConnection(true);
1572: }
1573:
1574: /**
1575: Real implementations of this method are provided by a generated class.
1576: */
1577: public java.sql.ResultSet[][] getDynamicResults() {
1578: return null;
1579: }
1580:
1581: /**
1582: Real implementations of this method are provided by a generated class.
1583: */
1584: public int getMaxDynamicResults() {
1585: return 0;
1586: }
1587:
1588: /**
1589: * Compute the DB2 compatible length of a value.
1590: *
1591: * @param value
1592: * @param constantLength The length, if it is a constant modulo null/not null. -1 if the length is not constant
1593: * @param reUse If non-null then re-use this as a container for the length
1594: *
1595: * @return the DB2 compatible length, set to null if value is null.
1596: */
1597: public NumberDataValue getDB2Length(DataValueDescriptor value,
1598: int constantLength, NumberDataValue reUse)
1599: throws StandardException {
1600: if (reUse == null)
1601: reUse = getDataValueFactory().getNullInteger(null);
1602: if (value.isNull())
1603: reUse.setToNull();
1604: else {
1605: if (constantLength >= 0)
1606: reUse.setValue(constantLength);
1607: else {
1608: reUse.setValue(value.getLength());
1609: }
1610: }
1611: return reUse;
1612: } // end of getDB2Length
1613: }
|