KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.compile.HashTableNode
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.services.context.ContextManager;
25
26 import org.apache.derby.iapi.sql.compile.Optimizable;
27 import org.apache.derby.iapi.sql.compile.OptimizablePredicate;
28 import org.apache.derby.iapi.sql.compile.OptimizablePredicateList;
29 import org.apache.derby.iapi.sql.compile.Optimizer;
30 import org.apache.derby.iapi.sql.compile.CostEstimate;
31 import org.apache.derby.iapi.sql.compile.OptimizableList;
32 import org.apache.derby.iapi.sql.compile.Visitable;
33 import org.apache.derby.iapi.sql.compile.Visitor;
34 import org.apache.derby.iapi.sql.compile.RequiredRowOrdering;
35 import org.apache.derby.iapi.sql.compile.RowOrdering;
36 import org.apache.derby.iapi.sql.compile.AccessPath;
37 import org.apache.derby.iapi.reference.ClassName;
38
39
40 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
41 import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;
42
43 import org.apache.derby.iapi.sql.Activation;
44 import org.apache.derby.iapi.sql.ResultSet;
45
46 import org.apache.derby.iapi.error.StandardException;
47
48 import org.apache.derby.iapi.store.access.TransactionController;
49
50 import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;
51 import org.apache.derby.impl.sql.compile.ActivationClassBuilder;
52
53 import org.apache.derby.iapi.services.compiler.MethodBuilder;
54
55 import org.apache.derby.iapi.services.loader.GeneratedMethod;
56
57 import org.apache.derby.iapi.services.sanity.SanityManager;
58
59 import org.apache.derby.catalog.types.ReferencedColumnsDescriptorImpl;
60
61 import org.apache.derby.iapi.services.io.FormatableArrayHolder;
62 import org.apache.derby.iapi.services.io.FormatableIntHolder;
63 import org.apache.derby.iapi.util.JBitSet;
64 import org.apache.derby.iapi.services.classfile.VMOpcode;
65
66 import java.util.Properties JavaDoc;
67
68 /**
69  * A HashTableNode represents a result set where a hash table is built.
70  *
71  * @author Jerry Brenner
72  */

