KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > impl > sql > compile > BaseTableNumbersVisitor


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.compile.BaseTableNumbersVisitor
4
5    Licensed to the Apache Software Foundation (ASF) under one or more
6    contributor license agreements. See the NOTICE file distributed with
7    this work for additional information regarding copyright ownership.
8    The ASF licenses this file to you under the Apache License, Version 2.0
9    (the "License"); you may not use this file except in compliance with
10    the License. You may obtain a copy of the License at
11
12       http://www.apache.org/licenses/LICENSE-2.0
13
14    Unless required by applicable law or agreed to in writing, software
15    distributed under the License is distributed on an "AS IS" BASIS,
16    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17    See the License for the specific language governing permissions and
18    limitations under the License.
19
20  */

21
22 package org.apache.derby.impl.sql.compile;
23
24 import org.apache.derby.iapi.sql.compile.Visitable;
25 import org.apache.derby.iapi.sql.compile.Visitor;
26 import org.apache.derby.iapi.util.JBitSet;
27
28 import org.apache.derby.iapi.error.StandardException;
29 import org.apache.derby.iapi.services.sanity.SanityManager;
30
31 /**
32  * Walk through a subtree and build a list of the assigned numbers for
33  * all tables that exist in that subtree. We do this by looking for any
34  * column references in the subtree and, for each column reference, we
35  * walk down the ColumnReference-ResultColumn chain until we find the
36  * the bottom-most table number, which should correspond to a base
37  * table.
38  */

39 public class BaseTableNumbersVisitor implements Visitor
40 {
41     // JBitSet to hold the table numbers that we find.
42
private JBitSet tableMap;
43
44     /**
45      * Constructor: takes a JBitSet to use as the holder for any base table
46      * numbers found while walking the subtree.
47      *
48      * @param tableMap JBitSet into which we put the table numbers we find.
49      */

50     public BaseTableNumbersVisitor(JBitSet tableMap)
51     {
52         this.tableMap = tableMap;
53     }
54
55     /**
56      * Set a new JBitSet to serve as the holder for base table numbers
57      * we find while walking.
58      *
59      * @param tableMap JBitSet into which we put the table numbers we find.
60      */

61     protected void setTableMap(JBitSet tableMap)
62     {
63         this.tableMap = tableMap;
64     }
65
66     ////////////////////////////////////////////////
67
//
68
// VISITOR INTERFACE
69
//
70
////////////////////////////////////////////////
71

72     /**
73      * @see org.apache.derby.iapi.sql.compile.Visitor#visit
74      */

75     public Visitable visit(Visitable node)
76         throws StandardException
77     {
78         ResultColumn rc = null;
79         if (node instanceof ColumnReference)
80         {
81             // Start by seeing if this column reference is the
82
// bottom-most one, meaning that there are no column
83
// references beneath this one.
84
rc = ((ColumnReference)node).getSource();
85
86             if (rc == null) {
87             // this can happen if column reference is pointing to a column
88
// that is not from a base table. For example, if we have a
89
// VALUES clause like
90
//
91
// (values (1, 2), (3, 4)) V1 (i, j)
92
//
93
// and then a column reference to VI.i, the column reference
94
// won't have a source.
95
return node;
96             }
97         }
98         else if (node instanceof ResultColumn)
99             rc = (ResultColumn)rc;
100         else if (node instanceof SelectNode)
101         {
102             // If the node is a SelectNode we just need to look at its
103
// FROM list.
104
((SelectNode)node).getFromList().accept(this);
105         }
106         else if (node instanceof FromBaseTable) {
107         // just grab the FBT's table number.
108
tableMap.set(((FromBaseTable)node).getTableNumber());
109         }
110
111         if (rc != null)
112         {
113             // This next call will walk through the ResultColumn tree
114
// until it finds another ColumnReference, and then will
115
// return the table number for that column reference. We
116
// can't stop there, though, because the column reference
117
// that we found might in turn have column references beneath
118
// it, and we only want the table number of the bottom-most
119
// column reference. So once we find the column reference,
120
// we have to recurse.
121

122             int baseTableNumber = rc.getTableNumber();
123             if (baseTableNumber >= 0) {
124             // Move down to the column reference that has the table
125
// number that we just found. There may be one or more
126
// VirtualColumnNode-to-ResultColumnNode links between
127
// the current ResultColumn and the column reference we're
128
// looking for, so we have to walk past those until we find
129
// the desired column reference.
130

131                 ValueNode rcExpr = rc.getExpression();
132                 while (rcExpr instanceof VirtualColumnNode) {
133                     rc = ((VirtualColumnNode)rcExpr).getSourceColumn();
134                     rcExpr = rc.getExpression();
135                 }
136
137                 if (rcExpr instanceof ColumnReference)
138                 // we found our column reference; recurse using that.
139
rcExpr.accept(this);
140                 else {
141                 // Else we must have found the table number someplace
142
// other than within a ColumnReference (ex. we may
143
// have pulled it from a VirtualColumnNode's source
144
// table); so just set the number.
145
tableMap.set(baseTableNumber);
146                 }
147             }
148             else if (node instanceof ColumnReference) {
149             // we couldn't find any other table numbers beneath the
150
// ColumnReference, so just use the table number for
151
// that reference.
152
((ColumnReference)node).getTablesReferenced(tableMap);
153             }
154         }
155
156         return node;
157     }
158
159     /**
160      * @see org.apache.derby.iapi.sql.compile.Visitor#skipChildren
161      */

162     public boolean skipChildren(Visitable node)
163     {
164         /* A SelectNode's children can include a where clause in the
165          * form of either a PredicateList or an AndNode. In either
166          * case we don't want to descend into the where clause because
167          * it's possible that it references a base table that is not
168          * in the subtree we're walking. So we skip the children of
169          * a SelectNode. Similarly, any other PredicateList may contain
170          * references to base tables that we don't want to include, so
171          * we skip a PredicateList's children as well. Note, though,
172          * that if this visitor is specifically targeted for a particular
173          * Predicate or AndNode (i.e. a call is directly made to
174          * Predicate.accept() or AndNode.accept()) then we _will_ descend
175          * into that predicate's operands and retrieve referenced base
176          * table numbers.
177          *
178          * And finally, if we visit a FromBaseTable we can just grab
179          * it's number and that's it--there's no need to go any further.
180          */

181         return (node instanceof FromBaseTable) ||
182             (node instanceof SelectNode) ||
183             (node instanceof PredicateList);
184     }
185
186     /**
187      * @see org.apache.derby.iapi.sql.compile.Visitor#stopTraversal
188      */

189     public boolean stopTraversal()
190     {
191         return false;
192     }
193
194 }
195
Popular Tags