001: /**
002: * com.mckoi.database.Expression 11 Jul 2000
003: *
004: * Mckoi SQL Database ( http://www.mckoi.com/database )
005: * Copyright (C) 2000, 2001, 2002 Diehl and Associates, Inc.
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * Version 2 as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License Version 2 for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * Version 2 along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
019: *
020: * Change Log:
021: *
022: *
023: */package com.mckoi.database;
024:
025: import java.util.Date;
026: import java.util.List;
027: import java.util.ArrayList;
028: import java.io.StringReader;
029: import java.io.IOException;
030: import java.io.ObjectInputStream;
031: import java.io.ObjectOutputStream;
032: import com.mckoi.database.sql.SQL;
033: import com.mckoi.util.BigNumber;
034:
035: /**
036: * An expression that can be evaluated in a statement. This is used as a more
037: * complete and flexible version of 'Condition' as well as representing column
038: * and aggregate functions.
039: * <p>
040: * This class can represent constant expressions (expressions that have no
041: * variable input), as well as variable expressions. Optimizations may be
042: * possible when evaluating constant expressions.
043: * <p>
044: * Some examples of constant expressions;<p><pre>
045: * ( 9 + 3 ) * 90
046: * ( ? * 9 ) / 1
047: * lower("CaPS MUMma")
048: * 40 & 0x0FF != 39
049: * </pre>
050: * Some examples of variable expressions;<p><pre>
051: * upper(Part.description)
052: * Part.id >= 50
053: * VendorMakesPart.part_id == Part.id
054: * Part.value_of <= Part.cost_of / 4
055: * </pre>
056: * <p>
057: * <strong>NOTE:</strong> the expression is stored in postfix orientation. eg.
058: * "8 + 9 * 3" becomes "8,9,3,*,+"
059: * <p>
060: * <strong>NOTE:</strong> This class is <b>NOT</b> thread safe. Do not use an
061: * expression instance between threads.
062: *
063: * @author Tobias Downer
064: */
065:
066: public final class Expression implements java.io.Serializable,
067: Cloneable {
068:
069: /**
070: * Serialization UID.
071: */
072: static final long serialVersionUID = 6981261114471924028L;
073:
074: /**
075: * The list of elements followed by operators in our expression. The
076: * expression elements may be of any type represented by the database
077: * (see 'addElement' method for the accepted objects). The expression
078: * operators may be '+', '-', '*', '*', '/', '=', '>=', '<>', etc (as an
079: * Operator object (see the Operator class for details)).
080: * <p>
081: * This list is stored in postfix order.
082: */
083: private ArrayList elements = new ArrayList();
084:
085: /**
086: * The evaluation stack for when the expression is evaluated.
087: */
088: private transient ArrayList eval_stack;
089:
090: /**
091: * The expression as a plain human readable string. This is in a form that
092: * can be readily parsed to an Expression object.
093: */
094: private StringBuffer text;
095:
096: /**
097: * Constructs a new Expression.
098: */
099: public Expression() {
100: text = new StringBuffer();
101: }
102:
103: /**
104: * Constructs a new Expression with a single object element.
105: */
106: public Expression(Object ob) {
107: this ();
108: addElement(ob);
109: }
110:
111: /**
112: * Constructs a copy of the given Expression.
113: */
114: public Expression(Expression exp) {
115: concat(exp);
116: text = new StringBuffer(new String(exp.text));
117: }
118:
119: /**
120: * Constructs a new Expression from the concatination of expression1 and
121: * expression2 and the operator for them.
122: */
123: public Expression(Expression exp1, Operator op, Expression exp2) {
124: // Remember, this is in postfix notation.
125: elements.addAll(exp1.elements);
126: elements.addAll(exp2.elements);
127: elements.add(op);
128: }
129:
130: /**
131: * Returns the StringBuffer that we can use to append plain text
132: * representation as we are parsing the expression.
133: */
134: public StringBuffer text() {
135: return text;
136: }
137:
138: /**
139: * Copies the text from the given expression.
140: */
141: public void copyTextFrom(Expression e) {
142: this .text = new StringBuffer(new String(e.text()));
143: }
144:
145: /**
146: * Static method that parses the given string which contains an expression
147: * into an Expression object. For example, this will parse strings such
148: * as '(a + 9) * 2 = b' or 'upper(concat('12', '56', id))'.
149: * <p>
150: * Care should be taken to not use this method inside an inner loop because
151: * it creates a lot of objects.
152: */
153: public static Expression parse(String expression) {
154: synchronized (expression_parser) {
155: try {
156: expression_parser.ReInit(new StringReader(expression));
157: expression_parser.reset();
158: Expression exp = expression_parser.parseExpression();
159:
160: exp.text().setLength(0);
161: exp.text().append(expression);
162: return exp;
163: } catch (com.mckoi.database.sql.ParseException e) {
164: throw new RuntimeException(e.getMessage());
165: }
166: }
167: }
168:
169: /**
170: * A static expression parser. To use this we must first synchronize over
171: * the object.
172: */
173: private final static SQL expression_parser = new SQL(
174: new StringReader(""));
175:
176: /**
177: * Generates a simple expression from two objects and an operator.
178: */
179: public static Expression simple(Object ob1, Operator op, Object ob2) {
180: Expression exp = new Expression(ob1);
181: exp.addElement(ob2);
182: exp.addElement(op);
183: return exp;
184: }
185:
186: /**
187: * Adds a new element into the expression. String, BigNumber, Boolean and
188: * Variable are the types of elements allowed.
189: * <p>
190: * Must be added in postfix order.
191: */
192: public void addElement(Object ob) {
193: if (ob == null) {
194: elements.add(TObject.nullVal());
195: } else if (ob instanceof TObject
196: || ob instanceof ParameterSubstitution
197: || ob instanceof CorrelatedVariable
198: || ob instanceof Variable || ob instanceof FunctionDef
199: || ob instanceof Operator
200: || ob instanceof StatementTreeObject) {
201: elements.add(ob);
202: } else {
203: throw new Error(
204: "Unknown element type added to expression: "
205: + ob.getClass());
206: }
207: }
208:
209: /**
210: * Merges an expression with this expression. For example, given the
211: * expression 'ab', if the expression 'abc+-' was added the expression would
212: * become 'ababc+-'.
213: * <p>
214: * This method is useful when copying parts of other expressions when forming
215: * an expression.
216: * <p>
217: * This always returns this expression. This does not change 'text()'.
218: */
219: public Expression concat(Expression expr) {
220: elements.addAll(expr.elements);
221: return this ;
222: }
223:
224: /**
225: * Adds a new operator into the expression. Operators are represented as
226: * an Operator (eg. ">", "+", "<<", "!=" )
227: * <p>
228: * Must be added in postfix order.
229: */
230: public void addOperator(Operator op) {
231: elements.add(op);
232: }
233:
234: /**
235: * Returns the number of elements and operators that are in this postfix
236: * list.
237: */
238: public int size() {
239: return elements.size();
240: }
241:
242: /**
243: * Returns the element at the given position in the postfix list. Note, this
244: * can return Operator's.
245: */
246: public Object elementAt(int n) {
247: return elements.get(n);
248: }
249:
250: /**
251: * Returns the element at the end of the postfix list (the last element).
252: */
253: public Object last() {
254: return elements.get(size() - 1);
255: }
256:
257: /**
258: * Sets the element at the given position in the postfix list. This should
259: * be called after the expression has been setup to alter variable alias
260: * names, etc.
261: */
262: public void setElementAt(int n, Object ob) {
263: elements.set(n, ob);
264: }
265:
266: /**
267: * Pushes an element onto the evaluation stack.
268: */
269: private final void push(Object ob) {
270: eval_stack.add(ob);
271: }
272:
273: /**
274: * Pops an element from the evaluation stack.
275: */
276: private final Object pop() {
277: return eval_stack.remove(eval_stack.size() - 1);
278: }
279:
280: /**
281: * Returns a complete List of Variable objects in this expression not
282: * including correlated variables.
283: */
284: public List allVariables() {
285: ArrayList vars = new ArrayList();
286: for (int i = 0; i < elements.size(); ++i) {
287: Object ob = elements.get(i);
288: if (ob instanceof Variable) {
289: vars.add(ob);
290: } else if (ob instanceof FunctionDef) {
291: Expression[] params = ((FunctionDef) ob)
292: .getParameters();
293: for (int n = 0; n < params.length; ++n) {
294: vars.addAll(params[n].allVariables());
295: }
296: } else if (ob instanceof TObject) {
297: TObject tob = (TObject) ob;
298: if (tob.getTType() instanceof TArrayType) {
299: Expression[] exp_list = (Expression[]) tob
300: .getObject();
301: for (int n = 0; n < exp_list.length; ++n) {
302: vars.addAll(exp_list[n].allVariables());
303: }
304: }
305: }
306: }
307: return vars;
308: }
309:
310: /**
311: * Returns a complete list of all element objects that are in this expression
312: * and in the parameters of the functions of this expression.
313: */
314: public List allElements() {
315: ArrayList elems = new ArrayList();
316: for (int i = 0; i < elements.size(); ++i) {
317: Object ob = elements.get(i);
318: if (ob instanceof Operator) {
319: } else if (ob instanceof FunctionDef) {
320: Expression[] params = ((FunctionDef) ob)
321: .getParameters();
322: for (int n = 0; n < params.length; ++n) {
323: elems.addAll(params[n].allElements());
324: }
325: } else if (ob instanceof TObject) {
326: TObject tob = (TObject) ob;
327: if (tob.getTType() instanceof TArrayType) {
328: Expression[] exp_list = (Expression[]) tob
329: .getObject();
330: for (int n = 0; n < exp_list.length; ++n) {
331: elems.addAll(exp_list[n].allElements());
332: }
333: } else {
334: elems.add(ob);
335: }
336: } else {
337: elems.add(ob);
338: }
339: }
340: return elems;
341: }
342:
343: /**
344: * A general prepare that cascades through the expression and its parents and
345: * substitutes an elements that the preparer wants to substitute.
346: * <p>
347: * NOTE: This will not cascade through to the parameters of Function objects
348: * however it will cascade through FunctionDef parameters. For this
349: * reason you MUST call 'prepareFunctions' after this method.
350: */
351: public void prepare(ExpressionPreparer preparer)
352: throws DatabaseException {
353: for (int n = 0; n < elements.size(); ++n) {
354: Object ob = elements.get(n);
355:
356: // If the preparer will prepare this type of object then set the
357: // entry with the prepared object.
358: if (preparer.canPrepare(ob)) {
359: elements.set(n, preparer.prepare(ob));
360: }
361:
362: Expression[] exp_list = null;
363: if (ob instanceof FunctionDef) {
364: FunctionDef func = (FunctionDef) ob;
365: exp_list = func.getParameters();
366: } else if (ob instanceof TObject) {
367: TObject tob = (TObject) ob;
368: if (tob.getTType() instanceof TArrayType) {
369: exp_list = (Expression[]) tob.getObject();
370: }
371: } else if (ob instanceof StatementTreeObject) {
372: StatementTreeObject stree = (StatementTreeObject) ob;
373: stree.prepareExpressions(preparer);
374: }
375:
376: if (exp_list != null) {
377: for (int p = 0; p < exp_list.length; ++p) {
378: exp_list[p].prepare(preparer);
379: }
380: }
381:
382: }
383: }
384:
385: /**
386: * Returns true if the expression doesn't include any variables or non
387: * constant functions (is constant). Note that a correlated variable is
388: * considered a constant.
389: */
390: public boolean isConstant() {
391: for (int n = 0; n < elements.size(); ++n) {
392: Object ob = elements.get(n);
393: if (ob instanceof TObject) {
394: TObject tob = (TObject) ob;
395: TType ttype = tob.getTType();
396: // If this is a query plan, return false
397: if (ttype instanceof TQueryPlanType) {
398: return false;
399: }
400: // If this is an array, check the array for constants
401: else if (ttype instanceof TArrayType) {
402: Expression[] exp_list = (Expression[]) tob
403: .getObject();
404: for (int p = 0; p < exp_list.length; ++p) {
405: if (!exp_list[p].isConstant()) {
406: return false;
407: }
408: }
409: }
410: } else if (ob instanceof Variable) {
411: return false;
412: } else if (ob instanceof FunctionDef) {
413: Expression[] params = ((FunctionDef) ob)
414: .getParameters();
415: for (int p = 0; p < params.length; ++p) {
416: if (!params[p].isConstant()) {
417: return false;
418: }
419: }
420: }
421: }
422: return true;
423: }
424:
425: /**
426: * Returns true if the expression has a subquery (eg 'in ( select ... )')
427: * somewhere in it (this cascades through function parameters also).
428: */
429: public boolean hasSubQuery() {
430: List list = allElements();
431: int len = list.size();
432: for (int n = 0; n < len; ++n) {
433: Object ob = list.get(n);
434: if (ob instanceof TObject) {
435: TObject tob = (TObject) ob;
436: if (tob.getTType() instanceof TQueryPlanType) {
437: return true;
438: }
439: }
440: }
441: return false;
442: }
443:
444: /**
445: * Returns true if the expression contains a NOT operator somewhere in it.
446: */
447: public boolean containsNotOperator() {
448: for (int n = 0; n < elements.size(); ++n) {
449: Object ob = elements.get(n);
450: if (ob instanceof Operator) {
451: if (((Operator) ob).isNot()) {
452: return true;
453: }
454: }
455: }
456: return false;
457: }
458:
459: /**
460: * Discovers all the correlated variables in this expression. If this
461: * expression contains a sub-query plan, we ask the plan to find the list of
462: * correlated variables. The discovery process increments the 'level'
463: * variable for each sub-plan.
464: */
465: public ArrayList discoverCorrelatedVariables(int level,
466: ArrayList list) {
467: List elems = allElements();
468: int sz = elems.size();
469: // For each element
470: for (int i = 0; i < sz; ++i) {
471: Object ob = elems.get(i);
472: if (ob instanceof CorrelatedVariable) {
473: CorrelatedVariable v = (CorrelatedVariable) ob;
474: if (v.getQueryLevelOffset() == level) {
475: list.add(v);
476: }
477: } else if (ob instanceof TObject) {
478: TObject tob = (TObject) ob;
479: if (tob.getTType() instanceof TQueryPlanType) {
480: QueryPlanNode node = (QueryPlanNode) tob
481: .getObject();
482: list = node.discoverCorrelatedVariables(level + 1,
483: list);
484: }
485: }
486: }
487: return list;
488: }
489:
490: /**
491: * Discovers all the tables in the sub-queries of this expression. This is
492: * used for determining all the tables that a query plan touches.
493: */
494: public ArrayList discoverTableNames(ArrayList list) {
495: List elems = allElements();
496: int sz = elems.size();
497: // For each element
498: for (int i = 0; i < sz; ++i) {
499: Object ob = elems.get(i);
500: if (ob instanceof TObject) {
501: TObject tob = (TObject) ob;
502: if (tob.getTType() instanceof TQueryPlanType) {
503: QueryPlanNode node = (QueryPlanNode) tob
504: .getObject();
505: list = node.discoverTableNames(list);
506: }
507: }
508: }
509: return list;
510: }
511:
512: /**
513: * Returns the QueryPlanNode object in this expression if it evaluates to a
514: * single QueryPlanNode, otherwise returns null.
515: */
516: public QueryPlanNode getQueryPlanNode() {
517: Object ob = elementAt(0);
518: if (size() == 1 && ob instanceof TObject) {
519: TObject tob = (TObject) ob;
520: if (tob.getTType() instanceof TQueryPlanType) {
521: return (QueryPlanNode) tob.getObject();
522: }
523: }
524: return null;
525: }
526:
527: /**
528: * Returns the Variable if this expression evaluates to a single variable,
529: * otherwise returns null. A correlated variable will not be returned.
530: */
531: public Variable getVariable() {
532: Object ob = elementAt(0);
533: if (size() == 1 && ob instanceof Variable) {
534: return (Variable) ob;
535: }
536: return null;
537: }
538:
539: /**
540: * Returns an array of two Expression objects that represent the left hand
541: * and right and side of the last operator in the post fix notation.
542: * For example, (a + b) - (c + d) will return { (a + b), (c + d) }. Or
543: * more a more useful example is;<p><pre>
544: * id + 3 > part_id - 2 will return ( id + 3, part_id - 2 }
545: * </pre>
546: */
547: public Expression[] split() {
548: if (size() <= 1) {
549: throw new Error(
550: "Can only split expressions with more than 1 element.");
551: }
552:
553: int midpoint = -1;
554: int stack_size = 0;
555: for (int n = 0; n < size() - 1; ++n) {
556: Object ob = elementAt(n);
557: if (ob instanceof Operator) {
558: --stack_size;
559: } else {
560: ++stack_size;
561: }
562:
563: if (stack_size == 1) {
564: midpoint = n;
565: }
566: }
567:
568: if (midpoint == -1) {
569: throw new Error("postfix format error: Midpoint not found.");
570: }
571:
572: Expression lhs = new Expression();
573: for (int n = 0; n <= midpoint; ++n) {
574: lhs.addElement(elementAt(n));
575: }
576:
577: Expression rhs = new Expression();
578: for (int n = midpoint + 1; n < size() - 1; ++n) {
579: rhs.addElement(elementAt(n));
580: }
581:
582: return new Expression[] { lhs, rhs };
583: }
584:
585: /**
586: * Returns the end Expression of this expression. For example, an expression
587: * of 'ab' has an end expression of 'b'. The expression 'abc+=' has an end
588: * expression of 'abc+='.
589: * <p>
590: * This is a useful method to call in the middle of an Expression object
591: * being formed. It allows for the last complete expression to be
592: * returned.
593: * <p>
594: * If this is called when an expression is completely formed it will always
595: * return the complete expression.
596: */
597: public Expression getEndExpression() {
598:
599: int stack_size = 1;
600: int end = size() - 1;
601: for (int n = end; n > 0; --n) {
602: Object ob = elementAt(n);
603: if (ob instanceof Operator) {
604: ++stack_size;
605: } else {
606: --stack_size;
607: }
608:
609: if (stack_size == 0) {
610: // Now, n .. end represents the new expression.
611: Expression new_exp = new Expression();
612: for (int i = n; i <= end; ++i) {
613: new_exp.addElement(elementAt(i));
614: }
615: return new_exp;
616: }
617: }
618:
619: return new Expression(this );
620: }
621:
622: /**
623: * Breaks this expression into a list of sub-expressions that are split
624: * by the given operator. For example, given the expression;
625: * <p><pre>
626: * (a = b AND b = c AND (a = 2 OR c = 1))
627: * </pre><p>
628: * Calling this method with logical_op = "and" will return a list of the
629: * three expressions.
630: * <p>
631: * This is a common function used to split up an expressions into logical
632: * components for processing.
633: */
634: public ArrayList breakByOperator(ArrayList list,
635: final String logical_op) {
636: // The last operator must be 'and'
637: Object ob = last();
638: if (ob instanceof Operator) {
639: Operator op = (Operator) ob;
640: if (op.is(logical_op)) {
641: // Last operator is 'and' so split and recurse.
642: Expression[] exps = split();
643: list = exps[0].breakByOperator(list, logical_op);
644: list = exps[1].breakByOperator(list, logical_op);
645: return list;
646: }
647: }
648: // If no last expression that matches then add this expression to the
649: // list.
650: list.add(this );
651: return list;
652: }
653:
654: /**
655: * Evaluates this expression and returns an Object that represents the
656: * result of the evaluation. The passed VariableResolver object is used
657: * to resolve the variable name to a value. The GroupResolver object is
658: * used if there are any aggregate functions in the evaluation - this can be
659: * null if evaluating an expression without grouping aggregates. The query
660: * context object contains contextual information about the environment of
661: * the query.
662: * <p>
663: * NOTE: This method is gonna be called a lot, so we need it to be optimal.
664: * <p>
665: * NOTE: This method is <b>not</b> thread safe! The reason it's not safe
666: * is because of the evaluation stack.
667: */
668: public TObject evaluate(GroupResolver group,
669: VariableResolver resolver, QueryContext context) {
670: // Optimization - trivial case of 'a' or 'ab*' postfix are tested for
671: // here.
672: int element_count = elements.size();
673: if (element_count == 1) {
674: return (TObject) elementToObject(0, group, resolver,
675: context);
676: } else if (element_count == 3) {
677: TObject o1 = (TObject) elementToObject(0, group, resolver,
678: context);
679: TObject o2 = (TObject) elementToObject(1, group, resolver,
680: context);
681: Operator op = (Operator) elements.get(2);
682: return op.eval(o1, o2, group, resolver, context);
683: }
684:
685: if (eval_stack == null) {
686: eval_stack = new ArrayList();
687: }
688:
689: for (int n = 0; n < element_count; ++n) {
690: Object val = elementToObject(n, group, resolver, context);
691: if (val instanceof Operator) {
692: // Pop the last two values off the stack, evaluate them and push
693: // the new value back on.
694: Operator op = (Operator) val;
695:
696: TObject v2 = (TObject) pop();
697: TObject v1 = (TObject) pop();
698:
699: push(op.eval(v1, v2, group, resolver, context));
700: } else {
701: push(val);
702: }
703: }
704: // We should end with a single value on the stack.
705: return (TObject) pop();
706: }
707:
708: /**
709: * Evaluation without a grouping table.
710: */
711: public TObject evaluate(VariableResolver resolver,
712: QueryContext context) {
713: return evaluate(null, resolver, context);
714: }
715:
716: /**
717: * Returns the element at the given position in the expression list. If
718: * the element is a variable then it is resolved on the VariableResolver.
719: * If the element is a function then it is evaluated and the result is
720: * returned.
721: */
722: private Object elementToObject(int n, GroupResolver group,
723: VariableResolver resolver, QueryContext context) {
724: Object ob = elements.get(n);
725: if (ob instanceof TObject || ob instanceof Operator) {
726: return ob;
727: } else if (ob instanceof Variable) {
728: return resolver.resolve((Variable) ob);
729: } else if (ob instanceof CorrelatedVariable) {
730: return ((CorrelatedVariable) ob).getEvalResult();
731: } else if (ob instanceof FunctionDef) {
732: Function fun = ((FunctionDef) ob).getFunction(context);
733: return fun.evaluate(group, resolver, context);
734: } else {
735: if (ob == null) {
736: throw new NullPointerException(
737: "Null element in expression");
738: }
739: throw new Error("Unknown element type: " + ob.getClass());
740: }
741: }
742:
743: /**
744: * Cascades through the expression and if any aggregate functions are found
745: * returns true, otherwise returns false.
746: */
747: public boolean hasAggregateFunction(QueryContext context) {
748: for (int n = 0; n < elements.size(); ++n) {
749: Object ob = elements.get(n);
750: if (ob instanceof FunctionDef) {
751: if (((FunctionDef) ob).isAggregate(context)) {
752: return true;
753: }
754: } else if (ob instanceof TObject) {
755: TObject tob = (TObject) ob;
756: if (tob.getTType() instanceof TArrayType) {
757: Expression[] list = (Expression[]) tob.getObject();
758: for (int i = 0; i < list.length; ++i) {
759: if (list[i].hasAggregateFunction(context)) {
760: return true;
761: }
762: }
763: }
764: }
765: }
766: return false;
767: }
768:
769: /**
770: * Determines the type of object this expression evaluates to. We determine
771: * this by looking at the last element of the expression. If the last
772: * element is a TType object, it returns the type. If the last element is a
773: * Function, Operator or Variable then it returns the type that these
774: * objects have set as their result type.
775: */
776: public TType returnTType(VariableResolver resolver,
777: QueryContext context) {
778: Object ob = elements.get(elements.size() - 1);
779: if (ob instanceof FunctionDef) {
780: Function fun = ((FunctionDef) ob).getFunction(context);
781: return fun.returnTType(resolver, context);
782: } else if (ob instanceof TObject) {
783: return ((TObject) ob).getTType();
784: } else if (ob instanceof Operator) {
785: Operator op = (Operator) ob;
786: return op.returnTType();
787: } else if (ob instanceof Variable) {
788: Variable variable = (Variable) ob;
789: return resolver.returnTType(variable);
790: } else if (ob instanceof CorrelatedVariable) {
791: CorrelatedVariable variable = (CorrelatedVariable) ob;
792: return variable.returnTType();
793: } else {
794: throw new Error("Unable to determine type for expression.");
795: }
796: }
797:
798: /**
799: * Performs a deep clone of this object, calling 'clone' on any elements
800: * that are mutable or shallow copying immutable members.
801: */
802: public Object clone() throws CloneNotSupportedException {
803: // Shallow clone
804: Expression v = (Expression) super .clone();
805: v.eval_stack = null;
806: // v.text = new StringBuffer(new String(text));
807: int size = elements.size();
808: ArrayList cloned_elements = new ArrayList(size);
809: v.elements = cloned_elements;
810:
811: // Clone items in the elements list
812: for (int i = 0; i < size; ++i) {
813: Object element = elements.get(i);
814:
815: if (element instanceof TObject) {
816: // TObject is immutable except for TArrayType and TQueryPlanType
817: TObject tob = (TObject) element;
818: TType ttype = tob.getTType();
819: // For a query plan
820: if (ttype instanceof TQueryPlanType) {
821: QueryPlanNode node = (QueryPlanNode) tob
822: .getObject();
823: node = (QueryPlanNode) node.clone();
824: element = new TObject(ttype, node);
825: }
826: // For an array
827: else if (ttype instanceof TArrayType) {
828: Expression[] arr = (Expression[]) tob.getObject();
829: arr = (Expression[]) arr.clone();
830: for (int n = 0; n < arr.length; ++n) {
831: arr[n] = (Expression) arr[n].clone();
832: }
833: element = new TObject(ttype, arr);
834: }
835: } else if (element instanceof Operator
836: || element instanceof ParameterSubstitution) {
837: // immutable so we do not need to clone these
838: } else if (element instanceof CorrelatedVariable) {
839: element = ((CorrelatedVariable) element).clone();
840: } else if (element instanceof Variable) {
841: element = ((Variable) element).clone();
842: } else if (element instanceof FunctionDef) {
843: element = ((FunctionDef) element).clone();
844: } else if (element instanceof StatementTreeObject) {
845: element = ((StatementTreeObject) element).clone();
846: } else {
847: throw new CloneNotSupportedException(element.getClass()
848: .toString());
849: }
850: cloned_elements.add(element);
851: }
852:
853: return v;
854: }
855:
856: /**
857: * Returns a string representation of this object for diagnostic
858: * purposes.
859: */
860: public String toString() {
861: StringBuffer buf = new StringBuffer();
862: buf.append("[ Expression ");
863: if (text() != null) {
864: buf.append("[");
865: buf.append(text().toString());
866: buf.append("]");
867: }
868: buf.append(": ");
869: for (int n = 0; n < elements.size(); ++n) {
870: buf.append(elements.get(n));
871: if (n < elements.size() - 1) {
872: buf.append(",");
873: }
874: }
875: buf.append(" ]");
876: return new String(buf);
877: }
878:
879: // ---------- Serialization methods ----------
880:
881: /**
882: * Writes the state of this object to the object stream. This method is
883: * implemented because GCJ doesn't like it if you implement readObject
884: * without writeObject.
885: */
886: private void writeObject(ObjectOutputStream out) throws IOException {
887: out.defaultWriteObject();
888: }
889:
890: /**
891: * Reads the state of this object from the object stream.
892: */
893: private void readObject(ObjectInputStream in) throws IOException,
894: ClassNotFoundException {
895: in.defaultReadObject();
896:
897: // This converts old types to the new TObject type system introduced
898: // in version 0.94.
899: int sz = elements.size();
900: for (int i = 0; i < sz; ++i) {
901: Object ob = elements.get(i);
902: TObject conv_object = null;
903: if (ob == null
904: || ob instanceof com.mckoi.database.global.NullObject) {
905: conv_object = TObject.nullVal();
906: } else if (ob instanceof String) {
907: conv_object = TObject.stringVal((String) ob);
908: } else if (ob instanceof java.math.BigDecimal) {
909: conv_object = TObject.bigNumberVal(BigNumber
910: .fromBigDecimal((java.math.BigDecimal) ob));
911: } else if (ob instanceof java.util.Date) {
912: conv_object = TObject.dateVal((java.util.Date) ob);
913: } else if (ob instanceof Boolean) {
914: conv_object = TObject.booleanVal(((Boolean) ob)
915: .booleanValue());
916: }
917: if (conv_object != null) {
918: elements.set(i, conv_object);
919: }
920: }
921: }
922:
923: }
|