0001: /*
0002:
0003: Derby - Class org.apache.derby.impl.sql.compile.DMLModStatementNode
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.GeneratedMethod;
0025:
0026: import org.apache.derby.iapi.services.context.ContextManager;
0027:
0028: import org.apache.derby.iapi.services.compiler.JavaFactory;
0029: import org.apache.derby.iapi.services.compiler.MethodBuilder;
0030:
0031: import org.apache.derby.iapi.services.sanity.SanityManager;
0032:
0033: import org.apache.derby.iapi.sql.depend.Dependent;
0034:
0035: import org.apache.derby.iapi.sql.compile.CompilerContext;
0036: import org.apache.derby.iapi.sql.compile.Parser;
0037: import org.apache.derby.iapi.sql.compile.CostEstimate;
0038: import org.apache.derby.iapi.sql.compile.OptimizerFactory;
0039: import org.apache.derby.iapi.sql.compile.C_NodeTypes;
0040: import org.apache.derby.iapi.sql.compile.NodeFactory;
0041:
0042: import org.apache.derby.iapi.sql.conn.Authorizer;
0043:
0044: import org.apache.derby.iapi.reference.ClassName;
0045: import org.apache.derby.iapi.reference.SQLState;
0046:
0047: import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
0048:
0049: import org.apache.derby.iapi.sql.dictionary.CheckConstraintDescriptor;
0050: import org.apache.derby.iapi.sql.dictionary.IndexRowGenerator;
0051: import org.apache.derby.iapi.sql.dictionary.ForeignKeyConstraintDescriptor;
0052: import org.apache.derby.iapi.sql.dictionary.GenericDescriptorList;
0053: import org.apache.derby.iapi.sql.dictionary.ReferencedKeyConstraintDescriptor;
0054: import org.apache.derby.iapi.sql.dictionary.KeyConstraintDescriptor;
0055: import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptor;
0056: import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptorList;
0057: import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;
0058: import org.apache.derby.iapi.sql.dictionary.DataDictionary;
0059: import org.apache.derby.iapi.sql.dictionary.DataDictionaryContext;
0060: import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;
0061: import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
0062: import org.apache.derby.iapi.sql.dictionary.TriggerDescriptor;
0063: import org.apache.derby.iapi.sql.dictionary.ColumnDescriptor;
0064: import org.apache.derby.iapi.sql.dictionary.ColumnDescriptorList;
0065:
0066: import org.apache.derby.iapi.sql.StatementType;
0067:
0068: import org.apache.derby.iapi.store.access.TransactionController;
0069:
0070: import org.apache.derby.impl.sql.compile.ActivationClassBuilder;
0071: import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;
0072:
0073: import org.apache.derby.iapi.error.StandardException;
0074:
0075: import org.apache.derby.impl.sql.execute.FKInfo;
0076: import org.apache.derby.impl.sql.execute.TriggerInfo;
0077:
0078: import org.apache.derby.iapi.types.RowLocation;
0079:
0080: import org.apache.derby.catalog.UUID;
0081: import java.util.Properties;
0082: import java.util.Vector;
0083: import java.util.Enumeration;
0084: import java.util.Hashtable;
0085: import org.apache.derby.iapi.services.io.FormatableBitSet;
0086: import org.apache.derby.iapi.services.classfile.VMOpcode;
0087:
0088: /**
0089: * A DMLStatement for a table modification: to wit, INSERT
0090: * UPDATE or DELETE.
0091: *
0092: * @author Jamie
0093: */
0094:
0095: abstract class DMLModStatementNode extends DMLStatementNode {
0096: // protected DataDictionary dataDictionary;
0097: protected FromVTI targetVTI;
0098: protected TableName targetTableName;
0099: protected ResultColumnList resultColumnList;
0100: protected int lockMode; // lock mode for the target table
0101:
0102: protected FKInfo[] fkInfo; // array of FKInfo structures
0103: // generated during bind
0104: protected TriggerInfo triggerInfo; // generated during bind
0105: public TableDescriptor targetTableDescriptor;
0106:
0107: /* The indexes that could be affected by this statement */
0108: public IndexRowGenerator[] indicesToMaintain;
0109: public long[] indexConglomerateNumbers;
0110: public String[] indexNames;
0111: protected ConstraintDescriptorList relevantCdl;
0112: protected GenericDescriptorList relevantTriggers;
0113:
0114: // PRIVATE
0115: private boolean requiresDeferredProcessing;
0116: private int statementType;
0117: private boolean bound;
0118: private ValueNode checkConstraints;
0119:
0120: /* Info required to perform referential actions */
0121: protected String[] fkTableNames; // referencing table names.
0122: protected int[] fkRefActions; //type of referential actions
0123: protected ColumnDescriptorList[] fkColDescriptors;
0124: protected long[] fkIndexConglomNumbers; //conglomerate number of the backing index
0125: protected boolean isDependentTable;
0126: protected int[][] fkColArrays;
0127: protected Hashtable graphHashTable;
0128: // Hash Table which maitains the querytreenode graph
0129: protected TableName synonymTableName;
0130:
0131: /**
0132: * Initializer for a DMLModStatementNode -- delegate to DMLStatementNode
0133: *
0134: * @param resultSet A ResultSetNode for the result set of the
0135: * DML statement
0136: */
0137: public void init(Object resultSet) {
0138: super .init(resultSet);
0139: statementType = getStatementType();
0140: }
0141:
0142: /**
0143: * Initializer for a DMLModStatementNode -- delegate to DMLStatementNode
0144: *
0145: * @param resultSet A ResultSetNode for the result set of the
0146: * DML statement
0147: * @param statementType used by nodes that allocate a DMLMod directly
0148: * (rather than inheriting it).
0149: */
0150: public void init(Object resultSet, Object statementType) {
0151: super .init(resultSet);
0152: this .statementType = ((Integer) statementType).intValue();
0153: }
0154:
0155: void setTarget(QueryTreeNode targetName) {
0156: if (targetName instanceof TableName) {
0157: this .targetTableName = (TableName) targetName;
0158: } else {
0159: if (SanityManager.DEBUG) {
0160: if (!(targetName instanceof FromVTI)) {
0161: SanityManager
0162: .THROWASSERT("targetName expected to be FromVTI, not "
0163: + targetName.getClass().getName());
0164: }
0165: }
0166: this .targetVTI = (FromVTI) targetName;
0167: targetVTI.setTarget();
0168: }
0169: }
0170:
0171: /**
0172: * If the DML is on a temporary table, generate the code to mark temporary table as modified in the current UOW.
0173: * At rollback transaction (or savepoint), we will check if the temporary table was modified in that UOW.
0174: * If yes, we will remove all the data from the temporary table
0175: *
0176: * @param acb The ActivationClassBuilder for the class being built
0177: * @param mb The execute() method to be built
0178: *
0179: * @exception StandardException Thrown on error
0180: */
0181: protected void generateCodeForTemporaryTable(
0182: ActivationClassBuilder acb, MethodBuilder mb)
0183: throws StandardException {
0184: if (targetTableDescriptor != null
0185: && targetTableDescriptor.getTableType() == TableDescriptor.GLOBAL_TEMPORARY_TABLE_TYPE
0186: && targetTableDescriptor.isOnRollbackDeleteRows() == true) {
0187: mb.pushThis();
0188: mb.callMethod(VMOpcode.INVOKEINTERFACE,
0189: ClassName.Activation,
0190: "getLanguageConnectionContext",
0191: ClassName.LanguageConnectionContext, 0);
0192: mb.push(targetTableDescriptor.getName());
0193: mb.callMethod(VMOpcode.INVOKEINTERFACE, null,
0194: "markTempTableAsModifiedInUnitOfWork", "void", 1);
0195: mb.endStatement();
0196: }
0197: }
0198:
0199: /**
0200: * Verify the target table. Get the TableDescriptor
0201: * if the target table is not a VTI.
0202: *
0203: * @exception StandardException Thrown on error
0204: */
0205: void verifyTargetTable() throws StandardException {
0206: DataDictionary dataDictionary = getDataDictionary();
0207: if (targetTableName != null) {
0208: /*
0209: ** Get the TableDescriptor for the table we are inserting into
0210: */
0211: SchemaDescriptor sdtc = getSchemaDescriptor(targetTableName
0212: .getSchemaName());
0213:
0214: targetTableDescriptor = getTableDescriptor(targetTableName
0215: .getTableName(), sdtc);
0216:
0217: if (targetTableDescriptor == null) {
0218: // Check if the reference is for a synonym.
0219: TableName synonymTab = resolveTableToSynonym(targetTableName);
0220: if (synonymTab == null)
0221: throw StandardException.newException(
0222: SQLState.LANG_TABLE_NOT_FOUND,
0223: targetTableName);
0224: synonymTableName = targetTableName;
0225: targetTableName = synonymTab;
0226: sdtc = getSchemaDescriptor(targetTableName
0227: .getSchemaName());
0228:
0229: targetTableDescriptor = getTableDescriptor(synonymTab
0230: .getTableName(), sdtc);
0231: if (targetTableDescriptor == null)
0232: throw StandardException.newException(
0233: SQLState.LANG_TABLE_NOT_FOUND,
0234: targetTableName);
0235: }
0236:
0237: switch (targetTableDescriptor.getTableType()) {
0238: case TableDescriptor.VIEW_TYPE:
0239: // Views are currently not updatable
0240: throw StandardException.newException(
0241: SQLState.LANG_VIEW_NOT_UPDATEABLE,
0242: targetTableName);
0243:
0244: case TableDescriptor.VTI_TYPE:
0245: // fall through - currently all vti tables are system tables.
0246: case TableDescriptor.SYSTEM_TABLE_TYPE:
0247: // System tables are not updatable
0248: throw StandardException.newException(
0249: SQLState.LANG_UPDATE_SYSTEM_TABLE_ATTEMPTED,
0250: targetTableName);
0251: default:
0252: break;
0253:
0254: }
0255:
0256: /* We need to get some kind of table lock (IX here), to prevent
0257: * another thread from adding a new index while we are binding,
0258: * if we are a reader in DDL mode. Just a row lock on system table
0259: * SYSCONGLOMERATE is not enough: that wouldn't prevent another
0260: * thread from adding a new entry. Part of the fix for Beetle 3976.
0261: * Same lock as in exec, compatible with row lock, for concurrency.
0262: */
0263: targetTableDescriptor = lockTableForCompilation(targetTableDescriptor);
0264:
0265: getCompilerContext()
0266: .createDependency(targetTableDescriptor);
0267: } else {
0268: /* VTI - VTIs in DML Mod are version 2 VTIs - They
0269: * must implement java.sql.PreparedStatement and have
0270: * the JDBC2.0 getMetaData() and getResultSetConcurrency()
0271: * methods and return an updatable ResultSet.
0272: */
0273: FromList dummyFromList = new FromList();
0274: targetVTI = (FromVTI) targetVTI.bindNonVTITables(
0275: dataDictionary, dummyFromList);
0276: targetVTI = (FromVTI) targetVTI
0277: .bindVTITables(dummyFromList);
0278: }
0279: }
0280:
0281: /**
0282: *
0283: * INSERT/UPDATE/DELETE are always atomic.
0284: *
0285: * @return true
0286: */
0287: public boolean isAtomic() {
0288: return true;
0289: }
0290:
0291: /**
0292: * Get a schema descriptor for the given table.
0293: * Uses this.targetTableName.
0294: *
0295: * @return Schema Descriptor
0296: *
0297: * @exception StandardException throws on schema name
0298: * that doesn't exist
0299: */
0300: public SchemaDescriptor getSchemaDescriptor()
0301: throws StandardException {
0302: SchemaDescriptor sd;
0303:
0304: sd = getSchemaDescriptor(targetTableName.getSchemaName());
0305:
0306: return sd;
0307: }
0308:
0309: /**
0310: Get a map to efficiently find heap columns from a compressed set of
0311: read columns. The returns a map such that
0312:
0313: <PRE>
0314: map[heapColId (0 based)] -> readCol id (0 based)
0315: </PRE>
0316:
0317: @param column_map_length The number of columns(ints) in the map.
0318: @param readColsBitSet A language style (1 based) bit set with bits for
0319: read heap columns set.
0320:
0321: RESOLVE: Replace this with a call to RowUtil when the store and
0322: the language both use 0 base or 1 base offsets for columns. Today
0323: we can't use the store function because we have a 1 based FormatableBitSet.
0324: */
0325: public static int[] getReadColMap(int column_map_length,
0326: FormatableBitSet readColsBitSet) {
0327: if (readColsBitSet == null)
0328: return null;
0329:
0330: int partial_col_cnt = 0;
0331: int column_map[] = new int[column_map_length];
0332: int readColsBitSetSize = readColsBitSet.size();
0333:
0334: for (int base_index = 0; base_index < column_map.length; base_index++) {
0335: if (readColsBitSetSize > base_index
0336: && readColsBitSet.get(base_index + 1))
0337: column_map[base_index] = partial_col_cnt++;
0338: else
0339: // this column map offset entry should never be referenced.
0340: column_map[base_index] = -1;
0341: }
0342:
0343: return (column_map);
0344: }
0345:
0346: /**
0347: * Get and bind the ResultColumnList representing the columns in the
0348: * target table, given the table's name.
0349: *
0350: * @exception StandardException Thrown on error
0351: */
0352: protected void getResultColumnList() throws StandardException {
0353: if (targetVTI == null) {
0354: getResultColumnList((ResultColumnList) null);
0355: } else {
0356: /* binding VTI - just point to VTI's RCL,
0357: * which was already bound.
0358: */
0359: resultColumnList = targetVTI.getResultColumns();
0360: }
0361: }
0362:
0363: /**
0364: * Get and bind the ResultColumnList representing the columns in the
0365: * target table, given the table's name.
0366: *
0367: * @exception StandardException Thrown on error
0368: */
0369: protected FromBaseTable getResultColumnList(
0370: ResultColumnList inputRcl) throws StandardException {
0371: /* Get a ResultColumnList representing all the columns in the target */
0372: FromBaseTable fbt = (FromBaseTable) (getNodeFactory().getNode(
0373: C_NodeTypes.FROM_BASE_TABLE, targetTableName, null,
0374: null, null, getContextManager()));
0375:
0376: fbt.bindNonVTITables(getDataDictionary(),
0377: (FromList) getNodeFactory().getNode(
0378: C_NodeTypes.FROM_LIST,
0379: getNodeFactory().doJoinOrderOptimization(),
0380: getContextManager()));
0381:
0382: getResultColumnList(fbt, inputRcl);
0383: return fbt;
0384: }
0385:
0386: /**
0387: * Get and bind the ResultColumnList representing the columns in the
0388: * target table, given a FromTable for the target table.
0389: *
0390: * @exception StandardException Thrown on error
0391: */
0392: private void getResultColumnList(FromBaseTable fromBaseTable,
0393: ResultColumnList inputRcl) throws StandardException {
0394: if (inputRcl == null) {
0395: resultColumnList = fromBaseTable.getAllResultColumns(null);
0396: resultColumnList
0397: .bindResultColumnsByPosition(targetTableDescriptor);
0398: } else {
0399: resultColumnList = fromBaseTable.getResultColumnsForList(
0400: null, inputRcl, fromBaseTable.getTableNameField());
0401:
0402: resultColumnList.bindResultColumnsByName(
0403: targetTableDescriptor, (DMLStatementNode) this );
0404: }
0405: }
0406:
0407: /**
0408: * Gets and binds all the constraints for an INSERT/UPDATE/DELETE.
0409: * First finds the constraints that are relevant to this node.
0410: * This is done by calling getAllRelevantConstriants(). If
0411: * getAllRelevantConstraints() has already been called, then
0412: * this list is used. Then it creates appropriate
0413: * dependencies. Then binds check constraints. It also
0414: * generates the array of FKInfo items that are used in
0415: * code generation.
0416:
0417: * Note: we have a new flag here to see if defer processing is enabled or
0418: * not, the only scenario that is disabled is when we reapply the
0419: * reply message we get from the source
0420: *
0421: *
0422: * @param dataDictionary The DataDictionary
0423: * @param nodeFactory Where to get query tree nodes.
0424: * @param targetTableDescriptor The TableDescriptor
0425: * @param dependent Parent object that will depend on all the constraints
0426: * that we look up. If this argument is null, then we
0427: * use the default dependent (the statement being compiled).
0428: * @param sourceRCL RCL of the table being changed
0429: * @param changedColumnIds If null, all columns being changed, otherwise array
0430: * of 1-based column ids for columns being changed
0431: * @param readColsBitSet bit set for the read scan
0432: * @param skipCheckConstraints whether to skip check constraints or not
0433: * @param includeTriggers whether triggers are included in the processing
0434: *
0435: * @return The bound, ANDed check constraints as a query tree.
0436: *
0437: * @exception StandardException Thrown on failure
0438: */
0439: public ValueNode bindConstraints(DataDictionary dataDictionary,
0440: NodeFactory nodeFactory,
0441: TableDescriptor targetTableDescriptor, Dependent dependent,
0442: ResultColumnList sourceRCL, int[] changedColumnIds,
0443: FormatableBitSet readColsBitSet,
0444: boolean skipCheckConstraints, boolean includeTriggers)
0445: throws StandardException {
0446: bound = true;
0447:
0448: /* Nothing to do if updatable VTI */
0449: if (targetVTI != null) {
0450: return null;
0451: }
0452:
0453: // Donot need privileges to execute constraints
0454: getCompilerContext().pushCurrentPrivType(Authorizer.NULL_PRIV);
0455: try {
0456: getAllRelevantConstraints(dataDictionary,
0457: targetTableDescriptor, skipCheckConstraints,
0458: changedColumnIds);
0459: createConstraintDependencies(dataDictionary, relevantCdl,
0460: dependent);
0461: generateFKInfo(relevantCdl, dataDictionary,
0462: targetTableDescriptor, readColsBitSet);
0463:
0464: getAllRelevantTriggers(dataDictionary,
0465: targetTableDescriptor, changedColumnIds,
0466: includeTriggers);
0467: createTriggerDependencies(relevantTriggers, dependent);
0468: generateTriggerInfo(relevantTriggers,
0469: targetTableDescriptor, changedColumnIds);
0470:
0471: if (skipCheckConstraints) {
0472: return null;
0473: }
0474:
0475: checkConstraints = generateCheckTree(relevantCdl,
0476: targetTableDescriptor);
0477:
0478: if (checkConstraints != null) {
0479: bindCheckConstraint(nodeFactory, targetTableDescriptor,
0480: sourceRCL, checkConstraints);
0481: }
0482: } finally {
0483: getCompilerContext().popCurrentPrivType();
0484: }
0485:
0486: return checkConstraints;
0487: }
0488:
0489: /**
0490: * Binds an already parsed check constraint
0491: *
0492: * @param nodeFactory Where to get query tree nodes.
0493: * @param targetTableDescriptor The TableDescriptor for the constrained table.
0494: * @param sourceRCL Result columns.
0495: * @param checkConstraint Parsed query tree for check constraint
0496: *
0497: * @exception StandardException Thrown on failure
0498: */
0499: public void bindCheckConstraint(NodeFactory nodeFactory,
0500: TableDescriptor targetTableDescriptor,
0501: ResultColumnList sourceRCL, ValueNode checkConstraint)
0502: throws StandardException {
0503:
0504: TableName targetTableName = makeTableName(targetTableDescriptor
0505: .getSchemaName(), targetTableDescriptor.getName());
0506:
0507: /* We now have the check constraints as a query tree. Now, we prepare
0508: * to bind that query tree to the source's RCL. That way, the
0509: * generated code for the check constraints will be evaluated against the
0510: * source row to be inserted into the target table or
0511: * against the after portion of the source row for the update
0512: * into the target table.
0513: * o Goober up a new FromList which has a single table,
0514: * a goobered up FromBaseTable for the target table
0515: * which has the source's RCL as it RCL.
0516: * (This allows the ColumnReferences in the check constraint
0517: * tree to be bound to the right RCs.)
0518: *
0519: * Note that in some circumstances we may not actually verify
0520: * the constraint against the source RCL but against a temp
0521: * row source used for deferred processing because of a trigger.
0522: * In this case, the caller of bindConstraints (UpdateNode)
0523: * has chosen to pass in the correct RCL to bind against.
0524: */
0525: FromList fakeFromList = (FromList) nodeFactory
0526: .getNode(C_NodeTypes.FROM_LIST, nodeFactory
0527: .doJoinOrderOptimization(), getContextManager());
0528: FromBaseTable table = (FromBaseTable) nodeFactory.getNode(
0529: C_NodeTypes.FROM_BASE_TABLE, targetTableName, null,
0530: sourceRCL, null, getContextManager());
0531: table.setTableNumber(0);
0532: fakeFromList.addFromTable(table);
0533:
0534: // Now we can do the bind.
0535: checkConstraint = checkConstraint.bindExpression(fakeFromList,
0536: (SubqueryList) null, (Vector) null);
0537: }
0538:
0539: /**
0540: * Determine whether or not there are check constraints on the
0541: * specified table.
0542: *
0543: * @param dd The DataDictionary to use
0544: * @param td The TableDescriptor for the table
0545: *
0546: * @return Whether or not there are check constraints on the specified table.
0547: *
0548: * @exception StandardException Thrown on failure
0549: */
0550: protected boolean hasCheckConstraints(DataDictionary dd,
0551: TableDescriptor td) throws StandardException {
0552: ConstraintDescriptorList cdl = dd.getConstraintDescriptors(td);
0553: if (cdl == null)
0554: return false;
0555: ConstraintDescriptorList ccCDL = cdl
0556: .getSubList(DataDictionary.CHECK_CONSTRAINT);
0557:
0558: return (ccCDL.size() > 0);
0559: }
0560:
0561: /**
0562: * Get the ANDing of all appropriate check constraints as 1 giant query tree.
0563: *
0564: * Makes the calling object (usually a Statement) dependent on all the constraints.
0565: *
0566: * @param cdl The constriant descriptor list
0567: * @param td The TableDescriptor
0568: *
0569: * @return The ANDing of all appropriate check constraints as a query tree.
0570: *
0571: * @exception StandardException Thrown on failure
0572: */
0573: private ValueNode generateCheckTree(ConstraintDescriptorList cdl,
0574: TableDescriptor td) throws StandardException {
0575: ConstraintDescriptorList ccCDL = cdl
0576: .getSubList(DataDictionary.CHECK_CONSTRAINT);
0577: int ccCDLSize = ccCDL.size();
0578: ValueNode checkTree = null;
0579:
0580: // Get the text of all the check constraints
0581: for (int index = 0; index < ccCDLSize; index++) {
0582: ConstraintDescriptor cd = ccCDL.elementAt(index);
0583:
0584: String constraintText = cd.getConstraintText();
0585:
0586: // Get the query tree for this constraint
0587: ValueNode oneConstraint = parseCheckConstraint(
0588: constraintText, td);
0589:
0590: // Put a TestConstraintNode above the constraint tree
0591: TestConstraintNode tcn = (TestConstraintNode) getNodeFactory()
0592: .getNode(C_NodeTypes.TEST_CONSTRAINT_NODE,
0593: oneConstraint,
0594: SQLState.LANG_CHECK_CONSTRAINT_VIOLATED,
0595: td.getQualifiedName(),
0596: cd.getConstraintName(), getContextManager());
0597:
0598: // Link consecutive TestConstraintNodes with AND nodes
0599: if (checkTree == null) {
0600: checkTree = tcn;
0601: } else {
0602: checkTree = (ValueNode) getNodeFactory().getNode(
0603: C_NodeTypes.AND_NODE, tcn, checkTree,
0604: getContextManager());
0605: }
0606: }
0607:
0608: return checkTree;
0609: }
0610:
0611: /**
0612: * Generate the FKInfo structures used during code generation.
0613: * For each constraint that isn't a check constraint, add another
0614: * one of these FKInfo structures and then package them up into
0615: * a single array.
0616: *
0617: * @param cdl The constriant descriptor list
0618: * @param dd The DataDictionary
0619: * @param td The TableDescriptor
0620: * @param readColsBitSet columns read
0621: *
0622: * @exception StandardException Thrown on failure
0623: */
0624: private void generateFKInfo(ConstraintDescriptorList cdl,
0625: DataDictionary dd, TableDescriptor td,
0626: FormatableBitSet readColsBitSet) throws StandardException {
0627: Vector fkVector = new Vector(10);
0628: int type;
0629: UUID[] uuids = null;
0630: long[] conglomNumbers = null;
0631: String[] fkNames = null;
0632: ConstraintDescriptorList fkcdl;
0633: ReferencedKeyConstraintDescriptor refcd;
0634: boolean[] isSelfReferencingFK;
0635: ConstraintDescriptorList activeList = dd
0636: .getActiveConstraintDescriptors(cdl);
0637: int[] rowMap = getRowMap(readColsBitSet, td);
0638: int[] raRules = null;
0639: Vector refTableNames = new Vector(1);
0640: Vector refIndexConglomNum = new Vector(1);
0641: Vector refActions = new Vector(1);
0642: Vector refColDescriptors = new Vector(1);
0643: Vector fkColMap = new Vector(1);
0644: int activeSize = activeList.size();
0645: for (int index = 0; index < activeSize; index++) {
0646: ConstraintDescriptor cd = activeList.elementAt(index);
0647:
0648: if (cd instanceof ForeignKeyConstraintDescriptor) {
0649: /*
0650: ** We are saving information for checking the
0651: ** primary/unique key that is referenced by this
0652: ** foreign key, so type is FOREIGN KEY.
0653: */
0654: type = FKInfo.FOREIGN_KEY;
0655: refcd = ((ForeignKeyConstraintDescriptor) cd)
0656: .getReferencedConstraint();
0657: uuids = new UUID[1];
0658: conglomNumbers = new long[1];
0659: fkNames = new String[1];
0660: isSelfReferencingFK = new boolean[1];
0661: raRules = new int[1];
0662: fkSetupArrays(dd, (ForeignKeyConstraintDescriptor) cd,
0663: 0, uuids, conglomNumbers, fkNames,
0664: isSelfReferencingFK, raRules);
0665:
0666: // oops, get the right constraint name -- for error
0667: // handling we want the FK name, not refcd name
0668: fkNames[0] = cd.getConstraintName();
0669: } else if (cd instanceof ReferencedKeyConstraintDescriptor) {
0670: refcd = (ReferencedKeyConstraintDescriptor) cd;
0671:
0672: /*
0673: ** We are saving information for checking the
0674: ** foreign key(s) that is dependent on this referenced
0675: ** key, so type is REFERENCED KEY.
0676: */
0677: type = FKInfo.REFERENCED_KEY;
0678: fkcdl = dd
0679: .getActiveConstraintDescriptors(((ReferencedKeyConstraintDescriptor) cd)
0680: .getForeignKeyConstraints(ConstraintDescriptor.ENABLED));
0681:
0682: int size = fkcdl.size();
0683: if (size == 0) {
0684: continue;
0685: }
0686:
0687: uuids = new UUID[size];
0688: fkNames = new String[size];
0689: conglomNumbers = new long[size];
0690: isSelfReferencingFK = new boolean[size];
0691: raRules = new int[size];
0692: ForeignKeyConstraintDescriptor fkcd = null;
0693: TableDescriptor fktd;
0694: ColumnDescriptorList coldl;
0695: int[] refColumns;
0696: ColumnDescriptor cold;
0697: int[] colArray = remapReferencedColumns(cd, rowMap);
0698: for (int inner = 0; inner < size; inner++) {
0699: fkcd = (ForeignKeyConstraintDescriptor) fkcdl
0700: .elementAt(inner);
0701: fkSetupArrays(dd, fkcd, inner, uuids,
0702: conglomNumbers, fkNames,
0703: isSelfReferencingFK, raRules);
0704: if ((raRules[inner] == StatementType.RA_CASCADE)
0705: || (raRules[inner] == StatementType.RA_SETNULL)) {
0706: //find the referencing table Name
0707: fktd = fkcd.getTableDescriptor();
0708: refTableNames.addElement(fktd.getSchemaName()
0709: + "." + fktd.getName());
0710: refActions.addElement(new Integer(
0711: raRules[inner]));
0712: //find the referencing column name required for update null.
0713: refColumns = fkcd.getReferencedColumns();
0714: coldl = fktd.getColumnDescriptorList();
0715: ColumnDescriptorList releventColDes = new ColumnDescriptorList();
0716: for (int i = 0; i < refColumns.length; i++) {
0717: cold = (ColumnDescriptor) coldl
0718: .elementAt(refColumns[i] - 1);
0719: releventColDes.add(cold);
0720: }
0721: refColDescriptors.addElement(releventColDes);
0722: refIndexConglomNum.addElement(new Long(
0723: conglomNumbers[inner]));
0724: fkColMap.addElement(colArray);
0725: }
0726: }
0727: } else {
0728: continue;
0729: }
0730:
0731: TableDescriptor pktd = refcd.getTableDescriptor();
0732: UUID pkuuid = refcd.getIndexId();
0733: ConglomerateDescriptor pkIndexConglom = pktd
0734: .getConglomerateDescriptor(pkuuid);
0735:
0736: TableDescriptor refTd = cd.getTableDescriptor();
0737: fkVector.addElement(new FKInfo(fkNames, // foreign key names
0738: refTd.getName(), // table being modified
0739: statementType, // INSERT|UPDATE|DELETE
0740: type, // FOREIGN_KEY|REFERENCED_KEY
0741: pkuuid, // referenced backing index uuid
0742: pkIndexConglom.getConglomerateNumber(), // referened backing index conglom
0743: uuids, // fk backing index uuids
0744: conglomNumbers, // fk backing index congloms
0745: isSelfReferencingFK, // is self ref array of bool
0746: remapReferencedColumns(cd, rowMap), // column referened by key
0747: dd.getRowLocationTemplate(
0748: getLanguageConnectionContext(), refTd),
0749: // row location template for table being modified
0750: raRules)); // referential action rules
0751:
0752: }
0753:
0754: /*
0755: ** Now convert the vector into an array.
0756: */
0757: int size = fkVector.size();
0758: if (size > 0) {
0759: fkInfo = new FKInfo[size];
0760: for (int i = 0; i < size; i++) {
0761: fkInfo[i] = (FKInfo) fkVector.elementAt(i);
0762: }
0763: }
0764:
0765: //convert the ref action info vectors to to arrays
0766: size = refActions.size();
0767: if (size > 0) {
0768: fkTableNames = new String[size];
0769: fkRefActions = new int[size];
0770: fkColDescriptors = new ColumnDescriptorList[size];
0771: fkIndexConglomNumbers = new long[size];
0772: fkColArrays = new int[size][];
0773: for (int i = 0; i < size; i++) {
0774: fkTableNames[i] = (String) refTableNames.elementAt(i);
0775: fkRefActions[i] = ((Integer) refActions.elementAt(i))
0776: .intValue();
0777: fkColDescriptors[i] = (ColumnDescriptorList) refColDescriptors
0778: .elementAt(i);
0779: fkIndexConglomNumbers[i] = ((Long) refIndexConglomNum
0780: .elementAt(i)).longValue();
0781: fkColArrays[i] = ((int[]) fkColMap.elementAt(i));
0782: }
0783: }
0784:
0785: }
0786:
0787: /*
0788: ** Simple little helper method
0789: */
0790: private void fkSetupArrays(DataDictionary dd,
0791: ForeignKeyConstraintDescriptor fkcd, int index,
0792: UUID[] uuids, long[] conglomNumbers, String[] fkNames,
0793: boolean[] isSelfReferencingFK, int[] raRules)
0794: throws StandardException {
0795: fkNames[index] = fkcd.getConstraintName();
0796: uuids[index] = fkcd.getIndexId();
0797: conglomNumbers[index] = fkcd.getIndexConglomerateDescriptor(dd)
0798: .getConglomerateNumber();
0799: isSelfReferencingFK[index] = fkcd.isSelfReferencingFK();
0800: if (statementType == StatementType.DELETE)
0801: raRules[index] = fkcd.getRaDeleteRule();
0802: else if (statementType == StatementType.UPDATE)
0803: raRules[index] = fkcd.getRaUpdateRule();
0804: }
0805:
0806: /**
0807: * Generate the TriggerInfo structures used during code generation.
0808: *
0809: * @param triggerList The trigger descriptor list
0810: * @param td The TableDescriptor
0811: * @param changedCols The columns that are being modified
0812: *
0813: * @exception StandardException Thrown on failure
0814: */
0815: private void generateTriggerInfo(GenericDescriptorList triggerList,
0816: TableDescriptor td, int[] changedCols)
0817: throws StandardException {
0818: if ((triggerList != null) && (triggerList.size() > 0)) {
0819: triggerInfo = new TriggerInfo(td, changedCols, triggerList);
0820: }
0821: }
0822:
0823: /**
0824: * Return the FKInfo structure. Just a little wrapper
0825: * to make sure we don't try to access it until after
0826: * binding.
0827: *
0828: * @return the array of fkinfos
0829: */
0830: public FKInfo[] getFKInfo() {
0831: if (SanityManager.DEBUG) {
0832: SanityManager.ASSERT(bound, "attempt to access FKInfo "
0833: + "before binding");
0834: }
0835: return fkInfo;
0836: }
0837:
0838: /**
0839: * Return the TriggerInfo structure. Just a little wrapper
0840: * to make sure we don't try to access it until after
0841: * binding.
0842: *
0843: * @return the trigger info
0844: */
0845: public TriggerInfo getTriggerInfo() {
0846: if (SanityManager.DEBUG) {
0847: SanityManager
0848: .ASSERT(bound, "attempt to access TriggerInfo "
0849: + "before binding");
0850: }
0851: return triggerInfo;
0852: }
0853:
0854: /**
0855: * Get the check constraints for this node
0856: *
0857: * @return the check constraints, may be null
0858: */
0859: public ValueNode getCheckConstraints() {
0860: if (SanityManager.DEBUG) {
0861: SanityManager.ASSERT(bound, "attempt to access FKInfo "
0862: + "before binding");
0863: }
0864: return checkConstraints;
0865: }
0866:
0867: /**
0868: * Makes the calling object (usually a Statement) dependent on all the constraints.
0869: *
0870: * @param tdl The trigger descriptor list
0871: * @param dependent Parent object that will depend on all the constraints
0872: * that we look up. If this argument is null, then we
0873: * use the default dependent (the statement being compiled).
0874: *
0875: * @exception StandardException Thrown on failure
0876: */
0877: private void createTriggerDependencies(GenericDescriptorList tdl,
0878: Dependent dependent) throws StandardException {
0879: CompilerContext compilerContext = getCompilerContext();
0880:
0881: Enumeration descs = tdl.elements();
0882:
0883: while (descs.hasMoreElements()) {
0884: TriggerDescriptor td = (TriggerDescriptor) descs
0885: .nextElement();
0886:
0887: /*
0888: ** The dependent now depends on this trigger.
0889: ** the default dependent is the statement
0890: ** being compiled.
0891: */
0892: if (dependent == null) {
0893: compilerContext.createDependency(td);
0894: } else {
0895: compilerContext.createDependency(dependent, td);
0896: }
0897: }
0898: }
0899:
0900: /**
0901: * Get all the triggers relevant to this DML operation
0902: *
0903: * @param dd The data dictionary
0904: * @param td The TableDescriptor
0905: * @param changedColumnIds If null, all columns being changed, otherwise array
0906: * of 1-based column ids for columns being changed
0907: * @param includeTriggers whether we allow trigger processing or not for
0908: * this table
0909: *
0910: * @return the constraint descriptor list
0911: *
0912: * @exception StandardException Thrown on failure
0913: */
0914: protected GenericDescriptorList getAllRelevantTriggers(
0915: DataDictionary dd, TableDescriptor td,
0916: int[] changedColumnIds, boolean includeTriggers)
0917: throws StandardException {
0918: if (relevantTriggers != null) {
0919: return relevantTriggers;
0920: }
0921:
0922: relevantTriggers = new GenericDescriptorList();
0923:
0924: if (!includeTriggers)
0925: return relevantTriggers;
0926:
0927: td.getAllRelevantTriggers(statementType, changedColumnIds,
0928: relevantTriggers);
0929: adjustDeferredFlag(relevantTriggers.size() > 0);
0930: return relevantTriggers;
0931: }
0932:
0933: protected void adjustDeferredFlag(boolean adjustment) {
0934: if (!requiresDeferredProcessing) {
0935: requiresDeferredProcessing = adjustment;
0936: }
0937: }
0938:
0939: /**
0940: * Get all of our dependents due to a constraint.
0941: *
0942: * Makes the calling object (usually a Statement) dependent on all the constraints.
0943: *
0944: * @param dd The data dictionary
0945: * @param cdl The constraint descriptor list
0946: * @param dependent Parent object that will depend on all the constraints
0947: * that we look up. If this argument is null, then we
0948: * use the default dependent (the statement being compiled).
0949: *
0950: * @exception StandardException Thrown on failure
0951: */
0952: private void createConstraintDependencies(DataDictionary dd,
0953: ConstraintDescriptorList cdl, Dependent dependent)
0954: throws StandardException {
0955: CompilerContext compilerContext = getCompilerContext();
0956:
0957: int cdlSize = cdl.size();
0958: for (int index = 0; index < cdlSize; index++) {
0959: ConstraintDescriptor cd = cdl.elementAt(index);
0960:
0961: /*
0962: ** The dependent now depends on this constraint.
0963: ** the default dependent is the statement
0964: ** being compiled.
0965: */
0966: if (dependent == null) {
0967: compilerContext.createDependency(cd);
0968: } else {
0969: compilerContext.createDependency(dependent, cd);
0970: }
0971:
0972: /*
0973: ** We are also dependent on all referencing keys --
0974: ** if one of them is deleted, we'll have to recompile.
0975: ** Also, if there is a BULK_INSERT on the table
0976: ** we are going to scan to validate the constraint,
0977: ** the index number will change, so we'll add a
0978: ** dependency on all tables we will scan.
0979: */
0980: if (cd instanceof ReferencedKeyConstraintDescriptor) {
0981: ConstraintDescriptorList fkcdl = dd
0982: .getActiveConstraintDescriptors(((ReferencedKeyConstraintDescriptor) cd)
0983: .getForeignKeyConstraints(ConstraintDescriptor.ENABLED));
0984:
0985: int fklSize = fkcdl.size();
0986: for (int inner = 0; inner < fklSize; inner++) {
0987: ConstraintDescriptor fkcd = fkcdl.elementAt(inner);
0988: if (dependent == null) {
0989: compilerContext.createDependency(fkcd);
0990: compilerContext.createDependency(fkcd
0991: .getTableDescriptor());
0992: } else {
0993: compilerContext.createDependency(dependent,
0994: fkcd);
0995: compilerContext.createDependency(dependent,
0996: fkcd.getTableDescriptor());
0997: }
0998: }
0999: } else if (cd instanceof ForeignKeyConstraintDescriptor) {
1000: ForeignKeyConstraintDescriptor fkcd = (ForeignKeyConstraintDescriptor) cd;
1001: if (dependent == null) {
1002: compilerContext.createDependency(fkcd
1003: .getReferencedConstraint()
1004: .getTableDescriptor());
1005: } else {
1006: compilerContext.createDependency(dependent, fkcd
1007: .getReferencedConstraint()
1008: .getTableDescriptor());
1009: }
1010: }
1011: }
1012: }
1013:
1014: /**
1015: * Get all the constraints relevant to this DML operation
1016: *
1017: * @param dd The DataDictionary
1018: * @param td The TableDescriptor
1019: * @param skipCheckConstraints Skip check constraints
1020: * @param changedColumnIds If null, all columns being changed, otherwise array
1021: * of 1-based column ids for columns being changed
1022: *
1023: * @return the constraint descriptor list
1024: *
1025: * @exception StandardException Thrown on failure
1026: */
1027: protected ConstraintDescriptorList getAllRelevantConstraints(
1028: DataDictionary dd, TableDescriptor td,
1029: boolean skipCheckConstraints, int[] changedColumnIds)
1030: throws StandardException {
1031: if (relevantCdl != null) {
1032: return relevantCdl;
1033: }
1034:
1035: boolean[] needsDeferredProcessing = new boolean[1];
1036: relevantCdl = new ConstraintDescriptorList();
1037:
1038: needsDeferredProcessing[0] = requiresDeferredProcessing;
1039: td.getAllRelevantConstraints(statementType,
1040: skipCheckConstraints, changedColumnIds,
1041: needsDeferredProcessing, relevantCdl);
1042:
1043: adjustDeferredFlag(needsDeferredProcessing[0]);
1044:
1045: return relevantCdl;
1046: }
1047:
1048: /**
1049: * Does this DML Node require deferred processing?
1050: * Set to true if we have triggers or referential
1051: * constraints that need deferred processing.
1052: *
1053: * @return true/false
1054: */
1055: public boolean requiresDeferredProcessing() {
1056: return requiresDeferredProcessing;
1057: }
1058:
1059: /**
1060: * Parse a check constraint and turn it into a query tree.
1061: *
1062: * @param checkConstraintText Text of CHECK CONSTRAINT.
1063: * @param td The TableDescriptor for the table the the constraint is on.
1064: *
1065: *
1066: * @return The parsed check constraint as a query tree.
1067: *
1068: * @exception StandardException Thrown on failure
1069: */
1070: public ValueNode parseCheckConstraint(String checkConstraintText,
1071: TableDescriptor td) throws StandardException {
1072: Parser p;
1073: ValueNode checkTree;
1074: LanguageConnectionContext lcc = getLanguageConnectionContext();
1075: CompilerContext compilerContext = getCompilerContext();
1076:
1077: /* Get a Statement to pass to the parser */
1078:
1079: /* We're all set up to parse. We have to build a compile SQL statement
1080: * before we can parse - we just have a WHERE clause right now.
1081: * So, we goober up a SELECT * FROM table WHERE checkDefs.
1082: */
1083: String select = "SELECT * FROM " + td.getQualifiedName()
1084: + " WHERE " + checkConstraintText;
1085:
1086: /*
1087: ** Get a new compiler context, so the parsing of the select statement
1088: ** doesn't mess up anything in the current context (it could clobber
1089: ** the ParameterValueSet, for example).
1090: */
1091: CompilerContext newCC = lcc.pushCompilerContext();
1092:
1093: p = newCC.getParser();
1094:
1095: /* Finally, we can call the parser */
1096: // Since this is always nested inside another SQL statement, so topLevel flag
1097: // should be false
1098: QueryTreeNode qt = p.parseStatement(select);
1099: if (SanityManager.DEBUG) {
1100: if (!(qt instanceof CursorNode)) {
1101: SanityManager
1102: .THROWASSERT("qt expected to be instanceof CursorNode, not "
1103: + qt.getClass().getName());
1104: }
1105: CursorNode cn = (CursorNode) qt;
1106: if (!(cn.getResultSetNode() instanceof SelectNode)) {
1107: SanityManager
1108: .THROWASSERT("cn.getResultSetNode() expected to be instanceof SelectNode, not "
1109: + cn.getResultSetNode().getClass()
1110: .getName());
1111: }
1112: }
1113:
1114: checkTree = ((SelectNode) ((CursorNode) qt).getResultSetNode())
1115: .getWhereClause();
1116:
1117: lcc.popCompilerContext(newCC);
1118:
1119: return checkTree;
1120: }
1121:
1122: /**
1123: * Generate the code to evaluate a tree of CHECK CONSTRAINTS.
1124: *
1125: * @param checkConstraints Bound query tree of ANDed check constraints.
1126: * @param ecb Expression Class Builder
1127: *
1128: *
1129: *
1130: * @exception StandardException Thrown on error
1131: */
1132: public void generateCheckConstraints(ValueNode checkConstraints,
1133: ExpressionClassBuilder ecb, MethodBuilder mb)
1134: throws StandardException {
1135: // for the check constraints, we generate an exprFun
1136: // that evaluates the expression of the clause
1137: // against the current row of the child's result.
1138: // if there are no check constraints, simply pass null
1139: // to optimize for run time performance.
1140:
1141: // generate the function and initializer:
1142: // Note: Boolean lets us return nulls (boolean would not)
1143: // private Boolean exprN()
1144: // {
1145: // return <<checkConstraints.generate(ps)>>;
1146: // }
1147: // static Method exprN = method pointer to exprN;
1148:
1149: // if there is no check constraint, we just want to pass null.
1150: if (checkConstraints == null) {
1151: mb.pushNull(ClassName.GeneratedMethod);
1152: } else {
1153: MethodBuilder userExprFun = generateCheckConstraints(
1154: checkConstraints, ecb);
1155:
1156: // check constraint is used in the final result set
1157: // as an access of the new static
1158: // field holding a reference to this new method.
1159: ecb.pushMethodReference(mb, userExprFun);
1160: }
1161: }
1162:
1163: /**
1164: * Generate a method to evaluate a tree of CHECK CONSTRAINTS.
1165: *
1166: * @param checkConstraints Bound query tree of ANDed check constraints.
1167: * @param ecb Expression Class Builder
1168: *
1169: *
1170: *
1171: * @exception StandardException Thrown on error
1172: */
1173: public MethodBuilder generateCheckConstraints(
1174: ValueNode checkConstraints, ExpressionClassBuilder ecb)
1175: throws StandardException {
1176: // this sets up the method and the static field.
1177: // generates:
1178: // java.lang.Object userExprFun { }
1179: MethodBuilder userExprFun = ecb.newUserExprFun();
1180:
1181: // check constraint knows it is returning its value;
1182:
1183: /* generates:
1184: * return <checkExpress.generate(ecb)>;
1185: * and adds it to userExprFun
1186: */
1187:
1188: checkConstraints.generateExpression(ecb, userExprFun);
1189: userExprFun.methodReturn();
1190:
1191: // we are done modifying userExprFun, complete it.
1192: userExprFun.complete();
1193:
1194: return userExprFun;
1195: }
1196:
1197: /**
1198: * Generate an optimized QueryTree from a bound QueryTree. Actually,
1199: * it can annotate the tree in place rather than generate a new tree,
1200: * but this interface allows the root node of the optimized QueryTree
1201: * to be different from the root node of the bound QueryTree.
1202: *
1203: * For non-optimizable statements, this method is a no-op.
1204: *
1205: * Throws an exception if the tree is not bound, or if the binding
1206: * is out of date.
1207: *
1208: * @return An optimized QueryTree
1209: *
1210: * @exception StandardException Thrown on failure
1211: */
1212: public QueryTreeNode optimize() throws StandardException {
1213: ResultSetNode originalRSNode = getResultSetNode();
1214:
1215: /* First optimize the query */
1216: QueryTreeNode retval = super .optimize();
1217:
1218: /* In language we always set it to row lock, it's up to store to
1219: * upgrade it to table lock. This makes sense for the default read
1220: * committed isolation level and update lock. For more detail, see
1221: * Beetle 4133.
1222: */
1223: lockMode = TransactionController.MODE_RECORD;
1224:
1225: return retval;
1226: }
1227:
1228: /**
1229: * Get the list of indexes that must be updated by this DML statement.
1230: * WARNING: As a side effect, it creates dependencies on those indexes.
1231: *
1232: * @param td The table descriptor for the table being updated
1233: * @param updatedColumns The updated column list. If not update, null
1234: * @param colBitSet a 1 based bit set of the columns in the list
1235: *
1236: * @exception StandardException Thrown on error
1237: */
1238: protected void getAffectedIndexes(TableDescriptor td,
1239: ResultColumnList updatedColumns, FormatableBitSet colBitSet)
1240: throws StandardException {
1241: Vector conglomVector = new Vector();
1242:
1243: DMLModStatementNode.getXAffectedIndexes(td, updatedColumns,
1244: colBitSet, conglomVector);
1245:
1246: markAffectedIndexes(conglomVector);
1247: }
1248:
1249: /**
1250: * Marks which indexes are affected by an UPDATE of the
1251: * desired shape.
1252: *
1253: * Is passed a list of updated columns. Does the following:
1254: *
1255: * 1) finds all indices which overlap the updated columns
1256: * 2) adds the index columns to a bitmap of affected columns
1257: * 3) adds the index descriptors to a list of conglomerate
1258: * descriptors.
1259: *
1260: * @param updatedColumns a list of updated columns
1261: * @param colBitSet OUT: evolving bitmap of affected columns
1262: * @param conglomVector OUT: vector of affected indices
1263: *
1264: * @exception StandardException Thrown on error
1265: */
1266: static void getXAffectedIndexes(TableDescriptor baseTable,
1267: ResultColumnList updatedColumns,
1268: FormatableBitSet colBitSet, Vector conglomVector)
1269: throws StandardException {
1270: ConglomerateDescriptor[] cds = baseTable
1271: .getConglomerateDescriptors();
1272:
1273: /* we only get distinct conglomerate numbers. If duplicate indexes
1274: * share one conglomerate, we only return one number.
1275: */
1276: long[] distinctConglomNums = new long[cds.length - 1];
1277: int distinctCount = 0;
1278:
1279: for (int index = 0; index < cds.length; index++) {
1280: ConglomerateDescriptor cd = cds[index];
1281:
1282: if (!cd.isIndex()) {
1283: continue;
1284: }
1285:
1286: /*
1287: ** If this index doesn't contain any updated
1288: ** columns, then we can skip it.
1289: */
1290: if ((updatedColumns != null)
1291: && (!updatedColumns
1292: .updateOverlaps(cd.getIndexDescriptor()
1293: .baseColumnPositions()))) {
1294: continue;
1295: }
1296:
1297: if (conglomVector != null) {
1298: int i;
1299: for (i = 0; i < distinctCount; i++) {
1300: if (distinctConglomNums[i] == cd
1301: .getConglomerateNumber())
1302: break;
1303: }
1304: if (i == distinctCount) // first appearence
1305: {
1306: distinctConglomNums[distinctCount++] = cd
1307: .getConglomerateNumber();
1308: conglomVector.addElement(cd);
1309: }
1310: }
1311:
1312: IndexRowGenerator ixd = cd.getIndexDescriptor();
1313: int[] cols = ixd.baseColumnPositions();
1314:
1315: if (colBitSet != null) {
1316: for (int i = 0; i < cols.length; i++) {
1317: colBitSet.set(cols[i]);
1318: }
1319: } // end IF
1320: } // end loop through conglomerates
1321:
1322: }
1323:
1324: protected void markAffectedIndexes(Vector affectedConglomerates)
1325: throws StandardException {
1326: ConglomerateDescriptor cd;
1327: int indexCount = affectedConglomerates.size();
1328: CompilerContext cc = getCompilerContext();
1329:
1330: indicesToMaintain = new IndexRowGenerator[indexCount];
1331: indexConglomerateNumbers = new long[indexCount];
1332: indexNames = new String[indexCount];
1333:
1334: for (int ictr = 0; ictr < indexCount; ictr++) {
1335: cd = (ConglomerateDescriptor) affectedConglomerates
1336: .elementAt(ictr);
1337:
1338: indicesToMaintain[ictr] = cd.getIndexDescriptor();
1339: indexConglomerateNumbers[ictr] = cd.getConglomerateNumber();
1340: indexNames[ictr] = ((cd.isConstraint()) ? null : cd
1341: .getConglomerateName());
1342:
1343: cc.createDependency(cd);
1344: }
1345:
1346: }
1347:
1348: public String statementToString() {
1349: return "DML MOD";
1350: }
1351:
1352: /**
1353: * Remap referenced columns in the cd to reflect the
1354: * passed in row map.
1355: *
1356: * @param cd constraint descriptor
1357: * @param rowMap 1 based row map
1358: */
1359: private int[] remapReferencedColumns(ConstraintDescriptor cd,
1360: int[] rowMap) {
1361: int[] oldCols = cd.getReferencedColumns();
1362: if (rowMap == null) {
1363: return oldCols;
1364: }
1365:
1366: int[] newCols = new int[oldCols.length];
1367: for (int i = 0; i < oldCols.length; i++) {
1368: newCols[i] = rowMap[oldCols[i]];
1369: if (SanityManager.DEBUG) {
1370: SanityManager
1371: .ASSERT(
1372: newCols[i] != 0,
1373: "attempt to map a column "
1374: + oldCols[i]
1375: + " which is not in our new column map. Something is "
1376: + "wrong with the logic to do partial reads for an update stmt");
1377: }
1378: }
1379: return newCols;
1380: }
1381:
1382: /**
1383: * Get a integer based row map from a bit set.
1384: *
1385: * @param bitSet
1386: * @param td
1387: *
1388: */
1389: private int[] getRowMap(FormatableBitSet bitSet, TableDescriptor td)
1390: throws StandardException {
1391: if (bitSet == null) {
1392: return (int[]) null;
1393: }
1394:
1395: int size = td.getMaxColumnID();
1396: int[] iArray = new int[size + 1];
1397: int j = 1;
1398: for (int i = 1; i <= size; i++) {
1399: if (bitSet.get(i)) {
1400: iArray[i] = j++;
1401: }
1402: }
1403: return iArray;
1404: }
1405:
1406: public void setRefActionInfo(long fkIndexConglomId,
1407: int[] fkColArray, String parentResultSetId,
1408: boolean dependentScan) {
1409: resultSet.setRefActionInfo(fkIndexConglomId, fkColArray,
1410: parentResultSetId, dependentScan);
1411: }
1412:
1413: /**
1414: * Normalize synonym column references to have the name of the base table.
1415: *
1416: * @param rcl The result column list of the target table
1417: * @param targetTableName The target tablename
1418: *
1419: * @exception StandardException Thrown on error
1420: */
1421: public void normalizeSynonymColumns(ResultColumnList rcl,
1422: TableName targetTableName) throws StandardException {
1423: if (synonymTableName == null)
1424: return;
1425:
1426: String synTableName = synonymTableName.getTableName();
1427:
1428: int count = rcl.size();
1429: for (int i = 0; i < count; i++) {
1430: ResultColumn column = (ResultColumn) rcl.elementAt(i);
1431: ColumnReference reference = column.getReference();
1432:
1433: if (reference != null) {
1434: String crTableName = reference.getTableName();
1435: if (crTableName != null) {
1436: if (synTableName.equals(crTableName)) {
1437: reference.setTableNameNode(targetTableName);
1438: } else {
1439: throw StandardException.newException(
1440: SQLState.LANG_TABLE_NAME_MISMATCH,
1441: synTableName, crTableName);
1442: }
1443: }
1444: }
1445: }
1446: }
1447: }
|