0001: /*
0002:
0003: Derby - Class org.apache.derby.impl.sql.compile.ColumnReference
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.sql.compile.C_NodeTypes;
0025: import org.apache.derby.iapi.sql.compile.NodeFactory;
0026:
0027: import org.apache.derby.iapi.sql.dictionary.DataDictionary;
0028: import org.apache.derby.iapi.types.DataTypeDescriptor;
0029:
0030: import org.apache.derby.iapi.error.StandardException;
0031: import org.apache.derby.iapi.reference.SQLState;
0032:
0033: import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;
0034: import org.apache.derby.iapi.services.compiler.MethodBuilder;
0035:
0036: import org.apache.derby.iapi.services.sanity.SanityManager;
0037:
0038: import org.apache.derby.iapi.store.access.Qualifier;
0039:
0040: import org.apache.derby.iapi.util.JBitSet;
0041:
0042: import java.util.Vector;
0043:
0044: /**
0045: * A ColumnReference represents a column in the query tree. The parser generates a
0046: * ColumnReference for each column reference. A column refercence could be a column in
0047: * a base table, a column in a view (which could expand into a complex
0048: * expression), or a column in a subquery in the FROM clause.
0049: *
0050: * @author Jerry Brenner
0051: */
0052:
0053: public class ColumnReference extends ValueNode {
0054: String columnName;
0055:
0056: /*
0057: ** This is the user-specified table name. It will be null if the
0058: ** user specifies a column without a table name. Leave it null even
0059: ** when the column is bound as it is only used in binding.
0060: */
0061: TableName tableName;
0062: /* The table this column reference is bound to */
0063: private int tableNumber;
0064: /* The column number in the underlying base table */
0065: private int columnNumber;
0066: /* This is where the value for this column reference will be coming from */
0067: private ResultColumn source;
0068:
0069: /* For unRemapping */
0070: ResultColumn origSource;
0071: private String origName;
0072: int origTableNumber = -1;
0073: int origColumnNumber = -1;
0074:
0075: /* Reuse generated code where possible */
0076: //Expression genResult;
0077: private boolean replacesAggregate;
0078:
0079: private int nestingLevel = -1;
0080: private int sourceLevel = -1;
0081:
0082: /* Whether or not this column reference been scoped for the
0083: sake of predicate pushdown.
0084: */
0085: private boolean scoped;
0086:
0087: /* List of saved remap data if this ColumnReference is scoped
0088: and has been remapped multiple times.
0089: */
0090: private java.util.ArrayList remaps;
0091:
0092: /**
0093: * Initializer.
0094: * This one is called by the parser where we could
0095: * be dealing with delimited identifiers.
0096: *
0097: * @param columnName The name of the column being referenced
0098: * @param tableName The qualification for the column
0099: * @param tokBeginOffset begin position of token for the column name
0100: * identifier from parser.
0101: * @param tokEndOffset end position of token for the column name
0102: * identifier from parser.
0103: */
0104:
0105: public void init(Object columnName, Object tableName,
0106: Object tokBeginOffset, Object tokEndOffset) {
0107: this .columnName = (String) columnName;
0108: this .tableName = (TableName) tableName;
0109: this .setBeginOffset(((Integer) tokBeginOffset).intValue());
0110: this .setEndOffset(((Integer) tokEndOffset).intValue());
0111: tableNumber = -1;
0112: remaps = null;
0113: }
0114:
0115: /**
0116: * Initializer.
0117: *
0118: * @param columnName The name of the column being referenced
0119: * @param tableName The qualification for the column
0120: */
0121:
0122: public void init(Object columnName, Object tableName) {
0123: this .columnName = (String) columnName;
0124: this .tableName = (TableName) tableName;
0125: tableNumber = -1;
0126: remaps = null;
0127: }
0128:
0129: /**
0130: * Convert this object to a String. See comments in QueryTreeNode.java
0131: * for how this should be done for tree printing.
0132: *
0133: * @return This object as a String
0134: */
0135:
0136: public String toString() {
0137: if (SanityManager.DEBUG) {
0138: return "columnName: "
0139: + columnName
0140: + "\n"
0141: + "tableNumber: "
0142: + tableNumber
0143: + "\n"
0144: + "columnNumber: "
0145: + columnNumber
0146: + "\n"
0147: + "replacesAggregate: "
0148: + replacesAggregate
0149: + "\n"
0150: + "tableName: "
0151: + ((tableName != null) ? tableName.toString()
0152: : "null") + "\n" + "nestingLevel: "
0153: + nestingLevel + "\n" + "sourceLevel: "
0154: + sourceLevel + "\n" + super .toString();
0155: } else {
0156: return "";
0157: }
0158: }
0159:
0160: /**
0161: * Prints the sub-nodes of this object. See QueryTreeNode.java for
0162: * how tree printing is supposed to work.
0163: *
0164: * @param depth The depth of this node in the tree
0165: */
0166:
0167: public void printSubNodes(int depth) {
0168: if (SanityManager.DEBUG) {
0169: super .printSubNodes(depth);
0170:
0171: if (source != null) {
0172: printLabel(depth, "source: ");
0173: source.treePrint(depth + 1);
0174: }
0175: }
0176: }
0177:
0178: /**
0179: * Return whether or not this CR is correlated.
0180: *
0181: * @return Whether or not this CR is correlated.
0182: */
0183: boolean getCorrelated() {
0184: if (SanityManager.DEBUG) {
0185: SanityManager.ASSERT(nestingLevel != -1, "nestingLevel on "
0186: + columnName + " is not expected to be -1");
0187: SanityManager.ASSERT(sourceLevel != -1, "sourceLevel on "
0188: + columnName + " is not expected to be -1");
0189: }
0190: return sourceLevel != nestingLevel;
0191: }
0192:
0193: /**
0194: * Set the nesting level for this CR. (The nesting level
0195: * at which the CR appears.)
0196: *
0197: * @param nestingLevel The Nesting level at which the CR appears.
0198: */
0199: void setNestingLevel(int nestingLevel) {
0200: if (SanityManager.DEBUG) {
0201: SanityManager.ASSERT(nestingLevel != -1,
0202: "nestingLevel is not expected to be -1");
0203: }
0204: this .nestingLevel = nestingLevel;
0205: }
0206:
0207: /**
0208: * Get the nesting level for this CR.
0209: *
0210: * @return The nesting level for this CR.
0211: */
0212: int getNestingLevel() {
0213: return nestingLevel;
0214: }
0215:
0216: /**
0217: * Set the source level for this CR. (The nesting level
0218: * of the source of the CR.)
0219: *
0220: * @param sourceLevel The Nesting level of the source of the CR.
0221: */
0222: void setSourceLevel(int sourceLevel) {
0223: if (SanityManager.DEBUG) {
0224: SanityManager.ASSERT(sourceLevel != -1,
0225: "sourceLevel is not expected to be -1");
0226: }
0227: this .sourceLevel = sourceLevel;
0228: }
0229:
0230: /**
0231: * Get the source level for this CR.
0232: *
0233: * @return The source level for this CR.
0234: */
0235: int getSourceLevel() {
0236: return sourceLevel;
0237: }
0238:
0239: /**
0240: * Mark this node as being generated to replace an aggregate.
0241: * (Useful for replacing aggregates in the HAVING clause with
0242: * column references to the matching aggregate in the
0243: * user's SELECT.
0244: */
0245: public void markGeneratedToReplaceAggregate() {
0246: replacesAggregate = true;
0247: }
0248:
0249: /**
0250: * Determine whether or not this node was generated to
0251: * replace an aggregate in the user's SELECT.
0252: *
0253: * @return boolean Whether or not this node was generated to replace
0254: * an aggregate in the user's SELECT.
0255: */
0256: public boolean getGeneratedToReplaceAggregate() {
0257: return replacesAggregate;
0258: }
0259:
0260: /**
0261: * Return a clone of this node.
0262: *
0263: * @return ValueNode A clone of this node.
0264: *
0265: * @exception StandardException Thrown on error
0266: */
0267: public ValueNode getClone() throws StandardException {
0268: ColumnReference newCR = (ColumnReference) getNodeFactory()
0269: .getNode(C_NodeTypes.COLUMN_REFERENCE, columnName,
0270: tableName, getContextManager());
0271:
0272: newCR.copyFields(this );
0273: return newCR;
0274: }
0275:
0276: /**
0277: * Copy all of the "appropriate fields" for a shallow copy.
0278: *
0279: * @param oldCR The ColumnReference to copy from.
0280: *
0281: * @exception StandardException Thrown on error
0282: */
0283: public void copyFields(ColumnReference oldCR)
0284: throws StandardException {
0285: super .copyFields(oldCR);
0286:
0287: tableName = oldCR.getTableNameNode();
0288: tableNumber = oldCR.getTableNumber();
0289: columnNumber = oldCR.getColumnNumber();
0290: source = oldCR.getSource();
0291: nestingLevel = oldCR.getNestingLevel();
0292: sourceLevel = oldCR.getSourceLevel();
0293: replacesAggregate = oldCR.getGeneratedToReplaceAggregate();
0294: scoped = oldCR.isScoped();
0295: }
0296:
0297: /**
0298: * Bind this expression. This means binding the sub-expressions,
0299: * as well as figuring out what the return type is for this expression.
0300: *
0301: * NOTE: We must explicitly check for a null FromList here, column reference
0302: * without a FROM list, as the grammar allows the following:
0303: * insert into t1 values(c1)
0304: *
0305: * @param fromList The FROM list for the query this
0306: * expression is in, for binding columns.
0307: * @param subqueryList The subquery list being built as we find SubqueryNodes
0308: * @param aggregateVector The aggregate vector being built as we find AggregateNodes
0309: *
0310: * @return The new top of the expression tree.
0311: *
0312: * @exception StandardException Thrown on error
0313: */
0314:
0315: public ValueNode bindExpression(FromList fromList,
0316: SubqueryList subqueryList, Vector aggregateVector)
0317: throws StandardException {
0318: ResultColumn matchingRC;
0319:
0320: if (SanityManager.DEBUG) {
0321: SanityManager.ASSERT(fromList != null,
0322: "fromList is expected to be non-null");
0323: }
0324:
0325: if (fromList.size() == 0) {
0326: throw StandardException.newException(
0327: SQLState.LANG_ILLEGAL_COLUMN_REFERENCE, columnName);
0328: }
0329:
0330: matchingRC = fromList.bindColumnReference(this );
0331:
0332: /* Error if no match found in fromList */
0333: if (matchingRC == null) {
0334: throw StandardException.newException(
0335: SQLState.LANG_COLUMN_NOT_FOUND, getSQLColumnName());
0336: }
0337:
0338: /* Set the columnNumber from the base table.
0339: * Useful for optimizer and generation.
0340: */
0341: columnNumber = matchingRC.getColumnPosition();
0342:
0343: return this ;
0344: }
0345:
0346: /**
0347: * Get the column name for purposes of error
0348: * messages or debugging. This returns the column
0349: * name as used in the SQL statement. Thus if it was qualified
0350: * with a table, alias name that will be included.
0351: *
0352: * @return The column name in the form [[schema.]table.]column
0353: */
0354:
0355: public String getSQLColumnName() {
0356: if (tableName == null)
0357: return columnName;
0358:
0359: return tableName.toString() + "." + columnName;
0360: }
0361:
0362: /**
0363: * Get the name of this column
0364: *
0365: * @return The name of this column
0366: */
0367:
0368: public String getColumnName() {
0369: return columnName;
0370: }
0371:
0372: /**
0373: * Set the name of this column
0374: *
0375: * @param columnName The name of this column
0376: */
0377:
0378: public void setColumnName(String columnName) {
0379: this .columnName = columnName;
0380: }
0381:
0382: /**
0383: * Get the table number for this ColumnReference.
0384: *
0385: * @return int The table number for this ColumnReference
0386: */
0387:
0388: public int getTableNumber() {
0389: return tableNumber;
0390: }
0391:
0392: /**
0393: * Set this ColumnReference to refer to the given table number.
0394: *
0395: * @param tableNumber The table number this ColumnReference will refer to
0396: */
0397:
0398: public void setTableNumber(int tableNumber) {
0399: if (SanityManager.DEBUG) {
0400: SanityManager.ASSERT(tableNumber != -1,
0401: "tableNumber not expected to be -1");
0402: }
0403: this .tableNumber = tableNumber;
0404: }
0405:
0406: /**
0407: * Get the user-supplied table name of this column. This will be null
0408: * if the user did not supply a name (for example, select a from t).
0409: * The method will return B for this example, select b.a from t as b
0410: * The method will return T for this example, select t.a from t
0411: *
0412: * @return The user-supplied name of this column. Null if no user-
0413: * supplied name.
0414: */
0415:
0416: public String getTableName() {
0417: return ((tableName != null) ? tableName.getTableName() : null);
0418: }
0419:
0420: /**
0421: * Get the name of the underlying(base) table this column comes from, if any.
0422: * Following example queries will all return T
0423: * select a from t
0424: * select b.a from t as b
0425: * select t.a from t
0426: *
0427: * @return The name of the base table that this column comes from.
0428: * Null if not a ColumnReference.
0429: */
0430:
0431: public String getSourceTableName() {
0432: return ((source != null) ? source.getTableName() : null);
0433: }
0434:
0435: /**
0436: * Get the name of the schema for the Column's base table, if any.
0437: * Following example queries will all return APP (assuming user is in schema APP)
0438: * select t.a from t
0439: * select b.a from t as b
0440: * select app.t.a from t
0441: *
0442: * @return The name of the schema for Column's base table. If the column
0443: * is not in a schema (i.e. is a derived column), it returns NULL.
0444: */
0445: public String getSourceSchemaName() throws StandardException {
0446: return ((source != null) ? source.getSchemaName() : null);
0447: }
0448:
0449: /**
0450: * Is the column wirtable by the cursor or not. (ie, is it in the list of FOR UPDATE columns list)
0451: *
0452: * @return TRUE, if the column is a base column of a table and is
0453: * writable by cursor.
0454: */
0455: public boolean updatableByCursor() {
0456: return ((source != null) ? source.updatableByCursor() : false);
0457: }
0458:
0459: /**
0460: Return the table name as the node it is.
0461: @return the column's table name.
0462: */
0463: public TableName getTableNameNode() {
0464: return tableName;
0465: }
0466:
0467: public void setTableNameNode(TableName tableName) {
0468: this .tableName = tableName;
0469: }
0470:
0471: /**
0472: * Get the column number for this ColumnReference.
0473: *
0474: * @return int The column number for this ColumnReference
0475: */
0476:
0477: public int getColumnNumber() {
0478: return columnNumber;
0479: }
0480:
0481: /**
0482: * Set the column number for this ColumnReference. This is
0483: * used when scoping predicates for pushdown.
0484: *
0485: * @param colNum The new column number.
0486: */
0487:
0488: public void setColumnNumber(int colNum) {
0489: this .columnNumber = colNum;
0490: }
0491:
0492: /**
0493: * Get the source this columnReference
0494: *
0495: * @return The source of this columnReference
0496: */
0497:
0498: public ResultColumn getSource() {
0499: return source;
0500: }
0501:
0502: /**
0503: * Set the source this columnReference
0504: *
0505: * @param source The source of this columnReference
0506: */
0507:
0508: public void setSource(ResultColumn source) {
0509: this .source = source;
0510: }
0511:
0512: /**
0513: * Do the 1st step in putting an expression into conjunctive normal
0514: * form. This step ensures that the top level of the expression is
0515: * a chain of AndNodes.
0516: *
0517: * @return The modified expression
0518: *
0519: * @exception StandardException Thrown on error
0520: */
0521: public ValueNode putAndsOnTop() throws StandardException {
0522: BinaryComparisonOperatorNode equalsNode;
0523: BooleanConstantNode trueNode;
0524: NodeFactory nodeFactory = getNodeFactory();
0525: ValueNode andNode;
0526:
0527: trueNode = (BooleanConstantNode) nodeFactory.getNode(
0528: C_NodeTypes.BOOLEAN_CONSTANT_NODE, Boolean.TRUE,
0529: getContextManager());
0530: equalsNode = (BinaryComparisonOperatorNode) nodeFactory
0531: .getNode(C_NodeTypes.BINARY_EQUALS_OPERATOR_NODE, this ,
0532: trueNode, getContextManager());
0533: /* Set type info for the operator node */
0534: equalsNode.bindComparisonOperator();
0535: andNode = (ValueNode) nodeFactory.getNode(C_NodeTypes.AND_NODE,
0536: equalsNode, trueNode, getContextManager());
0537: ((AndNode) andNode).postBindFixup();
0538: return andNode;
0539: }
0540:
0541: /**
0542: * Categorize this predicate. Initially, this means
0543: * building a bit map of the referenced tables for each predicate.
0544: * If the source of this ColumnReference (at the next underlying level)
0545: * is not a ColumnReference or a VirtualColumnNode then this predicate
0546: * will not be pushed down.
0547: *
0548: * For example, in:
0549: * select * from (select 1 from s) a (x) where x = 1
0550: * we will not push down x = 1.
0551: * NOTE: It would be easy to handle the case of a constant, but if the
0552: * inner SELECT returns an arbitrary expression, then we would have to copy
0553: * that tree into the pushed predicate, and that tree could contain
0554: * subqueries and method calls.
0555: *
0556: * Also, don't allow a predicate to be pushed down if it contains a
0557: * ColumnReference that replaces an aggregate. This can happen if
0558: * the aggregate is in the HAVING clause. In this case, we would be
0559: * pushing the predicate into the SelectNode that evaluates the aggregate,
0560: * which doesn't make sense, since the having clause is supposed to be
0561: * applied to the result of the SelectNode.
0562: *
0563: * RESOLVE - revisit this issue once we have views.
0564: *
0565: * @param referencedTabs JBitSet with bit map of referenced FromTables
0566: * @param simplePredsOnly Whether or not to consider method
0567: * calls, field references and conditional nodes
0568: * when building bit map
0569: *
0570: * @return boolean Whether or not source.expression is a ColumnReference
0571: * or a VirtualColumnNode or a ConstantNode.
0572: */
0573: public boolean categorize(JBitSet referencedTabs,
0574: boolean simplePredsOnly) {
0575: if (SanityManager.DEBUG)
0576: SanityManager.ASSERT(tableNumber >= 0,
0577: "tableNumber is expected to be non-negative");
0578: referencedTabs.set(tableNumber);
0579:
0580: return (!replacesAggregate)
0581: && ((source.getExpression() instanceof ColumnReference)
0582: || (source.getExpression() instanceof VirtualColumnNode) || (source
0583: .getExpression() instanceof ConstantNode));
0584: }
0585:
0586: /**
0587: * Remap all of the ColumnReferences in this expression tree
0588: * to point to the ResultColumn that is 1 level under their
0589: * current source ResultColumn.
0590: * This is useful for pushing down single table predicates.
0591: *
0592: * RESOLVE: Once we start pushing join clauses, we will need to walk the
0593: * ResultColumn/VirtualColumnNode chain for them to remap the references.
0594: */
0595: public void remapColumnReferences() {
0596: ValueNode expression = source.getExpression();
0597:
0598: if (SanityManager.DEBUG) {
0599: // SanityManager.ASSERT(origSource == null,
0600: // "Trying to remap ColumnReference twice without unremapping it.");
0601: }
0602:
0603: if (!((expression instanceof VirtualColumnNode) || (expression instanceof ColumnReference))) {
0604: return;
0605: }
0606:
0607: /* Scoped column references are a special case: they can be
0608: * remapped several times (once for every ProjectRestrictNode
0609: * through which the scoped ColumnReference is pushed before
0610: * reaching its target result set) and will be un-remapped
0611: * several times, as well (as the scoped predicate is "pulled"
0612: * back up the query tree to it's original location). So we
0613: * have to keep track of the "orig" info for every remap
0614: * operation, not just for the most recent one.
0615: */
0616: if (scoped && (origSource != null)) {
0617: if (remaps == null)
0618: remaps = new java.util.ArrayList();
0619: remaps.add(new RemapInfo(columnNumber, tableNumber,
0620: columnName, source));
0621: } else {
0622: origSource = source;
0623: origName = columnName;
0624: origColumnNumber = columnNumber;
0625: origTableNumber = tableNumber;
0626: }
0627:
0628: /* Find the matching ResultColumn */
0629: source = getSourceResultColumn();
0630: columnName = source.getName();
0631: columnNumber = source.getColumnPosition();
0632:
0633: if (source.getExpression() instanceof ColumnReference) {
0634: ColumnReference cr = (ColumnReference) source
0635: .getExpression();
0636: tableNumber = cr.getTableNumber();
0637: if (SanityManager.DEBUG) {
0638: // if dummy cr generated to replace aggregate, it may not have table number
0639: // because underneath can be more than 1 table.
0640: if (tableNumber == -1
0641: && !cr.getGeneratedToReplaceAggregate()) {
0642: SanityManager
0643: .THROWASSERT("tableNumber not expected to be -1, origName = "
0644: + origName);
0645: }
0646: }
0647: }
0648: }
0649:
0650: public void unRemapColumnReferences() {
0651: if (origSource == null)
0652: return;
0653:
0654: if (SanityManager.DEBUG) {
0655: // SanityManager.ASSERT(origSource != null,
0656: // "Trying to unremap a ColumnReference that was not remapped.");
0657: }
0658:
0659: if ((remaps == null) || (remaps.size() == 0)) {
0660: source = origSource;
0661: origSource = null;
0662: columnName = origName;
0663: origName = null;
0664: tableNumber = origTableNumber;
0665: columnNumber = origColumnNumber;
0666: } else {
0667: // This CR is multiply-remapped, so undo the most
0668: // recent (and only the most recent) remap operation.
0669: RemapInfo rI = (RemapInfo) remaps.remove(remaps.size() - 1);
0670: source = rI.getSource();
0671: columnName = rI.getColumnName();
0672: tableNumber = rI.getTableNumber();
0673: columnNumber = rI.getColumnNumber();
0674: rI = null;
0675: if (remaps.size() == 0)
0676: remaps = null;
0677: }
0678: }
0679:
0680: /**
0681: * Returns true if this ColumnReference has been remapped; false
0682: * otherwise.
0683: *
0684: * @return Whether or not this ColumnReference has been remapped.
0685: */
0686: protected boolean hasBeenRemapped() {
0687: return (origSource != null);
0688: }
0689:
0690: /*
0691: * Get the ResultColumn that the source points to. This is useful for
0692: * getting what the source will be after this ColumnReference is remapped.
0693: */
0694: public ResultColumn getSourceResultColumn() {
0695: ValueNode expression = source.getExpression();
0696:
0697: /* Find the matching ResultColumn */
0698: if (expression instanceof VirtualColumnNode) {
0699: return ((VirtualColumnNode) expression)
0700: .getSourceResultColumn();
0701: } else {
0702: /* RESOLVE - If expression is a ColumnReference, then we are hitting
0703: * the top of a query block (derived table or view.)
0704: * In order to be able to push the expression down into the next
0705: * query block, it looks like we should reset the contents of the
0706: * current ColumnReference to be the same as expression. (This probably
0707: * only means names and tableNumber.) We would then "rebind" the top
0708: * level predicate somewhere up the call stack and see if we could push
0709: * the predicate through.
0710: */
0711: return ((ColumnReference) expression)
0712: .getSourceResultColumn();
0713: }
0714: }
0715:
0716: /**
0717: * Remap all ColumnReferences in this tree to be clones of the
0718: * underlying expression.
0719: *
0720: * @return ValueNode The remapped expression tree.
0721: *
0722: * @exception StandardException Thrown on error
0723: */
0724: public ValueNode remapColumnReferencesToExpressions()
0725: throws StandardException {
0726: ResultColumn rc;
0727: ResultColumn sourceRC = source;
0728:
0729: /* Nothing to do if we are not pointing to a redundant RC */
0730: if (!source.isRedundant()) {
0731: return this ;
0732: }
0733:
0734: /* Find the last redundant RC in the chain. We
0735: * want to clone its expression.
0736: */
0737: for (rc = source; rc != null && rc.isRedundant();) {
0738: ResultColumn nextRC = null;
0739: ValueNode expression = rc.getExpression();
0740:
0741: /* Find the matching ResultColumn */
0742: if (expression instanceof VirtualColumnNode) {
0743: nextRC = ((VirtualColumnNode) expression)
0744: .getSourceResultColumn();
0745: } else if (expression instanceof ColumnReference) {
0746: nextRC = ((ColumnReference) expression)
0747: .getSourceResultColumn();
0748: } else {
0749: nextRC = null;
0750: }
0751:
0752: if (nextRC != null && nextRC.isRedundant()) {
0753: sourceRC = nextRC;
0754: }
0755: rc = nextRC;
0756: }
0757:
0758: if (SanityManager.DEBUG) {
0759: if (sourceRC == null) {
0760: SanityManager
0761: .THROWASSERT("sourceRC is expected to be non-null for "
0762: + columnName);
0763: }
0764:
0765: if (!sourceRC.isRedundant()) {
0766: SanityManager
0767: .THROWASSERT("sourceRC is expected to be redundant for "
0768: + columnName);
0769: }
0770: }
0771:
0772: /* If last expression is a VCN, then we can't clone it.
0773: * Instead, we just reset our source to point to the
0774: * source of the VCN, those chopping out the layers.
0775: * Otherwise, we return a clone of the underlying expression.
0776: */
0777: if (sourceRC.getExpression() instanceof VirtualColumnNode) {
0778: VirtualColumnNode vcn = (VirtualColumnNode) (sourceRC
0779: .getExpression());
0780: ResultSetNode rsn = vcn.getSourceResultSet();
0781: if (rsn instanceof FromTable) {
0782: tableNumber = ((FromTable) rsn).getTableNumber();
0783: if (SanityManager.DEBUG) {
0784: SanityManager.ASSERT(tableNumber != -1,
0785: "tableNumber not expected to be -1");
0786: }
0787: } else {
0788: if (SanityManager.DEBUG) {
0789: SanityManager
0790: .THROWASSERT("rsn expected to be a FromTable, but is a "
0791: + rsn.getClass().getName());
0792: }
0793: }
0794: source = ((VirtualColumnNode) sourceRC.getExpression())
0795: .getSourceResultColumn();
0796: return this ;
0797: } else {
0798: return sourceRC.getExpression().getClone();
0799: }
0800: }
0801:
0802: /**
0803: * Update the table map to reflect the source
0804: * of this CR.
0805: *
0806: * @param refs The table map.
0807: */
0808: void getTablesReferenced(JBitSet refs) {
0809: if (refs.size() < tableNumber)
0810: refs.grow(tableNumber);
0811:
0812: if (tableNumber != -1) // it may not be set if replacesAggregate is true
0813: refs.set(tableNumber);
0814: }
0815:
0816: /**
0817: * Return whether or not this expression tree is cloneable.
0818: *
0819: * @return boolean Whether or not this expression tree is cloneable.
0820: */
0821: public boolean isCloneable() {
0822: return true;
0823: }
0824:
0825: /** @see ValueNode#constantExpression */
0826: public boolean constantExpression(PredicateList whereClause) {
0827: return whereClause.constantColumn(this );
0828: }
0829:
0830: /**
0831: * ColumnReference's are to the current row in the system.
0832: * This lets us generate
0833: * a faster get that simply returns the column from the
0834: * current row, rather than getting the value out and
0835: * returning that, only to have the caller (in the situations
0836: * needed) stuffing it back into a new column holder object.
0837: * We will assume the general generate() path is for getting
0838: * the value out, and use generateColumn() when we want to
0839: * keep the column wrapped.
0840: *
0841: * @exception StandardException Thrown on error
0842: */
0843: public void generateExpression(ExpressionClassBuilder acb,
0844: MethodBuilder mb) throws StandardException {
0845: int sourceResultSetNumber = source.getResultSetNumber();
0846:
0847: //PUSHCOMPILE
0848: /* Reuse generated code, where possible */
0849:
0850: /*
0851: ** If the source is redundant, return the generation of its source.
0852: ** Most redundant nodes will be flattened out by this point, but
0853: ** in at least one case (elimination of redundant ProjectRestricts
0854: ** during generation) we don't do this.
0855: */
0856: if (source.isRedundant()) {
0857: source.generateExpression(acb, mb);
0858: return;
0859: }
0860:
0861: if (SanityManager.DEBUG) {
0862: if (sourceResultSetNumber < 0) {
0863: SanityManager
0864: .THROWASSERT("sourceResultSetNumber expected to be >= 0 for "
0865: + getTableName()
0866: + "."
0867: + getColumnName());
0868: }
0869: }
0870:
0871: /* The ColumnReference is from an immediately underlying ResultSet.
0872: * The Row for that ResultSet is Activation.row[sourceResultSetNumber],
0873: * where sourceResultSetNumber is the resultSetNumber for that ResultSet.
0874: *
0875: * The generated java is the expression:
0876: * (<interface>) this.row[sourceResultSetNumber].getColumn(#columnId);
0877: *
0878: * where <interface> is the appropriate Datatype protocol interface
0879: * for the type of the column.
0880: */
0881: acb.pushColumnReference(mb, sourceResultSetNumber, source
0882: .getVirtualColumnId());
0883:
0884: mb.cast(getTypeCompiler().interfaceName());
0885:
0886: /* Remember generated code for possible resuse */
0887: }
0888:
0889: /**
0890: * Get the user-supplied schema name of this column. This will be null
0891: * if the user did not supply a name (for example, select t.a from t).
0892: * Another example for null return value (for example, select b.a from t as b).
0893: * But for following query select app.t.a from t, this will return APP
0894: * Code generation of aggregate functions relies on this method
0895: *
0896: * @return The user-supplied schema name of this column. Null if no user-
0897: * supplied name.
0898: */
0899:
0900: public String getSchemaName() {
0901: return ((tableName != null) ? tableName.getSchemaName() : null);
0902: }
0903:
0904: /**
0905: * Return the variant type for the underlying expression.
0906: * The variant type can be:
0907: * VARIANT - variant within a scan
0908: * (method calls and non-static field access)
0909: * SCAN_INVARIANT - invariant within a scan
0910: * (column references from outer tables)
0911: * QUERY_INVARIANT - invariant within the life of a query
0912: * (constant expressions)
0913: *
0914: * @return The variant type for the underlying expression.
0915: */
0916: protected int getOrderableVariantType() {
0917: // ColumnReferences are invariant for the life of the scan
0918: return Qualifier.SCAN_INVARIANT;
0919: }
0920:
0921: /**
0922: * Return whether or not the source of this ColumnReference is itself a ColumnReference.
0923: *
0924: * @return Whether or not the source of this ColumnReference is itself a ColumnReference.
0925: */
0926: boolean pointsToColumnReference() {
0927: return (source.getExpression() instanceof ColumnReference);
0928: }
0929:
0930: /**
0931: * Get the DataTypeServices from this Node.
0932: *
0933: * @return The DataTypeServices from this Node. This
0934: * may be null if the node isn't bound yet.
0935: */
0936: public DataTypeDescriptor getTypeServices()
0937: throws StandardException {
0938: DataTypeDescriptor dtd = super .getTypeServices();
0939: if (dtd == null && source != null) {
0940: dtd = source.getTypeServices();
0941: if (dtd != null)
0942: setType(dtd);
0943: }
0944: return dtd;
0945: } // end of getTypeServices
0946:
0947: /**
0948: * Find the source result set for this ColumnReference and
0949: * return it. Also, when the source result set is found,
0950: * return the position (within the source result set's RCL)
0951: * of the column referenced by this ColumnReference. The
0952: * position is returned vai the colNum parameter.
0953: *
0954: * @param colNum Place to store the position of the column
0955: * to which this ColumnReference points (position is w.r.t
0956: * the source result set).
0957: * @return The source result set for this ColumnReference;
0958: * null if there is no source result set.
0959: */
0960: protected ResultSetNode getSourceResultSet(int[] colNum)
0961: throws StandardException {
0962: if (source == null) {
0963: /* this can happen if column reference is pointing to a column
0964: * that is not from a base table. For example, if we have a
0965: * VALUES clause like
0966: *
0967: * (values (1, 2), (3, 4)) V1 (i, j)
0968: *
0969: * and then a column reference to VI.i, the column reference
0970: * won't have a source.
0971: */
0972: return null;
0973: }
0974:
0975: ValueNode rcExpr = null;
0976: ResultColumn rc = getSource();
0977:
0978: // Walk the ResultColumn->ColumnReference chain until we
0979: // find a ResultColumn whose expression is a VirtualColumnNode.
0980:
0981: rcExpr = rc.getExpression();
0982: colNum[0] = getColumnNumber();
0983:
0984: /* We have to make sure we enter this loop if rc is redundant,
0985: * so that we can navigate down to the actual source result
0986: * set (DERBY-1777). If rc *is* redundant, then rcExpr is not
0987: * guaranteed to be a ColumnReference, so we have to check
0988: * for that case inside the loop.
0989: */
0990: while ((rcExpr != null)
0991: && (rc.isRedundant() || (rcExpr instanceof ColumnReference))) {
0992: if (rcExpr instanceof ColumnReference) {
0993: colNum[0] = ((ColumnReference) rcExpr)
0994: .getColumnNumber();
0995: rc = ((ColumnReference) rcExpr).getSource();
0996: }
0997:
0998: /* If "rc" is redundant then that means it points to another
0999: * ResultColumn that in turn points to the source expression.
1000: * This can happen in cases where "rc" points to a subquery
1001: * that has been flattened into the query above it (flattening
1002: * of subqueries occurs during preprocessing). In that case
1003: * we want to skip over the redundant rc and find the
1004: * ResultColumn that actually holds the source expression.
1005: */
1006: while (rc.isRedundant()) {
1007: rcExpr = rc.getExpression();
1008: if (rcExpr instanceof VirtualColumnNode)
1009: rc = ((VirtualColumnNode) rcExpr)
1010: .getSourceResultColumn();
1011: else if (rcExpr instanceof ColumnReference) {
1012: colNum[0] = ((ColumnReference) rcExpr)
1013: .getColumnNumber();
1014: rc = ((ColumnReference) rcExpr).getSource();
1015: } else {
1016: /* If rc isn't pointing to a VirtualColumnNode nor
1017: * to a ColumnReference, then it's not pointing to
1018: * a result set. It could, for example, be pointing
1019: * to a constant node or to the result of an aggregate
1020: * or function. Break out of both loops and return
1021: * null since there is no source result set.
1022: */
1023: rcExpr = null;
1024: break;
1025: }
1026: }
1027: rcExpr = rc.getExpression();
1028: }
1029:
1030: // If we found a VirtualColumnNode, return the VirtualColumnNode's
1031: // sourceResultSet. The column within that sourceResultSet that
1032: // is referenced by this ColumnReference is also returned, via
1033: // the colNum parameter, and was set above.
1034: if ((rcExpr != null) && (rcExpr instanceof VirtualColumnNode))
1035: return ((VirtualColumnNode) rcExpr).getSourceResultSet();
1036:
1037: // If we get here then the ColumnReference doesn't reference
1038: // a result set, so return null.
1039: colNum[0] = -1;
1040: return null;
1041: }
1042:
1043: protected boolean isEquivalent(ValueNode o)
1044: throws StandardException {
1045: if (!isSameNodeType(o)) {
1046: return false;
1047: }
1048: ColumnReference other = (ColumnReference) o;
1049: return (tableNumber == other.tableNumber && columnName
1050: .equals(other.getColumnName()));
1051: }
1052:
1053: /**
1054: * Mark this column reference as "scoped", which means that it
1055: * was created (as a clone of another ColumnReference) to serve
1056: * as the left or right operand of a scoped predicate.
1057: */
1058: protected void markAsScoped() {
1059: scoped = true;
1060: }
1061:
1062: /**
1063: * Return whether or not this ColumnReference is scoped.
1064: */
1065: protected boolean isScoped() {
1066: return scoped;
1067: }
1068:
1069: /**
1070: * Helper class to keep track of remap data when a ColumnReference
1071: * is remapped multiple times. This allows the CR to be UN-
1072: * remapped multiple times, as well.
1073: */
1074: private class RemapInfo {
1075: int colNum;
1076: int tableNum;
1077: String colName;
1078: ResultColumn source;
1079:
1080: RemapInfo(int cNum, int tNum, String cName, ResultColumn rc) {
1081: colNum = cNum;
1082: tableNum = tNum;
1083: colName = cName;
1084: source = rc;
1085: }
1086:
1087: int getColumnNumber() {
1088: return colNum;
1089: }
1090:
1091: int getTableNumber() {
1092: return tableNum;
1093: }
1094:
1095: String getColumnName() {
1096: return colName;
1097: }
1098:
1099: ResultColumn getSource() {
1100: return source;
1101: }
1102:
1103: void setColNumber(int cNum) {
1104: colNum = cNum;
1105: }
1106:
1107: void setTableNumber(int tNum) {
1108: tableNum = tNum;
1109: }
1110:
1111: void setColName(String cName) {
1112: colName = cName;
1113: }
1114:
1115: void setSource(ResultColumn rc) {
1116: source = rc;
1117: }
1118: }
1119: }
|