KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > versant > core > jdbc > sql > exp > SelectExp


1
2 /*
3  * Copyright (c) 1998 - 2005 Versant Corporation
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  * Versant Corporation - initial API and implementation
11  */

12 package com.versant.core.jdbc.sql.exp;
13
14 import com.versant.core.common.Debug;
15 import com.versant.core.metadata.ClassMetaData;
16 import com.versant.core.metadata.MDStatics;
17 import com.versant.core.jdo.query.*;
18 import com.versant.core.jdbc.metadata.*;
19 import com.versant.core.jdbc.sql.SqlDriver;
20 import com.versant.core.jdbc.query.JDOQLNodeToSqlExp;
21 import com.versant.core.jdbc.fetch.FetchSpec;
22 import com.versant.core.util.CharBuf;
23
24 import java.util.Map JavaDoc;
25
26 import com.versant.core.common.BindingSupportImpl;
27
28 /**
29  * A 'select ... from ... where ... order by ...' expression.
30  */

31 public class SelectExp extends LeafExp {
32     public static final ColumnStruct[] EMPTY_COLUMS_STRUCT = new ColumnStruct[0];
33
34     /**
35      * Linked list of expressions to select (null if none).
36      */

37     public SqlExp selectList;
38     /**
39      * Is this a 'select distinct'?
40      */

41     public boolean distinct;
42     /**
43      * Is this a 'select for update'?
44      */

45     public boolean forUpdate;
46     /**
47      * The table to select from.
48      */

49     public JdbcTable table;
50     /**
51      * The field that was navigated to get to this table (null if none).
52      */

53     public JdbcField jdbcField;
54     /**
55      * The variable this expression belongs to (null if none).
56      */

57     public VarNode var;
58     /**
59      * The alias assigned to our table (null if none).
60      */

61     public String JavaDoc alias;
62     /**
63      * The 'join' expression for a sub select (null if none). This will end
64      * up in the where clause but is kept separately so nested sub selects can
65      * be converted into joins easily.
66      */

67     public SqlExp subSelectJoinExp;
68     /**
69      * The where clause expression (null if none).
70      */

71     public SqlExp whereExp;
72     /**
73      * Linked list of expressions to order by (null if none).
74      */

75     public SqlExp orderByList;
76     public SqlExp resultList;
77     public SqlExp groupByList;
78     public HavingExp havingExp;
79     /**
80      * Is table involved in an outer join as the outer table?
81      */

82     public boolean outer;
83     /**
84      * Linked list of joins (null if none). Note that the selectExp for
85      * each entry in the list may have its own joinList and so on
86      * recusively (i.e. this is actually a tree).
87      */

88     public Join joinList;
89
90     /**
91      * Index of the first column in the select list as of the last call to
92      * appendSQL.
93      */

94     public int selectListStartIndex;
95     /**
96      * Index of the last charcter of the first column in the select list + 1
97      * as of the last call to appendSQL.
98      */

99     public int selectListFirstColEndIndex;
100     /**
101      * Index of the last column in the select list + 1 as of the last call
102      * to appendSQL.
103      */

104     public int selectListEndIndex;
105     /**
106      * Index of the start of the "order by ..." clause as of the last call to
107      * appendSQL.
108      */

109     public int orderByStartIndex;
110     /**
111      * Index of the end of the "order by ..." clause + 1 as of the last call to
112      * appendSQL.
113      */

114     public int orderByEndIndex;
115
116     public int selectListCountBeforeAggregate;
117
118     public FetchSpec fetchSpec;
119
120     private static final char ALIAS_PREPEND_CONSTANT = 'x';
121
122     public SelectExp() {
123     }
124
125     public SqlExp createInstance() {
126         return new SelectExp();
127     }
128
129     public SqlExp getClone(SqlExp clone, Map JavaDoc cloneMap) {
130         SelectExp cst = (SelectExp)clone;
131         super.getClone(cst, cloneMap);
132
133         if (selectList != null) cst.selectList = createClone(selectList, cloneMap);
134         cst.distinct = distinct;
135         cst.forUpdate = forUpdate;
136         cst.table = table;
137         cst.jdbcField = jdbcField;
138         cst.var = var;
139         cst.alias = alias;
140         if (subSelectJoinExp != null) cst.subSelectJoinExp = createClone(subSelectJoinExp, cloneMap);
141         if (whereExp != null) cst.whereExp = createClone(whereExp, cloneMap);
142         if (orderByList != null) cst.orderByList = createClone(orderByList, cloneMap);
143         cst.outer = outer;
144         if (joinList != null) cst.joinList = joinList.getClone(cloneMap);
145         cst.selectListStartIndex = selectListStartIndex;
146         cst.selectListEndIndex = selectListEndIndex;
147         cst.orderByStartIndex = orderByStartIndex;
148         cst.orderByEndIndex = orderByEndIndex;
149
150         return cst;
151     }
152
153     public String JavaDoc toString() {
154         return super.toString() + (outer ? " OUTER " : " ") +
155                 table.name + (alias == null ? "": "aliased to " + alias) +
156                 (jdbcField != null ? " " + jdbcField : "") +
157                 (var != null ? " " + var : "");
158     }
159
160     /**
161      * Count the number of columns in the select list and all joined to lists.
162      */

163     public int getSelectListColumnCount() {
164         if (selectList == null) return 0;
165         int count = 0;
166         for (SqlExp se = selectList; se != null; se = se.next) {
167             count++;
168         }
169         count += countSelect(joinList);
170         return count;
171     }
172
173     /**
174      * Dump debugging info to System.out.
175      */

176     public void dump(String JavaDoc indent) {
177         Debug.OUT.println(indent + this);
178         String JavaDoc is = indent + " ";
179         if (selectList != null) {
180             Debug.OUT.println(indent + "selectList");
181             selectList.dumpList(is);
182         }
183         if (joinList != null) {
184             Debug.OUT.println(indent + "joinList");
185             joinList.dumpList(is);
186         }
187         if (subSelectJoinExp != null) {
188             Debug.OUT.println(indent + "subSelectJoinExp");
189             subSelectJoinExp.dump(is);
190         }
191         if (whereExp != null) {
192             Debug.OUT.println(indent + "whereExp");
193             whereExp.dump(is);
194         }
195         if (orderByList != null) {
196             Debug.OUT.println(indent + "orderByList");
197             orderByList.dumpList(is);
198         }
199     }
200
201     /**
202      * Add a Join to end of the joinList.
203      */

204     public void addJoin(Join join) {
205         if (joinList == null) {
206             joinList = join;
207         } else {
208             for (Join j = joinList; ;) {
209                 Join next = j.next;
210                 if (next == null) {
211                     j.next = join;
212                     return;
213                 }
214                 j = next;
215             }
216         }
217     }
218
219     /**
220      * Add a Join to end of the joinList. This is an attempt to not add uncess.
221      * joins.
222      */

223     public void addJoinMerge(Join aJoin) {
224         Join origJoin = aJoin;
225         if (joinList == null) {
226             joinList = aJoin;
227         } else {
228             getTailJoin(joinList).next = aJoin;
229             addJoinImp(joinList, aJoin, origJoin);
230         }
231     }
232
233     private static Join getPrevJoin(Join joinList, Join aJoin) {
234         if (joinList.next == null) {
235             throw BindingSupportImpl.getInstance().internal("");
236         }
237
238         for (Join j = joinList;;) {
239             if (j.next == aJoin) {
240                 return j;
241             }
242             j = j.next;
243             if (j == null) return null;
244         }
245     }
246
247     private static Join getTailJoin(Join joinList) {
248         for (Join j = joinList;;) {
249             if (j.next == null) return j;
250             j = j.next;
251         }
252     }
253
254     private static void addJoinImp(Join currentJoin, Join aJoinToAdd, Join origJoin) {
255         Join j = currentJoin;
256         Join restartJoin = null;
257         Join stopJoin = getTailJoin(currentJoin);
258         for (;j != null;) {
259             if (aJoinToAdd == null) {
260                 break;
261             }
262             if (Join.isCurrentEqaul(j, aJoinToAdd)) {
263                 /**
264                  * Update the whereExp of the origJoin with the new selectExp
265                  */

266                 if (origJoin.selectExp.whereExp != null) {
267                     origJoin.selectExp.whereExp.replaceSelectExpRef(origJoin.selectExp,
268                             j.selectExp);
269                 }
270
271                 Join subCurrentJoin = j.selectExp.joinList;
272                 Join subJoinToAdd = aJoinToAdd.selectExp.joinList;
273
274                 if (subCurrentJoin == null && subJoinToAdd == null) {
275                 } else if (subJoinToAdd == null) {
276                 } else if (subCurrentJoin == null) {
277                     //just set it
278
j.selectExp.joinList = aJoinToAdd.selectExp.joinList;
279                     ((JoinExp)aJoinToAdd.selectExp.joinList.exp).setLeftTable(j.selectExp);
280                 } else {
281                     addJoinImp(subJoinToAdd, subCurrentJoin, origJoin);
282                 }
283                 Join tmpJoin = aJoinToAdd.next;
284                 /**
285                  * Fix up the lList
286                  */

287                 getPrevJoin(currentJoin, aJoinToAdd).next = aJoinToAdd.next;
288                 aJoinToAdd.next = null;
289
290                 aJoinToAdd = tmpJoin;
291                 j = j.next;
292             } else {
293                 if (j.next == stopJoin) {
294                     //no match found so move to next aJoinToAdd and to currentJoin
295
aJoinToAdd = aJoinToAdd.next;
296                     j = restartJoin;
297                 } else {
298                     j = j.next;
299                 }
300             }
301
302         }
303     }
304
305     /**
306      * Add a join to the end of the join list.
307      */

308     public Join addJoin(JdbcColumn[] leftCols, JdbcColumn[] rightCols,
309             SelectExp right) {
310         if (Debug.DEBUG) {
311             System.out.println("SelectExp.addJoin from " + table.name + " to " + right.table.name);
312             String JavaDoc join = "";
313             if (right.outer) {
314                 join = "OUTER";
315             } else {
316                 join = "INNER";
317             }
318             System.out.println("--- SelectExp.addJoin from "
319                     + leftCols[0].table.name + " -- " + join + " --> "
320                     + right.table.name);
321         }
322         Join j = new Join();
323         j.exp = createJoinExp(leftCols, rightCols, right);
324         j.selectExp = right;
325         addJoin(j);
326         return j;
327     }
328
329     /**
330      * Search our join list for a join for the field. This is not recursive
331      * i.e. it only finds joins in our join list. Returns null if not found.
332      * @see #findJoinRec(com.versant.core.jdbc.metadata.JdbcField)
333      */

334     public Join findJoin(JdbcField jdbcField) {
335         for (Join j = joinList; j != null; j = j.next) {
336             if (j.selectExp.jdbcField == jdbcField) return j;
337         }
338         return null;
339     }
340
341     /**
342      * Find a join by table and refField.
343      */

344     public Join findJoin(JdbcTable table, JdbcField jdbcField) {
345         for (Join j = joinList; j != null; j = j.next) {
346             if (j.selectExp.jdbcField == jdbcField
347                     && j.selectExp.table == table) return j;
348         }
349         return null;
350     }
351
352     public SelectExp findTableRecursive(JdbcTable t, JdbcField field) {
353         if (t == table && jdbcField == field) return this;
354         for (Join j = joinList; j != null; j = j.next) {
355             if (j.selectExp.table == t && j.selectExp.jdbcField == field) return j.selectExp;
356         }
357
358         for (Join j = joinList; j != null; j = j.next) {
359             SelectExp se = j.selectExp.findTableRecursive(t, field);
360             if (se != null) return se;
361         }
362         return null;
363     }
364
365     /**
366      * Recursively search our join list for a join for the field. Returns null
367      * if not found.
368      * @see #findJoin(com.versant.core.jdbc.metadata.JdbcField)
369      */

370     public Join findJoinRec(JdbcField jdbcField) {
371         for (Join j = joinList; j != null; j = j.next) {
372             if (j.selectExp.jdbcField == jdbcField) return j;
373             Join ans = j.selectExp.findJoinRec(jdbcField);
374             if (ans != null) return ans;
375         }
376         return null;
377     }
378
379     /**
380      * Search our join list for a join to the expression. This is not recursive
381      * i.e. it only finds joins in our join list. Returns null if not found.
382      */

383     public Join findJoin(SelectExp se) {
384         for (Join j = joinList; j != null; j = j.next) {
385             if (j.selectExp == se) return j;
386         }
387         return null;
388     }
389
390     /**
391      * If our table is t then return this. Otherwise search our join list
392      * for a join for the table. This is not recursive i.e. it only finds
393      * tables in our join list. Returns null if not found.
394      */

395     public SelectExp findTable(JdbcTable t) {
396         if (t == table) {
397             return this;
398         }
399         for (Join j = joinList; j != null; j = j.next) {
400             if (j.selectExp.table == t) {
401                 return j.selectExp;
402             }
403         }
404         return null;
405     }
406
407     public SelectExp findTableRecursive(JdbcTable t) {
408         if (t == table) return this;
409         for (Join j = joinList; j != null; j = j.next) {
410             if (j.selectExp.table == t) return j.selectExp;
411         }
412
413         for (Join j = joinList; j != null; j = j.next) {
414             SelectExp se = j.selectExp.findTable(t);
415             if (se != null) return se;
416         }
417         return null;
418     }
419
420     /**
421      * Create an expression to join us to right.
422      */

423     public SqlExp createJoinExp(JdbcColumn[] leftCols,
424             JdbcColumn[] rightCols, SelectExp right) {
425         if (leftCols.length == 1) {
426             return new JoinExp(leftCols[0], this,
427                     rightCols[0], right);
428         } else {
429             JoinExp first = new JoinExp(leftCols[0], this, rightCols[0], right);
430             int nc = leftCols.length;
431             SqlExp j = first;
432             for (int i = 1; i < nc; i++) {
433                 j = j.next = new JoinExp(leftCols[i], this, rightCols[i], right);
434             }
435             return new AndJoinExp(first);
436         }
437     }
438
439     public Join getLastJoin() {
440         for (Join j = joinList; j != null; j = j.next) {
441             if (j.next == null) {
442                 return j;
443             }
444         }
445         return null;
446     }
447
448     /**
449      * Create an aliases for any tables we may have if we do not already have
450      * an alias.
451      */

452     public int createAlias(int index) {
453         if (alias == null) {
454             if (index < 26) {
455                 alias = new String JavaDoc(new char[]{(char)(index + 'a')});
456             } else {
457                 alias = "t" + index;
458             }
459             ++index;
460             for (Join j = joinList; j != null; j = j.next) {
461                 index = j.createAlias(index);
462             }
463             for (SqlExp e = whereExp; e != null; e = e.next) {
464                 index = e.createAlias(index);
465             }
466         }
467         return index;
468     }
469
470     /**
471      * Replace any references to old with nw. This is used when redundant
472      * joins are removed.
473      */

474     public void replaceSelectExpRef(SelectExp old, SelectExp nw) {
475         if (whereExp != null) whereExp.replaceSelectExpRef(old, nw);
476         if (subSelectJoinExp != null) subSelectJoinExp.replaceSelectExpRef(old, nw);
477     }
478
479     /**
480      * Normalize this node i.e. transform it into its simplist possible form.
481      * This will turn sub selects into joins and so on.
482      */

483     public SqlExp normalize(SqlDriver driver, SelectExp sel, boolean convertExists) {
484         for (Join j = joinList; j != null; j = j.next) {
485             SelectExp se = j.selectExp;
486             se.normalize(driver, sel, convertExists);
487             if (convertExists && se.whereExp != null) {
488                 j.findDeepestJoin().appendJoinExp(se.whereExp);
489                 se.whereExp = null;
490             }
491         }
492
493         if (whereExp == null) return null;
494         SqlExp r = whereExp.normalize(driver, this, convertExists);
495         if (r != null) whereExp = r;
496
497         int cj = whereExp.getConvertToJoin();
498         if (cj == SqlExp.YES || (convertExists && cj >= SqlExp.YES_DISTINCT)) {
499             // convert to join
500
boolean not = convertExists && cj == SqlExp.YES_DISTINCT_NOT;
501             SelectExp sub;
502             if (not) {
503                 sub = (SelectExp)(whereExp.childList.childList);
504             } else {
505                 sub = (SelectExp)(whereExp.childList);
506             }
507             if ( sub != null ) {
508                 Join j = new Join();
509                 j.selectExp = sub;
510                 j.exp = sub.subSelectJoinExp;
511                 sub.subSelectJoinExp = null;
512                 if (sub.whereExp != null) { // add to join clause
513
Join jj = j;
514                     for (;;jj = jj.selectExp.joinList) {
515                         if (jj.selectExp.joinList == null) break;
516                     }
517                     jj.appendJoinExp(sub.whereExp);
518                     sub.whereExp = null;
519                 }
520                 addJoin(j);
521             }
522             if (not) {
523                 sub.outer = true;
524                 whereExp = sub.getOuterJoinNotMatchedExp();
525             } else {
526                 whereExp = null;
527             }
528             if (cj >= SqlExp.YES_DISTINCT) distinct = true;
529             return null;
530         }
531         return null;
532     }
533
534     /**
535      * Append SQL for this node to s.
536      *
537      * @param driver The driver being used
538      * @param s Append the SQL here
539      * @param leftSibling
540      */

541     public void appendSQLImp(SqlDriver driver, CharBuf s, SqlExp leftSibling) {
542         // put in the select list (ours and all of our join tables)
543
boolean putOrderColsInSelect = driver.isPutOrderColsInSelect();
544         boolean selectListAppendedWithOrderByExp = false;
545
546         //Create a ColumnStruct[] for all the fields in the 'order by' exp.
547
ColumnStruct[] orderByStruct = createColumnStruct(orderByList);
548
549         int start = s.size();
550         if (distinct) s.append("SELECT DISTINCT ");
551         else s.append("SELECT ");
552         selectListStartIndex = s.size();
553         int colCount = appendFirstSelect(selectList, driver, s);
554         colCount += appendSelect(joinList, driver, s);
555         if (Debug.DEBUG) {
556             if (colCount != getSelectListColumnCount()) {
557                 throw BindingSupportImpl.getInstance().internal("");
558             }
559         }
560
561         if (orderByList != null) {
562             if (putOrderColsInSelect || (groupByList != null && driver.putOrderColsInGroupBy())) {
563                 selectListAppendedWithOrderByExp = appendSelectForOrderBy(orderByList,
564                         driver, s, orderByStruct);
565             }
566         }
567
568         finishSelectList(s, start);
569         selectListEndIndex = s.size();
570
571         // put in the from list
572
s.append(" FROM ");
573         driver.appendSqlFrom(table, alias, s);
574         appendFrom(joinList, driver, s);
575
576         // put all the expressions for the where clause into a list
577
SqlExp list = new SqlExp();
578         SqlExp pos = list;
579         if (subSelectJoinExp != null) pos = pos.next = subSelectJoinExp;
580         if (!driver.isAnsiJoinSyntax()) {
581             findWhereExp(findWhereJoinExp(pos));
582         } else {
583             findWhereExp(pos);
584         }
585
586         // build a single expression from this list (joins exps with and)
587
SqlExp exp = merge(list.next);
588         if (exp != null) {
589             s.append(" WHERE ");
590             exp.appendSQL(driver, s, null);
591         }
592
593         exp = groupByList;
594         int gIndex = 1;
595         if (exp != null) {
596             boolean thisDone = false;
597             s.append(" GROUP BY ");
598             for (; ;) {
599                 if (gIndex > 1) {
600                     s.append(',');
601                     s.append(' ');
602                 }
603                 if (exp instanceof GroupByThisExp) {
604                     if (!thisDone) {
605                         thisDone = true;
606                         appendFirstSelect(selectList, driver, s, selectListCountBeforeAggregate);
607                         appendSelect(joinList, driver, s);
608                     }
609                 } else {
610                     // The group by list can contain ColumnExp and OrderExp
611
// expressions. The OrderExp's just wrap a ColumnExp and
612
// add a descending indicator.
613
ColumnExp ce;
614                     if (exp instanceof ColumnExp) {
615                         ce = (ColumnExp)exp;
616                     } else {
617                         ce = (ColumnExp)exp.childList;
618                     }
619
620                     if (ce.isAliasedColumn()) {
621                         exp.appendSQL(driver, s, null);
622                     } else if (driver.useColumnIndexForGroupBy()) {
623                         int i = findIndexInSelectList(selectList, ce.selectExp, ce.col.name);
624                         if (i >= 0) {
625                             s.append(i);
626                         } else {
627                             exp.appendSQL(driver, s, null);
628                         }
629                     } else {
630                         exp.appendSQL(driver, s, null);
631                     }
632                 }
633                 gIndex++;
634                 if ((exp = exp.next) == null) break;
635             }
636         }
637
638         //update the groupBy expression with fields that was added to the selectlist
639
if (selectListAppendedWithOrderByExp && groupByList != null) {
640             appendGroupBy(s, orderByStruct, gIndex == 1, driver);
641         }
642
643         exp = havingExp;
644         if (exp != null) {
645             havingExp.appendSQL(driver, s, null);
646         }
647
648         // put in the order by list
649
exp = orderByList;
650         if (exp != null) {
651             orderByStartIndex = s.size();
652             s.append(" ORDER BY ");
653             if (driver.isUseIndexesForOrderCols()) {
654                 int index = 1;
655                 boolean first = true;
656                 for (; ;) {
657                     if (first) {
658                         first = false;
659                     } else {
660                         s.append(',');
661                         s.append(' ');
662                     }
663                     // The order by list can contain ColumnExp and OrderExp
664
// expressions. The OrderExp's just wrap a ColumnExp and
665
// add a descending indicator.
666
ColumnExp ce;
667                     if (exp instanceof ColumnExp) {
668                         ce = (ColumnExp)exp;
669                     } else {
670                         ce = (ColumnExp)exp.childList;
671                     }
672
673                     if (ce.isAliasedColumn()) {
674                         exp.appendSQL(driver, s, null);
675                     } else {
676                         ColumnStruct colStruct = orderByStruct[index - 1];
677                         int i = colStruct.indexInSelectList;
678                         if (i > 0) {
679                             s.append(i);
680                             if (ce != exp) { // exp is OrderExp as it is not ColumnExp
681
OrderExp oe = (OrderExp)exp;
682                                 if (oe.isDesc()) s.append(" DESC");
683                             }
684                         } else {
685                             //if appended to selectList
686
if (colStruct.columnNme != null) {
687                                 if (driver.useColAliasForAddedCols()) {
688                                     s.append(colStruct.alias);
689                                 } else {
690                                     s.append(colStruct.columnNme);
691                                 }
692
693                                 if (ce != exp) { // exp is OrderExp as it is not ColumnExp
694
OrderExp oe = (OrderExp)exp;
695                                     if (oe.isDesc()) s.append(" DESC");
696                                 }
697                             } else {
698                                 exp.appendSQL(driver, s, null);
699                             }
700                         }
701                     }
702                     index++;
703                     if ((exp = exp.next) == null) break;
704                 }
705             } else {
706                 //use the column name
707
int index = 1;
708                 boolean first = true;
709                 for (; exp != null; exp = exp.next) {
710                     if (first) {
711                         first = false;
712                     } else {
713                         s.append(',');
714                         s.append(' ');
715                     }
716                     ColumnExp ce;
717                     if (exp instanceof ColumnExp) {
718                         ce = (ColumnExp)exp;
719                     } else {
720                         ce = (ColumnExp)exp.childList;
721                     }
722                     if (ce.isAliasedColumn()) {
723                         exp.appendSQL(driver, s, null);
724                     } else {
725                         ColumnStruct colStruct = orderByStruct[index - 1];
726                         int i = colStruct.indexInSelectList;
727                         if (i > 0) {
728                             exp.appendSQL(driver, s, null);
729                         } else {
730                             if (selectListAppendedWithOrderByExp) {
731                                 if (driver.useColAliasForAddedCols()) {
732                                     s.append(colStruct.alias);
733                                 } else {
734                                     s.append(colStruct.columnNme);
735                                 }
736                                 if (ce != exp) { // exp is OrderExp as it is not ColumnExp
737
OrderExp oe = (OrderExp)exp;
738                                     if (oe.isDesc()) s.append(" DESC");
739                                 }
740                             } else {
741                                 exp.appendSQL(driver, s, null);
742                             }
743                         }
744                     }
745                     index++;
746                 }
747             }
748             orderByEndIndex = s.size();
749         } else {
750             orderByStartIndex = orderByEndIndex = 0;
751         }
752
753         if (forUpdate && (!distinct || driver.isSelectForUpdateWithDistinctOk())) {
754             char[] a = driver.getSelectForUpdate();
755             if (a != null) {
756                 s.append(a);
757                 if (driver.isSelectForUpdateAppendTable()) {
758                     if (alias == null) {
759                         s.append(table.name);
760                     } else {
761                         s.append(alias);
762                     }
763                 }
764             }
765         }
766     }
767
768     /**
769      * Find the index of a matching entry (i.e. same column from same table)
770      * in the select list (first is 1) for ce or -1 if none found.
771      */

772     private int findIndexInSelectList(SqlExp toSearch, SelectExp se, String JavaDoc name) {
773         int[] indexArray = new int[2];
774         findIndexInSelectListImp(toSearch, se, name, indexArray);
775
776         if (indexArray[1] == 0) {
777             //must check more
778
findIndexInJoin(joinList, se, name, indexArray);
779         }
780
781         if (indexArray[1] == 1) {
782             return indexArray[0] + 1;
783         } else {
784             return -1;
785         }
786     }
787
788     private void findIndexInJoin(Join j, SelectExp exp, String JavaDoc name,
789             int[] index) {
790         for (; j != null; j = j.next) {
791             SelectExp se = j.selectExp;
792             findIndexInSelectListImp(se.selectList, exp, name, index);
793
794             if (index[1] == 0) {
795                 findIndexInJoin(se.joinList, exp, name, index);
796             }
797             break;
798         }
799     }
800
801     private void findIndexInSelectListImp(SqlExp se, SelectExp exp,
802             String JavaDoc name, int[] index) {
803         for (SqlExp e = se; e != null; e = e.next, index[0]++) {
804             if (e instanceof ColumnExp) {
805                 ColumnExp ce = (ColumnExp)e;
806                 if (ce.selectExp == exp && ce.col.name.equals(name)) {
807                     index[1] = 1;
808                     return;
809                 }
810             }
811         }
812     }
813
814     private static boolean isDesc(SqlExp e) {
815         return e instanceof OrderExp && ((OrderExp)e).isDesc();
816     }
817
818     /**
819      * Check that the select list is valid.
820      */

821     protected void finishSelectList(CharBuf s, int start) {
822         int sz = s.size();
823         int n = sz - start;
824         if (n <= 7) {
825             if (start == 0) {
826                 throw BindingSupportImpl.getInstance().internal("no columns in select list");
827             }
828             s.append('1');
829         } else {
830             s.setSize(sz - 2); // remove the extra comma and space
831
}
832     }
833
834     /**
835      * Recursively append the select lists for all the joins to s using a
836      * depth first traversal. NOP if j is null.
837      */

838     private int appendSelect(Join j, SqlDriver driver, CharBuf s) {
839         int count = 0;
840         for (; j != null; j = j.next) {
841             SelectExp se = j.selectExp;
842             count += appendSelect(se.selectList, driver, s);
843             count += appendSelect(se.joinList, driver, s);
844         }
845         return count;
846     }
847
848     /**
849      * Recursively count the colums of all joined to selectExp's selectList.
850      */

851     private int countSelect(Join j) {
852         int count = 0;
853         for (; j != null; j = j.next) {
854             SelectExp se = j.selectExp;
855             count += countSelect(se.selectList);
856             count += countSelect(se.joinList);
857         }
858         return count;
859     }
860
861     /**
862      * Append all the expressions in the list starting at e. NOP if e is null.
863      * Follow each expression with ', '. Record the last index of
864      */

865     private int appendFirstSelect(SqlExp e, SqlDriver driver, CharBuf s) {
866         if (e == null) return 0;
867         int count = 1;
868         e.appendSQL(driver, s, null);
869         selectListFirstColEndIndex = s.size();
870         s.append(',');
871         s.append(' ');
872         for (e = e.next; e != null; e = e.next) {
873             e.appendSQL(driver, s, null);
874             s.append(',');
875             s.append(' ');
876             count++;
877         }
878         return count;
879     }
880
881     private void appendFirstSelect(SqlExp e, SqlDriver driver, CharBuf s, int columnCount) {
882         if (e == null) return;
883         e.appendSQL(driver, s, null);
884         selectListFirstColEndIndex = s.size();
885         int count = 1;
886         for (e = e.next; e != null; e = e.next) {
887             if (count++ >= columnCount) break;
888             s.append(',');
889             s.append(' ');
890             e.appendSQL(driver, s, null);
891         }
892     }
893
894     /**
895      * Append all the expressions in the list starting at e. NOP if e is null.
896      * Follow each expression with ', '.
897      */

898     private int appendSelect(SqlExp e, SqlDriver driver, CharBuf s) {
899         int count = 0;
900         for (; e != null; e = e.next) {
901             count++;
902             e.appendSQL(driver, s, null);
903             s.append(',');
904             s.append(' ');
905         }
906         return count;
907     }
908
909     private int countSelect(SqlExp e) {
910         int count = 0;
911         for (; e != null; e = e.next) {
912             count++;
913         }
914         return count;
915     }
916
917     /**
918      * Append all the expressions in the list starting at e. NOP if e is null.
919      * Follow each expression with an alias and ', '. This is used to add
920      * columns used in the order by to the select list for databases that
921      * require this e.g. informix.
922      */

923     private boolean appendSelectForOrderBy(SqlExp e, SqlDriver driver,
924             CharBuf s, ColumnStruct[] columnStructs) {
925         boolean appended = false;
926         int c = 1;
927         for (; e != null; e = e.next) {
928             ColumnStruct colStruct = columnStructs[c - 1];
929             if (colStruct.indexInSelectList == -1) {
930                 int offset = s.size();
931                 if (e instanceof OrderExp) {
932                     e.childList.appendSQL(driver, s, null);
933                 } else {
934                     e.appendSQL(driver, s, null);
935                 }
936                 colStruct.columnNme = s.toString(offset, s.size() - offset);
937                 colStruct.alias = ALIAS_PREPEND_CONSTANT + "j" + c;
938
939                 //not in select list
940
s.append(driver.getAliasPrepend());
941                 s.append(colStruct.alias);
942                 s.append(',');
943                 s.append(' ');
944                 appended = true;
945             }
946             c++;
947         }
948         return appended;
949     }
950
951     private ColumnStruct[] createColumnStruct(SqlExp e) {
952         SqlExp startExp = e;
953         int count = 0;
954         for (; e != null; e = e.next) {
955             count++;
956         }
957         if (count == 0) return EMPTY_COLUMS_STRUCT;
958         ColumnStruct[] colStructs = new ColumnStruct[count];
959         count = 0;
960         e = startExp;
961         for (; e != null; e = e.next) {
962             ColumnExp ce;
963             if (e instanceof ColumnExp) {
964                 ce = (ColumnExp)e;
965             } else {
966                 ce = (ColumnExp)e.childList;
967             }
968             if (ce.isAliasedColumn()) {
969                 colStructs[count++] = new ColumnStruct(0);
970             } else {
971                 colStructs[count++] = new ColumnStruct(findIndexInSelectList(selectList, ce.selectExp, ce.col.name));
972             }
973
974         }
975         return colStructs;
976     }
977
978     /**
979      * This is a struct to hold information about the order by columns that were added.
980      */

981     private class ColumnStruct {
982         /**
983          * The alias of the appended column.
984          */

985         String JavaDoc alias;
986         /**
987          * The columnName of the appended column. This field is only filled in
988          * if this column was appended to the original select exp.
989          */

990         String JavaDoc columnNme;
991         /**
992          * The index of this column in the select list.
993          */

994         int indexInSelectList;
995
996         public ColumnStruct(int indexInSelectList) {
997             this.indexInSelectList = indexInSelectList;
998         }
999     }
1000
1001    /**
1002     * Some drivers will automatically add fields that are in the orderBy
1003     * to the select exp. This method must check to see if these fields
1004     * are in the groupby and if not it must be added.
1005     */

1006    private void appendGroupBy(CharBuf s, ColumnStruct[] columnStructs,
1007                               boolean first, SqlDriver driver) {
1008        for (int i = 0; i < columnStructs.length; i++) {
1009            ColumnStruct columnStruct = columnStructs[i];
1010            if (columnStruct.columnNme != null) {
1011                if (first) {
1012                    first = false;
1013                } else {
1014                    s.append(',');
1015                }
1016                if (driver.useColAliasForAddedCols()) {
1017                    s.append(columnStruct.alias);
1018                } else {
1019                    s.append(columnStruct.columnNme);
1020                }
1021            }
1022        }
1023    }
1024
1025    /**
1026     * Recursively append the from list entries for all the joins to s using a
1027     * depth first traversal. NOP if j is null.
1028     */

1029    private void appendFrom(Join j, SqlDriver driver, CharBuf s) {
1030        for (; j != null; j = j.next) {
1031            SelectExp se = j.selectExp;
1032            if (j.isMerged()) continue;
1033            driver.appendSqlFromJoin(se.table, se.alias, j.exp, se.outer, s);
1034            appendFrom(se.joinList, driver, s);
1035        }
1036    }
1037
1038    /**
1039     * Recursively add all where expressions we can find to list and
1040     * return the new head of list.
1041     */

1042    private SqlExp findWhereExp(SqlExp list) {
1043        SqlExp e = whereExp;
1044        if (e != null) list = list.next = e;
1045        for (Join j = joinList; j != null; j = j.next) {
1046            list = j.selectExp.findWhereExp(list);
1047        }
1048        return list;
1049    }
1050
1051    /**
1052     * Recursively add all join expressions we can find to list and
1053     * return the new head of list.
1054     */

1055    private SqlExp findWhereJoinExp(SqlExp list) {
1056        for (Join j = joinList; j != null; j = j.next) {
1057            SqlExp e = j.exp;
1058            if (e != null) list = list.next = e;
1059            list = j.selectExp.findWhereJoinExp(list);
1060        }
1061        return list;
1062    }
1063
1064    /**
1065     * Combine a list of expressions into a single expression by anding
1066     * all the expressions together. This flattens nested 'and' expressions.
1067     */

1068    private SqlExp merge(SqlExp first) {
1069        if (first == null) return null;
1070        if (first.next == null) return first;
1071        // flatten enclosed 'and' expressions by adding them to the list
1072
// and processing their children
1073
for (SqlExp pos = first; pos != null;) {
1074            SqlExp e = pos.next;
1075            if (e instanceof AndExp) {
1076                pos = pos.next = e.childList;
1077                SqlExp f = pos;
1078                for (; f.next != null; f = f.next) ;
1079                f.next = e.next;
1080            } else {
1081                pos = e;
1082            }
1083        }
1084        return new AndExp(first);
1085    }
1086
1087    /**
1088     * Set our outer flag and follow all our joins and make then outer as
1089     * well.
1090     */

1091    public void setOuterRec() {
1092        outer = true;
1093        for (Join j = joinList; j != null; j = j.next) {
1094            j.selectExp.setOuterRec();
1095        }
1096    }
1097
1098    /**
1099     * Get an expression that is true if this join does not produce a fully
1100     * populated row (i.e. one or more of the outer most pk columns are null
1101     * indicating that an outer join was not matched).
1102     */

1103    public SqlExp getOuterJoinNotMatchedExp() {
1104        if (joinList == null) {
1105            return new IsNullExp(table.pk[0].toSqlExp(this));
1106        } else if (joinList.next == null) {
1107            return joinList.selectExp.getOuterJoinNotMatchedExp();
1108        } else {
1109            // join expressions with OrExp
1110
SqlExp root = joinList.selectExp.getOuterJoinNotMatchedExp();
1111            SqlExp p = root;
1112            for (Join j = joinList.next; ;) {
1113                p = p.next = j.selectExp.getOuterJoinNotMatchedExp();
1114                if ((j = j.next) == null) break;
1115            }
1116            return new OrExp(root);
1117        }
1118    }
1119
1120    /**
1121     * Get an expression that is true if this join produces a fully
1122     * populated row (i.e. all of the outer most pk columns are not null
1123     * indicating that all outer joins were matched).
1124     */

1125    public SqlExp getOuterJoinMatchedExp() {
1126        if (joinList == null) {
1127            return new IsNotNullExp(table.pk[0].toSqlExp(this));
1128        } else if (joinList.next == null) {
1129            return joinList.selectExp.getOuterJoinMatchedExp();
1130        } else {
1131            // join expressions with AndExp
1132
SqlExp root = joinList.selectExp.getOuterJoinMatchedExp();
1133            SqlExp p = root;
1134            for (Join j = joinList.next; ;) {
1135                p = p.next = j.selectExp.getOuterJoinMatchedExp();
1136                if ((j = j.next) == null) break;
1137            }
1138            return new AndExp(root);
1139        }
1140    }
1141
1142    /**
1143     * Add an order-by expression this to this select.
1144     */

1145    public SqlExp addOrderBy(OrderNode[] orders, boolean append) {
1146        return addOrderBy(orders, append, JDOQLNodeToSqlExp.INSTANCE);
1147    }
1148
1149    /**
1150     * Add an order-by expression this to this select.
1151     */

1152    public SqlExp addOrderBy(OrderNode[] orders, boolean append,
1153            JDOQLNodeToSqlExp visitor) {
1154        // create the order by list including joins to pickup columns as needed
1155
int len = orders.length;
1156        SqlExp oePos = null;
1157        if (append) {
1158            oePos = findTailOrderByExp();
1159        }
1160        for (int i = 0; i < len; i++) {
1161            OrderNode on = orders[i];
1162            SelectExp se = this;
1163            Node prevNode = null;
1164            for (Node n = on.childList; n != null; n = n.childList) {
1165                if (n instanceof FieldNode) {
1166                    SelectExp oSe = se;
1167                    if (prevNode != null && prevNode instanceof FieldNavNode) {
1168                        JdbcField refField = (JdbcField)((FieldNavNode)prevNode).fmd.storeField;
1169                        JdbcField orderByField = (JdbcField)((FieldNode)n).fmd.storeField;
1170
1171                        Join join = se.findJoin(orderByField.mainTable, refField);
1172                        if (join == null) {
1173                            oSe = new SelectExp();
1174                            oSe.table = orderByField.mainTable;
1175                            oSe.outer = true;
1176                            oSe.jdbcField = refField;
1177
1178                            if (refField instanceof JdbcPolyRefField) {
1179                                se.addJoin(((JdbcPolyRefField)refField).refCols, oSe.table.pk, oSe);
1180                            } else {
1181                                se.addJoin(refField.mainTableCols, oSe.table.pk, oSe);
1182                            }
1183
1184                        } else {
1185                            oSe = join.selectExp;
1186                        }
1187
1188                    } else if (prevNode == null) {
1189                        //look to join to superTable if in different table
1190
JdbcField orderByField = (JdbcField)((FieldNode)n).fmd.storeField;
1191                        if (orderByField.mainTable != se.table) {
1192                            oSe = se.findTable(orderByField.mainTable);
1193                            if (oSe == null) {
1194                                oSe = new SelectExp();
1195                                oSe.table = orderByField.mainTable;
1196                                oSe.outer = false;
1197                                se.addJoin(se.table.pk, oSe.table.pk, oSe);
1198                            }
1199                        }
1200                    }
1201
1202                    oePos = addOrderExp(
1203                            handleOrderByFieldNode((FieldNode)n, oSe, visitor),
1204                            (on.order == OrderNode.ORDER_DESCENDING),
1205                            oePos);
1206                } else if (n instanceof AsValueNode) {
1207                    oePos = addOrderExp(new ColumnExp(((AsValueNode)n).value),
1208                            (on.order == OrderNode.ORDER_DESCENDING),
1209                            oePos);
1210                } else if (n instanceof ReservedFieldNode) {
1211                    ColumnExp[] cExps = createColumnExpForOrdering(((ReservedFieldNode)n).getTarget(), se);
1212                    for (int j = 0; j < cExps.length; j++) {
1213                        oePos = addOrderExp(cExps[j],
1214                                (on.order == OrderNode.ORDER_DESCENDING),
1215                                oePos);
1216                    }
1217                } else if (n instanceof FieldNavNode) {
1218                    se = handleOrderByFieldNavNode((FieldNavNode)n, se, prevNode);
1219                } else {
1220                    throw BindingSupportImpl.getInstance().internal("Invalid node in orders: " + n);
1221                }
1222                prevNode = n;
1223            }
1224        }
1225        return oePos;
1226    }
1227
1228    /**
1229     * Insert the columns at the start of the orderByList as ascending.
1230     */

1231    public void prependOrderByForColumns(JdbcColumn[] columns) {
1232        SqlExp current = orderByList;
1233
1234        SqlExp oePos = null;
1235        ColumnExp[] columnExps = new ColumnExp[columns.length];
1236        for (int i = 0; i < columnExps.length; i++) {
1237            columnExps[i] = new ColumnExp(columns[i], this, null);
1238            oePos = addOrderExp(columnExps[i], false, oePos);
1239        }
1240
1241        if (current != null) {
1242            oePos.next = current;
1243        }
1244    }
1245
1246    /**
1247     * Append the columns at the end of the orderByList as ascending.
1248     */

1249    public void appendOrderByForColumns(JdbcColumn[] columns) {
1250        SqlExp oePos = findTailOrderByExp();
1251        for (int i = 0; i < columns.length; i++) {
1252            if (containsOrderExp(columns[i])) {
1253                continue;
1254            }
1255            oePos = addOrderExp(new ColumnExp(columns[i], this, null), false, oePos);
1256        }
1257    }
1258
1259    /**
1260     * Append the column at the end of the orderByList as ascending.
1261     */

1262    public void appendOrderByForColumns(JdbcColumn column) {
1263        SqlExp oePos = findTailOrderByExp();
1264        if (!containsOrderExp(column)) {
1265            oePos = addOrderExp(new ColumnExp(column, this, null), false, oePos);
1266        }
1267    }
1268
1269
1270    /**
1271     * Append the orderExp at the end of the current orderExp.
1272     */

1273    public void appendOrderByExp(SqlExp orderExp) {
1274        SqlExp oePos = findTailOrderByExp();
1275        if (oePos == null) {
1276            orderByList = orderExp;
1277        } else {
1278            if (oePos != orderExp) {
1279                oePos.next = orderExp;
1280            }
1281        }
1282    }
1283
1284    /**
1285     * Append the columns to the orderByList
1286     */

1287    public void appendOrderByForColumns(JdbcColumn[] columns, SelectExp se) {
1288        SqlExp oePos = findTailOrderByExp();
1289        for (int i = 0; i < columns.length; i++) {
1290            if (containsOrderExp(columns[i])/* || se.containsOrderExp(columns[i])*/) {
1291                continue;
1292            }
1293            oePos = addOrderExp(new ColumnExp(columns[i], se, null), false, oePos);
1294        }
1295    }
1296
1297    public boolean containsOrderExp(JdbcColumn jdbcColumn) {
1298        for (SqlExp e = orderByList; e != null; e = e.next) {
1299            if (((ColumnExp)((OrderExp)e).childList).col == jdbcColumn) return true;
1300        }
1301        return false;
1302    }
1303
1304    /**
1305     * return the tail of the orderExp
1306     */

1307    private SqlExp findTailOrderByExp() {
1308        for (SqlExp e = orderByList; e != null; e = e.next) {
1309            if (e.next == null) return e;
1310        }
1311        return null;
1312    }
1313
1314    public ColumnExp[] createColumnExpForOrdering(ClassMetaData target,
1315            SelectExp root) {
1316        JdbcColumn[] pk = ((JdbcClass)target.storeClass).table.pk;
1317        ColumnExp[] columnExps = new ColumnExp[pk.length];
1318        for (int i = 0; i < pk.length; i++) {
1319            columnExps[i] = new ColumnExp(pk[i], root, pk[i].refField);
1320        }
1321        return columnExps;
1322    }
1323
1324    private SqlExp addOrderExp(SqlExp list, boolean desc, SqlExp oePos) {
1325        // add a new OrderExp to the order by list
1326
OrderExp oe = new OrderExp(list, desc);
1327        if (oePos == null) {
1328            orderByList = oe;
1329        } else {
1330            oePos.next = oe;
1331        }
1332        oePos = oe;
1333        return oePos;
1334    }
1335
1336    /**
1337     * The idea here is to only add a join if the previous node is a FieldNavNode.
1338     */

1339    private SelectExp handleOrderByFieldNavNode(FieldNavNode nav, SelectExp se, Node prevNode) {
1340        if (prevNode != null && prevNode instanceof FieldNavNode) {
1341            //check if join is needed
1342
// see if there is a join to the table for the class we are navigating to
1343
JdbcField f = (JdbcField)((FieldNavNode)prevNode).fmd.storeField;
1344            Join j = se.findJoin(f);
1345            if (j != null) return j.selectExp;
1346
1347            // no join so add one
1348
SelectExp next = new SelectExp();
1349            next.jdbcField = f;
1350            ClassMetaData targetClass = ((FieldNavNode)prevNode).targetClass;
1351            next.table = ((JdbcClass)targetClass.storeClass).table;
1352            if (f instanceof JdbcPolyRefField) {
1353                se.addJoin(((JdbcPolyRefField)f).refCols, next.table.pk, next);
1354            } else {
1355                se.addJoin(f.mainTableCols, next.table.pk, next);
1356            }
1357            next.outer = f.fmd.nullValue != MDStatics.NULL_VALUE_EXCEPTION;
1358            return next;
1359        } else {
1360            return se;
1361        }
1362    }
1363
1364    private SqlExp handleOrderByFieldNode(FieldNode fn, SelectExp se,
1365            JDOQLNodeToSqlExp visitor) {
1366        if (!(fn.fmd.storeField instanceof JdbcSimpleField)) {
1367            throw BindingSupportImpl.getInstance().internal(
1368                    "Only simple fields may be used in an " +
1369                    "ordering statement: " + fn.fmd);
1370        }
1371        SqlExp list = visitor.toSqlExp(fn, se, null, 0, null);
1372        if (list.childList != null) {
1373            throw BindingSupportImpl.getInstance().internal(
1374                    "Only single column fields may be used in an " +
1375                    "ordering statement: " + fn.fmd);
1376        }
1377        return list;
1378    }
1379
1380    /**
1381     * Does this select contain a join to a many table that may produce
1382     * multiple rows? This is used to decide on setting the distinct flag
1383     * if this select is converterd into an outer join.
1384     */

1385    public boolean isJoinToManyTable() {
1386        return jdbcField instanceof JdbcCollectionField;
1387    }
1388
1389    /**
1390     * Append e to the where clause of this select. This will create a new
1391     * AndExp if needed.
1392     */

1393    public void appendToWhereExp(SqlExp e) {
1394        whereExp = SqlExp.appendWithAnd(whereExp, e);
1395    }
1396
1397    /**
1398     * Append e to the subSelectJoinExp clause of this select. This will
1399     * create a new AndExp if needed.
1400     */

1401    public void appendToSubSelectJoinExp(SqlExp e) {
1402        subSelectJoinExp = SqlExp.appendWithAnd(subSelectJoinExp, e);
1403    }
1404
1405    /**
1406     * Used to obtain a selectexp for a field. This will add a join to the supertable
1407     * if not already added.
1408     */

1409    public static SelectExp createJoinToSuperTable(SelectExp root, JdbcField jdbcField) {
1410        return createJoinToSuperTable(root, ((JdbcClass)jdbcField.fmd.classMetaData.storeClass).table);
1411    }
1412
1413    /**
1414     * Used to obtain a selectexp for a field. This will add a join to the supertable
1415     * if not already added.
1416     */

1417    public static SelectExp createJoinToSuperTable(SelectExp root, SelectExp joinFromExp,
1418                                                   JdbcColumn[] lJoinColumns, JdbcField jdbcField) {
1419        if (Debug.DEBUG) {
1420            JdbcRefField.isSubTableOf(root.table, jdbcField.fmd.classMetaData);
1421        }
1422        if (root.table != ((JdbcClass)jdbcField.fmd.classMetaData.storeClass).table) {
1423            Join join = joinFromExp.findJoin(jdbcField);
1424            if (join == null) {
1425                SelectExp se = new SelectExp();
1426                se.outer = root.outer;
1427                se.table = ((JdbcClass)jdbcField.fmd.classMetaData.storeClass).table;
1428                joinFromExp.addJoin(lJoinColumns, se.table.pk, se);
1429                return se;
1430            } else {
1431                return join.selectExp;
1432            }
1433        }
1434        return root;
1435    }
1436
1437    /**
1438     * Used to obtain a selectexp for a field. This will add a join to the supertable
1439     * if not already added.
1440     */

1441    public static SelectExp createJoinToSuperTable(SelectExp root, JdbcTable table) {
1442        // If the field is not in the table then join to the sub class table
1443
SelectExp se = (SelectExp)root.findTable(table);
1444        if (se == null) {
1445            se = new SelectExp();
1446            se.outer = root.outer;
1447            se.table = table;
1448            root.addJoin(root.table.pk, se.table.pk, se);
1449        }
1450        return se;
1451    }
1452
1453    public static void dumpJoinList(SelectExp joinFromExp, String JavaDoc val) {
1454        System.out.println(val + "dumping joinlist");
1455        Join j = joinFromExp.joinList;
1456        if (j == null) {
1457            System.out.println("-- no joins ");
1458            return;
1459        }
1460        for (;;) {
1461            System.out.println("j = " + j);
1462            j = j.next;
1463            if (j == null) break;
1464        }
1465    }
1466
1467    public static void dumpJoinListRec(SelectExp joinFromExp, String JavaDoc indent) {
1468        Join j = joinFromExp.joinList;
1469        if (j == null) {
1470// System.out.println(indent + "-- no joins --");
1471
return;
1472        }
1473        for (;;) {
1474            System.out.println(indent + j);
1475            dumpJoinListRec(j.selectExp, indent + " ");
1476            j = j.next;
1477            if (j == null) break;
1478        }
1479    }
1480
1481    public static void mergeJoinList(Join j) {
1482        if (j == null) return;
1483        if (j.next == null) return;
1484
1485        for (Join nextJoin = j.next; nextJoin != null; nextJoin = nextJoin.next) {
1486            if (nextJoin.isMerged()) {
1487                continue;
1488            }
1489            if (Join.isCurrentEqaul(j, nextJoin)) {
1490                nextJoin.setMergedWith(j);
1491                continue;
1492            }
1493        }
1494        mergeJoinList(j.selectExp.joinList);
1495        mergeJoinList(j.next);
1496    }
1497
1498}
1499
Popular Tags