Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/hsqldb/Expression.java


1   /* Copyrights and Licenses
2    *
3    * This product includes Hypersonic SQL.
4    * Originally developed by Thomas Mueller and the Hypersonic SQL Group. 
5    *
6    * Copyright (c) 1995-2000 by the Hypersonic SQL Group. All rights reserved. 
7    * Redistribution and use in source and binary forms, with or without modification, are permitted
8    * provided that the following conditions are met: 
9    *     -  Redistributions of source code must retain the above copyright notice, this list of conditions
10   *         and the following disclaimer. 
11   *     -  Redistributions in binary form must reproduce the above copyright notice, this list of
12   *         conditions and the following disclaimer in the documentation and/or other materials
13   *         provided with the distribution. 
14   *     -  All advertising materials mentioning features or use of this software must display the
15   *        following acknowledgment: "This product includes Hypersonic SQL." 
16   *     -  Products derived from this software may not be called "Hypersonic SQL" nor may
17   *        "Hypersonic SQL" appear in their names without prior written permission of the
18   *         Hypersonic SQL Group. 
19   *     -  Redistributions of any form whatsoever must retain the following acknowledgment: "This
20   *          product includes Hypersonic SQL." 
21   * This software is provided "as is" and any expressed or implied warranties, including, but
22   * not limited to, the implied warranties of merchantability and fitness for a particular purpose are
23   * disclaimed. In no event shall the Hypersonic SQL Group or its contributors be liable for any
24   * direct, indirect, incidental, special, exemplary, or consequential damages (including, but
25   * not limited to, procurement of substitute goods or services; loss of use, data, or profits;
26   * or business interruption). However caused any on any theory of liability, whether in contract,
27   * strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this
28   * software, even if advised of the possibility of such damage. 
29   * This software consists of voluntary contributions made by many individuals on behalf of the
30   * Hypersonic SQL Group.
31   *
32   *
33   * For work added by the HSQL Development Group:
34   *
35   * Copyright (c) 2001-2002, The HSQL Development Group
36   * All rights reserved.
37   *
38   * Redistribution and use in source and binary forms, with or without
39   * modification, are permitted provided that the following conditions are met:
40   *
41   * Redistributions of source code must retain the above copyright notice, this
42   * list of conditions and the following disclaimer, including earlier
43   * license statements (above) and comply with all above license conditions.
44   *
45   * Redistributions in binary form must reproduce the above copyright notice,
46   * this list of conditions and the following disclaimer in the documentation
47   * and/or other materials provided with the distribution, including earlier
48   * license statements (above) and comply with all above license conditions.
49   *
50   * Neither the name of the HSQL Development Group nor the names of its
51   * contributors may be used to endorse or promote products derived from this
52   * software without specific prior written permission.
53   *
54   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
55   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57   * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG, 
58   * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
59   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
60   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
61   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
62   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
63   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
64   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
65   */
66  
67  
68  package org.hsqldb;
69  
70  import java.sql.SQLException;
71  import java.sql.Types;
72  import java.util.Hashtable;
73  import java.util.Vector;
74  
75  // fredt@users 20020215 - patch 1.7.0 by fredt
76  // to preserve column size etc. when SELECT INTO TABLE is used
77  
78  /**
79   * Expression class declaration
80   *
81   *
82   * @version    1.7.0
83   */
84  class Expression {
85  
86      // leaf types
87      static final int VALUE     = 1,
88                       COLUMN    = 2,
89                       QUERY     = 3,
90                       TRUE      = 4,
91                       VALUELIST = 5,
92                       ASTERIX   = 6,
93                       FUNCTION  = 7;
94  
95      // operations
96      static final int NEGATE   = 9,
97                       ADD      = 10,
98                       SUBTRACT = 11,
99                       MULTIPLY = 12,
100                      DIVIDE   = 14,
101                      CONCAT   = 15;
102 
103     // logical operations
104     static final int NOT           = 20,
105                      EQUAL         = 21,
106                      BIGGER_EQUAL  = 22,
107                      BIGGER        = 23,
108                      SMALLER       = 24,
109                      SMALLER_EQUAL = 25,
110                      NOT_EQUAL     = 26,
111                      LIKE          = 27,
112                      AND           = 28,
113                      OR            = 29,
114                      IN            = 30,
115                      EXISTS        = 31;
116 
117     // aggregate functions
118     static final int COUNT      = 40,
119                      SUM        = 41,
120                      MIN        = 42,
121                      MAX        = 43,
122                      AVG        = 44,
123                      DIST_COUNT = 45;
124 
125     // system functions
126     static final int IFNULL   = 60,
127                      CONVERT  = 61,
128                      CASEWHEN = 62;
129 
130     // temporary used during paring
131     static final int PLUS         = 100,
132                      OPEN         = 101,
133                      CLOSE        = 102,
134                      SELECT       = 103,
135                      COMMA        = 104,
136                      STRINGCONCAT = 105,
137                      BETWEEN      = 106,
138                      CAST         = 107,
139                      END          = 108;
140     private int      iType;
141 
142     // nodes
143     private Expression eArg, eArg2;
144 
145     // VALUE, VALUELIST
146     private Object    oData;
147     private Hashtable hList;
148     private boolean   hListHasNull;
149     private int       iDataType;
150 
151     // QUERY (correlated subquery)
152     private Select sSelect;
153 
154     // FUNCTION
155     private Function fFunction;
156 
157     // LIKE
158     private char cLikeEscape;
159 
160     // COLUMN
161     private String      sTable;
162     private String      sColumn;
163     private TableFilter tFilter;        // null if not yet resolved
164     private int         iColumn;
165     private boolean     columnQuoted;
166     private int         iColumnSize;
167     private int         iColumnScale;
168     private String      sAlias;         // if it is a column of a select column list
169     private boolean     aliasQuoted;
170     private boolean     bDescending;    // if it is a column in a order by
171 
172 // rougier@users 20020522 - patch 552830 - COUNT(DISTINCT)
173     // {COUNT|SUM|MIN|MAX|AVG}(distinct ...)
174     private boolean      isDistinctAggregate;
175     static final Integer INTEGER_0 = new Integer(0);
176     static final Integer INTEGER_1 = new Integer(1);
177 
178     /**
179      * Constructor declaration
180      *
181      *
182      * @param f
183      */
184     Expression(Function f) {
185         iType     = FUNCTION;
186         fFunction = f;
187     }
188 
189     /**
190      * Constructor declaration
191      *
192      *
193      * @param e
194      */
195     Expression(Expression e) {
196 
197         iType       = e.iType;
198         iDataType   = e.iDataType;
199         eArg        = e.eArg;
200         eArg2       = e.eArg2;
201         cLikeEscape = e.cLikeEscape;
202         sSelect     = e.sSelect;
203         fFunction   = e.fFunction;
204     }
205 
206     /**
207      * Constructor declaration
208      *
209      *
210      * @param s
211      */
212     Expression(Select s) {
213         iType   = QUERY;
214         sSelect = s;
215     }
216 
217     /**
218      * Constructor declaration
219      *
220      *
221      * @param v
222      */
223     Expression(Vector v) {
224 
225         iType     = VALUELIST;
226         iDataType = Types.VARCHAR;
227 
228         int len = v.size();
229 
230         hList = new Hashtable(len, 1);
231 
232         for (int i = 0; i < len; i++) {
233             Object o = v.elementAt(i);
234 
235             if (o != null) {
236                 hList.put(o, this.INTEGER_1);
237             } else {
238                 this.hListHasNull = true;
239             }
240         }
241     }
242 
243     /**
244      * Constructor declaration
245      *
246      *
247      * @param type
248      * @param e
249      * @param e2
250      */
251     Expression(int type, Expression e, Expression e2) {
252 
253         iType = type;
254         eArg  = e;
255         eArg2 = e2;
256     }
257 
258     /**
259      * Constructor declaration
260      *
261      *
262      * @param table
263      * @param column
264      */
265     Expression(String table, String column) {
266 
267         sTable = table;
268 
269         if (column == null) {
270             iType = ASTERIX;
271         } else {
272             iType   = COLUMN;
273             sColumn = column;
274         }
275     }
276 
277     Expression(String table, String column, boolean isquoted) {
278 
279         sTable = table;
280 
281         if (column == null) {
282             iType = ASTERIX;
283         } else {
284             iType        = COLUMN;
285             sColumn      = column;
286             columnQuoted = isquoted;
287         }
288     }
289 
290     /**
291      * Constructor declaration
292      *
293      *
294      * @param datatype
295      * @param o
296      */
297     Expression(int datatype, Object o) {
298 
299         iType     = VALUE;
300         iDataType = datatype;
301         oData     = o;
302     }
303 
304     /**
305      * Method declaration
306      *
307      *
308      * @param c
309      */
310     void setLikeEscape(char c) {
311         cLikeEscape = c;
312     }
313 
314     /**
315      * Method declaration
316      *
317      *
318      * @param type
319      */
320     void setDataType(int type) {
321         iDataType = type;
322     }
323 
324     /**
325      * Method declaration
326      *
327      */
328     void setTrue() {
329         iType = TRUE;
330     }
331 
332     /**
333      * Method declaration
334      *
335      *
336      * @return
337      */
338     boolean isAggregate() {
339         return isAggregate(iType);
340     }
341 
342     static boolean isAggregate(int type) {
343 
344         if ((type == COUNT) || (type == MAX) || (type == MIN)
345                 || (type == SUM) || (type == AVG) || (type == DIST_COUNT)) {
346             return true;
347         }
348 
349         // todo: recurse eArg and eArg2; maybe they are grouped.
350         // grouping 'correctly' would be quite complex
351         return false;
352     }
353 
354     /**
355      * Method declaration
356      *
357      */
358     void setDescending() {
359         bDescending = true;
360     }
361 
362     /**
363      * Method declaration
364      *
365      *
366      * @return
367      */
368     boolean isDescending() {
369         return bDescending;
370     }
371 
372     /**
373      * Method declaration
374      *
375      *
376      * @param s
377      */
378     void setAlias(String s, boolean isquoted) {
379         sAlias      = s;
380         aliasQuoted = isquoted;
381     }
382 
383     /**
384      * Method declaration
385      *
386      *
387      * @return
388      */
389     String getAlias() {
390 
391         if (sAlias != null) {
392             return sAlias;
393         }
394 
395         if (iType == VALUE) {
396             return "";
397         }
398 
399         if (iType == COLUMN) {
400             return sColumn;
401         }
402 
403 // fredt@users 20020130 - patch 497872 by Nitin Chauhan - modified
404 // return column name for aggregates without alias
405         if (isAggregate()) {
406             return eArg.getColumnName();
407         }
408 
409         return "";
410     }
411 
412     /**
413      * Method declaration
414      *
415      *
416      * @return
417      */
418     boolean isAliasQuoted() {
419 
420         if (sAlias != null) {
421             return aliasQuoted;
422         }
423 
424         if (iType == COLUMN) {
425             return columnQuoted;
426         }
427 
428         if (isAggregate()) {
429             return eArg.columnQuoted;
430         }
431 
432         return false;
433     }
434 
435     /**
436      * Method declaration
437      *
438      *
439      * @return
440      */
441     int getType() {
442         return iType;
443     }
444 
445     /**
446      * Method declaration
447      *
448      *
449      * @return
450      */
451     Expression getArg() {
452         return eArg;
453     }
454 
455     /**
456      * Method declaration
457      *
458      *
459      * @return
460      */
461     Expression getArg2() {
462         return eArg2;
463     }
464 
465     /**
466      * Method declaration
467      *
468      *
469      * @return
470      */
471     TableFilter getFilter() {
472         return tFilter;
473     }
474 
475     /**
476      * Method declaration
477      *
478      *
479      * @throws SQLException
480      */
481     void checkResolved() throws SQLException {
482 
483         Trace.check((iType != COLUMN) || (tFilter != null),
484                     Trace.COLUMN_NOT_FOUND, sColumn);
485 
486         if (eArg != null) {
487             eArg.checkResolved();
488         }
489 
490         if (eArg2 != null) {
491             eArg2.checkResolved();
492         }
493 
494         if (sSelect != null) {
495             sSelect.checkResolved();
496         }
497 
498         if (fFunction != null) {
499             fFunction.checkResolved();
500         }
501     }
502 
503     /**
504      * Method declaration
505      *
506      *
507      * @param f
508      *
509      * @throws SQLException
510      */
511     void resolve(TableFilter f) throws SQLException {
512 
513         if ((f != null) && (iType == COLUMN)) {
514             if ((sTable == null) || f.getName().equals(sTable)) {
515                 int i = f.getTable().searchColumn(sColumn);
516 
517                 if (i != -1) {
518 
519 // fredt@users 20011110 - fix for 471711 - subselects
520                     // todo: other error message: multiple tables are possible
521                     Trace.check(
522                         tFilter == null
523                         || tFilter.getName().equals(
524                             f.getName()), Trace.COLUMN_NOT_FOUND, sColumn);
525 
526                     tFilter      = f;
527                     iColumn      = i;
528                     sTable       = f.getName();
529                     iDataType    = f.getTable().getColumn(i).getType();
530                     iColumnSize  = f.getTable().getColumn(i).getSize();
531                     iColumnScale = f.getTable().getColumn(i).getScale();
532                 }
533             }
534         }
535 
536         // currently sets only data type
537         // todo: calculate fixed expressions if possible
538         if (eArg != null) {
539             eArg.resolve(f);
540         }
541 
542         if (eArg2 != null) {
543             eArg2.resolve(f);
544         }
545 
546         if (sSelect != null) {
547             sSelect.resolve(f, false);
548             sSelect.resolve();
549         }
550 
551         if (fFunction != null) {
552             fFunction.resolve(f);
553         }
554 
555         if (iDataType != 0) {
556             return;
557         }
558 
559         switch (iType) {
560 
561             case FUNCTION :
562                 iDataType = fFunction.getReturnType();
563                 break;
564 
565             case QUERY :
566                 iDataType = sSelect.eColumn[0].iDataType;
567                 break;
568 
569             case NEGATE :
570                 iDataType = eArg.iDataType;
571                 break;
572 
573             case ADD :
574             case SUBTRACT :
575             case MULTIPLY :
576             case DIVIDE :
577 
578 // fredt@users 20011010 - patch 442993 by fredt
579                 iDataType = Column.getCombinedNumberType(eArg.iDataType,
580                         eArg2.iDataType, iType);
581                 break;
582 
583             case CONCAT :
584                 iDataType = Types.VARCHAR;
585                 break;
586 
587             case NOT :
588             case EQUAL :
589             case BIGGER_EQUAL :
590             case BIGGER :
591             case SMALLER :
592             case SMALLER_EQUAL :
593             case NOT_EQUAL :
594             case LIKE :
595             case AND :
596             case OR :
597             case IN :
598             case EXISTS :
599                 iDataType = Types.BIT;
600                 break;
601 
602             case COUNT :
603                 iDataType = Types.INTEGER;
604                 break;
605 
606             case DIST_COUNT :
607                 if (eArg.iType == ASTERIX) {
608                     iDataType = Types.INTEGER;
609                 }
610             case MAX :
611             case MIN :
612             case SUM :
613             case AVG :
614                 iDataType = eArg.iDataType;
615                 break;
616 
617             case CONVERT :
618 
619                 // it is already set
620                 break;
621 
622             case IFNULL :
623             case CASEWHEN :
624                 iDataType = eArg2.iDataType;
625                 break;
626         }
627     }
628 
629 // fredt@users 20021012 - patch 1.7.1 by hofhansl@users - use index with negate
630     /**
631      * Method declaration
632      *
633      *
634      * @return
635      */
636     boolean isResolved() {
637 
638         if (iType == VALUE || iType == NEGATE) {
639             return true;
640         }
641 
642         if (iType == COLUMN) {
643             return tFilter != null;
644         }
645 
646         // todo: could recurse here, but never miss a 'false'!
647         return false;
648     }
649 
650     /**
651      * Method declaration
652      *
653      *
654      * @param i
655      *
656      * @return
657      */
658     static boolean isCompare(int i) {
659 
660         switch (i) {
661 
662             case EQUAL :
663             case BIGGER_EQUAL :
664             case BIGGER :
665             case SMALLER :
666             case SMALLER_EQUAL :
667             case NOT_EQUAL :
668                 return true;
669         }
670 
671         return false;
672     }
673 
674     /**
675      * Method declaration
676      *
677      *
678      * @return
679      */
680     String getTableName() {
681 
682         if (iType == ASTERIX) {
683             return sTable;
684         }
685 
686         if (iType == COLUMN) {
687             if (tFilter == null) {
688                 return sTable;
689             } else {
690                 return tFilter.getTable().getName().name;
691             }
692         }
693 
694         // todo
695         return "";
696     }
697 
698     /**
699      * Method declaration
700      *
701      *
702      * @return
703      */
704     String getColumnName() {
705 
706         if (iType == COLUMN) {
707             if (tFilter == null) {
708                 return sColumn;
709             } else {
710                 return tFilter.getTable().getColumn(iColumn).columnName.name;
711             }
712         }
713 
714         return getAlias();
715     }
716 
717     /**
718      * Method declaration
719      *
720      *
721      * @return
722      */
723     int getColumnNr() {
724         return iColumn;
725     }
726 
727     /**
728      * Method declaration
729      *
730      *
731      * @return
732      */
733     int getColumnSize() {
734         return iColumnSize;
735     }
736 
737     /**
738      * Method declaration
739      *
740      *
741      * @return
742      */
743     int getColumnScale() {
744         return iColumnScale;
745     }
746 
747     /**
748      * Method declaration
749      *
750      * @return
751      */
752     boolean isDistinctAggregate() {
753         return isDistinctAggregate;
754     }
755 
756     /**
757      * Method declaration
758      *
759      * @param type
760      */
761     void setDistinctAggregate(boolean type) {
762 
763         isDistinctAggregate = type;
764 
765         if (iType == COUNT || iType == DIST_COUNT) {
766             iType     = type ? DIST_COUNT
767                              : COUNT;
768             iDataType = type ? iDataType
769                              : Types.INTEGER;
770         }
771     }
772 
773     /**
774      * Method declaration
775      *
776      *
777      * @throws SQLException
778      */
779     void swapCondition() throws SQLException {
780 
781         int i = EQUAL;
782 
783         switch (iType) {
784 
785             case BIGGER_EQUAL :
786                 i = SMALLER_EQUAL;
787                 break;
788 
789             case SMALLER_EQUAL :
790                 i = BIGGER_EQUAL;
791                 break;
792 
793             case SMALLER :
794                 i = BIGGER;
795                 break;
796 
797             case BIGGER :
798                 i = SMALLER;
799                 break;
800 
801             case EQUAL :
802                 break;
803 
804             default :
805                 Trace.doAssert(false, "Expression.swapCondition");
806         }
807 
808         iType = i;
809 
810         Expression e = eArg;
811 
812         eArg  = eArg2;
813         eArg2 = e;
814     }
815 
816     /**
817      * Method declaration
818      *
819      *
820      * @return
821      */
822     int getDataType() {
823         return iDataType;
824     }
825 
826     /**
827      * Method declaration
828      *
829      *
830      * @param type
831      *
832      * @return
833      *
834      * @throws SQLException
835      */
836     Object getValue(int type) throws SQLException {
837 
838         Object o = getValue();
839 
840         if ((o == null) || (iDataType == type)) {
841             return o;
842         }
843 
844         return Column.convertObject(o, type);
845     }
846 
847     /**
848      * Method declaration
849      *
850      *
851      * @return
852      *
853      * @throws SQLException
854      */
855     Object getValue() throws SQLException {
856 
857         switch (iType) {
858 
859             case VALUE :
860                 return oData;
861 
862             case COLUMN :
863                 try {
864                     return tFilter.oCurrentData[iColumn];
865                 } catch (NullPointerException e) {
866                     throw Trace.error(Trace.COLUMN_NOT_FOUND, sColumn);
867                 }
868             case FUNCTION :
869                 return fFunction.getValue();
870 
871             case QUERY :
872                 return sSelect.getValue(iDataType);
873 
874             case NEGATE :
875                 return Column.negate(eArg.getValue(iDataType), iDataType);
876 
877             case COUNT :
878 
879                 // count(*): sum(1); count(col): sum(col<>null)
880                 if (eArg.iType == ASTERIX) {
881                     return INTEGER_1;
882                 }
883 
884                 if (eArg.getValue() == null) {
885                     return INTEGER_0;
886                 } else {
887                     return INTEGER_1;
888                 }
889             case DIST_COUNT :
890                 if (eArg.iType == ASTERIX) {
891                     return INTEGER_1;
892                 }
893             case MAX :
894             case MIN :
895             case SUM :
896             case AVG :
897                 return eArg.getValue();
898 
899             case EXISTS :
900                 return new Boolean(test());
901 
902             case CONVERT :
903                 return eArg.getValue(iDataType);
904 
905             case CASEWHEN :
906                 if (eArg.test()) {
907                     return eArg2.eArg.getValue();
908                 } else {
909                     return eArg2.eArg2.getValue();
910                 }
911         }
912 
913         // todo: simplify this
914         Object a = null,
915                b = null;
916 
917         if (eArg != null) {
918             a = eArg.getValue(iDataType);
919         }
920 
921         if (eArg2 != null) {
922             b = eArg2.getValue(iDataType);
923         }
924 
925         switch (iType) {
926 
927             case ADD :
928                 return Column.add(a, b, iDataType);
929 
930             case SUBTRACT :
931                 return Column.subtract(a, b, iDataType);
932 
933             case MULTIPLY :
934                 return Column.multiply(a, b, iDataType);
935 
936             case DIVIDE :
937                 return Column.divide(a, b, iDataType);
938 
939             case CONCAT :
940                 return Column.concat(a, b);
941 
942             case IFNULL :
943                 return (a == null) ? b
944                                    : a;
945 
946             default :
947 
948                 // must be comparisation
949                 // todo: make sure it is
950                 return new Boolean(test());
951         }
952     }
953 
954     /**
955      * Method declaration
956      *
957      *
958      * @return
959      *
960      * @throws SQLException
961      */
962     boolean test() throws SQLException {
963 
964         switch (iType) {
965 
966             case TRUE :
967                 return true;
968 
969             case NOT :
970                 Trace.doAssert(eArg2 == null, "Expression.test");
971 
972                 return !eArg.test();
973 
974             case AND :
975                 return eArg.test() && eArg2.test();
976 
977             case OR :
978                 return eArg.test() || eArg2.test();
979 
980             case LIKE :
981 
982                 // todo: now for all tests a new 'like' object required!
983                 String s    = (String) eArg2.getValue(Types.VARCHAR);
984                 int    type = eArg.iDataType;
985                 Like l = new Like(s, cLikeEscape,
986                                   type == Column.VARCHAR_IGNORECASE);
987                 String c = (String) eArg.getValue(Types.VARCHAR);
988 
989                 return l.compare(c);
990 
991             case IN :
992                 return eArg2.testValueList(eArg.getValue(), eArg.iDataType);
993 
994             case EXISTS :
995                 Result r = eArg.sSelect.getResult(1);    // 1 is already enough
996 
997                 return r.rRoot != null;
998         }
999 
1000        Trace.check(eArg != null, Trace.GENERAL_ERROR);
1001
1002        Object o    = eArg.getValue();
1003        int    type = eArg.iDataType;
1004
1005        Trace.check(eArg2 != null, Trace.GENERAL_ERROR);
1006
1007        Object o2     = eArg2.getValue(type);
1008        int    result = Column.compare(o, o2, type);
1009
1010        switch (iType) {
1011
1012            case EQUAL :
1013                return result == 0;
1014
1015            case BIGGER :
1016                return result > 0;
1017
1018            case BIGGER_EQUAL :
1019                return result >= 0;
1020
1021            case SMALLER_EQUAL :
1022                return result <= 0;
1023
1024            case SMALLER :
1025                return result < 0;
1026
1027            case NOT_EQUAL :
1028                return result != 0;
1029        }
1030
1031        Trace.doAssert(false, "Expression.test2");
1032
1033        return false;
1034    }
1035
1036    /**
1037     * Method declaration
1038     *
1039     *
1040     * @param o
1041     * @param datatype
1042     *
1043     * @return
1044     *
1045     * @throws SQLException
1046     */
1047    private boolean testValueList(Object o,
1048                                  int datatype) throws SQLException {
1049
1050        if (iType == VALUELIST) {
1051            if (datatype != iDataType) {
1052                o = Column.convertObject(o, iDataType);
1053            }
1054
1055            if (o == null) {
1056                return hListHasNull;
1057            } else {
1058                return hList.containsKey(o);
1059            }
1060        } else if (iType == QUERY) {
1061
1062            // todo: convert to valuelist before if everything is resolvable
1063            Result r    = sSelect.getResult(0);
1064            Record n    = r.rRoot;
1065            int    type = r.colType[0];
1066
1067            if (datatype != type) {
1068                o = Column.convertObject(o, type);
1069            }
1070
1071            while (n != null) {
1072                Object o2 = n.data[0];
1073
1074                if ((o2 != null) && o2.equals(o)) {
1075                    return true;
1076                }
1077
1078                n = n.next;
1079            }
1080
1081            return false;
1082        }
1083
1084        throw Trace.error(Trace.WRONG_DATA_TYPE);
1085    }
1086}