KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > mckoi > database > Expression


1 /**
2  * com.mckoi.database.Expression 11 Jul 2000
3  *
4  * Mckoi SQL Database ( http://www.mckoi.com/database )
5  * Copyright (C) 2000, 2001, 2002 Diehl and Associates, Inc.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * Version 2 as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License Version 2 for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * Version 2 along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  *
20  * Change Log:
21  *
22  *
23  */

24
25 package com.mckoi.database;
26
27 import java.util.Date JavaDoc;
28 import java.util.List JavaDoc;
29 import java.util.ArrayList JavaDoc;
30 import java.io.StringReader JavaDoc;
31 import java.io.IOException JavaDoc;
32 import java.io.ObjectInputStream JavaDoc;
33 import java.io.ObjectOutputStream JavaDoc;
34 import com.mckoi.database.sql.SQL;
35 import com.mckoi.util.BigNumber;
36
37 /**
38  * An expression that can be evaluated in a statement. This is used as a more
39  * complete and flexible version of 'Condition' as well as representing column
40  * and aggregate functions.
41  * <p>
42  * This class can represent constant expressions (expressions that have no
43  * variable input), as well as variable expressions. Optimizations may be
44  * possible when evaluating constant expressions.
45  * <p>
46  * Some examples of constant expressions;<p><pre>
47  * ( 9 + 3 ) * 90
48  * ( ? * 9 ) / 1
49  * lower("CaPS MUMma")
50  * 40 & 0x0FF != 39
51  * </pre>
52  * Some examples of variable expressions;<p><pre>
53  * upper(Part.description)
54  * Part.id >= 50
55  * VendorMakesPart.part_id == Part.id
56  * Part.value_of <= Part.cost_of / 4
57  * </pre>
58  * <p>
59  * <strong>NOTE:</strong> the expression is stored in postfix orientation. eg.
60  * "8 + 9 * 3" becomes "8,9,3,*,+"
61  * <p>
62  * <strong>NOTE:</strong> This class is <b>NOT</b> thread safe. Do not use an
63  * expression instance between threads.
64  *
65  * @author Tobias Downer
66  */

