0001: /*
0002:
0003: Derby - Class org.apache.derby.impl.sql.compile.FromVTI
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.compile;
0023:
0024: import org.apache.derby.iapi.services.loader.ClassInspector;
0025: import org.apache.derby.iapi.services.loader.GeneratedMethod;
0026:
0027: import org.apache.derby.iapi.services.context.ContextManager;
0028:
0029: import org.apache.derby.iapi.services.compiler.MethodBuilder;
0030: import org.apache.derby.iapi.services.compiler.LocalField;
0031:
0032: import org.apache.derby.iapi.services.sanity.SanityManager;
0033:
0034: import org.apache.derby.iapi.error.StandardException;
0035:
0036: import org.apache.derby.iapi.sql.compile.CompilerContext;
0037: import org.apache.derby.iapi.sql.compile.OptimizablePredicateList;
0038: import org.apache.derby.iapi.sql.compile.Optimizer;
0039: import org.apache.derby.iapi.sql.compile.OptimizablePredicate;
0040: import org.apache.derby.iapi.sql.compile.Optimizable;
0041: import org.apache.derby.iapi.sql.compile.CostEstimate;
0042: import org.apache.derby.iapi.sql.compile.Visitable;
0043: import org.apache.derby.iapi.sql.compile.Visitor;
0044: import org.apache.derby.iapi.sql.compile.RowOrdering;
0045: import org.apache.derby.iapi.sql.compile.C_NodeTypes;
0046:
0047: import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
0048:
0049: import org.apache.derby.iapi.sql.dictionary.DataDictionary;
0050: import org.apache.derby.iapi.sql.dictionary.ColumnDescriptor;
0051: import org.apache.derby.iapi.sql.dictionary.ColumnDescriptorList;
0052: import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;
0053: import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
0054:
0055: import org.apache.derby.iapi.reference.ClassName;
0056: import org.apache.derby.iapi.reference.JDBC20Translation;
0057: import org.apache.derby.iapi.reference.SQLState;
0058:
0059: import org.apache.derby.iapi.sql.Activation;
0060:
0061: import org.apache.derby.catalog.UUID;
0062:
0063: import org.apache.derby.vti.DeferModification;
0064: import org.apache.derby.vti.VTICosting;
0065: import org.apache.derby.vti.VTIEnvironment;
0066:
0067: import org.apache.derby.iapi.util.JBitSet;
0068: import org.apache.derby.iapi.services.io.FormatableBitSet;
0069: import org.apache.derby.iapi.services.classfile.VMOpcode;
0070: import org.apache.derby.iapi.services.info.JVMInfo;
0071:
0072: import org.apache.derby.impl.sql.compile.ActivationClassBuilder;
0073: import org.apache.derby.iapi.sql.execute.ExecutionContext;
0074:
0075: import java.lang.reflect.Constructor;
0076: import java.lang.reflect.InvocationTargetException;
0077:
0078: import java.sql.PreparedStatement;
0079: import java.sql.ResultSet;
0080: import java.sql.ResultSetMetaData;
0081: import java.sql.SQLException;
0082: import java.sql.Types;
0083:
0084: import java.util.Enumeration;
0085: import java.util.Properties;
0086: import java.util.Vector;
0087: import org.apache.derby.iapi.services.io.FormatableHashtable;
0088:
0089: import java.lang.reflect.Modifier;
0090:
0091: /**
0092: * A FromVTI represents a VTI in the FROM list of a DML statement.
0093: *
0094: * @author Jerry Brenner
0095: */
0096: public class FromVTI extends FromTable implements VTIEnvironment {
0097:
0098: JBitSet correlationMap;
0099: JBitSet dependencyMap;
0100: NewInvocationNode newInvocation;
0101: TableName exposedName;
0102: SubqueryList subqueryList;
0103: boolean implements VTICosting;
0104: boolean optimized;
0105: boolean materializable;
0106: boolean isTarget;
0107: ResultSet rs;
0108:
0109: private FormatableHashtable compileTimeConstants;
0110:
0111: // Number of columns returned by the VTI
0112: protected int numVTICols;
0113:
0114: private PredicateList restrictionList;
0115:
0116: /**
0117: Was a FOR UPDATE clause specified in a SELECT statement.
0118: */
0119: private boolean forUpdatePresent;
0120:
0121: /**
0122: Was the FOR UPDATE clause empty (no columns specified).
0123: */
0124: private boolean emptyForUpdate;
0125:
0126: /*
0127: ** We don't know how expensive a virtual table will be.
0128: ** Let's say it has 10000 rows with a cost of 100000.
0129: */
0130: double estimatedCost = VTICosting.defaultEstimatedCost;
0131: double estimatedRowCount = VTICosting.defaultEstimatedRowCount;
0132: boolean supportsMultipleInstantiations = true;
0133: boolean vtiCosted;
0134:
0135: /* Version 1 or 2 VTI*/
0136: protected boolean version2;
0137: private boolean implements Pushable;
0138: private PreparedStatement ps;
0139:
0140: private JavaValueNode[] methodParms;
0141:
0142: private boolean controlsDeferral;
0143: private boolean isInsensitive;
0144: private int resultSetType = ResultSet.TYPE_FORWARD_ONLY;
0145:
0146: /**
0147: * @param newInvocation The constructor for the VTI
0148: * @param correlationName The correlation name
0149: * @param derivedRCL The derived column list
0150: * @param tableProperties Properties list associated with the table
0151: *
0152: * @exception StandardException Thrown on error
0153: */
0154: public void init(Object newInvocation, Object correlationName,
0155: Object derivedRCL, Object tableProperties)
0156: throws StandardException {
0157: init(newInvocation, correlationName, derivedRCL,
0158: tableProperties, makeTableName(null,
0159: (String) correlationName));
0160: }
0161:
0162: /**
0163: * @param newInvocation The constructor for the VTI
0164: * @param correlationName The correlation name
0165: * @param derivedRCL The derived column list
0166: * @param tableProperties Properties list associated with the table
0167: * @param exposedTableName The table name (TableName class)
0168: *
0169: * @exception StandardException Thrown on error
0170: */
0171: public void init(Object newInvocation, Object correlationName,
0172: Object derivedRCL, Object tableProperties,
0173: Object exposedTableName) throws StandardException {
0174: super .init(correlationName, tableProperties);
0175: this .newInvocation = (NewInvocationNode) newInvocation;
0176: resultColumns = (ResultColumnList) derivedRCL;
0177: subqueryList = (SubqueryList) getNodeFactory().getNode(
0178: C_NodeTypes.SUBQUERY_LIST, getContextManager());
0179:
0180: /* Cache exposed name for this table.
0181: * The exposed name becomes the qualifier for each column
0182: * in the expanded list.
0183: */
0184: this .exposedName = (TableName) exposedTableName;
0185: }
0186:
0187: // Optimizable interface
0188:
0189: /**
0190: * @see Optimizable#estimateCost
0191: *
0192: * @exception StandardException Thrown on error
0193: */
0194: public CostEstimate estimateCost(OptimizablePredicateList predList,
0195: ConglomerateDescriptor cd, CostEstimate outerCost,
0196: Optimizer optimizer, RowOrdering rowOrdering)
0197: throws StandardException {
0198: costEstimate = getCostEstimate(optimizer);
0199:
0200: /* Cost the VTI if it implements VTICosting.
0201: * Otherwise we use the defaults.
0202: * NOTE: We only cost the VTI once.
0203: */
0204: if (implements VTICosting && !vtiCosted) {
0205: try {
0206: VTICosting vtic = (version2) ? (VTICosting) ps
0207: : (VTICosting) rs;
0208: estimatedCost = vtic
0209: .getEstimatedCostPerInstantiation(this );
0210: estimatedRowCount = vtic.getEstimatedRowCount(this );
0211: supportsMultipleInstantiations = vtic
0212: .supportsMultipleInstantiations(this );
0213:
0214: if (ps != null) {
0215: ps.close();
0216: ps = null;
0217: }
0218: if (rs != null) {
0219: rs.close();
0220: rs = null;
0221: }
0222: } catch (SQLException sqle) {
0223: throw StandardException.unexpectedUserException(sqle);
0224: }
0225: vtiCosted = true;
0226: }
0227:
0228: costEstimate.setCost(estimatedCost, estimatedRowCount,
0229: estimatedRowCount);
0230:
0231: /*
0232: ** Let the join strategy decide whether the cost of the base
0233: ** scan is a single scan, or a scan per outer row.
0234: ** NOTE: The multiplication should only be done against the
0235: ** total row count, not the singleScanRowCount.
0236: ** RESOLVE - If the join strategy does not do materialization,
0237: ** the VTI does not support multiple instantiations and the
0238: ** outer row count is not exactly 1 row, then we need to change
0239: ** the costing formula to take into account the cost of creating
0240: ** the temp conglomerate, writing to it and reading from it
0241: ** outerCost.rowCount() - 1 times.
0242: */
0243: if (getCurrentAccessPath().getJoinStrategy()
0244: .multiplyBaseCostByOuterRows()) {
0245: costEstimate.multiply(outerCost.rowCount(), costEstimate);
0246: }
0247:
0248: if (!optimized) {
0249: subqueryList.optimize(optimizer.getDataDictionary(),
0250: costEstimate.rowCount());
0251: subqueryList.modifyAccessPaths();
0252: }
0253:
0254: optimized = true;
0255:
0256: return costEstimate;
0257: }
0258:
0259: /**
0260: * @see Optimizable#legalJoinOrder
0261: */
0262: public boolean legalJoinOrder(JBitSet assignedTableMap) {
0263: /* In order to tell if this is a legal join order, we
0264: * need to see if the assignedTableMap, ORed with the
0265: * outer tables that we are correlated with, contains
0266: * our dependency map.
0267: */
0268: JBitSet tempBitSet = (JBitSet) assignedTableMap;
0269: tempBitSet.or(correlationMap);
0270:
0271: /* Have all of our dependencies been satisified? */
0272: return tempBitSet.contains(dependencyMap);
0273: }
0274:
0275: /** @see Optimizable#isMaterializable
0276: *
0277: */
0278: public boolean isMaterializable() {
0279: return materializable;
0280: }
0281:
0282: /** @see Optimizable#supportsMultipleInstantiations */
0283: public boolean supportsMultipleInstantiations() {
0284: return supportsMultipleInstantiations;
0285: }
0286:
0287: /**
0288: * @see Optimizable#modifyAccessPath
0289: *
0290: * @exception StandardException Thrown on error
0291: */
0292: public Optimizable modifyAccessPath(JBitSet outerTables)
0293: throws StandardException {
0294: /* Close the rs if one was instantiated */
0295: if (rs != null) {
0296: try {
0297: rs.close();
0298: rs = null;
0299: } catch (Throwable t) {
0300: throw StandardException.unexpectedUserException(t);
0301: }
0302: }
0303:
0304: return super .modifyAccessPath(outerTables);
0305: }
0306:
0307: public boolean pushOptPredicate(
0308: OptimizablePredicate optimizablePredicate)
0309: throws StandardException {
0310: if (!implements Pushable)
0311: return false;
0312:
0313: // Do not push down join predicates: those referencing more than one table.
0314: if (!optimizablePredicate.getReferencedMap().hasSingleBitSet())
0315: return false;
0316:
0317: if (restrictionList == null) {
0318: restrictionList = (PredicateList) getNodeFactory().getNode(
0319: C_NodeTypes.PREDICATE_LIST, getContextManager());
0320: }
0321:
0322: restrictionList.addPredicate((Predicate) optimizablePredicate);
0323: return true;
0324: }
0325:
0326: /**
0327: * Convert this object to a String. See comments in QueryTreeNode.java
0328: * for how this should be done for tree printing.
0329: *
0330: * @return This object as a String
0331: */
0332:
0333: public String toString() {
0334: if (SanityManager.DEBUG) {
0335: return "materializable: " + materializable + "\n"
0336: + super .toString();
0337: } else {
0338: return "";
0339: }
0340: }
0341:
0342: /**
0343: * Prints the sub-nodes of this object. See QueryTreeNode.java for
0344: * how tree printing is supposed to work.
0345: *
0346: * @param depth The depth of this node in the tree
0347: */
0348:
0349: public void printSubNodes(int depth) {
0350: if (SanityManager.DEBUG) {
0351: super .printSubNodes(depth);
0352:
0353: if (newInvocation != null) {
0354: printLabel(depth, "newInvocation: ");
0355: newInvocation.treePrint(depth + 1);
0356: }
0357:
0358: if (exposedName != null) {
0359: printLabel(depth, "exposedName: ");
0360: exposedName.treePrint(depth + 1);
0361: }
0362:
0363: if (subqueryList != null) {
0364: printLabel(depth, "subqueryList: ");
0365: subqueryList.treePrint(depth + 1);
0366: }
0367: }
0368: }
0369:
0370: /**
0371: * Return the new invocation from this node.
0372: *
0373: * @return ResultSetNode The new invocation from this node.
0374: */
0375: public NewInvocationNode getNewInvocation() {
0376: return newInvocation;
0377: }
0378:
0379: /**
0380: * Get the exposed name for this table, which is the name that can
0381: * be used to refer to it in the rest of the query.
0382: *
0383: * @return The exposed name for this table.
0384: */
0385:
0386: public String getExposedName() {
0387: return correlationName;
0388: }
0389:
0390: /**
0391: * @return the table name used for matching with column references.
0392: *
0393: */
0394: public TableName getExposedTableName() {
0395: return exposedName;
0396: }
0397:
0398: /**
0399: * Mark this VTI as the target of a delete or update.
0400: */
0401: void setTarget() {
0402: isTarget = true;
0403: version2 = true;
0404: }
0405:
0406: /**
0407: * Bind the non VTI tables in this ResultSetNode. This includes getting their
0408: * descriptors from the data dictionary and numbering them.
0409: *
0410: * @param dataDictionary The DataDictionary to use for binding
0411: * @param fromListParam FromList to use/append to.
0412: *
0413: * @return ResultSetNode
0414: *
0415: * @exception StandardException Thrown on error
0416: */
0417:
0418: public ResultSetNode bindNonVTITables(
0419: DataDictionary dataDictionary, FromList fromListParam)
0420: throws StandardException {
0421:
0422: /* Assign the tableNumber. (All other work done in bindVTITables() */
0423: if (tableNumber == -1) // allow re-bind, in which case use old number
0424: tableNumber = getCompilerContext().getNextTableNumber();
0425: return this ;
0426: }
0427:
0428: /**
0429: * @return The name of the VTI, mainly for debugging and error messages.
0430: */
0431: String getVTIName() {
0432: return newInvocation.getJavaClassName();
0433: } // end of getVTIName
0434:
0435: /**
0436: * Bind this VTI that appears in the FROM list.
0437: *
0438: * @param fromListParam FromList to use/append to.
0439: *
0440: * @return ResultSetNode The bound FromVTI.
0441: *
0442: * @exception StandardException Thrown on error
0443: */
0444:
0445: public ResultSetNode bindVTITables(FromList fromListParam)
0446: throws StandardException {
0447: ResultColumnList derivedRCL = resultColumns;
0448:
0449: LanguageConnectionContext lcc = getLanguageConnectionContext();
0450:
0451: /* NOTE - setting of table number moved to FromList.bindTables()
0452: * in order to avoid an ordering problem with join columns in
0453: * parameters.
0454: */
0455:
0456: /* Bind the constructor - does basic error checking.
0457: * Correlated subqueries are not allowed as parameters to
0458: * a VTI, so pass an empty FromList.
0459: */
0460: Vector aggregateVector = new Vector();
0461: newInvocation.bindExpression(fromListParam, subqueryList,
0462: aggregateVector);
0463:
0464: /* We have a valid constructor. Does class implement the correct interface?
0465: * If version2 is true, then it must implement PreparedStatement, otherwise
0466: * it can implement either PreparedStatement or ResultSet. (We check for
0467: * PreparedStatement first.)
0468: */
0469:
0470: if (!newInvocation.assignableTo("java.sql.PreparedStatement")) {
0471: if (version2) {
0472: throw StandardException.newException(
0473: SQLState.LANG_DOES_NOT_IMPLEMENT, getVTIName(),
0474: "java.sql.PreparedStatement");
0475: } else if (!newInvocation
0476: .assignableTo("java.sql.ResultSet")) {
0477: throw StandardException.newException(
0478: SQLState.LANG_DOES_NOT_IMPLEMENT, getVTIName(),
0479: "java.sql.ResultSet");
0480: }
0481: } else {
0482: version2 = true;
0483: }
0484:
0485: /* If this is a version 2 VTI */
0486: if (version2) {
0487: // Does it support predicates
0488: implements Pushable = newInvocation
0489: .assignableTo("org.apache.derby.vti.IQualifyable");
0490: }
0491:
0492: // Remember whether or not the VTI implements the VTICosting interface
0493: implements VTICosting = newInvocation
0494: .assignableTo(ClassName.VTICosting);
0495:
0496: // Is the parameter list to the constructor valid for a VTI?
0497: methodParms = newInvocation.getMethodParms();
0498:
0499: /* Build the RCL for this VTI. We instantiate an object in order
0500: * to get the ResultSetMetaData.
0501: *
0502: * If we have a special trigger vti, then we branch off and get
0503: * its rcl from the trigger table that is waiting for us in
0504: * the compiler context.
0505: */
0506: UUID triggerTableId;
0507: if ((triggerTableId = getSpecialTriggerVTITableName(lcc,
0508: newInvocation.getJavaClassName())) != null) {
0509: TableDescriptor td = getDataDictionary()
0510: .getTableDescriptor(triggerTableId);
0511: resultColumns = genResultColList(td);
0512:
0513: // costing info
0514: vtiCosted = true;
0515: estimatedCost = 50d;
0516: estimatedRowCount = 5d;
0517: supportsMultipleInstantiations = true;
0518: } else {
0519: ResultSetMetaData rsmd = getResultSetMetaData();
0520:
0521: /* Wouldn't it be nice if we knew that the class/object would never
0522: * return a null ResultSetMetaData.
0523: */
0524: if (rsmd == null) {
0525: throw StandardException.newException(
0526: SQLState.LANG_NULL_RESULT_SET_META_DATA,
0527: getVTIName());
0528: }
0529:
0530: // Remember how many columns VTI returns for partial row calculation
0531: try {
0532: numVTICols = rsmd.getColumnCount();
0533: } catch (SQLException sqle) {
0534: numVTICols = 0;
0535: }
0536:
0537: try {
0538: for (int i = 1; i <= numVTICols; i++) {
0539: int columnType = rsmd.getColumnType(i);
0540: if (columnType == Types.BLOB
0541: || columnType == Types.CLOB)
0542: throw StandardException
0543: .newException(
0544: SQLState.LANG_VTI_BLOB_CLOB_UNSUPPORTED,
0545: getVTIName(), rsmd
0546: .getColumnName(i));
0547: }
0548: } catch (SQLException sqle) {
0549: throw StandardException.unexpectedUserException(sqle);
0550: }
0551:
0552: resultColumns = (ResultColumnList) getNodeFactory()
0553: .getNode(C_NodeTypes.RESULT_COLUMN_LIST,
0554: getContextManager());
0555: resultColumns.createListFromResultSetMetaData(rsmd,
0556: exposedName, newInvocation.getJavaClassName());
0557: }
0558: numVTICols = resultColumns.size();
0559:
0560: /* Propagate the name info from the derived column list */
0561: if (derivedRCL != null) {
0562: resultColumns.propagateDCLInfo(derivedRCL, correlationName);
0563: }
0564:
0565: return this ;
0566: }
0567:
0568: /**
0569: * Get the ResultSetMetaData for the class/object. We first look for
0570: * the optional static method which has the same signature as the constructor.
0571: * If it doesn't exist, then we instantiate an object and get the ResultSetMetaData
0572: * from that object.
0573: *
0574: * @return The ResultSetMetaData from the class/object.
0575: *
0576: * @exception StandardException Thrown on error
0577: */
0578: public ResultSetMetaData getResultSetMetaData()
0579: throws StandardException {
0580: // Get the actual
0581: ResultSetMetaData rsmd = null;
0582:
0583: try {
0584: if (version2) {
0585: ps = (PreparedStatement) getNewInstance();
0586:
0587: if (ps.getResultSetConcurrency() != JDBC20Translation.CONCUR_UPDATABLE) {
0588: throw StandardException
0589: .newException(
0590: SQLState.LANG_UPDATABLE_VTI_NON_UPDATABLE_RS,
0591: getVTIName());
0592: }
0593:
0594: rsmd = ps.getMetaData();
0595:
0596: controlsDeferral = (ps instanceof DeferModification);
0597:
0598: /* See if the result set is known to be insensitive or not.
0599: *
0600: * Some older VTI implementations do not implement getResultSetType(). UpdatableVTITemplate
0601: * does not implement it at all. UpdatableVTITemplate.getResultSetType throws an
0602: * exception. In either of these cases make the conservative assumption that the result set is sensitive.
0603: */
0604: try {
0605: resultSetType = ps.getResultSetType();
0606: } catch (SQLException sqle) {
0607: } catch (java.lang.AbstractMethodError ame) {
0608: } catch (java.lang.NoSuchMethodError nsme) {
0609: }
0610: isInsensitive = (resultSetType == ResultSet.TYPE_SCROLL_INSENSITIVE);
0611:
0612: if (!implements VTICosting) {
0613: ps.close();
0614: ps = null;
0615: }
0616:
0617: } else {
0618: rs = (ResultSet) getNewInstance();
0619:
0620: rsmd = rs.getMetaData();
0621:
0622: if (!implements VTICosting) {
0623: rs.close();
0624: rs = null;
0625: }
0626: }
0627: } catch (Throwable t) {
0628: throw StandardException.unexpectedUserException(t);
0629: }
0630:
0631: return rsmd;
0632: }
0633:
0634: private Object getNewInstance() throws StandardException {
0635: Class[] paramTypeClasses = newInvocation
0636: .getMethodParameterClasses();
0637: Object[] paramObjects = null;
0638:
0639: if (paramTypeClasses != null) {
0640: paramObjects = new Object[paramTypeClasses.length];
0641:
0642: for (int index = 0; index < paramTypeClasses.length; index++) {
0643: Class paramClass = paramTypeClasses[index];
0644:
0645: paramObjects[index] = methodParms[index]
0646: .getConstantValueAsObject();
0647:
0648: // As-per the JDBC spec SMALLINT and TINYINT map to java.lang.Integer
0649: // as objects. This means if getConstantValueAsObject() has returned an
0650: // Integer obejct in these cases, whereas Java method calling requires
0651: // Short or Byte object.
0652: if ((paramObjects[index] != null)
0653: && paramClass.isPrimitive()) {
0654:
0655: if (paramClass.equals(Short.TYPE)) {
0656: paramObjects[index] = new Short(
0657: ((Integer) paramObjects[index])
0658: .shortValue());
0659: } else if (paramClass.equals(Byte.TYPE)) {
0660: paramObjects[index] = new Byte(
0661: ((Integer) paramObjects[index])
0662: .byteValue());
0663: }
0664: }
0665:
0666: // Pass defaults for unknown primitive values
0667: if (paramObjects[index] == null
0668: && paramClass.isPrimitive()) {
0669: if (paramClass.equals(Integer.TYPE)) {
0670: paramObjects[index] = new Integer(0);
0671: } else if (paramClass.equals(Short.TYPE)) {
0672: paramObjects[index] = new Short((short) 0);
0673: } else if (paramClass.equals(Byte.TYPE)) {
0674: paramObjects[index] = new Byte((byte) 0);
0675: } else if (paramClass.equals(Long.TYPE)) {
0676: paramObjects[index] = new Long((long) 0);
0677: } else if (paramClass.equals(Float.TYPE)) {
0678: paramObjects[index] = new Float((float) 0);
0679: } else if (paramClass.equals(Double.TYPE)) {
0680: paramObjects[index] = new Double((double) 0);
0681: } else if (paramClass.equals(Boolean.TYPE)) {
0682: paramObjects[index] = Boolean.FALSE;
0683: } else if (paramClass.equals(Character.TYPE)) {
0684: paramObjects[index] = new Character(
0685: Character.MIN_VALUE);
0686: }
0687: }
0688: }
0689: } else {
0690: paramTypeClasses = new Class[0];
0691: paramObjects = new Object[0];
0692: }
0693:
0694: try {
0695: ClassInspector classInspector = getClassFactory()
0696: .getClassInspector();
0697: String javaClassName = newInvocation.getJavaClassName();
0698: Constructor constructor = classInspector.getClass(
0699: javaClassName).getConstructor(paramTypeClasses);
0700:
0701: return constructor.newInstance(paramObjects);
0702: } catch (Throwable t) {
0703: if (t instanceof InvocationTargetException) {
0704: InvocationTargetException ite = (InvocationTargetException) t;
0705: Throwable wrappedThrowable = ite.getTargetException();
0706: if (wrappedThrowable instanceof StandardException)
0707: throw (StandardException) wrappedThrowable;
0708: }
0709: throw StandardException.unexpectedUserException(t);
0710: }
0711: } // end of getNewInstance
0712:
0713: /**
0714: * Get the DeferModification interface associated with this VTI
0715: *
0716: * @return null if the VTI uses the default modification deferral
0717: */
0718: public DeferModification getDeferralControl()
0719: throws StandardException {
0720: if (!controlsDeferral)
0721: return null;
0722: try {
0723: return (DeferModification) getNewInstance();
0724: } catch (Throwable t) {
0725: throw StandardException.unexpectedUserException(t);
0726: }
0727: } // end of getDeferralControl
0728:
0729: /**
0730: * @return the ResultSet type of the VTI, TYPE_FORWARD_ONLY if the getResultSetType() method
0731: * of the VTI class throws an exception.
0732: */
0733: public int getResultSetType() {
0734: return resultSetType;
0735: }
0736:
0737: /**
0738: * Bind the expressions in this VTI. This means
0739: * binding the sub-expressions, as well as figuring out what the return
0740: * type is for each expression.
0741: *
0742: *
0743: * @exception StandardException Thrown on error
0744: */
0745:
0746: public void bindExpressions(FromList fromListParam)
0747: throws StandardException {
0748: ResultColumnList derivedRCL = resultColumns;
0749:
0750: /* Figure out if the VTIs parameters are QUERY_INVARIANT. If so,
0751: * then the VTI is a candidate for materialization at execution time
0752: * if it is the inner table of a join or in a subquery.
0753: */
0754: materializable = newInvocation.areParametersQueryInvariant();
0755:
0756: /* NOTE: We need to rebind any ColumnReferences that are parameters and are
0757: * from other VTIs that appear after this one in the FROM list.
0758: * These CRs will have uninitialized column and table numbers.
0759: */
0760: Vector colRefs = getNodesFromParameters(ColumnReference.class);
0761: Vector aggregateVector = null;
0762: for (Enumeration e = colRefs.elements(); e.hasMoreElements();) {
0763: ColumnReference ref = (ColumnReference) e.nextElement();
0764:
0765: // Rebind the CR if the tableNumber is uninitialized
0766: if (ref.getTableNumber() == -1) {
0767: // we need a fake agg list
0768: if (aggregateVector == null) {
0769: aggregateVector = new Vector();
0770: }
0771: ref.bindExpression(fromListParam, subqueryList,
0772: aggregateVector);
0773: }
0774: }
0775: }
0776:
0777: /**
0778: * Get all of the nodes of the specified class
0779: * from the parameters to this VTI.
0780: *
0781: * @param nodeClass The Class of interest.
0782: *
0783: * @return A vector containing all of the nodes of interest.
0784: *
0785: * @exception StandardException Thrown on error
0786: */
0787: Vector getNodesFromParameters(Class nodeClass)
0788: throws StandardException {
0789: CollectNodesVisitor getCRs = new CollectNodesVisitor(nodeClass);
0790: newInvocation.accept(getCRs);
0791: return getCRs.getList();
0792: }
0793:
0794: /**
0795: * Expand a "*" into a ResultColumnList with all of the
0796: * result columns from the subquery.
0797: * @exception StandardException Thrown on error
0798: */
0799: public ResultColumnList getAllResultColumns(TableName allTableName)
0800: throws StandardException {
0801: ResultColumnList rcList = null;
0802: ResultColumn resultColumn;
0803: ValueNode valueNode;
0804: String columnName;
0805: TableName toCompare;
0806:
0807: if (allTableName != null)
0808: toCompare = makeTableName(allTableName.getSchemaName(),
0809: correlationName);
0810: else
0811: toCompare = makeTableName(null, correlationName);
0812:
0813: if (allTableName != null && !allTableName.equals(toCompare)) {
0814: return null;
0815: }
0816:
0817: rcList = (ResultColumnList) getNodeFactory().getNode(
0818: C_NodeTypes.RESULT_COLUMN_LIST, getContextManager());
0819:
0820: /* Build a new result column list based off of resultColumns.
0821: * NOTE: This method will capture any column renaming due to
0822: * a derived column list.
0823: */
0824: int rclSize = resultColumns.size();
0825: for (int index = 0; index < rclSize; index++) {
0826: resultColumn = (ResultColumn) resultColumns
0827: .elementAt(index);
0828:
0829: if (resultColumn.isGenerated()) {
0830: continue;
0831: }
0832:
0833: // Build a ResultColumn/ColumnReference pair for the column //
0834: columnName = resultColumn.getName();
0835: valueNode = (ValueNode) getNodeFactory().getNode(
0836: C_NodeTypes.COLUMN_REFERENCE, columnName,
0837: exposedName, getContextManager());
0838: resultColumn = (ResultColumn) getNodeFactory().getNode(
0839: C_NodeTypes.RESULT_COLUMN, columnName, valueNode,
0840: getContextManager());
0841:
0842: // Build the ResultColumnList to return //
0843: rcList.addResultColumn(resultColumn);
0844: }
0845: return rcList;
0846: }
0847:
0848: /**
0849: * Try to find a ResultColumn in the table represented by this FromBaseTable
0850: * that matches the name in the given ColumnReference.
0851: *
0852: * @param columnReference The columnReference whose name we're looking
0853: * for in the given table.
0854: *
0855: * @return A ResultColumn whose expression is the ColumnNode
0856: * that matches the ColumnReference.
0857: * Returns null if there is no match.
0858: *
0859: * @exception StandardException Thrown on error
0860: */
0861:
0862: public ResultColumn getMatchingColumn(
0863: ColumnReference columnReference) throws StandardException {
0864: /* We could get called before our RCL is built. That's okay, we'll
0865: * just say that we don't match.
0866: */
0867: if (resultColumns == null) {
0868: return null;
0869: }
0870:
0871: ResultColumn resultColumn = null;
0872: TableName columnsTableName;
0873: TableName exposedTableName;
0874:
0875: columnsTableName = columnReference.getTableNameNode();
0876:
0877: /*
0878: ** If the column did not specify a name, or the specified name
0879: ** matches the table we're looking at, see whether the column
0880: ** is in this table.
0881: */
0882: if (columnsTableName == null
0883: || columnsTableName.equals(exposedName)) {
0884: resultColumn = resultColumns
0885: .getResultColumn(columnReference.getColumnName());
0886: /* Did we find a match? */
0887: if (resultColumn != null) {
0888: columnReference.setTableNumber(tableNumber);
0889: }
0890: }
0891:
0892: return resultColumn;
0893: }
0894:
0895: /**
0896: * Preprocess a ResultSetNode - this currently means:
0897: * o Generating a referenced table map for each ResultSetNode.
0898: * o Putting the WHERE and HAVING clauses in conjunctive normal form (CNF).
0899: * o Converting the WHERE and HAVING clauses into PredicateLists and
0900: * classifying them.
0901: * o Ensuring that a ProjectRestrictNode is generated on top of every
0902: * FromBaseTable and generated in place of every FromSubquery.
0903: * o Pushing single table predicates down to the new ProjectRestrictNodes.
0904: *
0905: * @param numTables The number of tables in the DML Statement
0906: * @param gbl The group by list, if any
0907: * @param fromList The from list, if any
0908: *
0909: * @return ResultSetNode at top of preprocessed tree.
0910: *
0911: * @exception StandardException Thrown on error
0912: */
0913:
0914: public ResultSetNode preprocess(int numTables, GroupByList gbl,
0915: FromList fromList) throws StandardException {
0916: newInvocation
0917: .preprocess(numTables, (FromList) getNodeFactory()
0918: .getNode(
0919: C_NodeTypes.FROM_LIST,
0920: getNodeFactory()
0921: .doJoinOrderOptimization(),
0922: getContextManager()),
0923: (SubqueryList) getNodeFactory().getNode(
0924: C_NodeTypes.SUBQUERY_LIST,
0925: getContextManager()),
0926: (PredicateList) getNodeFactory().getNode(
0927: C_NodeTypes.PREDICATE_LIST,
0928: getContextManager()));
0929: /* Generate the referenced table map */
0930: referencedTableMap = new JBitSet(numTables);
0931: referencedTableMap.set(tableNumber);
0932: newInvocation.categorize(referencedTableMap, false);
0933:
0934: // Create the dependency map
0935: dependencyMap = new JBitSet(numTables);
0936: for (int index = 0; index < numTables; index++) {
0937: if ((index != tableNumber) && referencedTableMap.get(index)) {
0938: dependencyMap.set(index);
0939: }
0940: }
0941:
0942: // Get a JBitSet of the outer tables represented in the parameter list
0943: correlationMap = new JBitSet(numTables);
0944: newInvocation.getCorrelationTables(correlationMap);
0945:
0946: return genProjectRestrict(numTables);
0947: }
0948:
0949: /**
0950: * Put a ProjectRestrictNode on top of each FromTable in the FromList.
0951: * ColumnReferences must continue to point to the same ResultColumn, so
0952: * that ResultColumn must percolate up to the new PRN. However,
0953: * that ResultColumn will point to a new expression, a VirtualColumnNode,
0954: * which points to the FromTable and the ResultColumn that is the source for
0955: * the ColumnReference.
0956: * (The new PRN will have the original of the ResultColumnList and
0957: * the ResultColumns from that list. The FromTable will get shallow copies
0958: * of the ResultColumnList and its ResultColumns. ResultColumn.expression
0959: * will remain at the FromTable, with the PRN getting a new
0960: * VirtualColumnNode for each ResultColumn.expression.)
0961: * We then project out the non-referenced columns. If there are no referenced
0962: * columns, then the PRN's ResultColumnList will consist of a single ResultColumn
0963: * whose expression is 1.
0964: *
0965: * @param numTables Number of tables in the DML Statement
0966: *
0967: * @return The generated ProjectRestrictNode atop the original FromTable.
0968: *
0969: * @exception StandardException Thrown on error
0970: */
0971:
0972: protected ResultSetNode genProjectRestrict(int numTables)
0973: throws StandardException {
0974: ResultColumnList prRCList;
0975:
0976: /* We get a shallow copy of the ResultColumnList and its
0977: * ResultColumns. (Copy maintains ResultColumn.expression for now.)
0978: */
0979: prRCList = resultColumns;
0980: resultColumns = resultColumns.copyListAndObjects();
0981:
0982: /* Replace ResultColumn.expression with new VirtualColumnNodes
0983: * in the ProjectRestrictNode's ResultColumnList. (VirtualColumnNodes include
0984: * pointers to source ResultSetNode, this, and source ResultColumn.)
0985: * NOTE: We don't want to mark the underlying RCs as referenced, otherwise
0986: * we won't be able to project out any of them.
0987: */
0988: prRCList.genVirtualColumnNodes(this , resultColumns, false);
0989:
0990: /* Project out any unreferenced columns. If there are no referenced
0991: * columns, generate and bind a single ResultColumn whose expression is 1.
0992: */
0993: prRCList.doProjection();
0994:
0995: /* Finally, we create the new ProjectRestrictNode */
0996: return (ResultSetNode) getNodeFactory().getNode(
0997: C_NodeTypes.PROJECT_RESTRICT_NODE, this , prRCList,
0998: null, /* Restriction */
0999: null, /* Restriction as PredicateList */
1000: null, /* Project subquery list */
1001: null, /* Restrict subquery list */
1002: tableProperties, getContextManager());
1003: }
1004:
1005: /**
1006: * Return whether or not to materialize this ResultSet tree.
1007: *
1008: * @return Whether or not to materialize this ResultSet tree.
1009: * would return valid results.
1010: *
1011: * @exception StandardException Thrown on error
1012: */
1013: public boolean performMaterialization(JBitSet outerTables)
1014: throws StandardException {
1015: /* We need to materialize the VTI iff:
1016: * o It is an inner table.
1017: * o The VTI can be materialized.
1018: * o The VTI cannot be instantiated multiple times.
1019: * o The join strategy does not do materialization.
1020: * RESOLVE - We don't have to materialize if all of the
1021: * outer tables are 1 row tables.
1022: */
1023: return (outerTables.getFirstSetBit() != -1
1024: && !outerTables.hasSingleBitSet() && // Not the outer table
1025: (!getTrulyTheBestAccessPath().getJoinStrategy()
1026: .doesMaterialization()) && // Join strategy does not do materialization
1027: isMaterializable() && // VTI can be materialized
1028: !supportsMultipleInstantiations // VTI does not support multiple instantiations
1029: );
1030: }
1031:
1032: /**
1033: * Generation on a FromVTI creates a wrapper around
1034: * the user's java.sql.ResultSet
1035: *
1036: * @param acb The ActivationClassBuilder for the class being built
1037: * @param mb The MethodBuilder for the execute() method to be built
1038: *
1039: * @exception StandardException Thrown on error
1040: */
1041: public void generate(ActivationClassBuilder acb, MethodBuilder mb)
1042: throws StandardException {
1043: /* NOTE: We need to remap any CRs within the parameters
1044: * so that we get their values from the right source
1045: * row. For example, if a CR is a join column, we need
1046: * to get the value from the source table and not the
1047: * join row since the join row hasn't been filled in yet.
1048: */
1049: RemapCRsVisitor rcrv = new RemapCRsVisitor(true);
1050: newInvocation.accept(rcrv);
1051:
1052: /* Get the next ResultSet #, so that we can number this ResultSetNode, its
1053: * ResultColumnList and ResultSet.
1054: */
1055: assignResultSetNumber();
1056:
1057: acb.pushGetResultSetFactoryExpression(mb);
1058: int nargs = getScanArguments(acb, mb);
1059: mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null,
1060: "getVTIResultSet", ClassName.NoPutResultSet, nargs);
1061: }
1062:
1063: private int getScanArguments(ActivationClassBuilder acb,
1064: MethodBuilder mb) throws StandardException {
1065: int rclSize = resultColumns.size();
1066: FormatableBitSet referencedCols = new FormatableBitSet(rclSize);
1067: int erdNumber = -1;
1068: int numSet = 0;
1069:
1070: // Get our final cost estimate.
1071: costEstimate = getFinalCostEstimate();
1072:
1073: for (int index = 0; index < rclSize; index++) {
1074: ResultColumn rc = (ResultColumn) resultColumns
1075: .elementAt(index);
1076: if (rc.isReferenced()) {
1077: referencedCols.set(index);
1078: numSet++;
1079: }
1080: }
1081:
1082: // Only add referencedCols if not all columns are accessed
1083: if (numSet != numVTICols) {
1084: erdNumber = acb.addItem(referencedCols);
1085: }
1086:
1087: // compileTimeConstants can be null
1088: int ctcNumber = acb.addItem(compileTimeConstants);
1089:
1090: acb.pushThisAsActivation(mb); // arg 1
1091:
1092: // get a function to allocate scan rows of the right shape and size
1093: resultColumns.generateHolder(acb, mb); // arg 2
1094:
1095: // For a Version 2 VTI we never maintain the java.sql.PreparedStatement
1096: // from compile time to execute time. This would rquire the PreparedStatement
1097: // to be shareable across multiple connections, which is not the model for
1098: // java.sql.PreparedStatement.
1099:
1100: // For a Version 2 VTI we do pass onto the ResultSet the re-useability
1101: // of the java.sql.PreparedStatement at runtime. The java.sql.PreparedStatement
1102: // is re-uesable if
1103: //
1104: // o No ? or ColumnReferences in parameters
1105:
1106: boolean reuseablePs = version2
1107: && (getNodesFromParameters(ParameterNode.class).size() == 0)
1108: && (getNodesFromParameters(ColumnReference.class)
1109: .size() == 0);
1110:
1111: mb.push(resultSetNumber); // arg 3
1112:
1113: // The generated method for the constructor
1114: generateConstructor(acb, mb, reuseablePs); // arg 4
1115:
1116: // Pass in the class name
1117: mb.push(newInvocation.getJavaClassName()); // arg 5
1118:
1119: if (restrictionList != null) {
1120: restrictionList.generateQualifiers(acb, mb, this , true);
1121: } else
1122: mb.pushNull(ClassName.Qualifier + "[][]");
1123:
1124: // Pass in the erdNumber for the referenced column FormatableBitSet
1125: mb.push(erdNumber); // arg 6
1126:
1127: // Whether or not this is a version 2 VTI
1128: mb.push(version2);
1129:
1130: mb.push(reuseablePs);
1131:
1132: mb.push(ctcNumber);
1133:
1134: // Whether or not this is a target VTI
1135: mb.push(isTarget);
1136:
1137: // isolation level of the scan (if specified)
1138: mb.push(getCompilerContext().getScanIsolationLevel());
1139:
1140: // estimated row count
1141: mb.push(costEstimate.rowCount());
1142:
1143: // estimated cost
1144: mb.push(costEstimate.getEstimatedCost());
1145:
1146: return 14;
1147: }
1148:
1149: private void generateConstructor(ActivationClassBuilder acb,
1150: MethodBuilder mb, boolean reuseablePs)
1151: throws StandardException {
1152:
1153: String vtiType = version2 ? "java.sql.PreparedStatement"
1154: : "java.sql.ResultSet";
1155: // this sets up the method and the static field.
1156: // generates:
1157: // java.sql.ResultSet userExprFun { }
1158: MethodBuilder userExprFun = acb.newGeneratedFun(vtiType,
1159: Modifier.PUBLIC);
1160: userExprFun.addThrownException("java.lang.Exception");
1161:
1162: // If it's a re-useable PreparedStatement then hold onto it.
1163: LocalField psHolder = reuseablePs ? acb.newFieldDeclaration(
1164: Modifier.PRIVATE, "java.sql.PreparedStatement") : null;
1165:
1166: if (reuseablePs) {
1167:
1168: userExprFun.getField(psHolder);
1169: userExprFun.conditionalIfNull();
1170: }
1171:
1172: newInvocation.generateExpression(acb, userExprFun);
1173: userExprFun.upCast(vtiType);
1174:
1175: if (reuseablePs) {
1176:
1177: userExprFun.putField(psHolder);
1178:
1179: userExprFun.startElseCode();
1180:
1181: userExprFun.getField(psHolder);
1182:
1183: userExprFun.completeConditional();
1184: }
1185:
1186: userExprFun.methodReturn();
1187:
1188: // newInvocation knows it is returning its value;
1189:
1190: /* generates:
1191: * return <newInvocation.generate(acb)>;
1192: */
1193: // we are done modifying userExprFun, complete it.
1194: userExprFun.complete();
1195:
1196: // constructor is used in the final result set as an access of the new static
1197: // field holding a reference to this new method.
1198: // generates:
1199: // ActivationClass.userExprFun
1200: // which is the static field that "points" to the userExprFun
1201: // that evaluates the where clause.
1202: acb.pushMethodReference(mb, userExprFun);
1203:
1204: // now add in code to close the reusable PreparedStatement when
1205: // the activation is closed.
1206: if (reuseablePs) {
1207: MethodBuilder closeActivationMethod = acb
1208: .getCloseActivationMethod();
1209:
1210: closeActivationMethod.getField(psHolder);
1211: closeActivationMethod.conditionalIfNull();
1212: // do nothing
1213: closeActivationMethod.push(0); // work around for no support for real if statements
1214: closeActivationMethod.startElseCode();
1215: closeActivationMethod.getField(psHolder);
1216: closeActivationMethod.callMethod(VMOpcode.INVOKEINTERFACE,
1217: "java.sql.Statement", "close", "void", 0);
1218: closeActivationMethod.push(0);
1219:
1220: closeActivationMethod.completeConditional();
1221: closeActivationMethod.endStatement();
1222: }
1223:
1224: }
1225:
1226: /**
1227: * Search to see if a query references the specifed table name.
1228: *
1229: * @param name Table name (String) to search for.
1230: * @param baseTable Whether or not name is for a base table
1231: *
1232: * @return true if found, else false
1233: *
1234: * @exception StandardException Thrown on error
1235: */
1236: public boolean referencesTarget(String name, boolean baseTable)
1237: throws StandardException {
1238: return (!baseTable)
1239: && name.equals(newInvocation.getJavaClassName());
1240: }
1241:
1242: /**
1243: * Accept a visitor, and call v.visit()
1244: * on child nodes as necessary.
1245: *
1246: * @param v the visitor
1247: *
1248: * @exception StandardException on error
1249: */
1250: public Visitable accept(Visitor v) throws StandardException {
1251: if (v.skipChildren(this )) {
1252: return v.visit(this );
1253: }
1254:
1255: Visitable returnNode = super .accept(v);
1256:
1257: if (!v.stopTraversal()) {
1258: newInvocation = (NewInvocationNode) newInvocation.accept(v);
1259: }
1260:
1261: return returnNode;
1262: }
1263:
1264: /**
1265: * Check and see if we have a special trigger VTI.
1266: * If it cannot be bound (because we aren't actually
1267: * compiling or executing a trigger), then throw
1268: * an exception.
1269: *
1270: * @return null if not a special trigger vti, or the table
1271: * id if it is
1272: */
1273: private UUID getSpecialTriggerVTITableName(
1274: LanguageConnectionContext lcc, String className)
1275: throws StandardException {
1276: if (className.equals(ClassName.TriggerNewTransitionRows)
1277: || className.equals(ClassName.TriggerOldTransitionRows)) {
1278: // if there isn't an active trigger being compiled, error
1279: if (lcc.getTriggerTable() != null) {
1280: return lcc.getTriggerTable().getUUID();
1281: } else if (lcc.getTriggerExecutionContext() != null) {
1282: return lcc.getTriggerExecutionContext()
1283: .getTargetTableId();
1284: } else {
1285: throw StandardException.newException(
1286: SQLState.LANG_CANNOT_BIND_TRIGGER_V_T_I,
1287: className);
1288: }
1289: }
1290: return (UUID) null;
1291: }
1292:
1293: private ResultColumnList genResultColList(TableDescriptor td)
1294: throws StandardException {
1295: ResultColumnList rcList = null;
1296: ResultColumn resultColumn;
1297: ValueNode valueNode;
1298: ColumnDescriptor colDesc = null;
1299:
1300: TableName tableName = makeTableName(td.getSchemaName(), td
1301: .getName());
1302:
1303: /* Add all of the columns in the table */
1304: rcList = (ResultColumnList) getNodeFactory().getNode(
1305: C_NodeTypes.RESULT_COLUMN_LIST, getContextManager());
1306: ColumnDescriptorList cdl = td.getColumnDescriptorList();
1307: int cdlSize = cdl.size();
1308:
1309: for (int index = 0; index < cdlSize; index++) {
1310: /* Build a ResultColumn/BaseColumnNode pair for the column */
1311: colDesc = (ColumnDescriptor) cdl.elementAt(index);
1312:
1313: valueNode = (ValueNode) getNodeFactory().getNode(
1314: C_NodeTypes.BASE_COLUMN_NODE,
1315: colDesc.getColumnName(), exposedName,
1316: colDesc.getType(), getContextManager());
1317: resultColumn = (ResultColumn) getNodeFactory().getNode(
1318: C_NodeTypes.RESULT_COLUMN, colDesc, valueNode,
1319: getContextManager());
1320:
1321: /* Build the ResultColumnList to return */
1322: rcList.addResultColumn(resultColumn);
1323: }
1324:
1325: return rcList;
1326: }
1327:
1328: public boolean needsSpecialRCLBinding() {
1329: return true;
1330: }
1331:
1332: boolean isUpdatableCursor() throws StandardException {
1333: return true;
1334: }
1335:
1336: protected void markUpdatableByCursor(Vector updateColumns) {
1337: super .markUpdatableByCursor(updateColumns);
1338: forUpdatePresent = true;
1339: emptyForUpdate = ((updateColumns == null) || (updateColumns
1340: .size() == 0));
1341: }
1342:
1343: private int[] getForUpdateColumnList() {
1344:
1345: int[] tempList = new int[getNumColumnsReturned()];
1346: int offset = 0;
1347:
1348: for (int col = 0; col < tempList.length; col++) {
1349: if (resultColumns.updatableByCursor(col))
1350: tempList[offset++] = col + 1; // JDBC id
1351: }
1352:
1353: int[] list;
1354:
1355: if (offset == tempList.length)
1356: list = tempList;
1357: else {
1358: list = new int[offset];
1359: System.arraycopy(tempList, 0, list, 0, offset);
1360: }
1361:
1362: return list;
1363: }
1364:
1365: /*
1366: ** VTIEnvironment
1367: */
1368: public final boolean isCompileTime() {
1369: return true;
1370: }
1371:
1372: public String getOriginalSQL() {
1373: return getCompilerContext().getParser().getSQLtext();
1374: }
1375:
1376: public final int getStatementIsolationLevel() {
1377: return ExecutionContext.CS_TO_JDBC_ISOLATION_LEVEL_MAP[getCompilerContext()
1378: .getScanIsolationLevel()];
1379: }
1380:
1381: public void setSharedState(String key, java.io.Serializable value) {
1382:
1383: if (key == null)
1384: return;
1385:
1386: if (compileTimeConstants == null)
1387: compileTimeConstants = new FormatableHashtable();
1388:
1389: compileTimeConstants.put(key, value);
1390: }
1391:
1392: public Object getSharedState(String key) {
1393: if ((key == null) || (compileTimeConstants == null))
1394: return null;
1395:
1396: return compileTimeConstants.get(key);
1397: }
1398: }
|