001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.compile.BaseTableNumbersVisitor
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to you under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.impl.sql.compile;
023:
024: import org.apache.derby.iapi.sql.compile.Visitable;
025: import org.apache.derby.iapi.sql.compile.Visitor;
026: import org.apache.derby.iapi.util.JBitSet;
027:
028: import org.apache.derby.iapi.error.StandardException;
029: import org.apache.derby.iapi.services.sanity.SanityManager;
030:
031: /**
032: * Walk through a subtree and build a list of the assigned numbers for
033: * all tables that exist in that subtree. We do this by looking for any
034: * column references in the subtree and, for each column reference, we
035: * walk down the ColumnReference-ResultColumn chain until we find the
036: * the bottom-most table number, which should correspond to a base
037: * table.
038: */
039: public class BaseTableNumbersVisitor implements Visitor {
040: // JBitSet to hold the table numbers that we find.
041: private JBitSet tableMap;
042:
043: /**
044: * Constructor: takes a JBitSet to use as the holder for any base table
045: * numbers found while walking the subtree.
046: *
047: * @param tableMap JBitSet into which we put the table numbers we find.
048: */
049: public BaseTableNumbersVisitor(JBitSet tableMap) {
050: this .tableMap = tableMap;
051: }
052:
053: /**
054: * Set a new JBitSet to serve as the holder for base table numbers
055: * we find while walking.
056: *
057: * @param tableMap JBitSet into which we put the table numbers we find.
058: */
059: protected void setTableMap(JBitSet tableMap) {
060: this .tableMap = tableMap;
061: }
062:
063: ////////////////////////////////////////////////
064: //
065: // VISITOR INTERFACE
066: //
067: ////////////////////////////////////////////////
068:
069: /**
070: * @see org.apache.derby.iapi.sql.compile.Visitor#visit
071: */
072: public Visitable visit(Visitable node) throws StandardException {
073: ResultColumn rc = null;
074: if (node instanceof ColumnReference) {
075: // Start by seeing if this column reference is the
076: // bottom-most one, meaning that there are no column
077: // references beneath this one.
078: rc = ((ColumnReference) node).getSource();
079:
080: if (rc == null) {
081: // this can happen if column reference is pointing to a column
082: // that is not from a base table. For example, if we have a
083: // VALUES clause like
084: //
085: // (values (1, 2), (3, 4)) V1 (i, j)
086: //
087: // and then a column reference to VI.i, the column reference
088: // won't have a source.
089: return node;
090: }
091: } else if (node instanceof ResultColumn)
092: rc = (ResultColumn) rc;
093: else if (node instanceof SelectNode) {
094: // If the node is a SelectNode we just need to look at its
095: // FROM list.
096: ((SelectNode) node).getFromList().accept(this );
097: } else if (node instanceof FromBaseTable) {
098: // just grab the FBT's table number.
099: tableMap.set(((FromBaseTable) node).getTableNumber());
100: }
101:
102: if (rc != null) {
103: // This next call will walk through the ResultColumn tree
104: // until it finds another ColumnReference, and then will
105: // return the table number for that column reference. We
106: // can't stop there, though, because the column reference
107: // that we found might in turn have column references beneath
108: // it, and we only want the table number of the bottom-most
109: // column reference. So once we find the column reference,
110: // we have to recurse.
111:
112: int baseTableNumber = rc.getTableNumber();
113: if (baseTableNumber >= 0) {
114: // Move down to the column reference that has the table
115: // number that we just found. There may be one or more
116: // VirtualColumnNode-to-ResultColumnNode links between
117: // the current ResultColumn and the column reference we're
118: // looking for, so we have to walk past those until we find
119: // the desired column reference.
120:
121: ValueNode rcExpr = rc.getExpression();
122: while (rcExpr instanceof VirtualColumnNode) {
123: rc = ((VirtualColumnNode) rcExpr).getSourceColumn();
124: rcExpr = rc.getExpression();
125: }
126:
127: if (rcExpr instanceof ColumnReference)
128: // we found our column reference; recurse using that.
129: rcExpr.accept(this );
130: else {
131: // Else we must have found the table number someplace
132: // other than within a ColumnReference (ex. we may
133: // have pulled it from a VirtualColumnNode's source
134: // table); so just set the number.
135: tableMap.set(baseTableNumber);
136: }
137: } else if (node instanceof ColumnReference) {
138: // we couldn't find any other table numbers beneath the
139: // ColumnReference, so just use the table number for
140: // that reference.
141: ((ColumnReference) node).getTablesReferenced(tableMap);
142: }
143: }
144:
145: return node;
146: }
147:
148: /**
149: * @see org.apache.derby.iapi.sql.compile.Visitor#skipChildren
150: */
151: public boolean skipChildren(Visitable node) {
152: /* A SelectNode's children can include a where clause in the
153: * form of either a PredicateList or an AndNode. In either
154: * case we don't want to descend into the where clause because
155: * it's possible that it references a base table that is not
156: * in the subtree we're walking. So we skip the children of
157: * a SelectNode. Similarly, any other PredicateList may contain
158: * references to base tables that we don't want to include, so
159: * we skip a PredicateList's children as well. Note, though,
160: * that if this visitor is specifically targeted for a particular
161: * Predicate or AndNode (i.e. a call is directly made to
162: * Predicate.accept() or AndNode.accept()) then we _will_ descend
163: * into that predicate's operands and retrieve referenced base
164: * table numbers.
165: *
166: * And finally, if we visit a FromBaseTable we can just grab
167: * it's number and that's it--there's no need to go any further.
168: */
169: return (node instanceof FromBaseTable)
170: || (node instanceof SelectNode)
171: || (node instanceof PredicateList);
172: }
173:
174: /**
175: * @see org.apache.derby.iapi.sql.compile.Visitor#stopTraversal
176: */
177: public boolean stopTraversal() {
178: return false;
179: }
180:
181: }
|