0001: /*
0002:
0003: Derby - Class org.apache.derby.impl.sql.compile.BinaryRelationalOperatorNode
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.reference.ClassName;
0025: import org.apache.derby.iapi.reference.JDBC30Translation;
0026:
0027: import org.apache.derby.iapi.util.JBitSet;
0028:
0029: import org.apache.derby.iapi.services.loader.GeneratedMethod;
0030:
0031: import org.apache.derby.iapi.services.compiler.MethodBuilder;
0032:
0033: import org.apache.derby.iapi.services.sanity.SanityManager;
0034:
0035: import org.apache.derby.iapi.error.StandardException;
0036:
0037: import org.apache.derby.iapi.sql.compile.C_NodeTypes;
0038: import org.apache.derby.iapi.sql.compile.Optimizable;
0039:
0040: import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;
0041:
0042: import org.apache.derby.iapi.store.access.Qualifier;
0043: import org.apache.derby.iapi.store.access.ScanController;
0044:
0045: import org.apache.derby.iapi.types.DataValueDescriptor;
0046: import org.apache.derby.iapi.types.TypeId;
0047: import org.apache.derby.iapi.types.DataValueDescriptor;
0048:
0049: import org.apache.derby.iapi.types.Orderable;
0050:
0051: import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;
0052:
0053: import java.sql.Types;
0054:
0055: /**
0056: * This class represents the 6 binary operators: LessThan, LessThanEquals,
0057: * Equals, NotEquals, GreaterThan and GreaterThanEquals.
0058: *
0059: * @author Manish Khettry
0060: */
0061:
0062: public class BinaryRelationalOperatorNode extends
0063: BinaryComparisonOperatorNode implements RelationalOperator {
0064: private int operatorType;
0065: /* RelationalOperator Interface */
0066:
0067: // Visitor for finding base tables beneath optimizables and column
0068: // references. Created once and re-used thereafter.
0069: private BaseTableNumbersVisitor btnVis;
0070:
0071: // Bit sets for holding base tables beneath optimizables and
0072: // column references. Created once and re-used thereafter.
0073: JBitSet optBaseTables;
0074: JBitSet valNodeBaseTables;
0075:
0076: public void init(Object leftOperand, Object rightOperand) {
0077: String methodName = "";
0078: String operatorName = "";
0079:
0080: switch (getNodeType()) {
0081: case C_NodeTypes.BINARY_EQUALS_OPERATOR_NODE:
0082: methodName = "equals";
0083: operatorName = "=";
0084: operatorType = RelationalOperator.EQUALS_RELOP;
0085: break;
0086:
0087: case C_NodeTypes.BINARY_GREATER_EQUALS_OPERATOR_NODE:
0088: methodName = "greaterOrEquals";
0089: operatorName = ">=";
0090: operatorType = RelationalOperator.GREATER_EQUALS_RELOP;
0091: break;
0092:
0093: case C_NodeTypes.BINARY_GREATER_THAN_OPERATOR_NODE:
0094: methodName = "greaterThan";
0095: operatorName = ">";
0096: operatorType = RelationalOperator.GREATER_THAN_RELOP;
0097: break;
0098:
0099: case C_NodeTypes.BINARY_LESS_EQUALS_OPERATOR_NODE:
0100: methodName = "lessOrEquals";
0101: operatorName = "<=";
0102: operatorType = RelationalOperator.LESS_EQUALS_RELOP;
0103: break;
0104:
0105: case C_NodeTypes.BINARY_LESS_THAN_OPERATOR_NODE:
0106: methodName = "lessThan";
0107: operatorName = "<";
0108: operatorType = RelationalOperator.LESS_THAN_RELOP;
0109: break;
0110: case C_NodeTypes.BINARY_NOT_EQUALS_OPERATOR_NODE:
0111: methodName = "notEquals";
0112: operatorName = "<>";
0113: operatorType = RelationalOperator.NOT_EQUALS_RELOP;
0114: break;
0115:
0116: default:
0117: if (SanityManager.DEBUG) {
0118: SanityManager
0119: .THROWASSERT("init for BinaryRelationalOperator called with wrong nodeType = "
0120: + getNodeType());
0121: }
0122: break;
0123: }
0124: super .init(leftOperand, rightOperand, operatorName, methodName);
0125: btnVis = null;
0126: }
0127:
0128: /** @see RelationalOperator#getColumnOperand */
0129: public ColumnReference getColumnOperand(Optimizable optTable,
0130: int columnPosition) {
0131: FromTable ft = (FromTable) optTable;
0132:
0133: // When searching for a matching column operand, we search
0134: // the entire subtree (if there is one) beneath optTable
0135: // to see if we can find any FromTables that correspond to
0136: // either of this op's column references.
0137:
0138: ColumnReference cr;
0139: boolean walkSubtree = true;
0140: if (leftOperand instanceof ColumnReference) {
0141: /*
0142: ** The left operand is a column reference.
0143: ** Is it the correct column?
0144: */
0145: cr = (ColumnReference) leftOperand;
0146: if (valNodeReferencesOptTable(cr, ft, false, walkSubtree)) {
0147: /*
0148: ** The table is correct, how about the column position?
0149: */
0150: if (cr.getSource().getColumnPosition() == columnPosition) {
0151: /* We've found the correct column - return it */
0152: return cr;
0153: }
0154: }
0155: walkSubtree = false;
0156: }
0157:
0158: if (rightOperand instanceof ColumnReference) {
0159: /*
0160: ** The right operand is a column reference.
0161: ** Is it the correct column?
0162: */
0163: cr = (ColumnReference) rightOperand;
0164: if (valNodeReferencesOptTable(cr, ft, false, walkSubtree)) {
0165: /*
0166: ** The table is correct, how about the column position?
0167: */
0168: if (cr.getSource().getColumnPosition() == columnPosition) {
0169: /* We've found the correct column - return it */
0170: return cr;
0171: }
0172: }
0173: }
0174:
0175: /* Neither side is the column we're looking for */
0176: return null;
0177: }
0178:
0179: /** @see RelationalOperator#getColumnOperand */
0180: public ColumnReference getColumnOperand(Optimizable optTable) {
0181: ColumnReference cr;
0182:
0183: boolean walkSubtree = true;
0184: if (leftOperand instanceof ColumnReference) {
0185: /*
0186: ** The left operand is a column reference.
0187: ** Is it the correct column?
0188: */
0189: cr = (ColumnReference) leftOperand;
0190: if (valNodeReferencesOptTable(cr, (FromTable) optTable,
0191: false, walkSubtree)) {
0192: /*
0193: ** The table is correct.
0194: */
0195: return cr;
0196: }
0197: walkSubtree = false;
0198: }
0199:
0200: if (rightOperand instanceof ColumnReference) {
0201: /*
0202: ** The right operand is a column reference.
0203: ** Is it the correct column?
0204: */
0205: cr = (ColumnReference) rightOperand;
0206: if (valNodeReferencesOptTable(cr, (FromTable) optTable,
0207: false, walkSubtree)) {
0208: /*
0209: ** The table is correct
0210: */
0211: return cr;
0212: }
0213: }
0214:
0215: /* Neither side is the column we're looking for */
0216: return null;
0217: }
0218:
0219: /**
0220: * @see RelationalOperator#getExpressionOperand
0221: */
0222: public ValueNode getExpressionOperand(int tableNumber,
0223: int columnPosition, FromTable ft) {
0224: ColumnReference cr;
0225: boolean walkSubtree = true;
0226:
0227: if (leftOperand instanceof ColumnReference) {
0228: /*
0229: ** The left operand is a column reference.
0230: ** Is it the correct column?
0231: */
0232: cr = (ColumnReference) leftOperand;
0233: if (valNodeReferencesOptTable(cr, ft, false, walkSubtree)) {
0234: /*
0235: ** The table is correct, how about the column position?
0236: */
0237: if (cr.getSource().getColumnPosition() == columnPosition) {
0238: /*
0239: ** We've found the correct column -
0240: ** return the other side
0241: */
0242: return rightOperand;
0243: }
0244: }
0245: walkSubtree = false;
0246: }
0247:
0248: if (rightOperand instanceof ColumnReference) {
0249: /*
0250: ** The right operand is a column reference.
0251: ** Is it the correct column?
0252: */
0253: cr = (ColumnReference) rightOperand;
0254: if (valNodeReferencesOptTable(cr, ft, false, walkSubtree)) {
0255: /*
0256: ** The table is correct, how about the column position?
0257: */
0258: if (cr.getSource().getColumnPosition() == columnPosition) {
0259: /*
0260: ** We've found the correct column -
0261: ** return the other side
0262: */
0263: return leftOperand;
0264: }
0265: }
0266: }
0267:
0268: return null;
0269: }
0270:
0271: /**
0272: * @see RelationalOperator#getOperand
0273: */
0274: public ValueNode getOperand(ColumnReference cRef, int refSetSize,
0275: boolean otherSide) {
0276: // Following call will initialize/reset the btnVis,
0277: // valNodeBaseTables, and optBaseTables fields of this object.
0278: initBaseTableVisitor(refSetSize, true);
0279:
0280: // We search for the column reference by getting the *base*
0281: // table number for each operand and checking to see if
0282: // that matches the *base* table number for the cRef
0283: // that we're looking for. If so, then we the two
0284: // reference the same table so we go on to check
0285: // column position.
0286: try {
0287:
0288: // Use optBaseTables for cRef's base table numbers.
0289: btnVis.setTableMap(optBaseTables);
0290: cRef.accept(btnVis);
0291:
0292: // Use valNodeBaseTables for operand base table nums.
0293: btnVis.setTableMap(valNodeBaseTables);
0294:
0295: ColumnReference cr;
0296: if (leftOperand instanceof ColumnReference) {
0297: /*
0298: ** The left operand is a column reference.
0299: ** Is it the correct column?
0300: */
0301: cr = (ColumnReference) leftOperand;
0302: cr.accept(btnVis);
0303: valNodeBaseTables.and(optBaseTables);
0304: if (valNodeBaseTables.getFirstSetBit() != -1) {
0305: /*
0306: ** The table is correct, how about the column position?
0307: */
0308: if (cr.getSource().getColumnPosition() == cRef
0309: .getColumnNumber()) {
0310: /*
0311: ** We've found the correct column -
0312: ** return the appropriate side.
0313: */
0314: if (otherSide)
0315: return rightOperand;
0316: return leftOperand;
0317: }
0318: }
0319: }
0320:
0321: if (rightOperand instanceof ColumnReference) {
0322: /*
0323: ** The right operand is a column reference.
0324: ** Is it the correct column?
0325: */
0326: valNodeBaseTables.clearAll();
0327: cr = (ColumnReference) rightOperand;
0328: cr.accept(btnVis);
0329: valNodeBaseTables.and(optBaseTables);
0330: if (valNodeBaseTables.getFirstSetBit() != -1) {
0331: /*
0332: ** The table is correct, how about the column position?
0333: */
0334: if (cr.getSource().getColumnPosition() == cRef
0335: .getColumnNumber()) {
0336: /*
0337: ** We've found the correct column -
0338: ** return the appropriate side
0339: */
0340: if (otherSide)
0341: return leftOperand;
0342: return rightOperand;
0343: }
0344: }
0345: }
0346:
0347: } catch (StandardException se) {
0348: if (SanityManager.DEBUG) {
0349: SanityManager
0350: .THROWASSERT("Failed when trying to "
0351: + "find base table number for column reference check:\n"
0352: + se.getMessage());
0353: }
0354: }
0355:
0356: return null;
0357: }
0358:
0359: /**
0360: * @see RelationalOperator#generateExpressionOperand
0361: *
0362: * @exception StandardException Thrown on error
0363: */
0364: public void generateExpressionOperand(Optimizable optTable,
0365: int columnPosition, ExpressionClassBuilder acb,
0366: MethodBuilder mb) throws StandardException {
0367: ColumnReference cr;
0368: FromBaseTable ft;
0369:
0370: if (SanityManager.DEBUG) {
0371: SanityManager.ASSERT(optTable instanceof FromBaseTable);
0372: }
0373: ft = (FromBaseTable) optTable;
0374:
0375: ValueNode exprOp = getExpressionOperand(ft.getTableNumber(),
0376: columnPosition, ft);
0377:
0378: if (SanityManager.DEBUG) {
0379: if (exprOp == null) {
0380: SanityManager
0381: .THROWASSERT("ColumnReference for correct column (columnPosition = "
0382: + columnPosition
0383: + ", exposed table name = "
0384: + ft.getExposedName()
0385: + ") not found on either side of BinaryRelationalOperator");
0386: }
0387: }
0388:
0389: exprOp.generateExpression(acb, mb);
0390: }
0391:
0392: /** @see RelationalOperator#selfComparison
0393: *
0394: * @exception StandardException Thrown on error
0395: */
0396: public boolean selfComparison(ColumnReference cr)
0397: throws StandardException {
0398: ValueNode otherSide;
0399: JBitSet tablesReferenced;
0400:
0401: /*
0402: ** Figure out which side the given ColumnReference is on,
0403: ** and look for the same table on the other side.
0404: */
0405: if (leftOperand == cr) {
0406: otherSide = rightOperand;
0407: } else if (rightOperand == cr) {
0408: otherSide = leftOperand;
0409: } else {
0410: otherSide = null;
0411: if (SanityManager.DEBUG) {
0412: SanityManager
0413: .THROWASSERT("ColumnReference not found on either side of binary comparison.");
0414: }
0415: }
0416:
0417: tablesReferenced = otherSide.getTablesReferenced();
0418:
0419: /* Return true if the table we're looking for is in the bit map */
0420: return tablesReferenced.get(cr.getTableNumber());
0421: }
0422:
0423: /** @see RelationalOperator#usefulStartKey */
0424: public boolean usefulStartKey(Optimizable optTable) {
0425: /*
0426: ** Determine whether this operator is a useful start operator
0427: ** with knowledge of whether the key column is on the left or right.
0428: */
0429: int columnSide = columnOnOneSide(optTable);
0430:
0431: if (columnSide == NEITHER)
0432: return false;
0433: else
0434: return usefulStartKey(columnSide == LEFT);
0435: }
0436:
0437: /**
0438: * Return true if a key column for the given table is found on the
0439: * left side of this operator, false if it is found on the right
0440: * side of this operator.
0441: *
0442: * NOTE: This method assumes that a key column will be found on one
0443: * side or the other. If you don't know whether a key column exists,
0444: * use the columnOnOneSide() method (below).
0445: *
0446: * @param optTable The Optimizable table that we're looking for a key
0447: * column on.
0448: *
0449: * @return true if a key column for the given table is on the left
0450: * side of this operator, false if one is found on the right
0451: * side of this operator.
0452: */
0453: protected boolean keyColumnOnLeft(Optimizable optTable) {
0454: ColumnReference cr;
0455: boolean left = false;
0456:
0457: /* Is the key column on the left or the right? */
0458: if (leftOperand instanceof ColumnReference) {
0459: /*
0460: ** The left operand is a column reference.
0461: ** Is it the correct column?
0462: */
0463: cr = (ColumnReference) leftOperand;
0464: if (valNodeReferencesOptTable(cr, (FromTable) optTable,
0465: false, true)) {
0466: /* The left operand is the key column */
0467: left = true;
0468: }
0469: }
0470:
0471: // Else the right operand must be the key column.
0472: if (SanityManager.DEBUG) {
0473: if (!left) {
0474: SanityManager.ASSERT(
0475: (rightOperand instanceof ColumnReference)
0476: && valNodeReferencesOptTable(
0477: (ColumnReference) rightOperand,
0478: (FromTable) optTable, false,
0479: true),
0480: "Key column not found on either side.");
0481: }
0482: }
0483:
0484: return left;
0485: }
0486:
0487: /* Return values for columnOnOneSide */
0488: protected static final int LEFT = -1;
0489: protected static final int NEITHER = 0;
0490: protected static final int RIGHT = 1;
0491:
0492: /**
0493: * Determine whether there is a column from the given table on one side
0494: * of this operator, and if so, which side is it on?
0495: *
0496: * @param optTable The Optimizable table that we're looking for a key
0497: * column on.
0498: *
0499: * @return LEFT if there is a column on the left, RIGHT if there is
0500: * a column on the right, NEITHER if no column found on either
0501: * side.
0502: */
0503: protected int columnOnOneSide(Optimizable optTable) {
0504: ColumnReference cr;
0505: boolean left = false;
0506: boolean walkSubtree = true;
0507:
0508: /* Is a column on the left */
0509: if (leftOperand instanceof ColumnReference) {
0510: /*
0511: ** The left operand is a column reference.
0512: ** Is it the correct column?
0513: */
0514: cr = (ColumnReference) leftOperand;
0515: if (valNodeReferencesOptTable(cr, (FromTable) optTable,
0516: false, walkSubtree)) {
0517: /* Key column found on left */
0518: return LEFT;
0519: }
0520: walkSubtree = false;
0521: }
0522:
0523: if (rightOperand instanceof ColumnReference) {
0524: /*
0525: ** The right operand is a column reference.
0526: ** Is it the correct column?
0527: */
0528: cr = (ColumnReference) rightOperand;
0529: if (valNodeReferencesOptTable(cr, (FromTable) optTable,
0530: false, walkSubtree)) {
0531: /* Key column found on right */
0532: return RIGHT;
0533: }
0534: }
0535:
0536: return NEITHER;
0537: }
0538:
0539: /** @see RelationalOperator#usefulStopKey */
0540: public boolean usefulStopKey(Optimizable optTable) {
0541: /*
0542: ** Determine whether this operator is a useful start operator
0543: ** with knowledge of whether the key column is on the left or right.
0544: */
0545: int columnSide = columnOnOneSide(optTable);
0546:
0547: if (columnSide == NEITHER)
0548: return false;
0549: else
0550: return usefulStopKey(columnSide == LEFT);
0551: }
0552:
0553: /**
0554: * Determine whether this comparison operator is a useful stop key
0555: * with knowledge of whether the key column is on the left or right.
0556: *
0557: * @param left true means the key column is on the left, false means
0558: * it is on the right.
0559: *
0560: * @return true if this is a useful stop key
0561: */
0562: /** @see RelationalOperator#generateAbsoluteColumnId */
0563: public void generateAbsoluteColumnId(MethodBuilder mb,
0564: Optimizable optTable) {
0565: // Get the absolute column position for the column
0566: int columnPosition = getAbsoluteColumnPosition(optTable);
0567:
0568: mb.push(columnPosition);
0569: }
0570:
0571: /** @see RelationalOperator#generateRelativeColumnId */
0572: public void generateRelativeColumnId(MethodBuilder mb,
0573: Optimizable optTable) {
0574: // Get the absolute column position for the column
0575: int columnPosition = getAbsoluteColumnPosition(optTable);
0576: // Convert the absolute to the relative 0-based column position
0577: columnPosition = optTable
0578: .convertAbsoluteToRelativeColumnPosition(columnPosition);
0579:
0580: mb.push(columnPosition);
0581: }
0582:
0583: /**
0584: * Get the absolute 0-based column position of the ColumnReference from
0585: * the conglomerate for this Optimizable.
0586: *
0587: * @param optTable The Optimizable
0588: *
0589: * @return The absolute 0-based column position of the ColumnReference
0590: */
0591: private int getAbsoluteColumnPosition(Optimizable optTable) {
0592: ColumnReference cr;
0593: ConglomerateDescriptor bestCD;
0594: int columnPosition;
0595:
0596: if (keyColumnOnLeft(optTable)) {
0597: cr = (ColumnReference) leftOperand;
0598: } else {
0599: cr = (ColumnReference) rightOperand;
0600: }
0601:
0602: bestCD = optTable.getTrulyTheBestAccessPath()
0603: .getConglomerateDescriptor();
0604:
0605: /*
0606: ** Column positions are one-based, store is zero-based.
0607: */
0608: columnPosition = cr.getSource().getColumnPosition();
0609:
0610: /*
0611: ** If it's an index, find the base column position in the index
0612: ** and translate it to an index column position.
0613: */
0614: if (bestCD != null && bestCD.isIndex()) {
0615: columnPosition = bestCD.getIndexDescriptor()
0616: .getKeyColumnPosition(columnPosition);
0617:
0618: if (SanityManager.DEBUG) {
0619: SanityManager.ASSERT(columnPosition > 0,
0620: "Base column not found in index");
0621: }
0622: }
0623:
0624: // return the 0-based column position
0625: return columnPosition - 1;
0626: }
0627:
0628: /**
0629: * @exception StandardException Thrown on error
0630: */
0631: public void generateQualMethod(ExpressionClassBuilder acb,
0632: MethodBuilder mb, Optimizable optTable)
0633: throws StandardException {
0634: /* Generate a method that returns the expression */
0635: MethodBuilder qualMethod = acb.newUserExprFun();
0636:
0637: /*
0638: ** Generate the expression that's on the opposite side
0639: ** of the key column
0640: */
0641: if (keyColumnOnLeft(optTable)) {
0642: rightOperand.generateExpression(acb, qualMethod);
0643: } else {
0644: leftOperand.generateExpression(acb, qualMethod);
0645: }
0646:
0647: qualMethod.methodReturn();
0648: qualMethod.complete();
0649:
0650: /* push an expression that evaluates to the GeneratedMethod */
0651: acb.pushMethodReference(mb, qualMethod);
0652: }
0653:
0654: /** @see RelationalOperator#generateOrderedNulls */
0655: public void generateOrderedNulls(MethodBuilder mb) {
0656: mb.push(false);
0657: }
0658:
0659: /** @see RelationalOperator#orderedNulls */
0660: public boolean orderedNulls() {
0661: return false;
0662: }
0663:
0664: /** @see RelationalOperator#isQualifier
0665: *
0666: * @exception StandardException Thrown on error
0667: */
0668: public boolean isQualifier(Optimizable optTable, boolean forPush)
0669: throws StandardException {
0670: FromTable ft;
0671: ValueNode otherSide = null;
0672: JBitSet tablesReferenced;
0673: ColumnReference cr = null;
0674: boolean found = false;
0675: boolean walkSubtree = true;
0676:
0677: ft = (FromTable) optTable;
0678:
0679: if (leftOperand instanceof ColumnReference) {
0680: /*
0681: ** The left operand is a column reference.
0682: ** Is it the correct column?
0683: */
0684: cr = (ColumnReference) leftOperand;
0685: if (valNodeReferencesOptTable(cr, ft, forPush, walkSubtree)) {
0686: otherSide = rightOperand;
0687: found = true;
0688: }
0689: walkSubtree = false;
0690: }
0691:
0692: if ((!found) && (rightOperand instanceof ColumnReference)) {
0693: /*
0694: ** The right operand is a column reference.
0695: ** Is it the correct column?
0696: */
0697: cr = (ColumnReference) rightOperand;
0698: if (valNodeReferencesOptTable(cr, ft, forPush, walkSubtree)) {
0699: otherSide = leftOperand;
0700: found = true;
0701: }
0702: }
0703:
0704: /* Have we found a ColumnReference on either side? */
0705: if (!found) {
0706: /*
0707: ** Neither side is a ColumnReference to the table we're looking
0708: ** for, so it can't be a Qualifier
0709: */
0710: return false;
0711: }
0712:
0713: /*
0714: ** One side is a ColumnReference to the correct table. It is a
0715: ** Qualifier if the other side does not refer to the table we are
0716: ** optimizing.
0717: */
0718: return !valNodeReferencesOptTable(otherSide, ft, forPush, true);
0719: }
0720:
0721: /**
0722: * @see RelationalOperator#getOrderableVariantType
0723: *
0724: * @exception StandardException thrown on error
0725: */
0726: public int getOrderableVariantType(Optimizable optTable)
0727: throws StandardException {
0728: /* The Qualifier's orderable is on the opposite side from
0729: * the key column.
0730: */
0731: if (keyColumnOnLeft(optTable)) {
0732: return rightOperand.getOrderableVariantType();
0733: } else {
0734: return leftOperand.getOrderableVariantType();
0735: }
0736: }
0737:
0738: /** @see RelationalOperator#compareWithKnownConstant */
0739: public boolean compareWithKnownConstant(Optimizable optTable,
0740: boolean considerParameters) {
0741: ValueNode node = null;
0742: node = keyColumnOnLeft(optTable) ? rightOperand : leftOperand;
0743:
0744: if (considerParameters) {
0745: return (node instanceof ConstantNode)
0746: || ((node.requiresTypeFromContext()) && (((ParameterNode) node)
0747: .getDefaultValue() != null));
0748: } else {
0749: return node instanceof ConstantNode;
0750: }
0751: }
0752:
0753: /**
0754: * @see RelationalOperator#getCompareValue
0755: *
0756: * @exception StandardException Thrown on error
0757: */
0758: public DataValueDescriptor getCompareValue(Optimizable optTable)
0759: throws StandardException {
0760: ValueNode node = null;
0761:
0762: /* The value being compared to is on the opposite side from
0763: ** the key column.
0764: */
0765: node = keyColumnOnLeft(optTable) ? rightOperand : leftOperand;
0766:
0767: if (node instanceof ConstantNode) {
0768: return ((ConstantNode) node).getValue();
0769: } else if (node.requiresTypeFromContext()) {
0770: ParameterNode pn;
0771: if (node instanceof UnaryOperatorNode)
0772: pn = ((UnaryOperatorNode) node).getParameterOperand();
0773: else
0774: pn = (ParameterNode) (node);
0775: return pn.getDefaultValue();
0776: } else {
0777: return null;
0778: }
0779: }
0780:
0781: /**
0782: * Return 50% if this is a comparison with a boolean column, a negative
0783: * selectivity otherwise.
0784: */
0785: protected double booleanSelectivity(Optimizable optTable)
0786: throws StandardException {
0787: TypeId typeId = null;
0788: double retval = -1.0d;
0789: int columnSide;
0790:
0791: columnSide = columnOnOneSide(optTable);
0792:
0793: if (columnSide == LEFT)
0794: typeId = leftOperand.getTypeId();
0795: else if (columnSide == RIGHT)
0796: typeId = rightOperand.getTypeId();
0797:
0798: if (typeId != null
0799: && (typeId.getJDBCTypeId() == Types.BIT || typeId
0800: .getJDBCTypeId() == JDBC30Translation.SQL_TYPES_BOOLEAN))
0801: retval = 0.5d;
0802:
0803: return retval;
0804: }
0805:
0806: /**
0807: * The methods generated for this node all are on Orderable.
0808: * Overrides this method
0809: * in BooleanOperatorNode for code generation purposes.
0810: */
0811: public String getReceiverInterfaceName() {
0812: return ClassName.DataValueDescriptor;
0813: }
0814:
0815: /**
0816: * Returns the negation of this operator; negation of Equals is NotEquals.
0817: */
0818: BinaryOperatorNode getNegation(ValueNode leftOperand,
0819: ValueNode rightOperand) throws StandardException {
0820: BinaryOperatorNode negation;
0821: if (SanityManager.DEBUG)
0822: SanityManager.ASSERT(dataTypeServices != null,
0823: "dataTypeServices is expected to be non-null");
0824: /* xxxRESOLVE: look into doing this in place instead of allocating a new node */
0825: negation = (BinaryOperatorNode) getNodeFactory().getNode(
0826: getNegationNode(), leftOperand, rightOperand,
0827: getContextManager());
0828: negation.setType(dataTypeServices);
0829: return negation;
0830: }
0831:
0832: /* map current node to its negation */
0833: private int getNegationNode() {
0834: switch (getNodeType()) {
0835: case C_NodeTypes.BINARY_EQUALS_OPERATOR_NODE:
0836: return C_NodeTypes.BINARY_NOT_EQUALS_OPERATOR_NODE;
0837:
0838: case C_NodeTypes.BINARY_GREATER_EQUALS_OPERATOR_NODE:
0839: return C_NodeTypes.BINARY_LESS_THAN_OPERATOR_NODE;
0840:
0841: case C_NodeTypes.BINARY_GREATER_THAN_OPERATOR_NODE:
0842: return C_NodeTypes.BINARY_LESS_EQUALS_OPERATOR_NODE;
0843:
0844: case C_NodeTypes.BINARY_LESS_THAN_OPERATOR_NODE:
0845: return C_NodeTypes.BINARY_GREATER_EQUALS_OPERATOR_NODE;
0846:
0847: case C_NodeTypes.BINARY_LESS_EQUALS_OPERATOR_NODE:
0848: return C_NodeTypes.BINARY_GREATER_THAN_OPERATOR_NODE;
0849:
0850: case C_NodeTypes.BINARY_NOT_EQUALS_OPERATOR_NODE:
0851: return C_NodeTypes.BINARY_EQUALS_OPERATOR_NODE;
0852: }
0853:
0854: if (SanityManager.DEBUG) {
0855: SanityManager
0856: .THROWASSERT("getNegationNode called with invalid nodeType: "
0857: + getNodeType());
0858: }
0859:
0860: return -1;
0861: }
0862:
0863: /**
0864: * is this is useful start key? for example a predicate of the from
0865: * <em>column Lessthan 5</em> is not a useful start key but is a useful stop
0866: * key. However <em>5 Lessthan column </em> is a useful start key.
0867: *
0868: * @param columnOnLeft is true if the column is the left hand side of the
0869: * binary operator.
0870: */
0871: protected boolean usefulStartKey(boolean columnOnLeft) {
0872: switch (operatorType) {
0873: case RelationalOperator.EQUALS_RELOP:
0874: return true;
0875: case RelationalOperator.NOT_EQUALS_RELOP:
0876: return false;
0877: case RelationalOperator.GREATER_THAN_RELOP:
0878: case RelationalOperator.GREATER_EQUALS_RELOP:
0879: // col > 1
0880: return columnOnLeft;
0881: case RelationalOperator.LESS_THAN_RELOP:
0882: case RelationalOperator.LESS_EQUALS_RELOP:
0883: // col < 1
0884: return !columnOnLeft;
0885: default:
0886: return false;
0887: }
0888:
0889: }
0890:
0891: /** @see RelationalOperator#usefulStopKey */
0892: protected boolean usefulStopKey(boolean columnOnLeft) {
0893: switch (operatorType) {
0894: case RelationalOperator.EQUALS_RELOP:
0895: return true;
0896: case RelationalOperator.NOT_EQUALS_RELOP:
0897: return false;
0898: case RelationalOperator.GREATER_THAN_RELOP:
0899: case RelationalOperator.GREATER_EQUALS_RELOP:
0900: // col > 1
0901: return !columnOnLeft;
0902: case RelationalOperator.LESS_EQUALS_RELOP:
0903: case RelationalOperator.LESS_THAN_RELOP:
0904: // col < 1
0905: return columnOnLeft;
0906: default:
0907: return false;
0908: }
0909: }
0910:
0911: /** @see RelationalOperator#getStartOperator */
0912: public int getStartOperator(Optimizable optTable) {
0913: switch (operatorType) {
0914: case RelationalOperator.EQUALS_RELOP:
0915: case RelationalOperator.LESS_EQUALS_RELOP:
0916: case RelationalOperator.GREATER_EQUALS_RELOP:
0917: return ScanController.GE;
0918: case RelationalOperator.LESS_THAN_RELOP:
0919: case RelationalOperator.GREATER_THAN_RELOP:
0920: return ScanController.GT;
0921: case RelationalOperator.NOT_EQUALS_RELOP:
0922: if (SanityManager.DEBUG)
0923: SanityManager
0924: .THROWASSERT("!= cannot be a start operator");
0925: return ScanController.NA;
0926: default:
0927: return ScanController.NA;
0928:
0929: }
0930: }
0931:
0932: /** @see RelationalOperator#getStopOperator */
0933: public int getStopOperator(Optimizable optTable) {
0934: switch (operatorType) {
0935: case RelationalOperator.EQUALS_RELOP:
0936: case RelationalOperator.GREATER_EQUALS_RELOP:
0937: case RelationalOperator.LESS_EQUALS_RELOP:
0938: return ScanController.GT;
0939: case RelationalOperator.LESS_THAN_RELOP:
0940: case RelationalOperator.GREATER_THAN_RELOP:
0941: return ScanController.GE;
0942: case RelationalOperator.NOT_EQUALS_RELOP:
0943: if (SanityManager.DEBUG)
0944: SanityManager
0945: .THROWASSERT("!= cannot be a stop operator");
0946: return ScanController.NA;
0947: default:
0948: return ScanController.NA;
0949: }
0950: }
0951:
0952: /** @see RelationalOperator#generateOperator */
0953: public void generateOperator(MethodBuilder mb, Optimizable optTable) {
0954: switch (operatorType) {
0955: case RelationalOperator.EQUALS_RELOP:
0956: mb.push(Orderable.ORDER_OP_EQUALS);
0957: break;
0958:
0959: case RelationalOperator.NOT_EQUALS_RELOP:
0960: mb.push(Orderable.ORDER_OP_EQUALS);
0961: break;
0962:
0963: case RelationalOperator.LESS_THAN_RELOP:
0964: case RelationalOperator.GREATER_EQUALS_RELOP:
0965: mb
0966: .push(keyColumnOnLeft(optTable) ? Orderable.ORDER_OP_LESSTHAN
0967: : Orderable.ORDER_OP_LESSOREQUALS);
0968: break;
0969: case RelationalOperator.LESS_EQUALS_RELOP:
0970: case RelationalOperator.GREATER_THAN_RELOP:
0971: mb
0972: .push(keyColumnOnLeft(optTable) ? Orderable.ORDER_OP_LESSOREQUALS
0973: : Orderable.ORDER_OP_LESSTHAN);
0974:
0975: }
0976: }
0977:
0978: /** @see RelationalOperator#generateNegate */
0979: public void generateNegate(MethodBuilder mb, Optimizable optTable) {
0980: switch (operatorType) {
0981: case RelationalOperator.EQUALS_RELOP:
0982: mb.push(false);
0983: break;
0984: case RelationalOperator.NOT_EQUALS_RELOP:
0985: mb.push(true);
0986: break;
0987: case RelationalOperator.LESS_THAN_RELOP:
0988: case RelationalOperator.LESS_EQUALS_RELOP:
0989: mb.push(!keyColumnOnLeft(optTable));
0990: break;
0991: case RelationalOperator.GREATER_THAN_RELOP:
0992: case RelationalOperator.GREATER_EQUALS_RELOP:
0993: mb.push(keyColumnOnLeft(optTable));
0994: break;
0995: }
0996:
0997: return;
0998: }
0999:
1000: /** @see RelationalOperator#getOperator */
1001: public int getOperator() {
1002: return operatorType;
1003: }
1004:
1005: /** return the selectivity of this predicate.
1006: */
1007: public double selectivity(Optimizable optTable)
1008: throws StandardException {
1009: double retval = booleanSelectivity(optTable);
1010:
1011: if (retval >= 0.0d)
1012: return retval;
1013:
1014: switch (operatorType) {
1015: case RelationalOperator.EQUALS_RELOP:
1016: return 0.1;
1017: case RelationalOperator.NOT_EQUALS_RELOP:
1018: case RelationalOperator.LESS_THAN_RELOP:
1019: case RelationalOperator.LESS_EQUALS_RELOP:
1020: case RelationalOperator.GREATER_EQUALS_RELOP:
1021: if (getBetweenSelectivity())
1022: return 0.5d;
1023: /* fallthrough -- only */
1024: case RelationalOperator.GREATER_THAN_RELOP:
1025: return 0.33;
1026: }
1027:
1028: return 0.0;
1029: }
1030:
1031: /** @see RelationalOperator#getTransitiveSearchClause */
1032: public RelationalOperator getTransitiveSearchClause(
1033: ColumnReference otherCR) throws StandardException {
1034: return (RelationalOperator) getNodeFactory().getNode(
1035: getNodeType(), otherCR, rightOperand,
1036: getContextManager());
1037: }
1038:
1039: public boolean equalsComparisonWithConstantExpression(
1040: Optimizable optTable) {
1041: if (operatorType != EQUALS_RELOP)
1042: return false;
1043:
1044: boolean retval = false;
1045: ValueNode comparand = null;
1046:
1047: int side = columnOnOneSide(optTable);
1048: if (side == LEFT) {
1049: retval = rightOperand.isConstantExpression();
1050: } else if (side == RIGHT) {
1051: retval = leftOperand.isConstantExpression();
1052: }
1053:
1054: return retval;
1055: }
1056:
1057: /** @see ValueNode#isRelationalOperator */
1058: public boolean isRelationalOperator() {
1059: return true;
1060: }
1061:
1062: public boolean isBinaryEqualsOperatorNode() {
1063: return (operatorType == RelationalOperator.EQUALS_RELOP);
1064: }
1065:
1066: /** @see ValueNode#optimizableEqualityNode */
1067: public boolean optimizableEqualityNode(Optimizable optTable,
1068: int columnNumber, boolean isNullOkay)
1069: throws StandardException {
1070: if (operatorType != EQUALS_RELOP)
1071: return false;
1072:
1073: ColumnReference cr = getColumnOperand(optTable, columnNumber);
1074: if (cr == null)
1075: return false;
1076:
1077: if (selfComparison(cr))
1078: return false;
1079:
1080: if (implicitVarcharComparison())
1081: return false;
1082:
1083: return true;
1084: }
1085:
1086: /**
1087: * Return whether or not this binary relational predicate requires an implicit
1088: * (var)char conversion. This is important when considering
1089: * hash join since this type of equality predicate is not currently
1090: * supported for a hash join.
1091: *
1092: * @return Whether or not an implicit (var)char conversion is required for
1093: * this binary relational operator.
1094: *
1095: * @exception StandardException Thrown on error
1096: */
1097:
1098: private boolean implicitVarcharComparison()
1099: throws StandardException {
1100: TypeId leftType = leftOperand.getTypeId();
1101: TypeId rightType = rightOperand.getTypeId();
1102:
1103: if (leftType.isStringTypeId() && !rightType.isStringTypeId())
1104: return true;
1105:
1106: if (rightType.isStringTypeId() && (!leftType.isStringTypeId()))
1107: return true;
1108:
1109: return false;
1110: }
1111:
1112: /* @see BinaryOperatorNode#genSQLJavaSQLTree
1113: * @see BinaryComparisonOperatorNode#genSQLJavaSQLTree
1114: */
1115: public ValueNode genSQLJavaSQLTree() throws StandardException {
1116: if (operatorType == EQUALS_RELOP)
1117: return this ;
1118:
1119: return super .genSQLJavaSQLTree();
1120: }
1121:
1122: /**
1123: * Take a ResultSetNode and return a column reference that is scoped for
1124: * for the received ResultSetNode, where "scoped" means that the column
1125: * reference points to a specific column in the RSN. This is used for
1126: * remapping predicates from an outer query down to a subquery.
1127: *
1128: * For example, assume we have the following query:
1129: *
1130: * select * from
1131: * (select i,j from t1 union select i,j from t2) X1,
1132: * (select a,b from t3 union select a,b from t4) X2
1133: * where X1.j = X2.b;
1134: *
1135: * Then assume that this BinaryRelationalOperatorNode represents the
1136: * "X1.j = X2.b" predicate and that the childRSN we received as a
1137: * parameter represents one of the subqueries to which we want to push
1138: * the predicate; let's say it's:
1139: *
1140: * select i,j from t1
1141: *
1142: * Then what we want to do in this method is map one of the operands
1143: * X1.j or X2.b (depending on the 'whichSide' parameter) to the childRSN,
1144: * if possible. Note that in our example, "X2.b" should _NOT_ be mapped
1145: * because it doesn't apply to the childRSN for the subquery "select i,j
1146: * from t1"; thus we should leave it as it is. "X1.j", however, _does_
1147: * need to be scoped, and so this method will return a ColumnReference
1148: * pointing to "T1.j" (or whatever the corresponding column in T1 is).
1149: *
1150: * ASSUMPTION: We should only get to this method if we know that
1151: * exactly one operand in the predicate to which this operator belongs
1152: * can and should be mapped to the received childRSN.
1153: *
1154: * @param whichSide The operand are we trying to scope (LEFT or RIGHT)
1155: * @param parentRSNsTables Set of all table numbers referenced by
1156: * the ResultSetNode that is _parent_ to the received childRSN.
1157: * We need this to make sure we don't scope the operand to a
1158: * ResultSetNode to which it doesn't apply.
1159: * @param childRSN The result set node to which we want to create
1160: * a scoped predicate.
1161: * @param whichRC If not -1 then this tells us which ResultColumn
1162: * in the received childRSN we need to use for the scoped predicate;
1163: * if -1 then the column position of the scoped column reference
1164: * will be stored in this array and passed back to the caller.
1165: * @return A column reference scoped to the received childRSN, if possible.
1166: * If the operand is a ColumnReference that is not supposed to be scoped,
1167: * we return a _clone_ of the reference--this is necessary because the
1168: * reference is going to be pushed to two places (left and right children
1169: * of the parentRSN) and if both children are referencing the same
1170: * instance of the column reference, they'll interfere with each other
1171: * during optimization.
1172: */
1173: public ValueNode getScopedOperand(int whichSide,
1174: JBitSet parentRSNsTables, ResultSetNode childRSN,
1175: int[] whichRC) throws StandardException {
1176: ResultColumn rc = null;
1177: ColumnReference cr = whichSide == LEFT ? (ColumnReference) leftOperand
1178: : (ColumnReference) rightOperand;
1179:
1180: /* When we scope a predicate we only scope one side of it--the
1181: * side that is to be evaluated against childRSN. We figure out
1182: * if "cr" is that side by using table numbers, as seen below.
1183: * This means that for every scoped predicate there will be one
1184: * operand that is scoped and one operand that is not scoped.
1185: * When we get here for the operand that will not be scoped,
1186: * we'll just return a clone of that operand. So in the example
1187: * mentioned above, the scoped predicate for the left child of
1188: * X1 would be
1189: *
1190: * T1.j <scoped> = X2.b <clone>
1191: *
1192: * That said, the first thing we need to do is see if this
1193: * ColumnReference is supposed to be scoped for childRSN. We
1194: * do that by figuring out what underlying base table the column
1195: * reference is pointing to and then seeing if that base table
1196: * is included in the list of table numbers from the parentRSN.
1197: */
1198: JBitSet crTables = new JBitSet(parentRSNsTables.size());
1199: BaseTableNumbersVisitor btnVis = new BaseTableNumbersVisitor(
1200: crTables);
1201: cr.accept(btnVis);
1202:
1203: /* If the column reference in question is not intended for
1204: * the received result set node, just leave the operand as
1205: * it is (i.e. return a clone). In the example mentioned at
1206: * the start of this method, this will happen when the operand
1207: * is X2.b and childRSN is either "select i,j from t1" or
1208: * "select i,j from t2", in which case the operand does not
1209: * apply to childRSN. When we get here and try to map the
1210: * "X1.j" operand, though, the following "contains" check will
1211: * return true and thus we can go ahead and return a scoped
1212: * version of that operand.
1213: */
1214: if (!parentRSNsTables.contains(crTables))
1215: return (ColumnReference) cr.getClone();
1216:
1217: /* Find the target ResultColumn in the received result set. At
1218: * this point we know that we do in fact need to scope the column
1219: * reference for childRSN, so go ahead and do it. The way in
1220: * which we get the scope target column differs depending on
1221: * if childRSN corresponds to the left or right child of the
1222: * UNION node. Before explaining that, though, note that it's
1223: * not good enough to just search for the target column by
1224: * name. The reason is that it's possible the name provided
1225: * for the column reference to be scoped doesn't match the
1226: * name of the actual underlying column. Ex.
1227: *
1228: * select * from
1229: * (select i,j from t1 union select i,j from t2) X1 (x,y),
1230: * (select a,b from t3 union select a,b from t4) X2
1231: * where X1.x = X2.b;
1232: *
1233: * If we were scoping "X1.x" and we searched for "x" in the
1234: * childRSN "select i,j from t1" we wouldn't find it.
1235: *
1236: * It is similarly incorrect to search for the target column
1237: * by position (DERBY-1633). This is a bit more subtle, but
1238: * if the child to which we're scoping is a subquery whose RCL
1239: * does not match the column ordering of the RCL for cr's source
1240: * result set, then searching by column position can yield the
1241: * wrong results, as well. For a detailed example of how this
1242: * can happen, see the fix description attached to DERBY-1633.
1243: *
1244: * So how do we find the target column, then? As mentioned
1245: * above, the way in which we get the scope target column
1246: * differs depending on if childRSN corresponds to the left
1247: * or right child of the parent UNION node. And that said,
1248: * we can tell if we're scoping a left child by looking at
1249: * "whichRC" argument: if it is -1 then we know we're scoping
1250: * to the left child of a Union; otherwise we're scoping to
1251: * the right child.
1252: */
1253: if (whichRC[0] == -1) {
1254: /*
1255: * For the left side we start by figuring out what the source
1256: * result set and column position for "cr" are. Then, since
1257: * a) cr must be pointing to a result column in the parentRSN's
1258: * ResultColumnList, b) we know that the parent RSN is a
1259: * SetOperatorNode (at least for now, since we only get here
1260: * for Union nodes), and c) SetOpNode's RCLs are built from the
1261: * left child's RCL (see bindResultColumns() in SetOperatorNode),
1262: * we know that if we search the child's RCL for a reference
1263: * whose source result column is the same as cr's source result
1264: * column, we'll find a match. Once found, the position of the
1265: * matching column w.r.t childRSN's RCL will be stored in the
1266: * whichRC parameter.
1267: */
1268:
1269: // Find the source result set and source column position of cr.
1270: int[] sourceColPos = new int[] { -1 };
1271: ResultSetNode sourceRSN = cr
1272: .getSourceResultSet(sourceColPos);
1273:
1274: if (SanityManager.DEBUG) {
1275: /* We assumed that if we made it here "cr" was pointing
1276: * to a base table somewhere down the tree. If that's
1277: * true then sourceRSN won't be null. Make sure our
1278: * assumption was correct.
1279: */
1280: SanityManager.ASSERT(sourceRSN != null,
1281: "Failed to find source result set when trying to "
1282: + "scope column reference '"
1283: + cr.getTableName() + "."
1284: + cr.getColumnName());
1285: }
1286:
1287: // Now search for the corresponding ResultColumn in childRSN.
1288: rc = childRSN.getResultColumns().getResultColumn(
1289: sourceColPos[0], sourceRSN, whichRC);
1290: } else {
1291: /*
1292: * For the right side the story is slightly different. If we were
1293: * to search the right child's RCL for a reference whose source
1294: * result column was the same as cr's, we wouldn't find it. This
1295: * is because cr's source result column comes from the left child's
1296: * RCL and thus the right child doesn't know about it. That said,
1297: * though, for set operations like UNION, the left and right RCL's
1298: * are correlated by position--i.e. the operation occurs between
1299: * the nth column in the left RCL and the nth column in the right
1300: * RCL. So given that we will already have found the scope target
1301: * in the left child's RCL at the position in whichRC, we know that
1302: * that scope target for the right child's RCL is simply the
1303: * whichRC'th column in that RCL.
1304: */
1305: rc = childRSN.getResultColumns()
1306: .getResultColumn(whichRC[0]);
1307: }
1308:
1309: // rc shouldn't be null; if there was no matching ResultColumn at all,
1310: // then we shouldn't have made it this far.
1311: if (SanityManager.DEBUG) {
1312: SanityManager.ASSERT(rc != null,
1313: "Failed to locate scope target result column when trying to "
1314: + "scope operand '" + cr.getTableName()
1315: + "." + cr.getColumnName() + "'.");
1316: }
1317:
1318: /* If the ResultColumn we found has an expression that is a
1319: * ColumnReference, then that column reference has all of the
1320: * info we need.
1321: *
1322: * It is, however, possible that the ResultColumn's expression
1323: * is NOT a ColumnReference. For example, the expression would
1324: * be a constant expression if childRSN represented something
1325: * like:
1326: *
1327: * select 1, 1 from t1
1328: *
1329: * In this case the expression does not directly reference a
1330: * column in the underlying result set and is therefore
1331: * "scoped" as far as it can go. This means that the scoped
1332: * predicate will not necessarily have column references on
1333: * both sides, even though the predicate that we're scoping
1334: * will. That's not a problem, though, since a predicate with
1335: * a column reference on one side and a non-ColumnReference
1336: * on the other is still valid.
1337: */
1338:
1339: if (rc.getExpression() instanceof ColumnReference) {
1340: /* We create a clone of the column reference and mark
1341: * the clone as "scoped" so that we can do the right
1342: * thing when it comes time to remap the predicate;
1343: * see Predicate.remapScopedPred() for more.
1344: */
1345: ColumnReference cRef = (ColumnReference) ((ColumnReference) rc
1346: .getExpression()).getClone();
1347: cRef.markAsScoped();
1348: return cRef;
1349: }
1350:
1351: /* Else just return rc's expression. This means the scoped
1352: * predicate will have one operand that is _not_ a column
1353: * reference--but that's okay, so long as we account for
1354: * that when pushing/remapping the scoped predicate down
1355: * the query tree (see esp. "isScopedToSourceResultSet()"
1356: * in Predicate.java).
1357: */
1358: return rc.getExpression();
1359: }
1360:
1361: /**
1362: * Determine whether or not the received ValueNode (which will
1363: * usually be a ColumnReference) references either the received
1364: * optTable or else a base table in the subtree beneath that
1365: * optTable.
1366: *
1367: * @param valNode The ValueNode that has the reference(s).
1368: * @param optTable The table/subtree node to which we're trying
1369: * to find a reference.
1370: * @param forPush Whether or not we are searching with the intent
1371: * to push this operator to the target table.
1372: * @param walkOptTableSubtree Should we walk the subtree beneath
1373: * optTable to find base tables, or not? Will be false if we've
1374: * already done it for the left operand and now we're here
1375: * for the right operand.
1376: * @return True if valNode contains a reference to optTable or
1377: * to a base table in the subtree beneath optTable; false
1378: * otherwise.
1379: */
1380: private boolean valNodeReferencesOptTable(ValueNode valNode,
1381: FromTable optTable, boolean forPush,
1382: boolean walkOptTableSubtree) {
1383: // Following call will initialize/reset the btnVis,
1384: // valNodeBaseTables, and optBaseTables fields of this object.
1385: initBaseTableVisitor(optTable.getReferencedTableMap().size(),
1386: walkOptTableSubtree);
1387:
1388: boolean found = false;
1389: try {
1390:
1391: // Find all base tables beneath optTable and load them
1392: // into this object's optBaseTables map. This is the
1393: // list of table numbers we'll search to see if the
1394: // value node references any tables in the subtree at
1395: // or beneath optTable.
1396: if (walkOptTableSubtree)
1397: buildTableNumList(optTable, forPush);
1398:
1399: // Now get the base table numbers that are in valNode's
1400: // subtree. In most cases valNode will be a ColumnReference
1401: // and this will return a single base table number.
1402: btnVis.setTableMap(valNodeBaseTables);
1403: valNode.accept(btnVis);
1404:
1405: // And finally, see if there's anything in common.
1406: valNodeBaseTables.and(optBaseTables);
1407: found = (valNodeBaseTables.getFirstSetBit() != -1);
1408:
1409: } catch (StandardException se) {
1410: if (SanityManager.DEBUG) {
1411: SanityManager
1412: .THROWASSERT("Failed when trying to "
1413: + "find base table numbers for reference check:\n"
1414: + se.getMessage());
1415: }
1416: }
1417:
1418: return found;
1419: }
1420:
1421: /**
1422: * Initialize the fields used for retrieving base tables in
1423: * subtrees, which allows us to do a more extensive search
1424: * for table references. If the fields have already been
1425: * created, then just reset their values.
1426: *
1427: * @param numTablesInQuery Used for creating JBitSets that
1428: * can hold table numbers for the query.
1429: * @param initOptBaseTables Whether or not we should clear out
1430: * or initialize the optBaseTables bit set.
1431: */
1432: private void initBaseTableVisitor(int numTablesInQuery,
1433: boolean initOptBaseTables) {
1434: if (valNodeBaseTables == null)
1435: valNodeBaseTables = new JBitSet(numTablesInQuery);
1436: else
1437: valNodeBaseTables.clearAll();
1438:
1439: if (initOptBaseTables) {
1440: if (optBaseTables == null)
1441: optBaseTables = new JBitSet(numTablesInQuery);
1442: else
1443: optBaseTables.clearAll();
1444: }
1445:
1446: // Now create the visitor. We give it valNodeBaseTables
1447: // here for sake of creation, but this can be overridden
1448: // (namely, by optBaseTables) by the caller of this method.
1449: if (btnVis == null)
1450: btnVis = new BaseTableNumbersVisitor(valNodeBaseTables);
1451: }
1452:
1453: /**
1454: * Create a set of table numbers to search when trying to find
1455: * which (if either) of this operator's operands reference the
1456: * received target table. At the minimum this set should contain
1457: * the target table's own table number. After that, if we're
1458: * _not_ attempting to push this operator (or more specifically,
1459: * the predicate to which this operator belongs) to the target
1460: * table, we go on to search the subtree beneath the target
1461: * table and add any base table numbers to the searchable list.
1462: *
1463: * @param ft Target table for which we're building the search
1464: * list.
1465: * @param forPush Whether or not we are searching with the intent
1466: * to push this operator to the target table.
1467: */
1468: private void buildTableNumList(FromTable ft, boolean forPush)
1469: throws StandardException {
1470: // Start with the target table's own table number. Note
1471: // that if ft is an instanceof SingleChildResultSet, its
1472: // table number could be negative.
1473: if (ft.getTableNumber() >= 0)
1474: optBaseTables.set(ft.getTableNumber());
1475:
1476: if (forPush)
1477: // nothing else to do.
1478: return;
1479:
1480: // Add any table numbers from the target table's
1481: // reference map.
1482: optBaseTables.or(ft.getReferencedTableMap());
1483:
1484: // The table's reference map is not guaranteed to have
1485: // all of the tables that are actually used--for example,
1486: // if the table is a ProjectRestrictNode or a JoinNode
1487: // with a subquery as a child, the ref map will contain
1488: // the number for the PRN above the subquery, but it
1489: // won't contain the table numbers referenced by the
1490: // subquery. So here we go through and find ALL base
1491: // table numbers beneath the target node.
1492: btnVis.setTableMap(optBaseTables);
1493: ft.accept(btnVis);
1494: return;
1495: }
1496:
1497: }
|