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}