001: /**
002: * com.mckoi.database.Operator 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.HashMap;
026: import java.util.ArrayList;
027:
028: /**
029: * An operator for an expression.
030: *
031: * @author Tobias Downer
032: */
033:
034: public abstract class Operator implements java.io.Serializable {
035:
036: static final long serialVersionUID = 516615288995154064L;
037:
038: // ---------- Statics ----------
039:
040: /**
041: * The ANY and ALL enumerator.
042: */
043: public static final int NONE = 0, ANY = 1, ALL = 2;
044:
045: // ---------- Member ----------
046:
047: /**
048: * A string that represents this operator.
049: */
050: private String op;
051:
052: /**
053: * If this is a set operator such as ANY or ALL then this is set with the
054: * flag type.
055: */
056: private int set_type;
057:
058: /**
059: * The precedence of this operator.
060: */
061: private int precedence;
062:
063: /**
064: * Constructs the Operator.
065: */
066: protected Operator(String op) {
067: this (op, 0, NONE);
068: }
069:
070: protected Operator(String op, int precedence) {
071: this (op, precedence, NONE);
072: }
073:
074: protected Operator(String op, int precedence, int set_type) {
075: if (set_type != NONE && set_type != ANY && set_type != ALL) {
076: throw new Error("Invalid set_type.");
077: }
078: this .op = op;
079: this .precedence = precedence;
080: this .set_type = set_type;
081: }
082:
083: /**
084: * Returns true if this operator is equal to the operator string.
085: */
086: public boolean is(String given_op) {
087: return given_op.equals(op);
088: }
089:
090: public abstract TObject eval(TObject ob1, TObject ob2,
091: GroupResolver group, VariableResolver resolver,
092: QueryContext context);
093:
094: public int precedence() {
095: return precedence;
096: }
097:
098: public boolean isCondition() {
099: return (equals(eq_op) || equals(neq_op) || equals(g_op)
100: || equals(l_op) || equals(geq_op) || equals(leq_op)
101: || equals(is_op) || equals(isn_op));
102: }
103:
104: public boolean isMathematical() {
105: return (equals(add_op) || equals(sub_op) || equals(mul_op)
106: || equals(div_op) || equals(concat_op));
107: }
108:
109: public boolean isPattern() {
110: return (equals(like_op) || equals(nlike_op) || equals(regex_op));
111: }
112:
113: public boolean isLogical() {
114: return (equals(and_op) || equals(or_op));
115: }
116:
117: public boolean isNot() {
118: return equals(not_op);
119: }
120:
121: public boolean isSubQuery() {
122: return (set_type != NONE || equals(in_op) || equals(nin_op));
123: }
124:
125: /**
126: * Returns an Operator that is the reverse of this Operator. This is used
127: * for reversing a conditional expression. eg. 9 > id becomes id < 9.
128: */
129: public Operator reverse() {
130: if (equals(eq_op) || equals(neq_op) || equals(is_op)
131: || equals(isn_op)) {
132: return this ;
133: } else if (equals(g_op)) {
134: return l_op;
135: } else if (equals(l_op)) {
136: return g_op;
137: } else if (equals(geq_op)) {
138: return leq_op;
139: } else if (equals(leq_op)) {
140: return geq_op;
141: }
142: throw new Error("Can't reverse a non conditional operator.");
143: }
144:
145: /**
146: * Returns true if this operator is not inversible.
147: */
148: public boolean isNotInversible() {
149: // The REGEX op, and mathematical operators are not inversible.
150: return equals(regex_op) || isMathematical();
151: }
152:
153: /**
154: * Returns the inverse operator of this operator. For example, = becomes <>,
155: * > becomes <=, AND becomes OR.
156: */
157: public Operator inverse() {
158: if (isSubQuery()) {
159: int inv_type;
160: if (isSubQueryForm(ANY)) {
161: inv_type = ALL;
162: } else if (isSubQueryForm(ALL)) {
163: inv_type = ANY;
164: } else {
165: throw new RuntimeException(
166: "Can not handle sub-query form.");
167: }
168:
169: Operator inv_op = Operator.get(op).inverse();
170:
171: return inv_op.getSubQueryForm(inv_type);
172: } else if (equals(eq_op)) {
173: return neq_op;
174: } else if (equals(neq_op)) {
175: return eq_op;
176: } else if (equals(g_op)) {
177: return leq_op;
178: } else if (equals(l_op)) {
179: return geq_op;
180: } else if (equals(geq_op)) {
181: return l_op;
182: } else if (equals(leq_op)) {
183: return g_op;
184: } else if (equals(and_op)) {
185: return or_op;
186: } else if (equals(or_op)) {
187: return and_op;
188: } else if (equals(like_op)) {
189: return nlike_op;
190: } else if (equals(nlike_op)) {
191: return like_op;
192: } else if (equals(is_op)) {
193: return isn_op;
194: } else if (equals(isn_op)) {
195: return is_op;
196: } else {
197: throw new Error("Can't inverse operator '" + op + "'");
198: }
199:
200: }
201:
202: /**
203: * Given a parameter of either NONE, ANY, ALL or SINGLE, this returns true
204: * if this operator is of the given type.
205: */
206: public boolean isSubQueryForm(int type) {
207: return type == set_type;
208: }
209:
210: /**
211: * Returns the sub query representation of this operator.
212: */
213: int getSubQueryFormRepresentation() {
214: return set_type;
215: }
216:
217: /**
218: * Returns the ANY or ALL form of this operator.
219: */
220: public Operator getSubQueryForm(int type) {
221: Operator result_op = null;
222: if (type == ANY) {
223: result_op = (Operator) any_map.get(op);
224: } else if (type == ALL) {
225: result_op = (Operator) all_map.get(op);
226: } else if (type == NONE) {
227: result_op = get(op);
228: }
229:
230: if (result_op == null) {
231: throw new Error("Couldn't change the form of operator '"
232: + op + "'.");
233: }
234: return result_op;
235: }
236:
237: /**
238: * Same as above only it handles the type as a string.
239: */
240: public Operator getSubQueryForm(String type_str) {
241: String s = type_str.toUpperCase();
242: if (s.equals("SINGLE") || s.equals("ANY") || s.equals("SOME")) {
243: return getSubQueryForm(ANY);
244: } else if (s.equals("ALL")) {
245: return getSubQueryForm(ALL);
246: }
247: throw new Error("Do not understand subquery type '" + type_str
248: + "'");
249: }
250:
251: /**
252: * The type of object this Operator evaluates to.
253: */
254: public TType returnTType() {
255: if (equals(concat_op)) {
256: return TType.STRING_TYPE;
257: } else if (isMathematical()) {
258: return TType.NUMERIC_TYPE;
259: } else {
260: return TType.BOOLEAN_TYPE;
261: }
262: }
263:
264: /**
265: * Returns the string value of this operator.
266: */
267: String stringRepresentation() {
268: return op;
269: }
270:
271: public String toString() {
272: StringBuffer buf = new StringBuffer();
273: buf.append(op);
274: if (set_type == ANY) {
275: buf.append(" ANY");
276: } else if (set_type == ALL) {
277: buf.append(" ALL");
278: }
279: return new String(buf);
280: }
281:
282: public boolean equals(Object ob) {
283: if (this == ob)
284: return true;
285: Operator oob = (Operator) ob;
286: return op.equals(oob.op) && set_type == oob.set_type;
287: }
288:
289: /**
290: * Returns an Operator with the given string.
291: */
292: public static Operator get(String op) {
293: if (op.equals("+")) {
294: return add_op;
295: } else if (op.equals("-")) {
296: return sub_op;
297: } else if (op.equals("*")) {
298: return mul_op;
299: } else if (op.equals("/")) {
300: return div_op;
301: } else if (op.equals("||")) {
302: return concat_op;
303: }
304:
305: else if (op.equals("=") | op.equals("==")) {
306: return eq_op;
307: } else if (op.equals("<>") | op.equals("!=")) {
308: return neq_op;
309: } else if (op.equals(">")) {
310: return g_op;
311: } else if (op.equals("<")) {
312: return l_op;
313: } else if (op.equals(">=")) {
314: return geq_op;
315: } else if (op.equals("<=")) {
316: return leq_op;
317: }
318:
319: else if (op.equals("(")) {
320: return par1_op;
321: } else if (op.equals(")")) {
322: return par2_op;
323: }
324:
325: // Operators that are words, convert to lower case...
326: op = op.toLowerCase();
327: if (op.equals("is")) {
328: return is_op;
329: } else if (op.equals("is not")) {
330: return isn_op;
331: } else if (op.equals("like")) {
332: return like_op;
333: } else if (op.equals("not like")) {
334: return nlike_op;
335: } else if (op.equals("regex")) {
336: return regex_op;
337: }
338:
339: else if (op.equals("in")) {
340: return in_op;
341: } else if (op.equals("not in")) {
342: return nin_op;
343: }
344:
345: else if (op.equals("not")) {
346: return not_op;
347: } else if (op.equals("and")) {
348: return and_op;
349: } else if (op.equals("or")) {
350: return or_op;
351: }
352:
353: throw new Error("Unrecognised operator type: " + op);
354: }
355:
356: // ---------- Convenience methods ----------
357:
358: /**
359: * Returns true if the given TObject is a boolean and is true. If the
360: * TObject is not a boolean value or is null or is false, then it returns
361: * false.
362: */
363: private static boolean isTrue(TObject bool) {
364: return (!bool.isNull()
365: && bool.getTType() instanceof TBooleanType && bool
366: .getObject().equals(Boolean.TRUE));
367: }
368:
369: // ---------- The different types of operator's we can have ----------
370:
371: private final static AddOperator add_op = new AddOperator();
372: private final static SubtractOperator sub_op = new SubtractOperator();
373: private final static MultiplyOperator mul_op = new MultiplyOperator();
374: private final static DivideOperator div_op = new DivideOperator();
375: private final static ConcatOperator concat_op = new ConcatOperator();
376:
377: private final static EqualOperator eq_op = new EqualOperator();
378: private final static NotEqualOperator neq_op = new NotEqualOperator();
379: private final static GreaterOperator g_op = new GreaterOperator();
380: private final static LesserOperator l_op = new LesserOperator();
381: private final static GreaterEqualOperator geq_op = new GreaterEqualOperator();
382: private final static LesserEqualOperator leq_op = new LesserEqualOperator();
383:
384: private final static IsOperator is_op = new IsOperator();
385: private final static IsNotOperator isn_op = new IsNotOperator();
386:
387: private final static PatternMatchTrueOperator like_op = new PatternMatchTrueOperator();
388: private final static PatternMatchFalseOperator nlike_op = new PatternMatchFalseOperator();
389: private final static RegexOperator regex_op = new RegexOperator();
390:
391: private final static Operator in_op;
392: private final static Operator nin_op;
393:
394: private final static Operator not_op = new SimpleOperator("not", 3);
395:
396: private final static AndOperator and_op = new AndOperator();
397: private final static OrOperator or_op = new OrOperator();
398:
399: private final static ParenOperator par1_op = new ParenOperator("(");
400: private final static ParenOperator par2_op = new ParenOperator(")");
401:
402: // Maps from operator to 'any' operator
403: private final static HashMap any_map = new HashMap();
404: // Maps from operator to 'all' operator.
405: private final static HashMap all_map = new HashMap();
406:
407: static {
408: // Populate the static ANY and ALL mapping
409: any_map.put("=", new AnyOperator("="));
410: any_map.put("<>", new AnyOperator("<>"));
411: any_map.put(">", new AnyOperator(">"));
412: any_map.put(">=", new AnyOperator(">="));
413: any_map.put("<", new AnyOperator("<"));
414: any_map.put("<=", new AnyOperator("<="));
415:
416: all_map.put("=", new AllOperator("="));
417: all_map.put("<>", new AllOperator("<>"));
418: all_map.put(">", new AllOperator(">"));
419: all_map.put(">=", new AllOperator(">="));
420: all_map.put("<", new AllOperator("<"));
421: all_map.put("<=", new AllOperator("<="));
422:
423: // The IN and NOT IN operator are '= ANY' and '<> ALL' respectively.
424: in_op = (Operator) any_map.get("=");
425: nin_op = (Operator) all_map.get("<>");
426: }
427:
428: static class AddOperator extends Operator {
429: static final long serialVersionUID = 6995379384325694391L;
430:
431: public AddOperator() {
432: super ("+", 10);
433: }
434:
435: public TObject eval(TObject ob1, TObject ob2,
436: GroupResolver group, VariableResolver resolver,
437: QueryContext context) {
438: return ob1.operatorAdd(ob2);
439: }
440: };
441:
442: static class SubtractOperator extends Operator {
443: static final long serialVersionUID = 3035882496296296786L;
444:
445: public SubtractOperator() {
446: super ("-", 15);
447: }
448:
449: public TObject eval(TObject ob1, TObject ob2,
450: GroupResolver group, VariableResolver resolver,
451: QueryContext context) {
452: return ob1.operatorSubtract(ob2);
453: }
454: };
455:
456: static class MultiplyOperator extends Operator {
457: static final long serialVersionUID = 8191233936463163847L;
458:
459: public MultiplyOperator() {
460: super ("*", 20);
461: }
462:
463: public TObject eval(TObject ob1, TObject ob2,
464: GroupResolver group, VariableResolver resolver,
465: QueryContext context) {
466: return ob1.operatorMultiply(ob2);
467: }
468: };
469:
470: static class DivideOperator extends Operator {
471: static final long serialVersionUID = -2695205152105036247L;
472:
473: public DivideOperator() {
474: super ("/", 20);
475: }
476:
477: public TObject eval(TObject ob1, TObject ob2,
478: GroupResolver group, VariableResolver resolver,
479: QueryContext context) {
480: return ob1.operatorDivide(ob2);
481: }
482: };
483:
484: static class ConcatOperator extends Operator {
485: public ConcatOperator() {
486: super ("||", 10);
487: }
488:
489: public TObject eval(TObject ob1, TObject ob2,
490: GroupResolver group, VariableResolver resolver,
491: QueryContext context) {
492: return ob1.operatorConcat(ob2);
493: }
494: };
495:
496: static class EqualOperator extends Operator {
497: static final long serialVersionUID = -5022271093834866261L;
498:
499: public EqualOperator() {
500: super ("=", 4);
501: }
502:
503: public TObject eval(TObject ob1, TObject ob2,
504: GroupResolver group, VariableResolver resolver,
505: QueryContext context) {
506: return ob1.operatorEquals(ob2);
507: }
508: }
509:
510: static class NotEqualOperator extends Operator {
511: static final long serialVersionUID = 5868174826733282297L;
512:
513: public NotEqualOperator() {
514: super ("<>", 4);
515: }
516:
517: public TObject eval(TObject ob1, TObject ob2,
518: GroupResolver group, VariableResolver resolver,
519: QueryContext context) {
520: return ob1.operatorNotEquals(ob2);
521: }
522: }
523:
524: static class GreaterOperator extends Operator {
525: static final long serialVersionUID = -6870425685250387549L;
526:
527: public GreaterOperator() {
528: super (">", 4);
529: }
530:
531: public TObject eval(TObject ob1, TObject ob2,
532: GroupResolver group, VariableResolver resolver,
533: QueryContext context) {
534: return ob1.operatorGreater(ob2);
535: }
536: }
537:
538: static class LesserOperator extends Operator {
539: static final long serialVersionUID = 2962736161551360032L;
540:
541: public LesserOperator() {
542: super ("<", 4);
543: }
544:
545: public TObject eval(TObject ob1, TObject ob2,
546: GroupResolver group, VariableResolver resolver,
547: QueryContext context) {
548: return ob1.operatorLess(ob2);
549: }
550: }
551:
552: static class GreaterEqualOperator extends Operator {
553: static final long serialVersionUID = 6040843932499067476L;
554:
555: public GreaterEqualOperator() {
556: super (">=", 4);
557: }
558:
559: public TObject eval(TObject ob1, TObject ob2,
560: GroupResolver group, VariableResolver resolver,
561: QueryContext context) {
562: return ob1.operatorGreaterEquals(ob2);
563: }
564: }
565:
566: static class LesserEqualOperator extends Operator {
567: static final long serialVersionUID = 4298966494510169621L;
568:
569: public LesserEqualOperator() {
570: super ("<=", 4);
571: }
572:
573: public TObject eval(TObject ob1, TObject ob2,
574: GroupResolver group, VariableResolver resolver,
575: QueryContext context) {
576: return ob1.operatorLessEquals(ob2);
577: }
578: }
579:
580: static class IsOperator extends Operator {
581: static final long serialVersionUID = -5537856102106541908L;
582:
583: public IsOperator() {
584: super ("is", 4);
585: }
586:
587: public TObject eval(TObject ob1, TObject ob2,
588: GroupResolver group, VariableResolver resolver,
589: QueryContext context) {
590: return ob1.operatorIs(ob2);
591: }
592: }
593:
594: static class IsNotOperator extends Operator {
595: static final long serialVersionUID = 1224184162192790982L;
596:
597: public IsNotOperator() {
598: super ("is not", 4);
599: }
600:
601: public TObject eval(TObject ob1, TObject ob2,
602: GroupResolver group, VariableResolver resolver,
603: QueryContext context) {
604: return ob1.operatorIs(ob2).operatorNot();
605: }
606: }
607:
608: static class AnyOperator extends Operator {
609: static final long serialVersionUID = 6421321961221271735L;
610:
611: public AnyOperator(String op) {
612: super (op, 8, ANY);
613: }
614:
615: public TObject eval(TObject ob1, TObject ob2,
616: GroupResolver group, VariableResolver resolver,
617: QueryContext context) {
618: if (ob2.getTType() instanceof TQueryPlanType) {
619: // The sub-query plan
620: QueryPlanNode plan = (QueryPlanNode) ob2.getObject();
621: // Discover the correlated variables for this plan.
622: ArrayList list = plan.discoverCorrelatedVariables(1,
623: new ArrayList());
624:
625: if (list.size() > 0) {
626: // Set the correlated variables from the VariableResolver
627: for (int i = 0; i < list.size(); ++i) {
628: ((CorrelatedVariable) list.get(i))
629: .setFromResolver(resolver);
630: }
631: // Clear the cache in the context
632: context.clearCache();
633: }
634:
635: // Evaluate the plan,
636: Table t = plan.evaluate(context);
637:
638: // The ANY operation
639: Operator rev_plain_op = getSubQueryForm(NONE).reverse();
640: if (t.columnMatchesValue(0, rev_plain_op, ob1)) {
641: return TObject.BOOLEAN_TRUE;
642: }
643: return TObject.BOOLEAN_FALSE;
644:
645: } else if (ob2.getTType() instanceof TArrayType) {
646: Operator plain_op = getSubQueryForm(NONE);
647: Expression[] exp_list = (Expression[]) ob2.getObject();
648: // Assume there are no matches
649: TObject ret_val = TObject.BOOLEAN_FALSE;
650: for (int i = 0; i < exp_list.length; ++i) {
651: TObject exp_item = exp_list[i].evaluate(group,
652: resolver, context);
653: // If null value, return null if there isn't otherwise a match found.
654: if (exp_item.isNull()) {
655: ret_val = TObject.BOOLEAN_NULL;
656: }
657: // If there is a match, the ANY set test is true
658: else if (isTrue(plain_op.eval(ob1, exp_item, null,
659: null, null))) {
660: return TObject.BOOLEAN_TRUE;
661: }
662: }
663: // No matches, so return either false or NULL. If there are no matches
664: // and no nulls, return false. If there are no matches and there are
665: // nulls present, return null.
666: return ret_val;
667: } else {
668: throw new Error("Unknown RHS of ANY.");
669: }
670: }
671: }
672:
673: static class AllOperator extends Operator {
674: static final long serialVersionUID = -4605268759294925687L;
675:
676: public AllOperator(String op) {
677: super (op, 8, ALL);
678: }
679:
680: public TObject eval(TObject ob1, TObject ob2,
681: GroupResolver group, VariableResolver resolver,
682: QueryContext context) {
683: if (ob2.getTType() instanceof TQueryPlanType) {
684:
685: // The sub-query plan
686: QueryPlanNode plan = (QueryPlanNode) ob2.getObject();
687: // Discover the correlated variables for this plan.
688: ArrayList list = plan.discoverCorrelatedVariables(1,
689: new ArrayList());
690:
691: if (list.size() > 0) {
692: // Set the correlated variables from the VariableResolver
693: for (int i = 0; i < list.size(); ++i) {
694: ((CorrelatedVariable) list.get(i))
695: .setFromResolver(resolver);
696: }
697: // Clear the cache in the context
698: context.clearCache();
699: }
700:
701: // Evaluate the plan,
702: Table t = plan.evaluate(context);
703:
704: Operator rev_plain_op = getSubQueryForm(NONE).reverse();
705: if (t.allColumnMatchesValue(0, rev_plain_op, ob1)) {
706: return TObject.BOOLEAN_TRUE;
707: }
708: return TObject.BOOLEAN_FALSE;
709:
710: } else if (ob2.getTType() instanceof TArrayType) {
711: Operator plain_op = getSubQueryForm(NONE);
712: Expression[] exp_list = (Expression[]) ob2.getObject();
713: // Assume true unless otherwise found to be false or NULL.
714: TObject ret_val = TObject.BOOLEAN_TRUE;
715: for (int i = 0; i < exp_list.length; ++i) {
716: TObject exp_item = exp_list[i].evaluate(group,
717: resolver, context);
718: // If there is a null item, we return null if not otherwise found to
719: // be false.
720: if (exp_item.isNull()) {
721: ret_val = TObject.BOOLEAN_NULL;
722: }
723: // If it doesn't match return false
724: else if (!isTrue(plain_op.eval(ob1, exp_item, null,
725: null, null))) {
726: return TObject.BOOLEAN_FALSE;
727: }
728: }
729: // Otherwise return true or null. If all match and no NULLs return
730: // true. If all match and there are NULLs then return NULL.
731: return ret_val;
732: } else {
733: throw new Error("Unknown RHS of ALL.");
734: }
735: }
736: }
737:
738: static class RegexOperator extends Operator {
739: static final long serialVersionUID = 8062751421429261272L;
740:
741: public RegexOperator() {
742: super ("regex", 8);
743: }
744:
745: public TObject eval(TObject ob1, TObject ob2,
746: GroupResolver group, VariableResolver resolver,
747: QueryContext context) {
748: if (ob1.isNull()) {
749: return ob1;
750: }
751: if (ob2.isNull()) {
752: return ob2;
753: }
754: String val = ob1.castTo(TType.STRING_TYPE).toStringValue();
755: String pattern = ob2.castTo(TType.STRING_TYPE)
756: .toStringValue();
757: return TObject.booleanVal(PatternSearch.regexMatch(context
758: .getSystem(), pattern, val));
759: }
760: }
761:
762: static class PatternMatchTrueOperator extends Operator {
763: static final long serialVersionUID = 3038856811053114238L;
764:
765: public PatternMatchTrueOperator() {
766: super ("like", 8);
767: }
768:
769: public TObject eval(TObject ob1, TObject ob2,
770: GroupResolver group, VariableResolver resolver,
771: QueryContext context) {
772: if (ob1.isNull()) {
773: return ob1;
774: }
775: if (ob2.isNull()) {
776: return ob2;
777: }
778: String val = ob1.castTo(TType.STRING_TYPE).toStringValue();
779: String pattern = ob2.castTo(TType.STRING_TYPE)
780: .toStringValue();
781:
782: TObject result = TObject.booleanVal(PatternSearch
783: .fullPatternMatch(pattern, val, '\\'));
784: return result;
785: }
786: }
787:
788: static class PatternMatchFalseOperator extends Operator {
789: static final long serialVersionUID = 7271394661743778291L;
790:
791: public PatternMatchFalseOperator() {
792: super ("not like", 8);
793: }
794:
795: public TObject eval(TObject ob1, TObject ob2,
796: GroupResolver group, VariableResolver resolver,
797: QueryContext context) {
798: if (ob1.isNull()) {
799: return ob1;
800: }
801: if (ob2.isNull()) {
802: return ob2;
803: }
804: String val = ob1.castTo(TType.STRING_TYPE).toStringValue();
805: String pattern = ob2.castTo(TType.STRING_TYPE)
806: .toStringValue();
807: return TObject.booleanVal(!PatternSearch.fullPatternMatch(
808: pattern, val, '\\'));
809: }
810: }
811:
812: // and/or have lowest precedence
813: static class AndOperator extends Operator {
814: static final long serialVersionUID = -6044610739300316190L;
815:
816: public AndOperator() {
817: super ("and", 2);
818: }
819:
820: public TObject eval(TObject ob1, TObject ob2,
821: GroupResolver group, VariableResolver resolver,
822: QueryContext context) {
823:
824: Boolean b1 = ob1.toBoolean();
825: Boolean b2 = ob2.toBoolean();
826:
827: // If either ob1 or ob2 are null
828: if (b1 == null) {
829: if (b2 != null) {
830: if (b2.equals(Boolean.FALSE)) {
831: return TObject.BOOLEAN_FALSE;
832: }
833: }
834: return TObject.BOOLEAN_NULL;
835: } else if (b2 == null) {
836: if (b1.equals(Boolean.FALSE)) {
837: return TObject.BOOLEAN_FALSE;
838: }
839: return TObject.BOOLEAN_NULL;
840: }
841:
842: // If both true.
843: return TObject.booleanVal(b1.equals(Boolean.TRUE)
844: && b2.equals(Boolean.TRUE));
845: }
846: }
847:
848: static class OrOperator extends Operator {
849: static final long serialVersionUID = 6505549460035023998L;
850:
851: public OrOperator() {
852: super ("or", 1);
853: }
854:
855: public TObject eval(TObject ob1, TObject ob2,
856: GroupResolver group, VariableResolver resolver,
857: QueryContext context) {
858:
859: Boolean b1 = ob1.toBoolean();
860: Boolean b2 = ob2.toBoolean();
861:
862: // If either ob1 or ob2 are null
863: if (b1 == null) {
864: if (b2 != null) {
865: if (b2.equals(Boolean.TRUE)) {
866: return TObject.BOOLEAN_TRUE;
867: }
868: }
869: return TObject.BOOLEAN_NULL;
870: } else if (b2 == null) {
871: if (b1.equals(Boolean.TRUE)) {
872: return TObject.BOOLEAN_TRUE;
873: }
874: return TObject.BOOLEAN_NULL;
875: }
876:
877: // If both true.
878: return TObject.booleanVal(b1.equals(Boolean.TRUE)
879: || b2.equals(Boolean.TRUE));
880:
881: }
882: }
883:
884: static class ParenOperator extends Operator {
885: static final long serialVersionUID = -5720902399037456435L;
886:
887: public ParenOperator(String paren) {
888: super (paren);
889: }
890:
891: public TObject eval(TObject ob1, TObject ob2,
892: GroupResolver group, VariableResolver resolver,
893: QueryContext context) {
894: throw new Error("Parenthese should never be evaluated!");
895: }
896: }
897:
898: static class SimpleOperator extends Operator {
899: static final long serialVersionUID = 1136249637094226133L;
900:
901: public SimpleOperator(String str) {
902: super (str);
903: }
904:
905: public SimpleOperator(String str, int prec) {
906: super (str, prec);
907: }
908:
909: public TObject eval(TObject ob1, TObject ob2,
910: GroupResolver group, VariableResolver resolver,
911: QueryContext context) {
912: throw new Error("SimpleOperator should never be evaluated!");
913: }
914: }
915:
916: }
|