KickJava   Java API By Example, From Geeks To Geeks.

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


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.util.CharBuf;
15 import com.versant.core.jdbc.sql.SqlDriver;
16 import com.versant.core.jdo.query.ParamNode;
17 import com.versant.core.common.Debug;
18
19 import java.util.Map JavaDoc;
20 import java.util.HashMap JavaDoc;
21
22 import com.versant.core.common.BindingSupportImpl;
23
24 /**
25  * An expression in an SQL query.
26  */

27 public class SqlExp {
28
29     /** Do not convert this expression into a join. **/
30     public static final int NO = 0;
31     /** Convert into a join. **/
32     public static final int YES = 1;
33     /** Convert into a join and select distinct. **/
34     public static final int YES_DISTINCT = 2;
35     /** Convert into an outer join with is null check and select distinct. **/
36     public static final int YES_DISTINCT_NOT = 3;
37
38     /**
39      * This makes it easy to form linked lists of expressions. This is
40      * faster and uses less memory than arrays of expressions.
41      */

42     public SqlExp next;
43     /**
44      * Linked list of children formed using their next fields.
45      */

46     public SqlExp childList;
47
48     private int preFirstCharIndex;
49     private int lastCharIndex;
50
51     public SqlExp() {
52     }
53
54     public SqlExp createInstance() {
55         return new SqlExp();
56     }
57
58     /**
59      * Use this to clone a SqlExp tree.
60      * @param sqlExp
61      * @return
62      */

63     public static SqlExp createClone(SqlExp sqlExp) {
64         return createClone(sqlExp, new HashMap JavaDoc());
65     }
66
67     /**
68      * This is a util method that decides if a instance should be cloned. If the
69      * instance was already cloned then the already cloned instance is returned.
70      * @param inst
71      * @param cloneMap
72      * @return A cloned instance.
73      */

74     public static SqlExp createClone(SqlExp inst, Map JavaDoc cloneMap) {
75         if (inst == null) return null;
76         if (cloneMap.containsKey(inst)) {
77             return (SqlExp) cloneMap.get(inst);
78         } else {
79             cloneMap.put(inst, inst.createInstance());
80         }
81         return inst.getClone((SqlExp) cloneMap.get(inst), cloneMap);
82     }
83
84     /**
85      * Clone the current instance. This method is called by subclassed to create a clone of its
86      * superclass.
87      *
88      * @param clone The instance it must set the cloned values on.
89      * @param cloneMap This map is used to avoid creating multiple clones for a singel instance.
90      * @return The update SqlExp
91      */

92     public SqlExp getClone(SqlExp clone, Map JavaDoc cloneMap) {
93         if (next != null) clone.next = createClone(next, cloneMap);
94         if (childList != null) clone.childList = createClone(childList, cloneMap);
95         clone.preFirstCharIndex = preFirstCharIndex;
96         clone.lastCharIndex = lastCharIndex;
97         return clone;
98     }
99
100     public SqlExp(SqlExp childList) {
101         this.childList = childList;
102     }
103
104     public String JavaDoc toString() {
105         String JavaDoc n = getClass().getName();
106         int i = n.lastIndexOf('.');
107         if (i >= 0) n = n.substring(i + 1);
108         return n + "@" + Integer.toHexString(System.identityHashCode(this));
109     }
110
111     /**
112      * Dump debugging info to System.out.
113      */

114     public void dump(String JavaDoc indent) {
115         Debug.OUT.println(indent + this);
116         if (childList != null) childList.dumpList(indent + " ");
117     }
118
119     /**
120      * Dump us and our list to System.out.
121      */

122     public void dumpList(String JavaDoc indent) {
123         dump(indent);
124         for (SqlExp e = next; e != null; e = e.next) e.dump(indent);
125     }
126
127     /**
128      * Create an aliases for any subtables we may have.
129      */

130     public int createAlias(int index) {
131         for (SqlExp e = childList; e != null; e = e.next) {
132             index = e.createAlias(index);
133         }
134         return index;
135     }
136
137     /**
138      * Replace any references to old with nw. This is used when redundant
139      * joins are removed.
140      */

141     public void replaceSelectExpRef(SelectExp old, SelectExp nw) {
142         for (SqlExp e = childList; e != null; e = e.next) {
143             e.replaceSelectExpRef(old, nw);
144         }
145     }
146
147     /**
148      * Normalize this node i.e. transform it into its simplist possible form.
149      * This will turn sub selects into joins and so on. Return expression to
150      * replace us with or null if no change.
151      */

152     public SqlExp normalize(SqlDriver driver, SelectExp sel, boolean convertExists) {
153         SqlExp p = null;
154         for (SqlExp e = childList; e != null; e = e.next) {
155             SqlExp r = e.normalize(driver, sel, convertExists);
156             if (r == null) {
157                 p = e;
158             } else {
159                 if (p == null)
160                     childList = r;
161                 else
162                     p.next = r;
163                 r.next = e.next;
164             }
165         }
166         return null;
167     }
168
169     /**
170      * Append SQL for this node to s.
171      *
172      * @param driver The driver being used
173      * @param s Append the SQL here
174      * @param leftSibling The SqlExp to the left of us or null if none
175      */

176     public final void appendSQL(SqlDriver driver, CharBuf s,
177             SqlExp leftSibling) {
178         preFirstCharIndex = s.size();
179         appendSQLImp(driver, s, leftSibling);
180         lastCharIndex = s.size();
181     }
182
183     /**
184      * Append SQL for this node to s. This is the method that subclasses
185      * should override.
186      *
187      * @param driver The driver being used
188      * @param s Append the SQL here
189      * @param leftSibling The SqlExp to the left of us or null if none
190      */

191     protected void appendSQLImp(SqlDriver driver, CharBuf s,
192             SqlExp leftSibling) {
193     }
194
195     /**
196      * If this expression is added to an AndExp should it be enclosed in
197      * parenthesis?
198      */

199     public boolean requiresParensInAnd() {
200         return false;
201     }
202
203     /**
204      * If this expression is added to an MultiplyExp should it be enclosed in
205      * parenthesis?
206      */

207     public boolean requiresParensInMultiply() {
208         return false;
209     }
210
211     /**
212      * Get the index of first character of the this expression in the output
213      * buffer. This is used when the whole expression needs to be replaced.
214      */

215     public final int getPreFirstCharIndex() {
216         return preFirstCharIndex;
217     }
218
219     /**
220      * Get the index of first character of the 'is null' parameter
221      * replacement span for this expression.
222      */

223     public int getFirstCharIndex() {
224         throw BindingSupportImpl.getInstance().internal("getFirstCharIndex called on " +
225                 this);
226     }
227
228     /**
229      * Get the index of the character after the last character of the
230      * 'is null' parameter replacement span for this expression.
231      */

232     public final int getLastCharIndex() {
233         return lastCharIndex;
234     }
235
236     /**
237      * Is this a negative expression for the purposes of replacing parameter
238      * values with 'is null' (false) or 'is not null' (true)?
239      */

240     public boolean isNegative() {
241         return false;
242     }
243
244     /**
245      * What is the JDBC type of this expression (0 if unknown)?
246      */

247     public int getJdbcType() {
248         return 0;
249     }
250
251     /**
252      * What is the java type code of this expression (0 if unknown)?
253      */

254     public int getJavaTypeCode() {
255         return 0;
256     }
257
258     /**
259      * What is the class index for this expression (-1 if unknown)?
260      * @see ParamNode
261      */

262     public int getClassIndex() {
263         return -1;
264     }
265
266     /**
267      * Can this expression be removed and its child be converted into a join?
268      * @see ExistsExp
269      * @see #NO
270      * @see #YES
271      * @see #YES_DISTINCT
272      * @see #YES_DISTINCT_NOT
273      */

274     public int getConvertToJoin() {
275         return NO;
276     }
277
278     /**
279      * Add a list of expressions to the end of our childList.
280      */

281     public void append(SqlExp extra) {
282         if (childList == null) {
283             childList = extra;
284         } else {
285             SqlExp e;
286             for (e = childList; e.next != null; e = e.next) ;
287             e.next = extra;
288         }
289     }
290
291     /**
292      * Append e to base using an AndExp. If base is already an AndExp then
293      * e is simply appended. If base is null then e becomes base. Otherwise
294      * base becomes a a new AndExp created from the old base and e.
295      * @return New value for base
296      */

297     public static SqlExp appendWithAnd(SqlExp base, SqlExp e) {
298         if (e == null) return base;
299         if (base == null) {
300             if (e.next == null) {
301                 base = e;
302             } else {
303                 base = new AndExp(e);
304             }
305         } else if (base instanceof AndExp) {
306             base.append(e);
307         } else {
308             base.next = e;
309             base = new AndExp(base);
310         }
311         return base;
312     }
313
314     /**
315      * Make us an outer join or not. This is a NOP except for JoinExp and
316      * AndJoinExp.
317      * @see JoinExp
318      * @see AndJoinExp
319      */

320     public void setOuter(boolean on) {
321     }
322
323     /**
324      * If this expression involves a single table (other than exclude) only
325      * then return the SelectExp for the table (e.g. a.col1 == 10 returns a,
326      * a.col1 = b.col2 returns null, a.col1 = b.col2 with exclude = b returns
327      * a). This is used to detect expressions that can be moved
328      * into the ON list for the join to the table involved.
329      */

330     public SelectExp getSingleSelectExp(SelectExp exclude) {
331         return null;
332     }
333
334     /**
335      * Create an expression comparing the left and right exp with an
336      * operator. Only == and != really make sense. If left and right are
337      * lists then comparing matching exp's joined together in an 'and'
338      * list.
339      */

340     public static SqlExp createBinaryOpExp(SqlExp left, int op, SqlExp right) {
341         if (left.next == null && right.next == null) {
342             BinaryOpExp ans = new BinaryOpExp(left, op, right);
343             if (right instanceof ParamExp) {
344                 ParamExp p = (ParamExp)right;
345                 p.usage.expList = ans;
346                 if (left instanceof ColumnExp) p.usage.expCount = 1;
347             }
348             return ans;
349         } else {
350             SqlExp l = left.next;
351             SqlExp r = right.next;
352             SqlExp list = new BinaryOpExp(left, op, right);
353             AndExp ans = new AndExp(list);
354             ParamExp pe;
355             if (right instanceof ParamExp) {
356                 pe = (ParamExp)right;
357                 pe.usage.expList = list;
358             } else {
359                 pe = null;
360             }
361             boolean colExp = left instanceof ColumnExp;
362             int c = 1;
363             for (; l != null && r != null; c++) {
364                 left = l;
365                 right = r;
366                 l = left.next;
367                 r = right.next;
368                 BinaryOpExp e = new BinaryOpExp(left, op, right);
369                 list = list.next = e;
370             }
371             if (l != null || r != null) {
372                 throw BindingSupportImpl.getInstance().internal(
373                     "left and right lists have different length");
374             }
375             if (pe != null && colExp) pe.usage.expCount = c;
376             return ans;
377         }
378     }
379
380 }
381
Popular Tags