1 /*
2  * Copyright 2015-2018 HuntLabs.cn
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 module hunt.sql.visitor.SQLEvalVisitorUtils;
17 
18 import  hunt.sql.visitor.SQLEvalVisitor;
19 // import  hunt.sql.visitor.cast(Object)(SQLEvalVisitor.EVAL_ERROR);
20 // import  hunt.sql.visitor.SQLEvalVisitor.EVAL_EXPR;
21 // import  hunt.sql.visitor.SQLEvalVisitor.EVAL_VALUE;
22 // import  hunt.sql.visitor.SQLEvalVisitor.EVAL_VALUE_NULL;
23 
24 
25 import hunt.Exceptions;
26 import hunt.String;
27 import hunt.String;
28 import std.random;
29 import hunt.collection;
30 import std.uni;
31 import std.conv;
32 import std.math;
33 import std.exception;
34 import hunt.sql.SQLUtils;
35 import hunt.sql.ast.SQLExpr;
36 import hunt.sql.ast.SQLObject;
37 import hunt.sql.ast.expr;
38 import hunt.sql.ast.statement.SQLExprTableSource;
39 import hunt.sql.ast.statement.SQLSelect;
40 import hunt.sql.ast.statement.SQLSelectItem;
41 import hunt.sql.ast.statement.SQLSelectQueryBlock;
42 // import hunt.sql.dialect.db2.visitor.DB2EvalVisitor;
43 import hunt.sql.dialect.mysql.visitor.MySqlEvalVisitorImpl;
44 // import hunt.sql.dialect.oracle.visitor.OracleEvalVisitor;
45 import hunt.sql.dialect.postgresql.visitor.PGEvalVisitor;
46 // import hunt.sql.dialect.sqlserver.visitor.SQLServerEvalVisitor;
47 import hunt.sql.visitor.functions.Ascii;
48 import hunt.sql.visitor.functions.Bin;
49 import hunt.sql.visitor.functions.BitLength;
50 import hunt.sql.visitor.functions.Char;
51 import hunt.sql.visitor.functions.Concat;
52 import hunt.sql.visitor.functions.Elt;
53 import hunt.sql.visitor.functions.Function;
54 import hunt.sql.visitor.functions.Greatest;
55 import hunt.sql.visitor.functions.Hex;
56 import hunt.sql.visitor.functions.If;
57 import hunt.sql.visitor.functions.Insert;
58 import hunt.sql.visitor.functions.Instr;
59 import hunt.sql.visitor.functions.Isnull;
60 import hunt.sql.visitor.functions.Lcase;
61 import hunt.sql.visitor.functions.Least;
62 import hunt.sql.visitor.functions.Left;
63 import hunt.sql.visitor.functions.Length;
64 import hunt.sql.visitor.functions.Locate;
65 import hunt.sql.visitor.functions.Lpad;
66 import hunt.sql.visitor.functions.Ltrim;
67 import hunt.sql.visitor.functions.Now;
68 import hunt.sql.visitor.functions.OneParamFunctions;
69 import hunt.sql.visitor.functions.Reverse;
70 import hunt.sql.visitor.functions.Right;
71 import hunt.sql.visitor.functions.Substring;
72 import hunt.sql.visitor.functions.Trim;
73 import hunt.sql.visitor.functions.Ucase;
74 import hunt.sql.visitor.functions.Unhex;
75 import hunt.sql.util.HexBin;
76 import hunt.sql.util.DBType;
77 import hunt.sql.util.DBType;
78 import hunt.sql.util.Utils;
79 // import entity.wall.spi.WallVisitorUtils;
80 // import entity.wall.spi.WallVisitorUtils.WallConditionContext;
81 import hunt.sql.visitor.SQLEvalVisitorImpl;
82 import hunt.Boolean;
83 import hunt.Byte;
84 import hunt.Short;
85 import hunt.Integer;
86 import hunt.Long;
87 import hunt.Float;
88 import hunt.Double;
89 import hunt.Number;
90 import hunt.text;
91 import std.datetime;
92 import hunt.math;
93 
94 import std.concurrency : initOnce;
95 
96 public class SQLEvalVisitorUtils {
97 
98     static Map!(string, Function) functions()
99     {
100         __gshared Map!(string, Function) inst;
101         return initOnce!inst(registerBaseFunctions());
102     }
103 
104     // private static Map!(string, Function) functions;
105 
106     // static this() {
107     //     functions = new HashMap!(string, Function)();
108     //     registerBaseFunctions();
109     // }
110 
111     public static Object evalExpr(string dbType, string expr, Object[]  parameters...) {
112         SQLExpr sqlExpr = SQLUtils.toSQLExpr(expr, dbType);
113         return eval(dbType, sqlExpr, parameters);
114     }
115 
116     public static Object evalExpr(string dbType, string expr, List!(Object) parameters) {
117         SQLExpr sqlExpr = SQLUtils.toSQLExpr(expr);
118         return eval(dbType, sqlExpr, parameters);
119     }
120 
121     public static Object eval(string dbType, SQLObject sqlObject, Object[] parameters...) {
122         List!Object ls = new ArrayList!Object();
123         // ls.addAll(parameters);
124         foreach(Object o ; parameters)
125             ls.add(o);
126 
127         Object value = eval(dbType, sqlObject, ls);
128 
129         if (value == SQLEvalVisitor.EVAL_VALUE_NULL) {
130             value = null;
131         }
132 
133         return value;
134     }
135 
136     public static Object getValue(SQLObject sqlObject) {
137         if (cast(SQLNumericLiteralExpr)(sqlObject) !is null) {
138             return cast(Object)(cast(SQLNumericLiteralExpr) sqlObject).getNumber();
139         }
140 
141         return sqlObject.getAttributes().get(SQLEvalVisitor.EVAL_VALUE);
142     }
143 
144     public static Object eval(string dbType, SQLObject sqlObject, List!(Object) parameters) {
145         return eval(dbType, sqlObject, parameters, true);
146     }
147 
148     public static Object eval(string dbType, SQLObject sqlObject, List!(Object) parameters, bool throwError) {
149         SQLEvalVisitor visitor = createEvalVisitor(dbType);
150         visitor.setParameters(parameters);
151 
152         Object value;
153         if (cast(SQLValuableExpr)(sqlObject) !is null) {
154             value = (cast(SQLValuableExpr) sqlObject).getValue();
155         } else {
156             sqlObject.accept(visitor);
157   
158             value = getValue(sqlObject);
159 
160             if (value is null) {
161                 if (throwError && !sqlObject.getAttributes().containsKey(SQLEvalVisitor.EVAL_VALUE)) {
162                     throw new Exception("eval error : " ~ SQLUtils.toSQLString(sqlObject, dbType));
163                 }
164             }
165         }
166 
167         return value;
168     }
169 
170     public static SQLEvalVisitor createEvalVisitor(string dbType) {
171         if (DBType.MYSQL.opEquals(dbType)) {
172             return new MySqlEvalVisitorImpl();
173         }
174 
175         if (DBType.MARIADB.opEquals(dbType)) {
176             return new MySqlEvalVisitorImpl();
177         }
178 
179         if (DBType.H2.opEquals(dbType)) {
180             return new MySqlEvalVisitorImpl();
181         }
182 
183         // if (DBType.ORACLE.opEquals(dbType) || DBType.ALI_ORACLE.opEquals(dbType)) {
184         //     return new OracleEvalVisitor();
185         // }
186 
187         if (DBType.POSTGRESQL.opEquals(dbType)
188                 || DBType.ENTERPRISEDB.opEquals(dbType)) {
189             return new PGEvalVisitor();
190         }
191 
192         // if (DBType.SQL_SERVER.opEquals(dbType) || DBType.JTDS.opEquals(dbType)) {
193         //     return new SQLServerEvalVisitor();
194         // }
195 
196         // if (DBType.DB2.opEquals(dbType)) {
197         //     return new DB2EvalVisitor();
198         // }
199 
200         return new SQLEvalVisitorImpl();
201     }
202 
203     static Map!(string, Function) registerBaseFunctions() {
204         Map!(string, Function) functions = new HashMap!(string, Function)();
205         functions.put("now", Now.instance);
206         functions.put("concat", Concat.instance);
207         functions.put("concat_ws", Concat.instance);
208         functions.put("ascii", Ascii.instance);
209         functions.put("bin", Bin.instance);
210         functions.put("bit_length", BitLength.instance);
211         functions.put("insert", Insert.instance);
212         functions.put("instr", Instr.instance);
213         functions.put("char", Char.instance);
214         functions.put("elt", Elt.instance);
215         functions.put("left", Left.instance);
216         functions.put("locate", Locate.instance);
217         functions.put("lpad", Lpad.instance);
218         functions.put("ltrim", Ltrim.instance);
219         functions.put("mid", Substring.instance);
220         functions.put("substr", Substring.instance);
221         functions.put("substring", Substring.instance);
222         functions.put("right", Right.instance);
223         functions.put("reverse", Reverse.instance);
224         functions.put("len", Length.instance);
225         functions.put("length", Length.instance);
226         functions.put("char_length", Length.instance);
227         functions.put("character_length", Length.instance);
228         functions.put("trim", Trim.instance);
229         functions.put("ucase", Ucase.instance);
230         functions.put("upper", Ucase.instance);
231         functions.put("lcase", Lcase.instance);
232         functions.put("lower", Lcase.instance);
233         functions.put("hex", Hex.instance);
234         functions.put("unhex", Unhex.instance);
235         functions.put("greatest", Greatest.instance);
236         functions.put("least", Least.instance);
237         functions.put("isnull", Isnull.instance);
238         functions.put("if", If.instance);
239 
240         functions.put("md5", OneParamFunctions.instance);
241         functions.put("bit_count", OneParamFunctions.instance);
242         functions.put("soundex", OneParamFunctions.instance);
243         functions.put("space", OneParamFunctions.instance);
244 
245         return functions;
246     }
247 
248     public static bool visit(SQLEvalVisitor visitor, SQLMethodInvokeExpr x) {
249         string methodName =toLower(x.getMethodName());
250 
251         Function function_p = visitor.getFunction(methodName);
252 
253         if (function_p is null) {
254             function_p = functions.get(methodName);
255         }
256 
257         if (function_p !is null) {
258             Object result = function_p.eval(visitor, x);
259 
260             if (result != SQLEvalVisitor.EVAL_ERROR) {
261                 x.getAttributes().put(SQLEvalVisitor.EVAL_VALUE, result);
262             }
263             return false;
264         }
265 
266         if ("mod" == (methodName)) {
267             if (x.getParameters().size() != 2) {
268                 return false;
269             }
270 
271             SQLExpr param0 = x.getParameters().get(0);
272             SQLExpr param1 = x.getParameters().get(1);
273             param0.accept(visitor);
274             param1.accept(visitor);
275 
276             Object param0Value = param0.getAttributes().get(SQLEvalVisitor.EVAL_VALUE);
277             Object param1Value = param1.getAttributes().get(SQLEvalVisitor.EVAL_VALUE);
278             if (param0Value is null || param1Value is null) {
279                 return false;
280             }
281 
282             Long intValue0 = castToLong(param0Value);
283             Long intValue1 = castToLong(param1Value);
284 
285             long result = intValue0.longValue % intValue1.longValue;
286             if (result >= Integer.MIN_VALUE && result <= Integer.MAX_VALUE) {
287                 int intResult = cast(int) result;
288                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, new Integer(intResult));
289             } else {
290                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, new Long(result));
291             }
292         } else if ("abs" == (methodName)) {
293             if (x.getParameters().size() != 1) {
294                 return false;
295             }
296 
297             SQLExpr param0 = x.getParameters().get(0);
298             param0.accept(visitor);
299 
300             Object paramValue = param0.getAttributes().get(SQLEvalVisitor.EVAL_VALUE);
301             if (paramValue is null) {
302                 return false;
303             }
304 
305             Object result;
306             if (cast(Integer)(paramValue) !is null) {
307                 result = new Integer(abs((cast(Integer) paramValue).intValue()));
308             } else if (cast(Long)(paramValue) !is null) {
309                 result = new Long(abs((cast(Long) paramValue).longValue()));
310             } else {
311                 // result = new BigDecimal(abs(castToDecimal(paramValue)));//@gxc
312             }
313 
314             x.putAttribute(SQLEvalVisitor.EVAL_VALUE, result);
315         } else if ("acos" == (methodName)) {
316             if (x.getParameters().size() != 1) {
317                 return false;
318             }
319 
320             SQLExpr param0 = x.getParameters().get(0);
321             param0.accept(visitor);
322 
323             Object paramValue = param0.getAttributes().get(SQLEvalVisitor.EVAL_VALUE);
324             if (paramValue is null) {
325                 return false;
326             }
327 
328             auto dv = castToDouble(paramValue);
329             double result = acos(dv.doubleValue);
330 
331             if (isNaN(result)) {
332                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, null);
333             } else {
334                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, new Double(result));
335             }
336         } else if ("asin" == (methodName)) {
337             if (x.getParameters().size() != 1) {
338                 return false;
339             }
340 
341             SQLExpr param0 = x.getParameters().get(0);
342             param0.accept(visitor);
343 
344             Object paramValue = param0.getAttributes().get(SQLEvalVisitor.EVAL_VALUE);
345             if (paramValue is null) {
346                 return false;
347             }
348 
349             auto dv = castToDouble(paramValue);
350             double result = asin(dv.doubleValue);
351 
352             if (isNaN(result)) {
353                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, null);
354             } else {
355                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, new Double(result));
356             }
357         } else if ("atan" == (methodName)) {
358             if (x.getParameters().size() != 1) {
359                 return false;
360             }
361 
362             SQLExpr param0 = x.getParameters().get(0);
363             param0.accept(visitor);
364 
365             Object paramValue = param0.getAttributes().get(SQLEvalVisitor.EVAL_VALUE);
366             if (paramValue is null) {
367                 return false;
368             }
369 
370             auto dv = castToDouble(paramValue);
371             double result = atan(dv.doubleValue);
372 
373             if (isNaN(result)) {
374                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, null);
375             } else {
376                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, new Double(result));
377             }
378         } else if ("atan2" == (methodName)) {
379             if (x.getParameters().size() != 2) {
380                 return false;
381             }
382 
383             SQLExpr param0 = x.getParameters().get(0);
384             SQLExpr param1 = x.getParameters().get(1);
385             param0.accept(visitor);
386             param1.accept(visitor);
387 
388             Object param0Value = param0.getAttributes().get(SQLEvalVisitor.EVAL_VALUE);
389             Object param1Value = param1.getAttributes().get(SQLEvalVisitor.EVAL_VALUE);
390             if (param0Value is null || param1Value is null) {
391                 return false;
392             }
393 
394             auto doubleValue0 = castToDouble(param0Value);
395             auto doubleValue1 = castToDouble(param1Value);
396             double result = atan2(doubleValue0.doubleValue, doubleValue1.doubleValue);
397 
398             if (isNaN(result)) {
399                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, null);
400             } else {
401                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, new Double(result));
402             }
403         } else if ("ceil" == (methodName) || "ceiling" == (methodName)) {
404             if (x.getParameters().size() != 1) {
405                 return false;
406             }
407 
408             SQLExpr param0 = x.getParameters().get(0);
409             param0.accept(visitor);
410 
411             Object paramValue = param0.getAttributes().get(SQLEvalVisitor.EVAL_VALUE);
412             if (paramValue is null) {
413                 return false;
414             }
415 
416             auto dv = castToDouble(paramValue);
417             int result = cast(int) ceil(dv.doubleValue);
418 
419             if (result == int.init) {
420                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, null);
421             } else {
422                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, new Integer(result));
423             }
424         } else if ("cos" == (methodName)) {
425             if (x.getParameters().size() != 1) {
426                 return false;
427             }
428 
429             SQLExpr param0 = x.getParameters().get(0);
430             param0.accept(visitor);
431 
432             Object paramValue = param0.getAttributes().get(SQLEvalVisitor.EVAL_VALUE);
433             if (paramValue is null) {
434                 return false;
435             }
436 
437             auto dv = castToDouble(paramValue);
438             double result = cos(dv.doubleValue);
439 
440             if (isNaN(result)) {
441                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, null);
442             } else {
443                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, new Double(result));
444             }
445         } else if ("sin" == (methodName)) {
446             if (x.getParameters().size() != 1) {
447                 return false;
448             }
449 
450             SQLExpr param0 = x.getParameters().get(0);
451             param0.accept(visitor);
452 
453             Object paramValue = param0.getAttributes().get(SQLEvalVisitor.EVAL_VALUE);
454             if (paramValue is null) {
455                 return false;
456             }
457 
458             auto dv = castToDouble(paramValue);
459             double result = sin(dv.doubleValue);
460 
461             if (isNaN(result)) {
462                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, null);
463             } else {
464                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, new Double(result));
465             }
466         } else if ("log" == (methodName)) {
467             if (x.getParameters().size() != 1) {
468                 return false;
469             }
470 
471             SQLExpr param0 = x.getParameters().get(0);
472             param0.accept(visitor);
473 
474             Object paramValue = param0.getAttributes().get(SQLEvalVisitor.EVAL_VALUE);
475             if (paramValue is null) {
476                 return false;
477             }
478 
479             auto dv = castToDouble(paramValue);
480             double result = log(dv.doubleValue);
481 
482             if (isNaN(result)) {
483                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, null);
484             } else {
485                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, new Double(result));
486             }
487         } else if ("log10" == (methodName)) {
488             if (x.getParameters().size() != 1) {
489                 return false;
490             }
491 
492             SQLExpr param0 = x.getParameters().get(0);
493             param0.accept(visitor);
494 
495             Object paramValue = param0.getAttributes().get(SQLEvalVisitor.EVAL_VALUE);
496             if (paramValue is null) {
497                 return false;
498             }
499 
500             auto dv = castToDouble(paramValue);
501             double result = log10(dv.doubleValue);
502 
503             if (isNaN(result)) {
504                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, null);
505             } else {
506                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, new Double(result));
507             }
508         } else if ("tan" == (methodName)) {
509             if (x.getParameters().size() != 1) {
510                 return false;
511             }
512 
513             SQLExpr param0 = x.getParameters().get(0);
514             param0.accept(visitor);
515 
516             Object paramValue = param0.getAttributes().get(SQLEvalVisitor.EVAL_VALUE);
517             if (paramValue is null) {
518                 return false;
519             }
520 
521             auto dv = castToDouble(paramValue);
522             double result = tan(dv.doubleValue);
523 
524             if (isNaN(result)) {
525                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, null);
526             } else {
527                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, new Double(result));
528             }
529         } else if ("sqrt" == (methodName)) {
530             if (x.getParameters().size() != 1) {
531                 return false;
532             }
533 
534             SQLExpr param0 = x.getParameters().get(0);
535             param0.accept(visitor);
536 
537             Object paramValue = param0.getAttributes().get(SQLEvalVisitor.EVAL_VALUE);
538             if (paramValue is null) {
539                 return false;
540             }
541 
542             auto dv = castToDouble(paramValue);
543             double result = sqrt(dv.doubleValue);
544 
545             if (isNaN!double(result)) {
546                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, null);
547             } else {
548                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, new Double(result));
549             }
550         } else if ("power" == (methodName) || "pow" == (methodName)) {
551             if (x.getParameters().size() != 2) {
552                 return false;
553             }
554 
555             SQLExpr param0 = x.getParameters().get(0);
556             SQLExpr param1 = x.getParameters().get(1);
557             param0.accept(visitor);
558             param1.accept(visitor);
559 
560             Object param0Value = param0.getAttributes().get(SQLEvalVisitor.EVAL_VALUE);
561             Object param1Value = param1.getAttributes().get(SQLEvalVisitor.EVAL_VALUE);
562             if (param0Value is null || param1Value is null) {
563                 return false;
564             }
565 
566             auto doubleValue0 = castToDouble(param0Value);
567             auto doubleValue1 = castToDouble(param1Value);
568             double result = pow!(double,double)(doubleValue0.doubleValue, doubleValue1.doubleValue);
569 
570             if (isNaN!double(result)) {
571                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, null);
572             } else {
573                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, new Double(result));
574             }
575         } else if ("pi" == (methodName)) {
576             x.putAttribute(SQLEvalVisitor.EVAL_VALUE, new Double(3.1415));
577         } else if ("rand" == (methodName)) {
578             x.putAttribute(SQLEvalVisitor.EVAL_VALUE, new Double(uniform(0.0f,1000.0f)));
579         } else if ("chr" == (methodName) && x.getParameters().size() == 1) {
580             SQLExpr first = x.getParameters().get(0);
581             Object firstResult = getValue(first);
582             if (cast(Number)(firstResult) !is null) {
583                 int intValue = (cast(Number) firstResult).intValue();
584                 char ch = cast(char) intValue;
585                 string s = to!string(ch);
586                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, new String(s));
587             }
588         } else if ("current_user" == (methodName)) {
589             x.putAttribute(SQLEvalVisitor.EVAL_VALUE, new String("CURRENT_USER"));
590         }
591         return false;
592     }
593 
594     public static bool visit(SQLEvalVisitor visitor, SQLCharExpr x) {
595         x.putAttribute(SQLEvalVisitor.EVAL_VALUE, x.getText());
596         return true;
597     }
598 
599     public static bool visit(SQLEvalVisitor visitor, SQLHexExpr x) {
600         string hex = x.getHex();
601         byte[] bytes = HexBin.decode(hex);
602         if (bytes is null) {
603             x.putAttribute(SQLEvalVisitor.EVAL_VALUE, cast(Object)(SQLEvalVisitor.EVAL_ERROR));
604         } else {
605             String val = new String(cast(string)bytes);
606             x.putAttribute(SQLEvalVisitor.EVAL_VALUE, val);
607         }
608         return true;
609     }
610 
611     public static bool visit(SQLEvalVisitor visitor, SQLBinaryExpr x) {
612         string text = x.getText();
613 
614         long[] words = new long[text.length / 64 + 1];
615         for (int i = cast(int)(text.length-1); i >= 0 ; --i) {
616             char ch = charAt(text, i);
617             if (ch == '1') {
618                 int wordIndex = i >> 6;
619                 words[wordIndex] |= (1L << (text.length - 1 - i));
620             }
621         }
622 
623         Object val;
624 
625         if (words.length == 1) {
626             val = new Long(words[0]);
627         } else {
628             byte[] bytes = new byte[words.length * 8];
629 
630             for (int i = 0; i < words.length; ++i) {
631                 Utils.putLong(bytes, cast(int)(words.length-1-i) * 8, cast(int)words[i]);
632             }
633 
634             val = new BigInteger(bytes);
635         }
636 
637         x.putAttribute(SQLEvalVisitor.EVAL_VALUE, val);
638 
639         return false;
640     }
641 
642     public static SQLExpr unwrap(SQLExpr expr) {
643         if (expr is null) {
644             return null;
645         }
646 
647         if (cast(SQLQueryExpr)(expr) !is null) {
648             SQLSelect select = (cast(SQLQueryExpr) expr).getSubQuery();
649             if (select is null) {
650                 return null;
651             }
652             if (cast(SQLSelectQueryBlock) select.getQuery() !is null) {
653                 SQLSelectQueryBlock queryBlock = cast(SQLSelectQueryBlock) select.getQuery();
654                 if (queryBlock.getFrom() is null) {
655                     if (queryBlock.getSelectList().size() == 1) {
656                         return queryBlock.getSelectList().get(0).getExpr();
657                     }
658                 }
659             }
660         }
661 
662         return expr;
663     }
664 
665     public static bool visit(SQLEvalVisitor visitor, SQLBetweenExpr x) {
666         SQLExpr testExpr = unwrap(x.getTestExpr());
667         testExpr.accept(visitor);
668 
669         if (!testExpr.getAttributes().containsKey(SQLEvalVisitor.EVAL_VALUE)) {
670             return false;
671         }
672 
673         Object value = testExpr.getAttribute(SQLEvalVisitor.EVAL_VALUE);
674 
675         SQLExpr beginExpr = unwrap(x.getBeginExpr());
676         beginExpr.accept(visitor);
677         if (!beginExpr.getAttributes().containsKey(SQLEvalVisitor.EVAL_VALUE)) {
678             return false;
679         }
680 
681         Object begin = beginExpr.getAttribute(SQLEvalVisitor.EVAL_VALUE);
682 
683         if (lt(value, begin)) {
684             x.getAttributes().put(SQLEvalVisitor.EVAL_VALUE, x.isNot() ? Boolean.TRUE : Boolean.FALSE);
685             return false;
686         }
687 
688         SQLExpr endExpr = unwrap(x.getEndExpr());
689         endExpr.accept(visitor);
690         if (!endExpr.getAttributes().containsKey(SQLEvalVisitor.EVAL_VALUE)) {
691             return false;
692         }
693 
694         Object end = endExpr.getAttribute(SQLEvalVisitor.EVAL_VALUE);
695 
696         if (gt(value, end)) {
697             x.getAttributes().put(SQLEvalVisitor.EVAL_VALUE, x.isNot() ? Boolean.TRUE : Boolean.FALSE);
698             return false;
699         }
700 
701         x.getAttributes().put(SQLEvalVisitor.EVAL_VALUE, x.isNot() ? Boolean.FALSE : Boolean.TRUE);
702         return false;
703     }
704 
705     public static bool visit(SQLEvalVisitor visitor, SQLNullExpr x) {
706         x.getAttributes().put(SQLEvalVisitor.EVAL_VALUE, cast(Object)(SQLEvalVisitor.EVAL_VALUE_NULL));
707         return false;
708     }
709 
710     public static bool visit(SQLEvalVisitor visitor, SQLCaseExpr x) {
711         Object value;
712         if (x.getValueExpr() !is null) {
713             x.getValueExpr().accept(visitor);
714 
715             if (!x.getValueExpr().getAttributes().containsKey(SQLEvalVisitor.EVAL_VALUE)) {
716                 return false;
717             }
718 
719             value = x.getValueExpr().getAttribute(SQLEvalVisitor.EVAL_VALUE);
720         } else {
721             value = null;
722         }
723 
724         foreach(SQLCaseExpr.Item item ; x.getItems()) {
725             item.getConditionExpr().accept(visitor);
726 
727             if (!item.getConditionExpr().getAttributes().containsKey(SQLEvalVisitor.EVAL_VALUE)) {
728                 return false;
729             }
730 
731             Object conditionValue = item.getConditionExpr().getAttribute(SQLEvalVisitor.EVAL_VALUE);
732 
733             if ((x.getValueExpr() !is null && eq(value, conditionValue).booleanValue)
734                 || (x.getValueExpr() is null && cast(Boolean)(conditionValue) !is null && cast(Boolean) conditionValue == Boolean.TRUE)) {
735                 item.getValueExpr().accept(visitor);
736 
737                 if (item.getValueExpr().getAttributes().containsKey(SQLEvalVisitor.EVAL_VALUE)) {
738                     x.getAttributes().put(SQLEvalVisitor.EVAL_VALUE, item.getValueExpr().getAttribute(SQLEvalVisitor.EVAL_VALUE));
739                 }
740 
741                 return false;
742             }
743         }
744 
745         if (x.getElseExpr() !is null) {
746             x.getElseExpr().accept(visitor);
747 
748             if (x.getElseExpr().getAttributes().containsKey(SQLEvalVisitor.EVAL_VALUE)) {
749                 x.getAttributes().put(SQLEvalVisitor.EVAL_VALUE, x.getElseExpr().getAttribute(SQLEvalVisitor.EVAL_VALUE));
750             }
751         }
752 
753         return false;
754     }
755 
756     public static bool visit(SQLEvalVisitor visitor, SQLInListExpr x) {
757         SQLExpr valueExpr = x.getExpr();
758         valueExpr.accept(visitor);
759         if (!valueExpr.getAttributes().containsKey(SQLEvalVisitor.EVAL_VALUE)) {
760             return false;
761         }
762         Object value = valueExpr.getAttribute(SQLEvalVisitor.EVAL_VALUE);
763 
764         foreach(SQLExpr item ; x.getTargetList()) {
765             item.accept(visitor);
766             if (!item.getAttributes().containsKey(SQLEvalVisitor.EVAL_VALUE)) {
767                 return false;
768             }
769             Object itemValue = item.getAttribute(SQLEvalVisitor.EVAL_VALUE);
770             if (eq(value, itemValue).booleanValue) {
771                 x.getAttributes().put(SQLEvalVisitor.EVAL_VALUE, x.isNot() ? Boolean.FALSE : Boolean.TRUE);
772                 return false;
773             }
774         }
775 
776         x.getAttributes().put(SQLEvalVisitor.EVAL_VALUE, x.isNot() ? Boolean.TRUE : Boolean.FALSE);
777         return false;
778     }
779 
780     public static bool visit(SQLEvalVisitor visitor, SQLQueryExpr x) {
781         // if (WallVisitorUtils.isSimpleCountTableSource(null, (cast(SQLQueryExpr) x).getSubQuery())) {
782         //     x.putAttribute(SQLEvalVisitor.EVAL_VALUE, 1);
783         //     return false;
784         // }
785 
786         if ( cast(SQLSelectQueryBlock) x.getSubQuery().getQuery() !is null) {
787             SQLSelectQueryBlock queryBlock = cast(SQLSelectQueryBlock) x.getSubQuery().getQuery();
788 
789             bool nullFrom = false;
790             if (queryBlock.getFrom() is null) {
791                 nullFrom = true;
792             } else if ((cast(SQLExprTableSource) queryBlock.getFrom()).getExpr() !is null) {
793                 SQLExpr expr = (cast(SQLExprTableSource) queryBlock.getFrom()).getExpr();
794                 if (cast(SQLIdentifierExpr)(expr) !is null) {
795                     if ("dual".equalsIgnoreCase((cast(SQLIdentifierExpr) expr).getName())) {
796                         nullFrom = true;
797                     }
798                 }
799             }
800 
801             if (nullFrom) {
802                 List!(Object) row = new ArrayList!(Object)(queryBlock.getSelectList().size());
803                 for (int i = 0; i < queryBlock.getSelectList().size(); ++i) {
804                     SQLSelectItem item = queryBlock.getSelectList().get(i);
805                     item.getExpr().accept(visitor);
806                     Object cell = item.getExpr().getAttribute(SQLEvalVisitor.EVAL_VALUE);
807                     row.add(cell);
808                 }
809                 List!(List!Object) rows = new ArrayList!(List!(Object))(1);
810                 rows.add(row);
811 
812                 Object result = cast(Object)rows;
813                 queryBlock.putAttribute(SQLEvalVisitor.EVAL_VALUE, result);
814                 x.getSubQuery().putAttribute(SQLEvalVisitor.EVAL_VALUE, result);
815                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, result);
816 
817                 return false;
818             }
819         }
820 
821         return false;
822     }
823 
824     public static bool visit(SQLEvalVisitor visitor, SQLUnaryExpr x) {
825         //  WallConditionContext wallConditionContext = WallVisitorUtils.getWallConditionContext();
826         // if (x.getOperator() == SQLUnaryOperator.Compl && wallConditionContext !is null) {
827         //     wallConditionContext.setBitwise(true);
828         // }
829 
830         x.getExpr().accept(visitor);
831 
832         Object val = x.getExpr().getAttribute(SQLEvalVisitor.EVAL_VALUE);
833         if (val == SQLEvalVisitor.EVAL_ERROR) {
834             x.putAttribute(SQLEvalVisitor.EVAL_VALUE, cast(Object)(SQLEvalVisitor.EVAL_ERROR));
835             return false;
836         }
837 
838         if (val is null) {
839             x.putAttribute(SQLEvalVisitor.EVAL_VALUE, cast(Object)(SQLEvalVisitor.EVAL_VALUE_NULL));
840             return false;
841         }
842 
843         switch (x.getOperator().name) {
844             case SQLUnaryOperator.BINARY.name:
845             case SQLUnaryOperator.RAW.name:
846                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, val);
847                 break;
848             case SQLUnaryOperator.NOT.name:
849             case SQLUnaryOperator.Not.name: {
850                 Boolean bl = castToBoolean(val);
851                 if (bl !is null) {
852                     x.putAttribute(SQLEvalVisitor.EVAL_VALUE, new Boolean(!(bl.booleanValue)));
853                 }
854                 break;
855             }
856             case SQLUnaryOperator.Plus.name:
857                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, val);
858                 break;
859             case SQLUnaryOperator.Negative.name:
860                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, multi(val, new Integer(-1)));
861                 break;
862             case SQLUnaryOperator.Compl.name:
863                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, new Integer(~castToInteger(val).intValue));
864                 break;
865             default:
866                 break;
867         }
868 
869         return false;
870     }
871 
872     public static bool visit(SQLEvalVisitor visitor, SQLBinaryOpExpr x) {
873         SQLExpr left = unwrap(x.getLeft());
874         SQLExpr right = unwrap(x.getRight());
875 
876         //  WallConditionContext old = wallConditionContextLocal.get();
877 
878         left.accept(visitor);
879         right.accept(visitor);
880 
881         //  WallConditionContext wallConditionContext = WallVisitorUtils.getWallConditionContext();
882         // if (x.getOperator() == SQLBinaryOperator.BooleanOr) {
883         //     if (wallConditionContext !is null) {
884         //         if (left.getAttribute(SQLEvalVisitor.EVAL_VALUE) == Boolean.TRUE || right.getAttribute(SQLEvalVisitor.EVAL_VALUE) == Boolean.TRUE) {
885         //             wallConditionContext.setPartAlwayTrue(true);
886         //         }
887         //     }
888         // } else if (x.getOperator() == SQLBinaryOperator.BooleanAnd) {
889         //     if (wallConditionContext !is null) {
890         //         if (left.getAttribute(SQLEvalVisitor.EVAL_VALUE) == Boolean.FALSE || right.getAttribute(SQLEvalVisitor.EVAL_VALUE) == Boolean.FALSE) {
891         //             wallConditionContext.setPartAlwayFalse(true);
892         //         }
893         //     }
894         // } else if (x.getOperator() == SQLBinaryOperator.BooleanXor) {
895         //     if (wallConditionContext !is null) {
896         //         wallConditionContext.setXor(true);
897         //     }
898         // } else if (x.getOperator() == SQLBinaryOperator.BitwiseAnd //
899         //            || x.getOperator() == SQLBinaryOperator.BitwiseNot //
900         //            || x.getOperator() == SQLBinaryOperator.BitwiseOr //
901         //            || x.getOperator() == SQLBinaryOperator.BitwiseXor) {
902         //     if (wallConditionContext !is null) {
903         //         wallConditionContext.setBitwise(true);
904         //     }
905         // }
906 
907         Object leftValue = left.getAttribute(SQLEvalVisitor.EVAL_VALUE);
908         Object rightValue = right.getAttributes().get(SQLEvalVisitor.EVAL_VALUE);
909 
910         if (x.getOperator() == SQLBinaryOperator.Like) {
911             if (isAlwayTrueLikePattern(x.getRight())) {
912                 // x.putAttribute(WallVisitorUtils.HAS_TRUE_LIKE, Boolean.TRUE);
913                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, Boolean.TRUE);
914                 return false;
915             }
916         }
917 
918         if (x.getOperator() == SQLBinaryOperator.NotLike) {
919             if (isAlwayTrueLikePattern(x.getRight())) {
920                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, Boolean.FALSE);
921                 return false;
922             }
923         }
924 
925         bool leftHasValue = left.getAttributes().containsKey(SQLEvalVisitor.EVAL_VALUE);
926         bool rightHasValue = right.getAttributes().containsKey(SQLEvalVisitor.EVAL_VALUE);
927 
928         if ((!leftHasValue) && !rightHasValue) {
929             SQLExpr leftEvalExpr = cast(SQLExpr) left.getAttribute(SQLEvalVisitor.EVAL_EXPR);
930             SQLExpr rightEvalExpr = cast(SQLExpr) right.getAttribute(SQLEvalVisitor.EVAL_EXPR);
931 
932             if (leftEvalExpr !is null && (cast(Object)leftEvalExpr).opEquals(cast(Object)rightEvalExpr)) {
933                 switch (x.getOperator().name) {
934                     case SQLBinaryOperator.Like.name:
935                     case SQLBinaryOperator.Equality.name:
936                     case SQLBinaryOperator.GreaterThanOrEqual.name:
937                     case SQLBinaryOperator.LessThanOrEqual.name:
938                     case SQLBinaryOperator.NotLessThan.name:
939                     case SQLBinaryOperator.NotGreaterThan.name:
940                         x.putAttribute(SQLEvalVisitor.EVAL_VALUE, Boolean.TRUE);
941                         return false;
942                     case SQLBinaryOperator.NotEqual.name:
943                     case SQLBinaryOperator.NotLike.name:
944                     case SQLBinaryOperator.GreaterThan.name:
945                     case SQLBinaryOperator.LessThan.name:
946                         x.putAttribute(SQLEvalVisitor.EVAL_VALUE, Boolean.FALSE);
947                         return false;
948                     default:
949                         break;
950                 }
951             }
952         }
953 
954         if (!leftHasValue) {
955             return false;
956         }
957 
958         if (!rightHasValue) {
959             return false;
960         }
961 
962         // if (wallConditionContext !is null) {
963         //     wallConditionContext.setConstArithmetic(true);
964         // }
965 
966         leftValue = processValue(leftValue);
967         rightValue = processValue(rightValue);
968 
969         if (leftValue is null || rightValue is null) {
970             return false;
971         }
972 
973         Object value = null;
974         switch (x.getOperator().name) {
975             case SQLBinaryOperator.Add.name:
976                 value = add(leftValue, rightValue);
977                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, value);
978                 break;
979             case SQLBinaryOperator.Subtract.name:
980                 value = sub(leftValue, rightValue);
981                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, value);
982                 break;
983             case SQLBinaryOperator.Multiply.name:
984                 value = multi(leftValue, rightValue);
985                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, value);
986                 break;
987             case SQLBinaryOperator.Divide.name:
988                 value = div(leftValue, rightValue);
989                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, value);
990                 break;
991             case SQLBinaryOperator.RightShift.name:
992                 value = rightShift(leftValue, rightValue);
993                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, value);
994                 break;
995             case SQLBinaryOperator.BitwiseAnd.name:
996                 value = bitAnd(leftValue, rightValue);
997                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, value);
998                 break;
999             case SQLBinaryOperator.BitwiseOr.name:
1000                 value = bitOr(leftValue, rightValue);
1001                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, value);
1002                 break;
1003             case SQLBinaryOperator.GreaterThan.name:
1004                 value = gt(leftValue, rightValue);
1005                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, value);
1006                 break;
1007             case SQLBinaryOperator.GreaterThanOrEqual.name:
1008                 value = gteq(leftValue, rightValue);
1009                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, value);
1010                 break;
1011             case SQLBinaryOperator.LessThan.name:
1012                 value = lt(leftValue, rightValue);
1013                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, value);
1014                 break;
1015             case SQLBinaryOperator.LessThanOrEqual.name:
1016                 value = lteq(leftValue, rightValue);
1017                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, value);
1018                 break;
1019             case SQLBinaryOperator.Is.name:
1020                 if (rightValue == SQLEvalVisitor.EVAL_VALUE_NULL) {
1021                     if (leftValue !is null) {
1022                         value = new Boolean(leftValue == SQLEvalVisitor.EVAL_VALUE_NULL);
1023                         x.putAttribute(SQLEvalVisitor.EVAL_VALUE, value);
1024                         break;
1025                     }
1026                 }
1027                 break;
1028             case SQLBinaryOperator.Equality.name:
1029                 value = eq(leftValue, rightValue);
1030                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, value);
1031                 break;
1032             case SQLBinaryOperator.NotEqual.name:
1033                 value = new Boolean(!(eq(leftValue, rightValue).booleanValue));
1034                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, value);
1035                 break;
1036             case SQLBinaryOperator.IsNot.name:
1037                 if (leftValue == SQLEvalVisitor.EVAL_VALUE_NULL) {
1038                     x.putAttribute(SQLEvalVisitor.EVAL_VALUE, new Boolean(false));
1039                 } else if (leftValue !is null) {
1040                     x.putAttribute(SQLEvalVisitor.EVAL_VALUE, new Boolean(true));
1041                 }
1042                 break;
1043             case SQLBinaryOperator.RegExp.name:
1044             case SQLBinaryOperator.RLike.name: {
1045                 string pattern = castToString(rightValue);
1046                 string input = castToString(left.getAttributes().get(SQLEvalVisitor.EVAL_VALUE));
1047                 bool matchResult = Utils.matches(pattern, input);
1048                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, new Boolean(matchResult));
1049                 break;
1050             }
1051             case SQLBinaryOperator.NotRegExp.name:
1052             case SQLBinaryOperator.NotRLike.name: {
1053                 string pattern = castToString(rightValue);
1054                 string input = castToString(left.getAttributes().get(SQLEvalVisitor.EVAL_VALUE));
1055                 bool matchResult = !Utils.matches(pattern, input);
1056                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, new Boolean(matchResult));
1057                 break;
1058             }
1059             case SQLBinaryOperator.Like.name: {
1060                 string pattern = castToString(rightValue);
1061                 string input = castToString(left.getAttributes().get(SQLEvalVisitor.EVAL_VALUE));
1062                 auto matchResult = like(input, pattern);
1063                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, (matchResult));
1064                 break;
1065             }
1066             case SQLBinaryOperator.NotLike.name: {
1067                 string pattern = castToString(rightValue);
1068                 string input = castToString(left.getAttributes().get(SQLEvalVisitor.EVAL_VALUE));
1069                 bool matchResult = !(like(input, pattern).booleanValue);
1070                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE,new Boolean(matchResult));
1071                 break;
1072             }
1073             case SQLBinaryOperator.Concat.name: {
1074                 string result = (cast(Object)(leftValue)).toString() ~ (cast(Object)(rightValue)).toString();
1075                 x.putAttribute(SQLEvalVisitor.EVAL_VALUE, new String(result));
1076                 break;
1077             }
1078             case SQLBinaryOperator.BooleanAnd.name:
1079             {
1080             	bool first = eq(leftValue, Boolean.TRUE).booleanValue;
1081             	bool second = eq(rightValue, Boolean.TRUE).booleanValue;
1082             	x.putAttribute(SQLEvalVisitor.EVAL_VALUE, new Boolean(first&&second));
1083             	break;
1084             }
1085             case SQLBinaryOperator.BooleanOr.name:
1086             {
1087             	bool first = eq(leftValue, Boolean.TRUE).booleanValue;
1088             	bool second = eq(rightValue, Boolean.TRUE).booleanValue;
1089             	x.putAttribute(SQLEvalVisitor.EVAL_VALUE, new Boolean(first||second));
1090             	break;
1091             }
1092             default:
1093                 break;
1094         }
1095 
1096         return false;
1097     }
1098 
1099     //@SuppressWarnings("rawtypes")
1100     private static Object processValue(Object value) {
1101         if (cast(List!Object)(value) !is null) {
1102             List!Object list = cast(List!Object) value;
1103             if (list.size() == 1) {
1104                 return processValue(list.get(0));
1105             }
1106          } //else if (cast(Date)(value) !is null) {
1107         //     return (cast(Date) value).getTime();
1108         // }//@gxc
1109         return value;
1110     }
1111 
1112     private static bool isAlwayTrueLikePattern(SQLExpr x) {
1113         if (cast(SQLCharExpr)(x) !is null) {
1114             string text = (cast(SQLCharExpr) x).getText().value();
1115 
1116             if (text.length > 0) {
1117                 foreach(char ch ; text) {
1118                     if (ch != '%') {
1119                         return false;
1120                     }
1121                 }
1122                 return true;
1123             }
1124         }
1125         return false;
1126     }
1127 
1128     public static bool visit(SQLEvalVisitor visitor, SQLNumericLiteralExpr x) {
1129         x.getAttributes().put(SQLEvalVisitor.EVAL_VALUE, cast(Object)(x.getNumber()));
1130         return false;
1131     }
1132 
1133     public static bool visit(SQLEvalVisitor visitor, SQLVariantRefExpr x) {
1134         if (!("?" == x.getName())) {
1135             return false;
1136         }
1137 
1138         Map!(string, Object) attributes = x.getAttributes();
1139 
1140         int varIndex = x.getIndex();
1141 
1142         if (varIndex != -1 && visitor.getParameters().size() > varIndex) {
1143             bool containsValue = attributes.containsKey(SQLEvalVisitor.EVAL_VALUE);
1144             if (!containsValue) {
1145                 Object value = visitor.getParameters().get(varIndex);
1146                 if (value is null) {
1147                     value = cast(Object)(SQLEvalVisitor.EVAL_VALUE_NULL);
1148                 }
1149                 attributes.put(SQLEvalVisitor.EVAL_VALUE, value);
1150             }
1151         }
1152 
1153         return false;
1154     }
1155 
1156     public static Boolean castToBoolean(Object val) {
1157         if (val is null) {
1158             return null;
1159         }
1160 
1161         if (val == SQLEvalVisitor.EVAL_VALUE_NULL) {
1162             return null;
1163         }
1164 
1165         if (cast(Boolean)(val) !is null) {
1166             return cast(Boolean) val;
1167         }
1168 
1169         if (cast(Number)(val) !is null) {
1170             return new Boolean((cast(Number) val).intValue() > 0);
1171         }
1172 
1173         if (cast(String)(val) !is null) {
1174             if ("1" == (cast(String)(val)).value() || equalsIgnoreCase("true",(cast(String) val).value())) {
1175                 return new Boolean(true);
1176             }
1177 
1178             return new Boolean(false);
1179         }
1180 
1181         throw new Exception(typeid(val).name ~ " not supported.");
1182     }
1183 
1184     public static string castToString(Object val) {
1185         Object value = val;
1186 
1187         if (value is null) {
1188             return null;
1189         }
1190 
1191         return (cast(Object)(value)).toString();
1192     }
1193 
1194     public static Byte castToByte(Object val) {
1195         if (val is null) {
1196             return null;
1197         }
1198 
1199         if (cast(Byte)(val) !is null) {
1200             return cast(Byte) val;
1201         }
1202 
1203         if (cast(String)(val) !is null) {
1204             return new Byte(Byte.parseByte((cast(String) val).value()));
1205         }
1206 
1207         return new Byte((cast(Number) val).byteValue());
1208     }
1209 
1210     public static Short castToShort(Object val) {
1211         if (val is null || val == SQLEvalVisitor.EVAL_VALUE_NULL) {
1212             return null;
1213         }
1214 
1215         if (cast(Short)(val) !is null) {
1216             return cast(Short) val;
1217         }
1218 
1219         if (cast(String)(val) !is null) {
1220             return new Short(Short.parseShort((cast(String) val).value()));
1221         }
1222 
1223         return new Short((cast(Number) val).shortValue());
1224     }
1225 
1226     //@SuppressWarnings("rawtypes")
1227     public static Integer castToInteger(Object val) {
1228         if (val is null) {
1229             return null;
1230         }
1231 
1232         if (cast(Integer)(val) !is null) {
1233             return cast(Integer) val;
1234         }
1235 
1236         if (cast(String)(val) !is null) {
1237             return new Integer(Integer.parseInt((cast(String) val).value()));
1238         }
1239 
1240         if (cast(List!Object)(val) !is null) {
1241             List!Object list = cast(List!Object) val;
1242             if (list.size() == 1) {
1243                 return castToInteger(list.get(0));
1244             }
1245         }
1246 
1247         if (cast(Boolean)(val) !is null) {
1248             if ((cast(Boolean) val).booleanValue()) {
1249                 return new Integer(1);
1250             } else {
1251                 return new Integer(0);
1252             }
1253         }
1254 
1255         if (cast(Number)(val) !is null) {
1256             return new Integer((cast(Number) val).intValue());
1257         }
1258 
1259         throw new Exception("cast error");
1260     }
1261 
1262     //@SuppressWarnings("rawtypes")
1263     public static Long castToLong(Object val) {
1264         if (val is null) {
1265             return null;
1266         }
1267 
1268         if (cast(Long)(val) !is null) {
1269             return cast(Long) val;
1270         }
1271 
1272         if (cast(String)(val) !is null) {
1273             return new Long(Long.parseLong((cast(String) val).value()));
1274         }
1275 
1276         if (cast(List!Object)(val) !is null) {
1277             List!Object list = cast(List!Object) val;
1278             if (list.size() == 1) {
1279                 return castToLong(list.get(0));
1280             }
1281         }
1282 
1283         if (cast(Boolean)(val) !is null) {
1284             if ((cast(Boolean) val).booleanValue()) {
1285                 return new Long(1L);
1286             } else {
1287                 return new Long(0L);
1288             }
1289         }
1290 
1291         return new Long((cast(Number) val).longValue());
1292     }
1293 
1294     public static Float castToFloat(Object val) {
1295         if (val is null || val == SQLEvalVisitor.EVAL_VALUE_NULL) {
1296             return null;
1297         }
1298 
1299         if (cast(Float)(val) !is null) {
1300             return cast(Float) val;
1301         }
1302 
1303         return new Float((cast(Number) val).floatValue());
1304     }
1305 
1306     public static Double castToDouble(Object val) {
1307         if (val is null || val == SQLEvalVisitor.EVAL_VALUE_NULL) {
1308             return null;
1309         }
1310 
1311         if (cast(Double)(val) !is null) {
1312             return cast(Double) val;
1313         }
1314 
1315         return new Double((cast(Number) val).doubleValue());
1316     }
1317 
1318     public static BigInteger castToBigInteger(Object val) {
1319         if (val is null) {
1320             return null;
1321         }
1322 
1323         if (cast(BigInteger)(val) !is null) {
1324             return cast(BigInteger) val;
1325         }
1326 
1327         if (cast(String)(val) !is null) {
1328             return new BigInteger((cast(String) val).value());
1329         }
1330 
1331         return BigInteger.valueOf((cast(Number) val).longValue());
1332     }
1333 
1334     public static Object castToNumber(string val) {
1335         if (val is null) {
1336             return null;
1337         }
1338 
1339         try {
1340             return new Byte(Byte.parseByte(val));
1341         } catch (Exception e) {
1342         }
1343 
1344         try {
1345             return new Short(Short.parseShort(val));
1346         } catch (Exception e) {
1347         }
1348 
1349         try {
1350             return new Integer(Integer.parseInt(val));
1351         } catch (Exception e) {
1352         }
1353 
1354         try {
1355             return new Long(Long.parseLong(val));
1356         } catch (Exception e) {
1357         }
1358 
1359         try {
1360             return new Float(Float.parseFloat(val));
1361         } catch (Exception e) {
1362         }
1363 
1364         try {
1365             return new Double(to!double(val));
1366         } catch (Exception e) {
1367         }
1368 
1369         try {
1370             return new BigInteger(val);
1371         } catch (Exception e) {
1372         }
1373 
1374         try {
1375             return new BigDecimal(val);
1376         } catch (Exception e) {
1377             return null;
1378         }
1379     }
1380 
1381     public static Date castToDate(Object val) {
1382         // if (val is null) {
1383         //     return null;
1384         // }
1385 
1386         // if (cast(Number)(val) !is null) {
1387         //     return new Date((cast(Number) val).longValue());
1388         // } //@gxc
1389 
1390         // if (cast(String)(val) !is null) {
1391         //     return castToDate(cast(String) val);
1392         // }
1393 
1394         throw new Exception("can cast to date");
1395     }
1396 
1397     public static Date castToDate(string text) {
1398 
1399         implementationMissing();
1400 
1401         return Date.init;
1402         // if (text is null || text.length == 0) {
1403         //     return null;
1404         // }
1405 
1406         // string format;
1407 
1408         // if (text.length == "yyyy-MM-dd".length) {
1409         //     format = "yyyy-MM-dd";
1410         // } else {
1411         //     format = "yyyy-MM-dd HH:mm:ss";
1412         // }
1413 
1414         // try {
1415         //     return new SimpleDateFormat(format).parse(text);
1416         // } catch (ParseException e) {
1417         //     throw new Exception("format : " ~ format ~ ", value : " ~ text, e);
1418         // }
1419     }
1420 
1421     public static BigDecimal castToDecimal(Object val) {
1422         if (val is null) {
1423             return null;
1424         }
1425 
1426         if (cast(BigDecimal)(val) !is null) {
1427             return cast(BigDecimal) val;
1428         }
1429 
1430         if (cast(String)(val) !is null) {
1431             return new BigDecimal((cast(String) val).value());
1432         }
1433 
1434         if (cast(Float)(val) !is null) {
1435             return new BigDecimal((cast(Float) val).floatValue);
1436         }
1437 
1438         if (cast(Double)(val) !is null) {
1439             return new BigDecimal((cast(Double) val).doubleValue);
1440         }
1441 
1442         return BigDecimal.valueOf((cast(Number) val).longValue());
1443     }
1444 
1445     public static Object rightShift(Object a, Object b) {
1446         if (a is null || b is null) {
1447             return null;
1448         }
1449 
1450         if (cast(Long)(a) !is null || cast(Long)(b) !is null) {
1451             return new Long(castToLong(a).longValue() >> castToLong(b).longValue());
1452         }
1453 
1454         return new Integer(castToInteger(a).intValue() >> castToInteger(b).intValue());
1455     }
1456 
1457     public static Object bitAnd(Object a, Object b) {
1458         if (a is null || b is null) {
1459             return null;
1460         }
1461 
1462         if(a == SQLEvalVisitor.EVAL_VALUE_NULL || b == SQLEvalVisitor.EVAL_VALUE_NULL) {
1463             return null;
1464         }
1465 
1466         if (cast(String)(a) !is null) {
1467             a = castToNumber((cast(String) a).value());
1468         }
1469 
1470         if (cast(String)(b) !is null) {
1471             b = castToNumber((cast(String) b).value());
1472         }
1473 
1474         if (cast(Long)(a) !is null || cast(Long)(b) !is null) {
1475             return new Long(castToLong(a).longValue() & castToLong(b).longValue());
1476         }
1477 
1478         return new Integer(castToInteger(a).intValue() & castToInteger(b).intValue());
1479     }
1480 
1481     public static Object bitOr(Object a, Object b) {
1482         if (a is null || b is null) {
1483             return null;
1484         }
1485 
1486         if(a == SQLEvalVisitor.EVAL_VALUE_NULL || b == SQLEvalVisitor.EVAL_VALUE_NULL) {
1487             return null;
1488         }
1489 
1490         if (cast(String)(a) !is null) {
1491             a = castToNumber((cast(String) a).value());
1492         }
1493 
1494         if (cast(String)(b) !is null) {
1495             b = castToNumber((cast(String) b).value());
1496         }
1497 
1498         if (cast(Long)(a) !is null || cast(Long)(b) !is null) {
1499             return new Long(castToLong(a).longValue() | castToLong(b).longValue());
1500         }
1501 
1502         return new Integer(castToInteger(a).intValue() | castToInteger(b).intValue());
1503     }
1504 
1505     public static Object div(Object a, Object b) {
1506         if (a is null || b is null) {
1507             return null;
1508         }
1509 
1510         if(a == SQLEvalVisitor.EVAL_VALUE_NULL || b == SQLEvalVisitor.EVAL_VALUE_NULL) {
1511             return null;
1512         }
1513 
1514         if (cast(String)(a) !is null) {
1515             a = castToNumber((cast(String) a).value());
1516         }
1517 
1518         if (cast(String)(b) !is null) {
1519             b = castToNumber((cast(String) b).value());
1520         }
1521 
1522         if (cast(BigDecimal)(a) !is null || cast(BigDecimal)(b) !is null) {
1523             BigDecimal decimalA = castToDecimal(a);
1524             BigDecimal decimalB = castToDecimal(b);
1525             if (decimalB.scale() < decimalA.scale()) {
1526                 decimalB = decimalB.setScale(decimalA.scale());
1527             }
1528             try {
1529                 return decimalA.divide(decimalB);
1530             } catch (ArithmeticException ex) {
1531                 return decimalA.divide(decimalB, BigDecimal.ROUND_HALF_UP);
1532             }
1533         }
1534 
1535         if (cast(Double)(a) !is null || cast(Double)(b) !is null) {
1536             Double doubleA = castToDouble(a);
1537             Double doubleB = castToDouble(b);
1538             if (doubleA is null || doubleB is null) {
1539                 return null;
1540             }
1541             return new Double(doubleA.doubleValue / doubleB.doubleValue);
1542         }
1543 
1544         if (cast(Float)(a) !is null || cast(Float)(b) !is null) {
1545             Float floatA = castToFloat(a);
1546             Float floatB = castToFloat(b);
1547             if (floatA is null || floatB is null) {
1548                 return null;
1549             }
1550             return new Float(floatA.floatValue / floatB.floatValue);
1551         }
1552 
1553         if (cast(BigInteger)(a) !is null || cast(BigInteger)(b) !is null) {
1554             return castToBigInteger(a).divide(castToBigInteger(b));
1555         }
1556 
1557         if (cast(Long)(a) !is null || cast(Long)(b) !is null) {
1558             Long longA = castToLong(a);
1559             Long longB = castToLong(b);
1560             if (longB.longValue == 0) {
1561                 if (longA.longValue > 0) {
1562                     return new Double(Double.POSITIVE_INFINITY);
1563                 } else if (longA.longValue < 0) {
1564                     return new Double(Double.NEGATIVE_INFINITY);
1565                 } else {
1566                     return new Double(Double.NaN);
1567                 }
1568             }
1569             return new Long(longA.longValue / longB.longValue);
1570         }
1571 
1572         if (cast(Integer)(a) !is null || cast(Integer)(b) !is null) {
1573             Integer intA = castToInteger(a);
1574             Integer intB = castToInteger(b);
1575             if (intB.intValue == 0) {
1576                 if (intA.intValue > 0) {
1577                     return new Double(Double.POSITIVE_INFINITY);
1578                 } else if (intA.intValue < 0) {
1579                     return new Double(Double.NEGATIVE_INFINITY);
1580                 } else {
1581                     return new Double(Double.NaN);
1582                 }
1583             }
1584             return new Integer(intA.intValue / intB.intValue);
1585         }
1586 
1587         if (cast(Short)(a) !is null || cast(Short)(b) !is null) {
1588             return new Short(cast(short)(castToShort(a).shortValue / castToShort(b).shortValue));
1589         }
1590 
1591         if (cast(Byte)(a) !is null || cast(Byte)(b) !is null) {
1592             return new Byte(cast(byte)(castToByte(a).byteValue / castToByte(b).byteValue));
1593         }
1594 
1595         throw new Exception(typeid(a).name ~ " and " ~ typeid(b).name ~ " not supported.");
1596     }
1597 
1598     public static Boolean gt(Object a, Object b) {
1599         if (a is null || a == SQLEvalVisitor.EVAL_VALUE_NULL) {
1600             return new Boolean(false);
1601         }
1602 
1603         if (b is null || a == SQLEvalVisitor.EVAL_VALUE_NULL) {
1604             return new Boolean(true);
1605         }
1606 
1607         if (cast(String)(a) !is null || cast(String)(b) !is null) {
1608             return new Boolean(castToString(a).compareTo(castToString(b)) > 0);
1609         }
1610 
1611         if (cast(BigDecimal)(a) !is null || cast(BigDecimal)(b) !is null) {
1612             // return new Boolean(castToDecimal(a).compareTo(castToDecimal(b)) > 0);//@gxc
1613         }
1614 
1615         if (cast(BigInteger)(a) !is null || cast(BigInteger)(b) !is null) {
1616             return new Boolean(castToBigInteger(a).compareTo(castToBigInteger(b)) > 0);
1617         }
1618 
1619         if (cast(Long)(a) !is null || cast(Long)(b) !is null) {
1620             return new Boolean(castToLong(a) > castToLong(b));
1621         }
1622 
1623         if (cast(Integer)(a) !is null || cast(Integer)(b) !is null) {
1624             return new Boolean(castToInteger(a) > castToInteger(b));
1625         }
1626 
1627         if (cast(Short)(a) !is null || cast(Short)(b) !is null) {
1628             return new Boolean(castToShort(a) > castToShort(b));
1629         }
1630 
1631         if (cast(Byte)(a) !is null || cast(Byte)(b) !is null) {
1632             return new Boolean(castToByte(a) > castToByte(b));
1633         }
1634 
1635         //@gxc
1636         // if (cast(Date)(a) !is null || cast(Date)(b) !is null) {
1637         //     Date d1 = castToDate(a);
1638         //     Date d2 = castToDate(b);
1639 
1640         //     if (d1 == d2) {
1641         //         return new Boolean(false);
1642         //     }
1643 
1644         //     if (d1 is null) {
1645         //         return new Boolean(false);
1646         //     }
1647 
1648         //     if (d2 is null) {
1649         //         return new Boolean(true);
1650         //     }
1651 
1652         //     return new Boolean(d1.compareTo(d2) > 0);
1653         // }
1654 
1655         throw new Exception(typeid(a).name ~ " and " ~ typeid(b).name ~ " not supported.");
1656     }
1657 
1658     public static Boolean gteq(Object a, Object b) {
1659         if (eq(a, b).booleanValue) {
1660             return new Boolean(true);
1661         }
1662 
1663         return gt(a, b);
1664     }
1665 
1666     public static Boolean lt(Object a, Object b) {
1667         if (a is null) {
1668             return new Boolean(true);
1669         }
1670 
1671         if (b is null) {
1672             return new Boolean(false);
1673         }
1674 
1675         if (cast(String)(a) !is null || cast(String)(b) !is null) {
1676             return new Boolean((castToString(a)).compareTo(castToString(b)) < 0);
1677         }
1678 
1679         if (cast(BigDecimal)(a) !is null || cast(BigDecimal)(b) !is null) {
1680             // return new Boolean(castToDecimal(a).compareTo(castToDecimal(b)) < 0);//@gxc
1681         }
1682 
1683         if (cast(BigInteger)(a) !is null || cast(BigInteger)(b) !is null) {
1684             return new Boolean(castToBigInteger(a).compareTo(castToBigInteger(b)) < 0);
1685         }
1686 
1687         if (cast(Long)(a) !is null || cast(Long)(b) !is null) {
1688             return new Boolean(castToLong(a) < castToLong(b));
1689         }
1690 
1691         if (cast(Integer)(a) !is null || cast(Integer)(b) !is null) {
1692             Integer intA = castToInteger(a);
1693             Integer intB = castToInteger(b);
1694             return new Boolean(intA < intB);
1695         }
1696 
1697         if (cast(Short)(a) !is null || cast(Short)(b) !is null) {
1698             return new Boolean(castToShort(a) < castToShort(b));
1699         }
1700 
1701         if (cast(Byte)(a) !is null || cast(Byte)(b) !is null) {
1702             return new Boolean(castToByte(a) < castToByte(b));
1703         }
1704 
1705         // if (cast(Date)(a) !is null || cast(Date)(b) !is null) {
1706         //     Date d1 = castToDate(a);
1707         //     Date d2 = castToDate(b);
1708 
1709         //     if (d1 == d2) {
1710         //         return new Boolean(false);
1711         //     }
1712 
1713         //     if (d1 is null) {
1714         //         return new Boolean(true);
1715         //     }
1716 
1717         //     if (d2 is null) {
1718         //         return new Boolean(false);
1719         //     }
1720 
1721         //     return new Boolean(d1.compareTo(d2) < 0);
1722         // }//@gxc
1723 
1724         throw new Exception(typeid(a).name ~ " and " ~ typeid(b).name ~ " not supported.");
1725     }
1726 
1727     public static Boolean lteq(Object a, Object b) {
1728         if (eq(a, b).booleanValue) {
1729             return new Boolean(true);
1730         }
1731 
1732         return lt(a, b);
1733     }
1734 
1735     public static Boolean eq(Object a, Object b) {
1736         if (a == b) {
1737             return new Boolean(true);
1738         }
1739 
1740         if (a is null || b is null) {
1741             return new Boolean(false);
1742         }
1743 
1744         if (a == SQLEvalVisitor.EVAL_VALUE_NULL || b == SQLEvalVisitor.EVAL_VALUE_NULL) {
1745             return new Boolean(false);
1746         }
1747 
1748         if (a.opEquals(b)) {
1749             return new Boolean(true);
1750         }
1751 
1752         if (cast(String)(a) !is null || cast(String)(b) !is null) {
1753             return new Boolean(castToString(a) == (castToString(b)));
1754         }
1755 
1756         if (cast(BigDecimal)(a) !is null || cast(BigDecimal)(b) !is null) {
1757             // return new Boolean(castToDecimal(a).compareTo(castToDecimal(b)) == 0);//@gxc
1758         }
1759 
1760         if (cast(BigInteger)(a) !is null || cast(BigInteger)(b) !is null) {
1761             return new Boolean(castToBigInteger(a).compareTo(castToBigInteger(b)) == 0);
1762         }
1763 
1764         if (cast(Long)(a) !is null || cast(Long)(b) !is null) {
1765             return new Boolean(castToLong(a).opEquals(cast(Object)castToLong(b)));
1766         }
1767 
1768         if (cast(Integer)(a) !is null || cast(Integer)(b) !is null) {
1769             Integer inta = castToInteger(a);
1770             Integer intb = castToInteger(b);
1771             if (inta is null || intb is null) {
1772                 return new Boolean(false);
1773             }
1774             return new Boolean(inta.opEquals(cast(Object)intb));
1775         }
1776 
1777         if (cast(Short)(a) !is null || cast(Short)(b) !is null) {
1778             return new Boolean(castToShort(a).opEquals(cast(Object)castToShort(b)));
1779         }
1780 
1781         if (cast(Boolean)(a) !is null || cast(Boolean)(b) !is null) {
1782             return new Boolean(castToBoolean(a).opEquals(castToBoolean(b)));
1783         }
1784 
1785         if (cast(Byte)(a) !is null || cast(Byte)(b) !is null) {
1786             return new Boolean(castToByte(a).opEquals(cast(Object)castToByte(b)));
1787         }
1788 
1789         //@gxc
1790         // if (cast(Date)(a) !is null || cast(Date)(b) !is null) {
1791         //     Date d1 = castToDate(a);
1792         //     Date d2 = castToDate(b);
1793 
1794         //     if (d1 == d2) {
1795         //         return new Boolean(true);
1796         //     }
1797 
1798         //     if (d1 is null || d2 is null) {
1799         //         return new Boolean(false);
1800         //     }
1801 
1802         //     return new Boolean(d1.opEquals(d2));
1803         // }
1804 
1805         throw new Exception(typeid(a).name ~ " and " ~ typeid(b).name ~ " not supported.");
1806     }
1807 
1808     public static Object add(Object a, Object b) {
1809         if (a is null) {
1810             return b;
1811         }
1812 
1813         if (b is null) {
1814             return a;
1815         }
1816 
1817         if (a == SQLEvalVisitor.EVAL_VALUE_NULL || b == SQLEvalVisitor.EVAL_VALUE_NULL) {
1818             return cast(Object)SQLEvalVisitor.EVAL_VALUE_NULL;
1819         }
1820 
1821         if (cast(String)(a) !is null && !(cast(String)(b) !is null)) {
1822             a = castToNumber((cast(String) a).value());
1823         }
1824 
1825         if (cast(String)(b) !is null && !(cast(String)(a) !is null)) {
1826             b = castToNumber((cast(String) b).value());
1827         }
1828 
1829         if (cast(BigDecimal)(a) !is null || cast(BigDecimal)(b) !is null) {
1830             return castToDecimal(a).add(castToDecimal(b));
1831         }
1832 
1833         if (cast(BigInteger)(a) !is null || cast(BigInteger)(b) !is null) {
1834             return castToBigInteger(a).add(castToBigInteger(b));
1835         }
1836 
1837         if (cast(Double)(a) !is null || cast(Double)(b) !is null) {
1838             return new Double(castToDouble(a).doubleValue + castToDouble(b).doubleValue);
1839         }
1840 
1841         if (cast(Float)(a) !is null || cast(Float)(b) !is null) {
1842             return new Float(castToFloat(a).floatValue + castToFloat(b).floatValue);
1843         }
1844 
1845         if (cast(Long)(a) !is null || cast(Long)(b) !is null) {
1846             return new Long(castToLong(a).longValue + castToLong(b).longValue);
1847         }
1848 
1849         if (cast(Integer)(a) !is null || cast(Integer)(b) !is null) {
1850             return new Integer(castToInteger(a).intValue+ castToInteger(b).intValue);
1851         }
1852 
1853         if (cast(Short)(a) !is null || cast(Short)(b) !is null) {
1854             return new Short(cast(short)(castToShort(a).shortValue + castToShort(b).shortValue));
1855         }
1856 
1857         if (cast(Boolean)(a) !is null || cast(Boolean)(b) !is null) {
1858             int aI = 0, bI = 0;
1859             if (castToBoolean(a)) aI = 1;
1860             if (castToBoolean(b)) bI = 1;
1861             return new Integer(aI + bI);
1862         }
1863 
1864         if (cast(Byte)(a) !is null || cast(Byte)(b) !is null) {
1865             return new Byte(cast(byte)(castToByte(a).byteValue + castToByte(b).byteValue));
1866         }
1867 
1868         if (cast(String)(a) !is null && cast(String)(b) !is null) {
1869             return new String(castToString(a) ~ castToString(b));
1870         }
1871 
1872         throw new Exception(typeid(a).name ~ " and " ~ typeid(b).name ~ " not supported.");
1873     }
1874 
1875     public static Object sub(Object a, Object b) {
1876         if (a is null) {
1877             return null;
1878         }
1879 
1880         if (b is null) {
1881             return a;
1882         }
1883 
1884         if (a == SQLEvalVisitor.EVAL_VALUE_NULL || b == SQLEvalVisitor.EVAL_VALUE_NULL) {
1885             return cast(Object)SQLEvalVisitor.EVAL_VALUE_NULL;
1886         }
1887 
1888         // if (cast(Date)(a) !is null || cast(Date)(b) !is null) {
1889         //     return cast(Object)(SQLEvalVisitor.EVAL_ERROR);
1890         // }//@gxc
1891 
1892         if (cast(String)(a) !is null) {
1893             a = castToNumber((cast(String) a).value());
1894         }
1895 
1896         if (cast(String)(b) !is null) {
1897             b = castToNumber((cast(String) b).value());
1898         }
1899 
1900         if (cast(BigDecimal)(a) !is null || cast(BigDecimal)(b) !is null) {
1901             return castToDecimal(a).subtract(castToDecimal(b));
1902         }
1903 
1904         if (cast(BigInteger)(a) !is null || cast(BigInteger)(b) !is null) {
1905             return castToBigInteger(a).subtract(castToBigInteger(b));
1906         }
1907 
1908         if (cast(Double)(a) !is null || cast(Double)(b) !is null) {
1909             return new Double(castToDouble(a).doubleValue - castToDouble(b).doubleValue);
1910         }
1911 
1912         if (cast(Float)(a) !is null || cast(Float)(b) !is null) {
1913             return new Float(castToFloat(a).floatValue - castToFloat(b).floatValue);
1914         }
1915 
1916         if (cast(Long)(a) !is null || cast(Long)(b) !is null) {
1917             return new Long(castToLong(a).longValue - castToLong(b).longValue);
1918         }
1919 
1920         if (cast(Integer)(a) !is null || cast(Integer)(b) !is null) {
1921             return new Integer(castToInteger(a).intValue - castToInteger(b).intValue);
1922         }
1923 
1924         if (cast(Short)(a) !is null || cast(Short)(b) !is null) {
1925             return new Short(cast(short)(castToShort(a).shortValue - castToShort(b).shortValue));
1926         }
1927 
1928         if (cast(Boolean)(a) !is null || cast(Boolean)(b) !is null) {
1929             int aI = 0, bI = 0;
1930             if (castToBoolean(a)) aI = 1;
1931             if (castToBoolean(b)) bI = 1;
1932             return new Boolean(cast(long) (aI - bI));
1933         }
1934 
1935         if (cast(Byte)(a) !is null || cast(Byte)(b) !is null) {
1936             return new Byte(cast(byte)(castToByte(a).byteValue - castToByte(b).byteValue));
1937         }
1938 
1939         // return cast(Object)(SQLEvalVisitor.EVAL_ERROR);
1940         throw new Exception(typeid(a).name ~ " and " ~ typeid(b).name ~ " not supported.");
1941     }
1942 
1943     public static Object multi(Object a, Object b) {
1944         if (a is null || b is null) {
1945             return null;
1946         }
1947 
1948         if (cast(String)(a) !is null) {
1949             a = castToNumber((cast(String) a).value());
1950         }
1951 
1952         if (cast(String)(b) !is null) {
1953             b = castToNumber((cast(String) b).value());
1954         }
1955 
1956         if (cast(BigDecimal)(a) !is null || cast(BigDecimal)(b) !is null) {
1957             return castToDecimal(a).multiply(castToDecimal(b));
1958         }
1959 
1960         if (cast(BigInteger)(a) !is null || cast(BigInteger)(b) !is null) {
1961             return castToBigInteger(a).multiply(castToBigInteger(b));
1962         }
1963 
1964         if (cast(Double)(a) !is null || cast(Double)(b) !is null) {
1965             return new Double(castToDouble(a).doubleValue * castToDouble(b).doubleValue);
1966         }
1967 
1968         if (cast(Float)(a) !is null || cast(Float)(b) !is null) {
1969             return new Float(castToFloat(a).floatValue * castToFloat(b).floatValue);
1970         }
1971 
1972         if (cast(Long)(a) !is null || cast(Long)(b) !is null) {
1973             return new Long(castToLong(a).longValue * castToLong(b).longValue);
1974         }
1975 
1976         if (cast(Integer)(a) !is null || cast(Integer)(b) !is null) {
1977             return new Integer(castToInteger(a).intValue * castToInteger(b).intValue);
1978         }
1979 
1980         if (cast(Short)(a) !is null || cast(Short)(b) !is null) {
1981             Short shortA = castToShort(a);
1982             Short shortB = castToShort(b);
1983 
1984             if (shortA is null || shortB is null) {
1985                 return  null;
1986             }
1987 
1988             return new Short(cast(short)(shortA.shortValue * shortB.shortValue));
1989         }
1990 
1991         if (cast(Byte)(a) !is null || cast(Byte)(b) !is null) {
1992             return new Byte(cast(byte)(castToByte(a).byteValue * castToByte(b).byteValue));
1993         }
1994 
1995         throw new Exception(typeid(a).name ~ " and " ~ typeid(b).name ~ " not supported.");
1996     }
1997 
1998     public static Boolean like(string input, string pattern) {
1999         if (pattern is null) {
2000             throw new Exception("pattern is null");
2001         }
2002 
2003         StringBuilder regexprBuilder = new StringBuilder(pattern.length + 4);
2004 
2005          int STAT_NOTSET = 0;
2006          int STAT_RANGE = 1;
2007          int STAT_LITERAL = 2;
2008 
2009         int stat = STAT_NOTSET;
2010 
2011         int blockStart = -1;
2012         for (int i = 0; i < pattern.length; ++i) {
2013             char ch = charAt(pattern, i);
2014 
2015             if (stat == STAT_LITERAL //
2016                 && (ch == '%' || ch == '_' || ch == '[')) {
2017                 string block = pattern.substring(blockStart, i);
2018                 regexprBuilder.append("\\Q");
2019                 regexprBuilder.append(block);
2020                 regexprBuilder.append("\\E");
2021                 blockStart = -1;
2022                 stat = STAT_NOTSET;
2023             }
2024 
2025             if (ch == '%') {
2026                 regexprBuilder.append("");
2027             } else if (ch == '_') {
2028                 regexprBuilder.append('.');
2029             } else if (ch == '[') {
2030                 if (stat == STAT_RANGE) {
2031                     throw new Exception("illegal pattern : " ~ pattern);
2032                 }
2033                 stat = STAT_RANGE;
2034                 blockStart = i;
2035             } else if (ch == ']') {
2036                 if (stat != STAT_RANGE) {
2037                     throw new Exception("illegal pattern : " ~ pattern);
2038                 }
2039                 string block = pattern.substring(blockStart, i + 1);
2040                 regexprBuilder.append(block);
2041 
2042                 blockStart = -1;
2043             } else {
2044                 if (stat == STAT_NOTSET) {
2045                     stat = STAT_LITERAL;
2046                     blockStart = i;
2047                 }
2048 
2049                 if (stat == STAT_LITERAL && i == pattern.length - 1) {
2050                     string block = pattern.substring(blockStart, i + 1);
2051                     regexprBuilder.append("\\Q");
2052                     regexprBuilder.append(block);
2053                     regexprBuilder.append("\\E");
2054                 }
2055             }
2056         }
2057         if ("%" == (pattern) || "%%" == (pattern)) {
2058             return new Boolean(true);
2059         }
2060 
2061         string regexpr = (cast(Object)(regexprBuilder)).toString();
2062         return new Boolean(Utils.matches(regexpr, input));
2063     }
2064 
2065     public static bool visit(SQLEvalVisitor visitor, SQLIdentifierExpr x) {
2066         x.putAttribute(SQLEvalVisitor.EVAL_EXPR, x);
2067         return false;
2068     }
2069 }