67
68 public final class Expression implements java.io.Serializable JavaDoc, Cloneable JavaDoc {
69
70   /**
71    * Serialization UID.
72    */

73   static final long serialVersionUID = 6981261114471924028L;
74
75   /**
76    * The list of elements followed by operators in our expression. The
77    * expression elements may be of any type represented by the database
78    * (see 'addElement' method for the accepted objects). The expression
79    * operators may be '+', '-', '*', '*', '/', '=', '>=', '<>', etc (as an
80    * Operator object (see the Operator class for details)).
81    * <p>
82    * This list is stored in postfix order.
83    */

84   private ArrayList JavaDoc elements = new ArrayList JavaDoc();
85
86   /**
87    * The evaluation stack for when the expression is evaluated.
88    */

89   private transient ArrayList JavaDoc eval_stack;
90
91   /**
92    * The expression as a plain human readable string. This is in a form that
93    * can be readily parsed to an Expression object.
94    */

95   private StringBuffer JavaDoc text;
96
97
98   /**
99    * Constructs a new Expression.
100    */

101   public Expression() {
102     text = new StringBuffer JavaDoc();
103   }
104
105   /**
106    * Constructs a new Expression with a single object element.
107    */

108   public Expression(Object JavaDoc ob) {
109     this();
110     addElement(ob);
111   }
112
113   /**
114    * Constructs a copy of the given Expression.
115    */

116   public Expression(Expression exp) {
117     concat(exp);
118     text = new StringBuffer JavaDoc(new String JavaDoc(exp.text));
119   }
120
121   /**
122    * Constructs a new Expression from the concatination of expression1 and
123    * expression2 and the operator for them.
124    */

125   public Expression(Expression exp1, Operator op, Expression exp2) {
126     // Remember, this is in postfix notation.
127
elements.addAll(exp1.elements);
128     elements.addAll(exp2.elements);
129     elements.add(op);
130   }
131
132   /**
133    * Returns the StringBuffer that we can use to append plain text
134    * representation as we are parsing the expression.
135    */

136   public StringBuffer JavaDoc text() {
137     return text;
138   }
139
140   /**
141    * Copies the text from the given expression.
142    */

143   public void copyTextFrom(Expression e) {
144     this.text = new StringBuffer JavaDoc(new String JavaDoc(e.text()));
145   }
146
147   /**
148    * Static method that parses the given string which contains an expression
149    * into an Expression object. For example, this will parse strings such
150    * as '(a + 9) * 2 = b' or 'upper(concat('12', '56', id))'.
151    * <p>
152    * Care should be taken to not use this method inside an inner loop because
153    * it creates a lot of objects.
154    */

155   public static Expression parse(String JavaDoc expression) {
156     synchronized (expression_parser) {
157       try {
158         expression_parser.ReInit(new StringReader JavaDoc(expression));
159         expression_parser.reset();
160         Expression exp = expression_parser.parseExpression();
161
162         exp.text().setLength(0);
163         exp.text().append(expression);
164         return exp;
165       }
166       catch (com.mckoi.database.sql.ParseException e) {
167         throw new RuntimeException JavaDoc(e.getMessage());
168       }
169     }
170   }
171
172   /**
173    * A static expression parser. To use this we must first synchronize over
174    * the object.
175    */

176   private final static SQL expression_parser = new SQL(new StringReader JavaDoc(""));
177
178   /**
179    * Generates a simple expression from two objects and an operator.
180    */

181   public static Expression simple(Object JavaDoc ob1, Operator op, Object JavaDoc ob2) {
182     Expression exp = new Expression(ob1);
183     exp.addElement(ob2);
184     exp.addElement(op);
185     return exp;
186   }
187
188
189   /**
190    * Adds a new element into the expression. String, BigNumber, Boolean and
191    * Variable are the types of elements allowed.
192    * <p>
193    * Must be added in postfix order.
194    */

195   public void addElement(Object JavaDoc ob) {
196     if (ob == null) {
197       elements.add(TObject.nullVal());
198     }
199     else if (ob instanceof TObject ||
200              ob instanceof ParameterSubstitution ||
201              ob instanceof CorrelatedVariable ||
202              ob instanceof Variable ||
203              ob instanceof FunctionDef ||
204              ob instanceof Operator ||
205              ob instanceof StatementTreeObject
206         ) {
207       elements.add(ob);
208     }
209     else {
210       throw new Error JavaDoc("Unknown element type added to expression: " +
211                       ob.getClass());
212     }
213   }
214
215   /**
216    * Merges an expression with this expression. For example, given the
217    * expression 'ab', if the expression 'abc+-' was added the expression would
218    * become 'ababc+-'.
219    * <p>
220    * This method is useful when copying parts of other expressions when forming
221    * an expression.
222    * <p>
223    * This always returns this expression. This does not change 'text()'.
224    */

225   public Expression concat(Expression expr) {
226     elements.addAll(expr.elements);
227     return this;
228   }
229
230   /**
231    * Adds a new operator into the expression. Operators are represented as
232    * an Operator (eg. ">", "+", "<<", "!=" )
233    * <p>
234    * Must be added in postfix order.
235    */

236   public void addOperator(Operator op) {
237     elements.add(op);
238   }
239
240   /**
241    * Returns the number of elements and operators that are in this postfix
242    * list.
243    */

244   public int size() {
245     return elements.size();
246   }
247
248   /**
249    * Returns the element at the given position in the postfix list. Note, this
250    * can return Operator's.
251    */

252   public Object JavaDoc elementAt(int n) {
253     return elements.get(n);
254   }
255
256   /**
257    * Returns the element at the end of the postfix list (the last element).
258    */

259   public Object JavaDoc last() {
260     return elements.get(size() - 1);
261   }
262
263
264   /**
265    * Sets the element at the given position in the postfix list. This should
266    * be called after the expression has been setup to alter variable alias
267    * names, etc.
268    */

269   public void setElementAt(int n, Object JavaDoc ob) {
270     elements.set(n, ob);
271   }
272
273   /**
274    * Pushes an element onto the evaluation stack.
275    */

276   private final void push(Object JavaDoc ob) {
277     eval_stack.add(ob);
278   }
279
280   /**
281    * Pops an element from the evaluation stack.
282    */

283   private final Object JavaDoc pop() {
284     return eval_stack.remove(eval_stack.size() - 1);
285   }
286
287
288   /**
289    * Returns a complete List of Variable objects in this expression not
290    * including correlated variables.
291    */

292   public List JavaDoc allVariables() {
293     ArrayList JavaDoc vars = new ArrayList JavaDoc();
294     for (int i = 0; i < elements.size(); ++i) {
295       Object JavaDoc ob = elements.get(i);
296       if (ob instanceof Variable) {
297         vars.add(ob);
298       }
299       else if (ob instanceof FunctionDef) {
300         Expression[] params = ((FunctionDef)ob).getParameters();
301         for (int n = 0; n < params.length; ++n) {
302           vars.addAll(params[n].allVariables());
303         }
304       }
305       else if (ob instanceof TObject) {
306         TObject tob = (TObject) ob;
307         if (tob.getTType() instanceof TArrayType) {
308           Expression[] exp_list = (Expression[]) tob.getObject();
309           for (int n = 0; n < exp_list.length; ++n) {
310             vars.addAll(exp_list[n].allVariables());
311           }
312         }
313       }
314     }
315     return vars;
316   }
317
318   /**
319    * Returns a complete list of all element objects that are in this expression
320    * and in the parameters of the functions of this expression.
321    */

322   public List JavaDoc allElements() {
323     ArrayList JavaDoc elems = new ArrayList JavaDoc();
324     for (int i = 0; i < elements.size(); ++i) {
325       Object JavaDoc ob = elements.get(i);
326       if (ob instanceof Operator) {
327       }
328       else if (ob instanceof FunctionDef) {
329         Expression[] params = ((FunctionDef) ob).getParameters();
330         for (int n = 0; n < params.length; ++n) {
331           elems.addAll(params[n].allElements());
332         }
333       }
334       else if (ob instanceof TObject) {
335         TObject tob = (TObject) ob;
336         if (tob.getTType() instanceof TArrayType) {
337           Expression[] exp_list = (Expression[]) tob.getObject();
338           for (int n = 0; n < exp_list.length; ++n) {
339             elems.addAll(exp_list[n].allElements());
340           }
341         }
342         else {
343           elems.add(ob);
344         }
345       }
346       else {
347         elems.add(ob);
348       }
349     }
350     return elems;
351   }
352
353   /**
354    * A general prepare that cascades through the expression and its parents and
355    * substitutes an elements that the preparer wants to substitute.
356    * <p>
357    * NOTE: This will not cascade through to the parameters of Function objects
358    * however it will cascade through FunctionDef parameters. For this
359    * reason you MUST call 'prepareFunctions' after this method.
360    */

361   public void prepare(ExpressionPreparer preparer) throws DatabaseException {
362     for (int n = 0; n < elements.size(); ++n) {
363       Object JavaDoc ob = elements.get(n);
364
365       // If the preparer will prepare this type of object then set the
366
// entry with the prepared object.
367
if (preparer.canPrepare(ob)) {
368         elements.set(n, preparer.prepare(ob));
369       }
370
371       Expression[] exp_list = null;
372       if (ob instanceof FunctionDef) {
373         FunctionDef func = (FunctionDef) ob;
374         exp_list = func.getParameters();
375       }
376       else if (ob instanceof TObject) {
377         TObject tob = (TObject) ob;
378         if (tob.getTType() instanceof TArrayType) {
379           exp_list = (Expression[]) tob.getObject();
380         }
381       }
382       else if (ob instanceof StatementTreeObject) {
383         StatementTreeObject stree = (StatementTreeObject) ob;
384         stree.prepareExpressions(preparer);
385       }
386
387       if (exp_list != null) {
388         for (int p = 0; p < exp_list.length; ++p) {
389           exp_list[p].prepare(preparer);
390         }
391       }
392
393     }
394   }
395
396
397   /**
398    * Returns true if the expression doesn't include any variables or non
399    * constant functions (is constant). Note that a correlated variable is
400    * considered a constant.
401    */

402   public boolean isConstant() {
403     for (int n = 0; n < elements.size(); ++n) {
404       Object JavaDoc ob = elements.get(n);
405       if (ob instanceof TObject) {
406         TObject tob = (TObject) ob;
407         TType ttype = tob.getTType();
408         // If this is a query plan, return false
409
if (ttype instanceof TQueryPlanType) {
410           return false;
411         }
412         // If this is an array, check the array for constants
413
else if (ttype instanceof TArrayType) {
414           Expression[] exp_list = (Expression[]) tob.getObject();
415           for (int p = 0; p < exp_list.length; ++p) {
416             if (!exp_list[p].isConstant()) {
417               return false;
418             }
419           }
420         }
421       }
422       else if (ob instanceof Variable) {
423         return false;
424       }
425       else if (ob instanceof FunctionDef) {
426         Expression[] params = ((FunctionDef) ob).getParameters();
427         for (int p = 0; p < params.length; ++p) {
428           if (!params[p].isConstant()) {
429             return false;
430           }
431         }
432       }
433     }
434     return true;
435   }
436
437   /**
438    * Returns true if the expression has a subquery (eg 'in ( select ... )')
439    * somewhere in it (this cascades through function parameters also).
440    */

441   public boolean hasSubQuery() {
442     List JavaDoc list = allElements();
443     int len = list.size();
444     for (int n = 0; n < len; ++n) {
445       Object JavaDoc ob = list.get(n);
446       if (ob instanceof TObject) {
447         TObject tob = (TObject) ob;
448         if (tob.getTType() instanceof TQueryPlanType) {
449           return true;
450         }
451       }
452     }
453     return false;
454   }
455
456   /**
457    * Returns true if the expression contains a NOT operator somewhere in it.
458    */

459   public boolean containsNotOperator() {
460     for (int n = 0; n < elements.size(); ++n) {
461       Object JavaDoc ob = elements.get(n);
462       if (ob instanceof Operator) {
463         if (((Operator) ob).isNot()) {
464           return true;
465         }
466       }
467     }
468     return false;
469   }
470
471   /**
472    * Discovers all the correlated variables in this expression. If this
473    * expression contains a sub-query plan, we ask the plan to find the list of
474    * correlated variables. The discovery process increments the 'level'
475    * variable for each sub-plan.
476    */

477   public ArrayList JavaDoc discoverCorrelatedVariables(int level, ArrayList JavaDoc list) {
478     List JavaDoc elems = allElements();
479     int sz = elems.size();
480     // For each element
481
for (int i = 0; i < sz; ++i) {
482       Object JavaDoc ob = elems.get(i);
483       if (ob instanceof CorrelatedVariable) {
484         CorrelatedVariable v = (CorrelatedVariable) ob;
485         if (v.getQueryLevelOffset() == level) {
486           list.add(v);
487         }
488       }
489       else if (ob instanceof TObject) {
490         TObject tob = (TObject) ob;
491         if (tob.getTType() instanceof TQueryPlanType) {
492           QueryPlanNode node = (QueryPlanNode) tob.getObject();
493           list = node.discoverCorrelatedVariables(level + 1, list);
494         }
495       }
496     }
497     return list;
498   }
499
500   /**
501    * Discovers all the tables in the sub-queries of this expression. This is
502    * used for determining all the tables that a query plan touches.
503    */

504   public ArrayList JavaDoc discoverTableNames(ArrayList JavaDoc list) {
505     List JavaDoc elems = allElements();
506     int sz = elems.size();
507     // For each element
508
for (int i = 0; i < sz; ++i) {
509       Object JavaDoc ob = elems.get(i);
510       if (ob instanceof TObject) {
511         TObject tob = (TObject) ob;
512         if (tob.getTType() instanceof TQueryPlanType) {
513           QueryPlanNode node = (QueryPlanNode) tob.getObject();
514           list = node.discoverTableNames(list);
515         }
516       }
517     }
518     return list;
519   }
520
521   /**
522    * Returns the QueryPlanNode object in this expression if it evaluates to a
523    * single QueryPlanNode, otherwise returns null.
524    */

525   public QueryPlanNode getQueryPlanNode() {
526     Object JavaDoc ob = elementAt(0);
527     if (size() == 1 && ob instanceof TObject) {
528       TObject tob = (TObject) ob;
529       if (tob.getTType() instanceof TQueryPlanType) {
530         return (QueryPlanNode) tob.getObject();
531       }
532     }
533     return null;
534   }
535
536   /**
537    * Returns the Variable if this expression evaluates to a single variable,
538    * otherwise returns null. A correlated variable will not be returned.
539    */

540   public Variable getVariable() {
541     Object JavaDoc ob = elementAt(0);
542     if (size() == 1 && ob instanceof Variable) {
543       return (Variable) ob;
544     }
545     return null;
546   }
547
548   /**
549    * Returns an array of two Expression objects that represent the left hand
550    * and right and side of the last operator in the post fix notation.
551    * For example, (a + b) - (c + d) will return { (a + b), (c + d) }. Or
552    * more a more useful example is;<p><pre>
553    * id + 3 > part_id - 2 will return ( id + 3, part_id - 2 }
554    * </pre>
555    */

556   public Expression[] split() {
557     if (size() <= 1) {
558       throw new Error JavaDoc("Can only split expressions with more than 1 element.");
559     }
560
561     int midpoint = -1;
562     int stack_size = 0;
563     for (int n = 0; n < size() - 1; ++n) {
564       Object JavaDoc ob = elementAt(n);
565       if (ob instanceof Operator) {
566         --stack_size;
567       }
568       else {
569         ++stack_size;
570       }
571
572       if (stack_size == 1) {
573         midpoint = n;
574       }
575     }
576
577     if (midpoint == -1) {
578       throw new Error JavaDoc("postfix format error: Midpoint not found.");
579     }
580
581     Expression lhs = new Expression();
582     for (int n = 0; n <= midpoint; ++n) {
583       lhs.addElement(elementAt(n));
584     }
585
586     Expression rhs = new Expression();
587     for (int n = midpoint + 1; n < size() - 1; ++n) {
588       rhs.addElement(elementAt(n));
589     }
590
591     return new Expression[] { lhs, rhs };
592   }
593
594   /**
595    * Returns the end Expression of this expression. For example, an expression
596    * of 'ab' has an end expression of 'b'. The expression 'abc+=' has an end
597    * expression of 'abc+='.
598    * <p>
599    * This is a useful method to call in the middle of an Expression object
600    * being formed. It allows for the last complete expression to be
601    * returned.
602    * <p>
603    * If this is called when an expression is completely formed it will always
604    * return the complete expression.
605    */

606   public Expression getEndExpression() {
607
608     int stack_size = 1;
609     int end = size() - 1;
610     for (int n = end; n > 0; --n) {
611       Object JavaDoc ob = elementAt(n);
612       if (ob instanceof Operator) {
613         ++stack_size;
614       }
615       else {
616         --stack_size;
617       }
618
619       if (stack_size == 0) {
620         // Now, n .. end represents the new expression.
621
Expression new_exp = new Expression();
622         for (int i = n; i <= end; ++i) {
623           new_exp.addElement(elementAt(i));
624         }
625         return new_exp;
626       }
627     }
628
629     return new Expression(this);
630   }
631
632   /**
633    * Breaks this expression into a list of sub-expressions that are split
634    * by the given operator. For example, given the expression;
635    * <p><pre>
636    * (a = b AND b = c AND (a = 2 OR c = 1))
637    * </pre><p>
638    * Calling this method with logical_op = "and" will return a list of the
639    * three expressions.
640    * <p>
641    * This is a common function used to split up an expressions into logical
642    * components for processing.
643    */

644   public ArrayList JavaDoc breakByOperator(ArrayList JavaDoc list, final String JavaDoc logical_op) {
645     // The last operator must be 'and'
646
Object JavaDoc ob = last();
647     if (ob instanceof Operator) {
648       Operator op = (Operator) ob;
649       if (op.is(logical_op)) {
650         // Last operator is 'and' so split and recurse.
651
Expression[] exps = split();
652         list = exps[0].breakByOperator(list, logical_op);
653         list = exps[1].breakByOperator(list, logical_op);
654         return list;
655       }
656     }
657     // If no last expression that matches then add this expression to the
658
// list.
659
list.add(this);
660     return list;
661   }
662
663   /**
664    * Evaluates this expression and returns an Object that represents the
665    * result of the evaluation. The passed VariableResolver object is used
666    * to resolve the variable name to a value. The GroupResolver object is
667    * used if there are any aggregate functions in the evaluation - this can be
668    * null if evaluating an expression without grouping aggregates. The query
669    * context object contains contextual information about the environment of
670    * the query.
671    * <p>
672    * NOTE: This method is gonna be called a lot, so we need it to be optimal.
673    * <p>
674    * NOTE: This method is <b>not</b> thread safe! The reason it's not safe
675    * is because of the evaluation stack.
676    */

677   public TObject evaluate(GroupResolver group, VariableResolver resolver,
678                           QueryContext context) {
679     // Optimization - trivial case of 'a' or 'ab*' postfix are tested for
680
// here.
681
int element_count = elements.size();
682     if (element_count == 1) {
683       return (TObject) elementToObject(0, group, resolver, context);
684     }
685     else if (element_count == 3) {
686       TObject o1 = (TObject) elementToObject(0, group, resolver, context);
687       TObject o2 = (TObject) elementToObject(1, group, resolver, context);
688       Operator op = (Operator) elements.get(2);
689       return op.eval(o1, o2, group, resolver, context);
690     }
691
692     if (eval_stack == null) {
693       eval_stack = new ArrayList JavaDoc();
694     }
695
696     for (int n = 0; n < element_count; ++n) {
697       Object JavaDoc val = elementToObject(n, group, resolver, context);
698       if (val instanceof Operator) {
699         // Pop the last two values off the stack, evaluate them and push
700
// the new value back on.
701
Operator op = (Operator) val;
702
703         TObject v2 = (TObject) pop();
704         TObject v1 = (TObject) pop();
705
706         push(op.eval(v1, v2, group, resolver, context));
707       }
708       else {
709         push(val);
710       }
711     }
712     // We should end with a single value on the stack.
713
return (TObject) pop();
714   }
715
716   /**
717    * Evaluation without a grouping table.
718    */

719   public TObject evaluate(VariableResolver resolver, QueryContext context) {
720     return evaluate(null, resolver, context);
721   }
722
723   /**
724    * Returns the element at the given position in the expression list. If
725    * the element is a variable then it is resolved on the VariableResolver.
726    * If the element is a function then it is evaluated and the result is
727    * returned.
728    */

729   private Object JavaDoc elementToObject(int n, GroupResolver group,
730                            VariableResolver resolver, QueryContext context) {
731     Object JavaDoc ob = elements.get(n);
732     if (ob instanceof TObject ||
733         ob instanceof Operator) {
734       return ob;
735     }
736     else if (ob instanceof Variable) {
737       return resolver.resolve((Variable) ob);
738     }
739     else if (ob instanceof CorrelatedVariable) {
740       return ((CorrelatedVariable) ob).getEvalResult();
741     }
742     else if (ob instanceof FunctionDef) {
743       Function fun = ((FunctionDef) ob).getFunction(context);
744       return fun.evaluate(group, resolver, context);
745     }
746     else {
747       if (ob == null) {
748         throw new NullPointerException JavaDoc("Null element in expression");
749       }
750       throw new Error JavaDoc("Unknown element type: " + ob.getClass());
751     }
752   }
753
754   /**
755    * Cascades through the expression and if any aggregate functions are found
756    * returns true, otherwise returns false.
757    */

758   public boolean hasAggregateFunction(QueryContext context) {
759     for (int n = 0; n < elements.size(); ++n) {
760       Object JavaDoc ob = elements.get(n);
761       if (ob instanceof FunctionDef) {
762         if (((FunctionDef) ob).isAggregate(context)) {
763           return true;
764         }
765       }
766       else if (ob instanceof TObject) {
767         TObject tob = (TObject) ob;
768         if (tob.getTType() instanceof TArrayType) {
769           Expression[] list = (Expression[]) tob.getObject();
770           for (int i = 0; i < list.length; ++i) {
771             if (list[i].hasAggregateFunction(context)) {
772               return true;
773             }
774           }
775         }
776       }
777     }
778     return false;
779   }
780
781   /**
782    * Determines the type of object this expression evaluates to. We determine
783    * this by looking at the last element of the expression. If the last
784    * element is a TType object, it returns the type. If the last element is a
785    * Function, Operator or Variable then it returns the type that these
786    * objects have set as their result type.
787    */

788   public TType returnTType(VariableResolver resolver, QueryContext context) {
789     Object JavaDoc ob = elements.get(elements.size() - 1);
790     if (ob instanceof FunctionDef) {
791       Function fun = ((FunctionDef) ob).getFunction(context);
792       return fun.returnTType(resolver, context);
793     }
794     else if (ob instanceof TObject) {
795       return ((TObject)ob).getTType();
796     }
797     else if (ob instanceof Operator) {
798       Operator op = (Operator) ob;
799       return op.returnTType();
800     }
801     else if (ob instanceof Variable) {
802       Variable variable = (Variable) ob;
803       return resolver.returnTType(variable);
804     }
805     else if (ob instanceof CorrelatedVariable) {
806       CorrelatedVariable variable = (CorrelatedVariable) ob;
807       return variable.returnTType();
808     }
809     else {
810       throw new Error JavaDoc("Unable to determine type for expression.");
811     }
812   }
813
814   /**
815    * Performs a deep clone of this object, calling 'clone' on any elements
816    * that are mutable or shallow copying immutable members.
817    */

818   public Object JavaDoc clone() throws CloneNotSupportedException JavaDoc {
819     // Shallow clone
820
Expression v = (Expression) super.clone();
821     v.eval_stack = null;
822 // v.text = new StringBuffer(new String(text));
823
int size = elements.size();
824     ArrayList JavaDoc cloned_elements = new ArrayList JavaDoc(size);
825     v.elements = cloned_elements;
826
827     // Clone items in the elements list
828
for (int i = 0; i < size; ++i) {
829       Object JavaDoc element = elements.get(i);
830       
831       if (element instanceof TObject) {
832         // TObject is immutable except for TArrayType and TQueryPlanType
833
TObject tob = (TObject) element;
834         TType ttype = tob.getTType();
835         // For a query plan
836
if (ttype instanceof TQueryPlanType) {
837           QueryPlanNode node = (QueryPlanNode) tob.getObject();
838           node = (QueryPlanNode) node.clone();
839           element = new TObject(ttype, node);
840         }
841         // For an array
842
else if (ttype instanceof TArrayType) {
843           Expression[] arr = (Expression[]) tob.getObject();
844           arr = (Expression[]) arr.clone();
845           for (int n = 0; n < arr.length; ++n) {
846             arr[n] = (Expression) arr[n].clone();
847           }
848           element = new TObject(ttype, arr);
849         }
850       }
851       else if (element instanceof Operator ||
852                element instanceof ParameterSubstitution) {
853         // immutable so we do not need to clone these
854
}
855       else if (element instanceof CorrelatedVariable) {
856         element = ((CorrelatedVariable) element).clone();
857       }
858       else if (element instanceof Variable) {
859         element = ((Variable) element).clone();
860       }
861       else if (element instanceof FunctionDef) {
862         element = ((FunctionDef) element).clone();
863       }
864       else if (element instanceof StatementTreeObject) {
865         element = ((StatementTreeObject) element).clone();
866       }
867       else {
868         throw new CloneNotSupportedException JavaDoc(element.getClass().toString());
869       }
870       cloned_elements.add(element);
871     }
872
873     return v;
874   }
875
876   /**
877    * Returns a string representation of this object for diagnostic
878    * purposes.
879    */

880   public String JavaDoc toString() {
881     StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
882     buf.append("[ Expression ");
883     if (text() != null) {
884       buf.append("[");
885       buf.append(text().toString());
886       buf.append("]");
887     }
888     buf.append(": ");
889     for (int n = 0; n < elements.size(); ++n) {
890       buf.append(elements.get(n));
891       if (n < elements.size() - 1) {
892         buf.append(",");
893       }
894     }
895     buf.append(" ]");
896     return new String JavaDoc(buf);
897   }
898
899   // ---------- Serialization methods ----------
900

901   /**
902    * Writes the state of this object to the object stream. This method is
903    * implemented because GCJ doesn't like it if you implement readObject
904    * without writeObject.
905    */

906   private void writeObject(ObjectOutputStream JavaDoc out) throws IOException JavaDoc {
907     out.defaultWriteObject();
908   }
909   
910   /**
911    * Reads the state of this object from the object stream.
912    */

913   private void readObject(ObjectInputStream JavaDoc in)
914                                   throws IOException JavaDoc, ClassNotFoundException JavaDoc {
915     in.defaultReadObject();
916     
917     // This converts old types to the new TObject type system introduced
918
// in version 0.94.
919
int sz = elements.size();
920     for (int i = 0; i < sz; ++i) {
921       Object JavaDoc ob = elements.get(i);
922       TObject conv_object = null;
923       if (ob == null || ob instanceof com.mckoi.database.global.NullObject) {
924         conv_object = TObject.nullVal();
925       }
926       else if (ob instanceof String JavaDoc) {
927         conv_object = TObject.stringVal((String JavaDoc) ob);
928       }
929       else if (ob instanceof java.math.BigDecimal JavaDoc) {
930         conv_object = TObject.bigNumberVal(
931                        BigNumber.fromBigDecimal((java.math.BigDecimal JavaDoc) ob));
932       }
933       else if (ob instanceof java.util.Date JavaDoc) {
934         conv_object = TObject.dateVal((java.util.Date JavaDoc) ob);
935       }
936       else if (ob instanceof Boolean JavaDoc) {
937         conv_object = TObject.booleanVal(((Boolean JavaDoc) ob).booleanValue());
938       }
939       if (conv_object != null) {
940         elements.set(i, conv_object);
941       }
942     }
943   }
944
945 }
946
Popular Tags