73
74 public class HashTableNode extends SingleChildResultSetNode
75 {
76     PredicateList searchPredicateList;
77     PredicateList joinPredicateList;
78
79     SubqueryList pSubqueryList;
80     SubqueryList rSubqueryList;
81
82     /**
83      * Initializer for a HashTableNode.
84      *
85      * @param childResult The child result set
86      * @param tableProperties Properties list associated with the table
87      * @param resultColumns The RCL.
88      * @param searchPredicateList Single table clauses
89      * @param joinPredicateList Multi table clauses
90      * @param accessPath The access path
91      * @param costEstimate The cost estimate
92      * @param pSubqueryList List of subqueries in RCL
93      * @param rSubqueryList List of subqueries in Predicate lists
94      * @param hashKeyColumns Hash key columns
95      */

96
97     public void init(
98                          Object JavaDoc childResult,
99                          Object JavaDoc tableProperties,
100                          Object JavaDoc resultColumns,
101                          Object JavaDoc searchPredicateList,
102                          Object JavaDoc joinPredicateList,
103                          Object JavaDoc accessPath,
104                          Object JavaDoc costEstimate,
105                          Object JavaDoc pSubqueryList,
106                          Object JavaDoc rSubqueryList,
107                          Object JavaDoc hashKeyColumns)
108     {
109         super.init(childResult, tableProperties);
110         this.resultColumns = (ResultColumnList) resultColumns;
111         this.searchPredicateList = (PredicateList) searchPredicateList;
112         this.joinPredicateList = (PredicateList) joinPredicateList;
113         this.trulyTheBestAccessPath = (AccessPathImpl) accessPath;
114         this.costEstimate = (CostEstimate) costEstimate;
115         this.pSubqueryList = (SubqueryList) pSubqueryList;
116         this.rSubqueryList = (SubqueryList) rSubqueryList;
117         setHashKeyColumns((int[]) hashKeyColumns);
118     }
119
120     /*
121      * Optimizable interface
122      */

123
124     /**
125      * @see Optimizable#modifyAccessPath
126      *
127      * @exception StandardException Thrown on error
128      */

129     public Optimizable modifyAccessPath(JBitSet outerTables, Optimizer optimizer)
130         throws StandardException
131     {
132         return this;
133     }
134
135     /**
136      * Prints the sub-nodes of this object. See QueryTreeNode.java for
137      * how tree printing is supposed to work.
138      *
139      * @param depth The depth of this node in the tree
140      */

141
142     public void printSubNodes(int depth)
143     {
144         if (SanityManager.DEBUG)
145         {
146             super.printSubNodes(depth);
147
148             if (searchPredicateList != null)
149             {
150                 printLabel(depth, "searchPredicateList: ");
151                 searchPredicateList.treePrint(depth + 1);
152             }
153
154             if (joinPredicateList != null)
155             {
156                 printLabel(depth, "joinPredicateList: ");
157                 joinPredicateList.treePrint(depth + 1);
158             }
159         }
160     }
161
162     /**
163      * For joins, the tree will be (nodes are left out if the clauses
164      * are empty):
165      *
166      * ProjectRestrictResultSet -- for the having and the select list
167      * SortResultSet -- for the group by list
168      * ProjectRestrictResultSet -- for the where and the select list (if no group or having)
169      * the result set for the fromList
170      *
171      *
172      * @exception StandardException Thrown on error
173      */

174     public void generate(ActivationClassBuilder acb,
175                                 MethodBuilder mb)
176                             throws StandardException
177     {
178         if (SanityManager.DEBUG)
179         SanityManager.ASSERT(resultColumns != null, "Tree structure bad");
180
181         generateMinion( acb, mb, false);
182     }
183
184     /**
185      * General logic shared by Core compilation and by the Replication Filter
186      * compiler. A couple ResultSets (the ones used by PREPARE SELECT FILTER)
187      * implement this method.
188      *
189      * @param acb The ExpressionClassBuilder for the class being built
190      * @param mb the method the expression will go into
191      *
192      *
193      * @exception StandardException Thrown on error
194      */

195
196     public void generateResultSet(ExpressionClassBuilder acb,
197                                            MethodBuilder mb)
198                                     throws StandardException
199     {
200         generateMinion( acb, mb, true);
201     }
202
203     /**
204      * Logic shared by generate() and generateResultSet().
205      *
206      * @param acb The ExpressionClassBuilder for the class being built
207      * @param mb the method the expression will go into
208      *
209      * @exception StandardException Thrown on error
210      */

211
212     private void generateMinion(ExpressionClassBuilder acb,
213                                      MethodBuilder mb, boolean genChildResultSet)
214                                     throws StandardException
215     {
216         MethodBuilder userExprFun;
217         ValueNode searchClause = null;
218         ValueNode equijoinClause = null;
219
220
221         /* The tableProperties, if non-null, must be correct to get this far.
222          * We simply call verifyProperties to set initialCapacity and
223          * loadFactor.
224          */

225         verifyProperties(getDataDictionary());
226
227         // build up the tree.
228

229         /* Put the predicates back into the tree */
230         if (searchPredicateList != null)
231         {
232             // Remove any redundant predicates before restoring
233
searchPredicateList.removeRedundantPredicates();
234             searchClause = searchPredicateList.restorePredicates();
235             /* Allow the searchPredicateList to get garbage collected now
236              * that we're done with it.
237              */

238             searchPredicateList = null;
239         }
240
241         // for the single table predicates, we generate an exprFun
242
// that evaluates the expression of the clause
243
// against the current row of the child's result.
244
// if the restriction is empty, simply pass null
245
// to optimize for run time performance.
246

247         // generate the function and initializer:
248
// Note: Boolean lets us return nulls (boolean would not)
249
// private Boolean exprN()
250
// {
251
// return <<searchClause.generate(ps)>>;
252
// }
253
// static Method exprN = method pointer to exprN;
254

255
256
257
258
259         // Map the result columns to the source columns
260
int[] mapArray = resultColumns.mapSourceColumns();
261         int mapArrayItem = acb.addItem(new ReferencedColumnsDescriptorImpl(mapArray));
262
263         // Save the hash key columns
264

265         FormatableIntHolder[] fihArray =
266                 FormatableIntHolder.getFormatableIntHolders(hashKeyColumns());
267         FormatableArrayHolder hashKeyHolder = new FormatableArrayHolder(fihArray);
268         int hashKeyItem = acb.addItem(hashKeyHolder);
269
270         /* Generate the HashTableResultSet:
271          * arg1: childExpress - Expression for childResultSet
272          * arg2: searchExpress - Expression for single table predicates
273          * arg3 : equijoinExpress - Qualifier[] for hash table look up
274          * arg4: projectExpress - Expression for projection, if any
275          * arg5: resultSetNumber
276          * arg6: mapArrayItem - item # for mapping of source columns
277          * arg7: reuseResult - whether or not the result row can be reused
278          * (ie, will it always be the same)
279          * arg8: hashKeyItem - item # for int[] of hash column #s
280          * arg9: removeDuplicates - don't remove duplicates in hash table (for now)
281          * arg10: maxInMemoryRowCount - max row size for in-memory hash table
282          * arg11: initialCapacity - initialCapacity for java.util.Hashtable
283          * arg12 : loadFactor - loadFactor for java.util.Hashtable
284          * arg13: estimated row count
285          * arg14: estimated cost
286          * arg15: close method
287          */

288
289         acb.pushGetResultSetFactoryExpression(mb);
290
291         if (genChildResultSet)
292             childResult.generateResultSet(acb, mb);
293         else
294             childResult.generate((ActivationClassBuilder) acb, mb);
295
296         /* Get the next ResultSet #, so that we can number this ResultSetNode, its
297          * ResultColumnList and ResultSet.
298          */

299         assignResultSetNumber();
300
301         /* Set the point of attachment in all subqueries attached
302          * to this node.
303          */

304         if (pSubqueryList != null && pSubqueryList.size() > 0)
305         {
306             pSubqueryList.setPointOfAttachment(resultSetNumber);
307             if (SanityManager.DEBUG)
308             {
309                 SanityManager.ASSERT(pSubqueryList.size() == 0,
310                     "pSubqueryList.size() expected to be 0");
311             }
312         }
313         if (rSubqueryList != null && rSubqueryList.size() > 0)
314         {
315             rSubqueryList.setPointOfAttachment(resultSetNumber);
316             if (SanityManager.DEBUG)
317             {
318                 SanityManager.ASSERT(rSubqueryList.size() == 0,
319                     "rSubqueryList.size() expected to be 0");
320             }
321         }
322
323         // Get the final cost estimate based on child's cost.
324
costEstimate = childResult.getFinalCostEstimate();
325
326         // if there is no searchClause, we just want to pass null.
327
if (searchClause == null)
328         {
329             mb.pushNull(ClassName.GeneratedMethod);
330         }
331         else
332         {
333             // this sets up the method and the static field.
334
// generates:
335
// DataValueDescriptor userExprFun { }
336
userExprFun = acb.newUserExprFun();
337
338             // searchClause knows it is returning its value;
339

340             /* generates:
341              * return <searchClause.generate(acb)>;
342              * and adds it to userExprFun
343              * NOTE: The explicit cast to DataValueDescriptor is required
344              * since the searchClause may simply be a boolean column or subquery
345              * which returns a boolean. For example:
346              * where booleanColumn
347              */

348
349             searchClause.generateExpression(acb, userExprFun);
350             userExprFun.methodReturn();
351
352
353             /* PUSHCOMPILER
354             userSB.newReturnStatement(searchClause.generateExpression(acb, userSB));
355             */

356
357             // we are done modifying userExprFun, complete it.
358
userExprFun.complete();
359
360             // searchClause is used in the final result set as an access of the new static
361
// field holding a reference to this new method.
362
// generates:
363
// ActivationClass.userExprFun
364
// which is the static field that "points" to the userExprFun
365
// that evaluates the where clause.
366
acb.pushMethodReference(mb, userExprFun);
367         }
368         /* Generate the qualifiers for the look up into
369          * the hash table.
370          */

371         joinPredicateList.generateQualifiers(acb, mb, (Optimizable) childResult,
372                                                         false);
373
374         /* Determine whether or not reflection is needed for the projection.
375          * Reflection is not needed if all of the columns map directly to source
376          * columns.
377          */

378         if (reflectionNeededForProjection())
379         {
380             // for the resultColumns, we generate a userExprFun
381
// that creates a new row from expressions against
382
// the current row of the child's result.
383
// (Generate optimization: see if we can simply
384
// return the current row -- we could, but don't, optimize
385
// the function call out and have execution understand
386
// that a null function pointer means take the current row
387
// as-is, with the performance trade-off as discussed above.)
388

389             /* Generate the Row function for the projection */
390             resultColumns.generateCore(acb, mb, false);
391         }
392         else
393         {
394             mb.pushNull(ClassName.GeneratedMethod);
395         }
396
397         mb.push(resultSetNumber);
398         mb.push(mapArrayItem);
399         mb.push(resultColumns.reusableResult());
400         mb.push(hashKeyItem);
401         mb.push(false);
402         mb.push(-1L);
403         mb.push(initialCapacity);
404         mb.push(loadFactor);
405         mb.push(costEstimate.singleScanRowCount());
406         mb.push(costEstimate.getEstimatedCost());
407
408         mb.callMethod(VMOpcode.INVOKEINTERFACE, (String JavaDoc) null, "getHashTableResultSet",
409                 ClassName.NoPutResultSet, 14);
410     }
411
412     /**
413      * Accept a visitor, and call v.visit()
414      * on child nodes as necessary.
415      *
416      * @param v the visitor
417      *
418      * @exception StandardException on error
419      */

420     public Visitable accept(Visitor v)
421         throws StandardException
422     {
423         if (v.skipChildren(this))
424         {
425             return v.visit(this);
426         }
427
428         Visitable returnNode = super.accept(v);
429
430         if (searchPredicateList != null && !v.stopTraversal())
431         {
432             searchPredicateList = (PredicateList)searchPredicateList.accept(v);
433         }
434
435         if (joinPredicateList != null && !v.stopTraversal())
436         {
437             joinPredicateList = (PredicateList)joinPredicateList.accept(v);
438         }
439
440         return returnNode;
441     }
442 }
443
Popular Tags