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.parser.SQLExprParser;
17 
18 import hunt.collection;
19 
20 import hunt.sql.SQLUtils;
21 import hunt.sql.ast;
22 import hunt.sql.ast.expr;
23 import hunt.sql.ast.statement;
24 // import hunt.sql.dialect.oracle.ast.expr.OracleArgumentExpr;
25 import hunt.sql.dialect.postgresql.ast.expr.PGTypeCastExpr;
26 import hunt.sql.util.FnvHash;
27 import hunt.sql.util.DBType;
28 import hunt.sql.parser.SQLParser;
29 import hunt.sql.parser.Lexer;
30 import hunt.sql.parser.SQLSelectParser;
31 import hunt.sql.parser.Token;
32 import hunt.sql.ast.SQLObject;
33 import hunt.sql.util.Utils;
34 import hunt.Number;
35 import hunt.Integer;
36 import hunt.text;
37 import hunt.Boolean;
38 import hunt.Long;
39 import hunt.sql.parser.ParserException;
40 import hunt.String;
41 import std.algorithm.searching;
42 import hunt.sql.parser.SQLParserFeature;
43 import hunt.Exceptions;
44 import hunt.math;
45 
46 import hunt.logging;
47 
48 import std.concurrency : initOnce;
49 
50 public class SQLExprParser : SQLParser {
51 
52     private enum string[] strings = [ "AVG", "COUNT", "MAX", "MIN", "STDDEV", "SUM" ];
53     
54     static string[] AGGREGATE_FUNCTIONS() {
55         __gshared string[] inst;
56         return initOnce!inst({
57             long[] codes = AGGREGATE_FUNCTIONS_CODES();
58             string[] r = new string[codes.length];
59             
60             foreach(string str ; strings) {
61                 long hash = FnvHash.fnv1a_64_lower(str);
62                 int index = search(codes, hash);
63                 r[index] = str;
64             }
65             return r;
66         }());
67     }
68 
69     static long[] AGGREGATE_FUNCTIONS_CODES() {
70         __gshared long[] inst;
71         return initOnce!inst({
72             return FnvHash.fnv1a_64_lower(strings, true);
73         }());
74     }
75 
76 
77     // public   static string[] AGGREGATE_FUNCTIONS =[];
78 
79     // public   static long[] AGGREGATE_FUNCTIONS_CODES = [];
80 
81     // static this(){
82     //     string[] strings = [ "AVG", "COUNT", "MAX", "MIN", "STDDEV", "SUM" ];
83     //     AGGREGATE_FUNCTIONS_CODES = FnvHash.fnv1a_64_lower(strings, true);
84     //     AGGREGATE_FUNCTIONS = new string[AGGREGATE_FUNCTIONS_CODES.length];
85     //     foreach(string str ; strings) {
86     //         long hash = FnvHash.fnv1a_64_lower(str);
87     //         int index = search(AGGREGATE_FUNCTIONS_CODES, hash);
88     //         AGGREGATE_FUNCTIONS[index] = str;
89     //     }
90     // }
91 
92     protected string[]           aggregateFunctions;
93 
94     protected long[]             aggregateFunctionHashCodes;
95 
96     public this(string sql){
97         import std.stdio;
98         aggregateFunctions  = AGGREGATE_FUNCTIONS;
99          aggregateFunctionHashCodes = AGGREGATE_FUNCTIONS_CODES;
100         super(sql);
101     }
102 
103     public this(string sql, string dbType){
104         aggregateFunctions  = AGGREGATE_FUNCTIONS;
105          aggregateFunctionHashCodes = AGGREGATE_FUNCTIONS_CODES;
106         super(sql, dbType);
107     }
108 
109     public this(Lexer lexer){
110         aggregateFunctions  = AGGREGATE_FUNCTIONS;
111          aggregateFunctionHashCodes = AGGREGATE_FUNCTIONS_CODES;
112         super(lexer);
113     }
114 
115     public this(Lexer lexer, string dbType){
116         aggregateFunctions  = AGGREGATE_FUNCTIONS;
117          aggregateFunctionHashCodes = AGGREGATE_FUNCTIONS_CODES;
118         super(lexer, dbType);
119     }
120 
121     public SQLExpr expr() {
122         if (lexer.token == Token.STAR) {
123             lexer.nextToken();
124 
125             SQLExpr expr = new SQLAllColumnExpr();
126 
127             if (lexer.token == Token.DOT) {
128                 lexer.nextToken();
129                 accept(Token.STAR);
130                 return new SQLPropertyExpr(expr, "*");
131             }
132 
133             return expr;
134         }
135 
136         SQLExpr expr = primary();
137 
138         Token token = lexer.token;
139         if (token == Token.COMMA) {
140             return expr;
141         } else if (token == Token.EQ) {
142             expr = relationalRest(expr);
143             expr = andRest(expr);
144             expr = xorRest(expr);
145             expr = orRest(expr);
146             return expr;
147         } else {
148             return exprRest(expr);
149         }
150     }
151 
152     public SQLExpr exprRest(SQLExpr expr) {
153         expr = bitXorRest(expr);
154         expr = multiplicativeRest(expr);
155         expr = additiveRest(expr);
156         expr = shiftRest(expr);
157         expr = bitAndRest(expr);
158         expr = bitOrRest(expr);
159         expr = inRest(expr);
160         expr = relationalRest(expr);
161 //        expr = equalityRest(expr);
162         expr = andRest(expr);
163         expr = xorRest(expr);
164         expr = orRest(expr);
165 
166         return expr;
167     }
168 
169     public  SQLExpr bitXor() {
170         SQLExpr expr = primary();
171         return bitXorRest(expr);
172     }
173 
174     public SQLExpr bitXorRest(SQLExpr expr) {
175         Token token = lexer.token;
176         switch (token) {
177             case Token.CARET: {
178                 lexer.nextToken();
179                 SQLBinaryOperator op;
180                 if (lexer.token == Token.EQ) {
181                     lexer.nextToken();
182                     op = SQLBinaryOperator.BitwiseXorEQ;
183                 } else {
184                     op = SQLBinaryOperator.BitwiseXor;
185                 }
186                 SQLExpr rightExp = primary();
187                 expr = new SQLBinaryOpExpr(expr, op, rightExp, dbType);
188                 expr = bitXorRest(expr);
189                 break;
190             }
191             case Token.SUBGT:{
192                 lexer.nextToken();
193                 SQLExpr rightExp = primary();
194                 expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.SubGt, rightExp, dbType);
195                 expr = bitXorRest(expr);
196                 break;
197             }
198             case Token.LT_SUB_GT: {
199                 lexer.nextToken();
200                 SQLExpr rightExp = primary();
201                 expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.PG_ST_DISTANCE, rightExp, dbType);
202                 expr = bitXorRest(expr);
203                 break;
204             }
205             case Token.SUBGTGT:{
206                 lexer.nextToken();
207                 SQLExpr rightExp = primary();
208                 expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.SubGtGt, rightExp, dbType);
209                 expr = bitXorRest(expr);
210                 break;
211             }
212             case Token.POUNDGT: {
213                 lexer.nextToken();
214                 SQLExpr rightExp = primary();
215                 expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.PoundGt, rightExp, dbType);
216                 expr = bitXorRest(expr);
217                 break;
218             }
219             case Token.POUNDGTGT: {
220                 lexer.nextToken();
221                 SQLExpr rightExp = primary();
222                 expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.PoundGtGt, rightExp, dbType);
223                 expr = bitXorRest(expr);
224                 break;
225             }
226             case Token.QUESQUES: {
227                 lexer.nextToken();
228                 SQLExpr rightExp = primary();
229                 expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.QuesQues, rightExp, dbType);
230                 expr = bitXorRest(expr);
231                 break;
232             }
233             case Token.QUESBAR: {
234                 lexer.nextToken();
235                 SQLExpr rightExp = primary();
236                 expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.QuesBar, rightExp, dbType);
237                 expr = bitXorRest(expr);
238                 break;
239             }
240             case Token.QUESAMP: {
241                 lexer.nextToken();
242                 SQLExpr rightExp = primary();
243                 expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.QuesAmp, rightExp, dbType);
244                 expr = bitXorRest(expr);
245                 break;
246             }
247 
248             default:
249                 break;
250         }
251 
252 
253         return expr;
254     }
255 
256     public  SQLExpr multiplicative() {
257         SQLExpr expr = bitXor();
258         return multiplicativeRest(expr);
259     }
260 
261     public SQLExpr multiplicativeRest(SQLExpr expr) {
262          Token token = lexer.token;
263         if (token == Token.STAR) {
264             lexer.nextToken();
265             SQLExpr rightExp = bitXor();
266             expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Multiply, rightExp, getDbType());
267             expr = multiplicativeRest(expr);
268         } else if (token == Token.SLASH) {
269             lexer.nextToken();
270             SQLExpr rightExp = bitXor();
271             expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Divide, rightExp, getDbType());
272             expr = multiplicativeRest(expr);
273         } else if (token == Token.PERCENT) {
274             lexer.nextToken();
275             SQLExpr rightExp = bitXor();
276             expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Modulus, rightExp, getDbType());
277             expr = multiplicativeRest(expr);
278         } else if (token == Token.DIV) {
279             lexer.nextToken();
280             SQLExpr rightExp = bitXor();
281             expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.DIV, rightExp, getDbType());
282             expr = multiplicativeRest(expr);
283         } else if (lexer.identifierEquals(FnvHash.Constants.MOD) || lexer.token == Token.MOD) {
284             Lexer.SavePoint savePoint = lexer.mark();
285             lexer.nextToken();
286 
287             if (lexer.token == Token.COMMA || lexer.token == Token.EOF) {
288                 lexer.reset(savePoint);
289                 return expr;
290             }
291 
292             SQLExpr rightExp = bitXor();
293 
294             expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Modulus, rightExp, dbType);
295 
296             expr = multiplicativeRest(expr);
297         }
298         return expr;
299     }
300     
301     public SQLIntegerExpr integerExpr() {
302         SQLIntegerExpr intExpr = new SQLIntegerExpr(lexer.integerValue());
303         accept(Token.LITERAL_INT);
304         return intExpr;
305     }
306 
307     public int parseIntValue() {
308         if (lexer.token == Token.LITERAL_INT) {
309             Number number = this.lexer.integerValue();
310             int intVal = (cast(Integer) number).intValue();
311             lexer.nextToken();
312             return intVal;
313         } else {
314             throw new ParserException("not int. " ~ lexer.info());
315         }
316     }
317 
318     public SQLExpr primary() {
319         List!(string) beforeComments = null;
320         if (lexer.isKeepComments() && lexer.hasComment()) {
321             beforeComments = lexer.readAndResetComments();
322         }
323 
324         SQLExpr sqlExpr = null;
325 
326          Token tok = lexer.token;
327 
328         switch (tok) {
329             case Token.LPAREN:
330                 lexer.nextToken();
331  
332                 sqlExpr = this.expr();
333                 if (lexer.token == Token.COMMA) {
334                     SQLListExpr listExpr = new SQLListExpr();
335                     listExpr.addItem(sqlExpr);
336                     do {
337                         lexer.nextToken();
338                         listExpr.addItem(this.expr());
339                     } while (lexer.token == Token.COMMA);
340 
341                     sqlExpr = listExpr;
342                 }
343 
344                 if (cast(SQLBinaryOpExpr)(sqlExpr) !is null) {
345                     (cast(SQLBinaryOpExpr) sqlExpr).setBracket(true);
346                 }
347                 
348                 accept(Token.RPAREN);
349 
350                 if (lexer.token == Token.UNION && cast(SQLQueryExpr)(sqlExpr) !is null) {
351                     SQLQueryExpr queryExpr = cast(SQLQueryExpr) sqlExpr;
352 
353                     SQLSelectQuery query = this.createSelectParser().queryRest(queryExpr.getSubQuery().getQuery());
354                     queryExpr.getSubQuery().setQuery(query);
355                 }
356                 break;
357             case Token.INSERT:
358                 lexer.nextToken();
359                 if (lexer.token != Token.LPAREN) {
360                     throw new ParserException("syntax error. " ~ lexer.info());
361                 }
362                 sqlExpr = new SQLIdentifierExpr("INSERT");
363                 break;
364             case Token.IDENTIFIER:
365                 string ident = lexer.stringVal();
366                 long hash_lower = lexer.hash_lower;
367                 lexer.nextToken();
368 
369                 if (hash_lower == FnvHash.Constants.DATE
370                         && (lexer.token == Token.LITERAL_CHARS || lexer.token == Token.VARIANT)
371                         && (DBType.ORACLE.name == (dbType)
372                             || DBType.POSTGRESQL.name == (dbType)
373                             || DBType.MYSQL.name == (dbType))) {
374                     SQLExpr literal = this.primary();
375                     SQLDateExpr dateExpr = new SQLDateExpr();
376                     dateExpr.setLiteral(literal);
377                     sqlExpr = dateExpr;
378                 } else if (hash_lower == FnvHash.Constants.TIMESTAMP
379                         && (lexer.token == Token.LITERAL_CHARS || lexer.token == Token.VARIANT)
380                         && !(DBType.ORACLE.name == (dbType))) {
381                     SQLTimestampExpr dateExpr = new SQLTimestampExpr(lexer.stringVal());
382                     lexer.nextToken();
383                     sqlExpr = dateExpr;
384                 } else if (equalsIgnoreCase(DBType.MYSQL.name, dbType) && ident.startsWith("0x") && (ident.length % 2) == 0) {
385                     sqlExpr = new SQLHexExpr(ident.substring(2));
386                 } else {
387                     sqlExpr = new SQLIdentifierExpr(ident, hash_lower);
388                 }
389                 break;
390             case Token.NEW:
391                 throw new ParserException("TODO " ~ lexer.info());
392             case Token.LITERAL_INT:
393                 sqlExpr = new SQLIntegerExpr(lexer.integerValue());
394                 lexer.nextToken();
395                 break;
396             case Token.LITERAL_FLOAT:
397                 sqlExpr = lexer.numberExpr();
398                 lexer.nextToken();
399                 break;
400             case Token.LITERAL_CHARS: {
401                 sqlExpr = new SQLCharExpr(lexer.stringVal());
402 
403                 if (DBType.MYSQL.name == (dbType)) {
404                     lexer.nextTokenValue();
405 
406                     for (; ; ) {
407                         if (lexer.token == Token.LITERAL_ALIAS) {
408                             string concat = (cast(SQLCharExpr) sqlExpr).getText().value();
409                             concat ~= lexer.stringVal();
410                             lexer.nextTokenValue();
411                             sqlExpr = new SQLCharExpr(concat);
412                         } else if (lexer.token == Token.LITERAL_CHARS || lexer.token == Token.LITERAL_NCHARS) {
413                             string concat = (cast(SQLCharExpr) sqlExpr).getText().value();
414                             concat ~= lexer.stringVal();
415                             lexer.nextTokenValue();
416                             sqlExpr = new SQLCharExpr(concat);
417                         } else {
418                             break;
419                         }
420                     }
421                 } else {
422                     lexer.nextToken();
423                 }
424                 break;
425             } case Token.LITERAL_NCHARS:
426                 sqlExpr = new SQLNCharExpr(lexer.stringVal());
427                 lexer.nextToken();
428 
429                 if (DBType.MYSQL.name == (dbType)) {
430                     SQLMethodInvokeExpr concat = null;
431                     for (; ; ) {
432                         if (lexer.token == Token.LITERAL_ALIAS) {
433                             if (concat is null) {
434                                 concat = new SQLMethodInvokeExpr("CONCAT");
435                                 concat.addParameter(sqlExpr);
436                                 sqlExpr = concat;
437                             }
438                             string _alias = lexer.stringVal();
439                             lexer.nextToken();
440                             SQLCharExpr concat_right = new SQLCharExpr(_alias.substring(1, cast(int)(_alias.length - 1)));
441                             concat.addParameter(concat_right);
442                         } else if (lexer.token == Token.LITERAL_CHARS || lexer.token == Token.LITERAL_NCHARS) {
443                             if (concat is null) {
444                                 concat = new SQLMethodInvokeExpr("CONCAT");
445                                 concat.addParameter(sqlExpr);
446                                 sqlExpr = concat;
447                             }
448 
449                             string chars = lexer.stringVal();
450                             lexer.nextToken();
451                             SQLCharExpr concat_right = new SQLCharExpr(chars);
452                             concat.addParameter(concat_right);
453                         } else {
454                             break;
455                         }
456                     }
457                 }
458                 break;
459             case Token.VARIANT: {
460                 string varName = lexer.stringVal();
461                 lexer.nextToken();
462 
463                 if (varName == (":") && lexer.token == Token.IDENTIFIER && DBType.ORACLE.name == (dbType)) {
464                     string part2 = lexer.stringVal();
465                     lexer.nextToken();
466                     varName ~= part2;
467                 }
468 
469                 SQLVariantRefExpr varRefExpr = new SQLVariantRefExpr(varName);
470                 if (varName.startsWith(":")) {
471                     varRefExpr.setIndex(lexer.nextVarIndex());
472                 }
473                 if (varRefExpr.getName() == ("@") && lexer.token == Token.LITERAL_CHARS) {
474                     varRefExpr.setName("@'" ~ lexer.stringVal() ~ "'");
475                     lexer.nextToken();
476                 } else if (varRefExpr.getName() == ("@@") && lexer.token == Token.LITERAL_CHARS) {
477                     varRefExpr.setName("@@'" ~ lexer.stringVal() ~ "'");
478                     lexer.nextToken();
479                 }
480                 sqlExpr = varRefExpr;
481             }
482                 break;
483             case Token.DEFAULT:
484                 sqlExpr = new SQLDefaultExpr();
485                 lexer.nextToken();
486                 break;
487             case Token.DUAL:
488             case Token.KEY:
489             case Token.DISTINCT:
490             case Token.LIMIT:
491             case Token.SCHEMA:
492             case Token.COLUMN:
493             case Token.IF:
494             case Token.END:
495             case Token.COMMENT:
496             case Token.COMPUTE:
497             case Token.ENABLE:
498             case Token.DISABLE:
499             case Token.INITIALLY:
500             case Token.SEQUENCE:
501             case Token.USER:
502             case Token.EXPLAIN:
503             case Token.WITH:
504             case Token.GRANT:
505             case Token.REPLACE:
506             case Token.INDEX:
507             case Token.MODEL:
508             case Token.PCTFREE:
509             case Token.INITRANS:
510             case Token.MAXTRANS:
511             case Token.SEGMENT:
512             case Token.CREATION:
513             case Token.IMMEDIATE:
514             case Token.DEFERRED:
515             case Token.STORAGE:
516             case Token.NEXT:
517             case Token.MINEXTENTS:
518             case Token.MAXEXTENTS:
519             case Token.MAXSIZE:
520             case Token.PCTINCREASE:
521             case Token.FLASH_CACHE:
522             case Token.CELL_FLASH_CACHE:
523             case Token.NONE:
524             case Token.LOB:
525             case Token.STORE:
526             case Token.ROW:
527             case Token.CHUNK:
528             case Token.CACHE:
529             case Token.NOCACHE:
530             case Token.LOGGING:
531             case Token.NOCOMPRESS:
532             case Token.KEEP_DUPLICATES:
533             case Token.EXCEPTIONS:
534             case Token.PURGE:
535             case Token.FULL:
536             case Token.TO:
537             case Token.IDENTIFIED:
538             case Token.PASSWORD:
539             case Token.BINARY:
540             case Token.WINDOW:
541             case Token.OFFSET:
542             case Token.SHARE:
543             case Token.START:
544             case Token.CONNECT:
545             case Token.MATCHED:
546             case Token.ERRORS:
547             case Token.REJECT:
548             case Token.UNLIMITED:
549             case Token.BEGIN:
550             case Token.EXCLUSIVE:
551             case Token.MODE:
552             case Token.ADVISE:
553             case Token.VIEW:
554             case Token.ESCAPE:
555             case Token.OVER:
556             case Token.ORDER:
557             case Token.CONSTRAINT:
558             case Token.TYPE:
559             case Token.OPEN:
560             case Token.REPEAT:
561             case Token.TABLE:
562             case Token.TRUNCATE:
563             case Token.EXCEPTION:
564             case Token.FUNCTION:
565             case Token.IDENTITY:
566             case Token.EXTRACT:
567             case Token.DESC:
568             case Token.DO:
569             case Token.GROUP:
570             case Token.MOD:
571             case Token.CONCAT:
572                 sqlExpr = new SQLIdentifierExpr(lexer.stringVal());
573                 lexer.nextToken();
574                 break;
575             case Token.CASE:
576                 SQLCaseExpr caseExpr = new SQLCaseExpr();
577                 lexer.nextToken();
578                 if (lexer.token != Token.WHEN) {
579                     caseExpr.setValueExpr(this.expr());
580                 }
581 
582                 accept(Token.WHEN);
583                 SQLExpr testExpr = this.expr();
584                 accept(Token.THEN);
585                 SQLExpr valueExpr = this.expr();
586                 SQLCaseExpr.Item caseItem = new SQLCaseExpr.Item(testExpr, valueExpr);
587                 caseExpr.addItem(caseItem);
588 
589                 while (lexer.token == Token.WHEN) {
590                     lexer.nextToken();
591                     testExpr = this.expr();
592                     accept(Token.THEN);
593                     valueExpr = this.expr();
594                     caseItem = new SQLCaseExpr.Item(testExpr, valueExpr);
595                     caseExpr.addItem(caseItem);
596                 }
597 
598                 if (lexer.token == Token.ELSE) {
599                     lexer.nextToken();
600                     caseExpr.setElseExpr(this.expr());
601                 }
602 
603                 accept(Token.END);
604 
605                 sqlExpr = caseExpr;
606                 break;
607             case Token.EXISTS:
608                 lexer.nextToken();
609                 accept(Token.LPAREN);
610                 sqlExpr = new SQLExistsExpr(createSelectParser().select());
611                 accept(Token.RPAREN);
612                 break;
613             case Token.NOT:
614                 lexer.nextToken();
615                 if (lexer.token == Token.EXISTS) {
616                     lexer.nextToken();
617                     accept(Token.LPAREN);
618                     sqlExpr = new SQLExistsExpr(createSelectParser().select(), true);
619                     accept(Token.RPAREN);
620                 } else if (lexer.token == Token.LPAREN) {
621                     lexer.nextToken();
622 
623                     SQLExpr notTarget = this.expr();
624 
625                     accept(Token.RPAREN);
626                     notTarget = relationalRest(notTarget);
627                     sqlExpr = new SQLNotExpr(notTarget);
628                     
629                     return primaryRest(sqlExpr);
630                 } else {
631                     SQLExpr restExpr = relational();
632                     sqlExpr = new SQLNotExpr(restExpr);
633                 }
634                 break;
635             case Token.SELECT:
636                 SQLQueryExpr queryExpr = new SQLQueryExpr(
637                         createSelectParser()
638                                 .select());
639                 sqlExpr = queryExpr;
640                 break;
641             case Token.CAST:
642                 lexer.nextToken();
643                 accept(Token.LPAREN);
644                 SQLCastExpr _cast = new SQLCastExpr();
645                 _cast.setExpr(this.expr());
646                 accept(Token.AS);
647                 _cast.setDataType(parseDataType(false));
648                 accept(Token.RPAREN);
649 
650                 sqlExpr = _cast;
651                 break;
652             case Token.SUB:
653                 lexer.nextToken();
654                 switch (lexer.token) {
655                     case Token.LITERAL_INT:
656                         Number integerValue = lexer.integerValue();
657                         if (cast(Integer)(integerValue) !is null) {
658                             int intVal = (cast(Integer) integerValue).intValue();
659                             if (intVal == Integer.MIN_VALUE) {
660                                 integerValue = Long.valueOf((cast(long) intVal) * -1);
661                             } else {
662                                 integerValue = Integer.valueOf(intVal * -1);
663                             }
664                         } else if (cast(Long)(integerValue) !is null) {
665                             long longVal = (cast(Long) integerValue).longValue();
666                             if (longVal == 2147483648L) {
667                                 integerValue = Integer.valueOf(cast(int) ((cast(long) longVal) * -1));
668                             } else {
669                                 integerValue = Long.valueOf(longVal * -1);
670                             }
671                         } else {
672                             integerValue = (cast(BigInteger) integerValue).negate();
673                         }
674                         sqlExpr = new SQLIntegerExpr(integerValue);
675                         lexer.nextToken();
676                         break;
677                     case Token.LITERAL_FLOAT:
678                         sqlExpr = lexer.numberExpr(true);
679                         lexer.nextToken();
680                         break;
681                     case Token.IDENTIFIER: // 当负号后面为字段的情况
682                         sqlExpr = new SQLIdentifierExpr(lexer.stringVal());
683                         lexer.nextToken();
684 
685                         if (lexer.token == Token.LPAREN || lexer.token == Token.LBRACKET) {
686                             sqlExpr = primaryRest(sqlExpr);
687                         }
688                         sqlExpr = new SQLUnaryExpr(SQLUnaryOperator.Negative, sqlExpr);
689 
690                         break;
691                     case Token.QUES: {
692                         SQLVariantRefExpr variantRefExpr = new SQLVariantRefExpr("?");
693                         variantRefExpr.setIndex(lexer.nextVarIndex());
694                         sqlExpr = new SQLUnaryExpr(SQLUnaryOperator.Negative, variantRefExpr);
695                         lexer.nextToken();
696                         break;
697                     }
698                     case Token.LPAREN:
699                         lexer.nextToken();
700                         sqlExpr = this.expr();
701                         accept(Token.RPAREN);
702                         sqlExpr = new SQLUnaryExpr(SQLUnaryOperator.Negative, sqlExpr);
703                         break;
704                     case Token.BANG:
705                         sqlExpr = this.expr();
706                         sqlExpr = new SQLUnaryExpr(SQLUnaryOperator.Negative, sqlExpr);
707                         break;
708                     default:
709                         throw new ParserException("TODO : " ~ lexer.info());
710                 }
711                 break;
712             case Token.PLUS:
713                 lexer.nextToken();
714                 switch (lexer.token) {
715                     case Token.LITERAL_INT:
716                         sqlExpr = new SQLIntegerExpr(lexer.integerValue());
717                         lexer.nextToken();
718                         break;
719                     case Token.LITERAL_FLOAT:
720                         sqlExpr = lexer.numberExpr();
721                         lexer.nextToken();
722                         break;
723                     case Token.IDENTIFIER: // 当~号后面为字段的情况
724                         sqlExpr = new SQLIdentifierExpr(lexer.stringVal());
725                         sqlExpr = new SQLUnaryExpr(SQLUnaryOperator.Plus, sqlExpr);
726                         lexer.nextToken();
727                         break;
728                     case Token.LPAREN:
729                         lexer.nextToken();
730                         sqlExpr = this.expr();
731                         accept(Token.RPAREN);
732                         sqlExpr = new SQLUnaryExpr(SQLUnaryOperator.Plus, sqlExpr);
733                         break;
734                     case Token.SUB:
735                         sqlExpr = this.expr();
736                         sqlExpr = new SQLUnaryExpr(SQLUnaryOperator.Plus, sqlExpr);
737                         break;
738                     default:
739                         throw new ParserException("TODO " ~ lexer.info());
740                 }
741                 break;
742             case Token.TILDE:
743                 lexer.nextToken();
744                 SQLExpr unaryValueExpr = primary();
745                 SQLUnaryExpr unary = new SQLUnaryExpr(SQLUnaryOperator.Compl, unaryValueExpr);
746                 sqlExpr = unary;
747                 break;
748             case Token.QUES:
749                 if (DBType.MYSQL.name == (dbType)) {
750                     lexer.nextTokenValue();
751                 } else {
752                     lexer.nextToken();
753                 }
754                 SQLVariantRefExpr quesVarRefExpr = new SQLVariantRefExpr("?");
755                 quesVarRefExpr.setIndex(lexer.nextVarIndex());
756                 sqlExpr = quesVarRefExpr;
757                 break;
758             case Token.LEFT:
759                 sqlExpr = new SQLIdentifierExpr("LEFT");
760                 lexer.nextToken();
761                 break;
762             case Token.RIGHT:
763                 sqlExpr = new SQLIdentifierExpr("RIGHT");
764                 lexer.nextToken();
765                 break;
766             case Token.DATABASE:
767                 sqlExpr = new SQLIdentifierExpr("DATABASE");
768                 lexer.nextToken();
769                 break;
770             case Token.LOCK:
771                 sqlExpr = new SQLIdentifierExpr("LOCK");
772                 lexer.nextToken();
773                 break;
774             case Token.NULL:
775                 sqlExpr = new SQLNullExpr();
776                 lexer.nextToken();
777                 break;
778             case Token.BANG:
779                 lexer.nextToken();
780                 SQLExpr bangExpr = primary();
781                 sqlExpr = new SQLUnaryExpr(SQLUnaryOperator.Not, bangExpr);
782                 break;
783             case Token.LITERAL_HEX:
784                 string hex = lexer.hexString();
785                 sqlExpr = new SQLHexExpr(hex);
786                 lexer.nextToken();
787                 break;
788             case Token.INTERVAL:
789                 sqlExpr = parseInterval();
790                 break;
791             case Token.COLON:
792                 lexer.nextToken();
793                 if (lexer.token == Token.LITERAL_ALIAS) {
794                     sqlExpr = new SQLVariantRefExpr(":\"" ~ lexer.stringVal() ~ "\"");
795                     lexer.nextToken();
796                 }
797                 break;
798             case Token.ANY:
799                 sqlExpr = parseAny();
800                 break;
801             case Token.SOME:
802                 sqlExpr = parseSome();
803                 break;
804             case Token.ALL:
805                 sqlExpr = parseAll();
806                 break;
807             case Token.LITERAL_ALIAS:
808                 sqlExpr = parseAliasExpr(lexer.stringVal());
809                 lexer.nextToken();
810                 break;
811             case Token.EOF:
812                 throw new ParserException("EOF");
813             case Token.TRUE:
814                 lexer.nextToken();
815                 sqlExpr = new SQLBooleanExpr(true);
816                 break;
817             case Token.FALSE:
818                 lexer.nextToken();
819                 sqlExpr = new SQLBooleanExpr(false);
820                 break;
821             case Token.BITS: {
822                 string strVal = lexer.stringVal();
823                 lexer.nextToken();
824                 sqlExpr = new SQLBinaryExpr(strVal);
825                 break;
826             }
827             case Token.CONTAINS:
828                 sqlExpr = inRest(null);
829                 break;
830             case Token.SET: {
831                 Lexer.SavePoint savePoint = lexer.mark();
832                 lexer.nextToken();
833                 if (lexer.token() == Token.LPAREN) {
834                     sqlExpr = new SQLIdentifierExpr("SET");
835                 } else {
836                     lexer.reset(savePoint);
837                     throw new ParserException("ERROR. " ~ lexer.info());
838                 }
839                 break;
840             }
841 
842             default:
843                 throw new ParserException("ERROR. " ~ lexer.info());
844         }
845 
846         SQLExpr expr = primaryRest(sqlExpr);
847 
848         if (beforeComments !is null) {
849             expr.addBeforeComment(beforeComments);
850         }
851 
852         return expr;
853     }
854 
855     protected SQLExpr parseAll() {
856         SQLExpr sqlExpr;
857         lexer.nextToken();
858         SQLAllExpr allExpr = new SQLAllExpr();
859 
860         accept(Token.LPAREN);
861         SQLSelect allSubQuery = createSelectParser().select();
862         allExpr.setSubQuery(allSubQuery);
863         accept(Token.RPAREN);
864 
865         allSubQuery.setParent(allExpr);
866 
867         sqlExpr = allExpr;
868         return sqlExpr;
869     }
870 
871     protected SQLExpr parseSome() {
872         SQLExpr sqlExpr;
873         lexer.nextToken();
874         SQLSomeExpr someExpr = new SQLSomeExpr();
875 
876         accept(Token.LPAREN);
877         SQLSelect someSubQuery = createSelectParser().select();
878         someExpr.setSubQuery(someSubQuery);
879         accept(Token.RPAREN);
880 
881         someSubQuery.setParent(someExpr);
882 
883         sqlExpr = someExpr;
884         return sqlExpr;
885     }
886 
887     protected SQLExpr parseAny() {
888         SQLExpr sqlExpr;
889         lexer.nextToken();
890         if (lexer.token == Token.LPAREN) {
891             accept(Token.LPAREN);
892 
893             if (lexer.token == Token.ARRAY || lexer.token == Token.IDENTIFIER) {
894                 SQLExpr expr = this.expr();
895                 SQLMethodInvokeExpr methodInvokeExpr = new SQLMethodInvokeExpr("ANY");
896                 methodInvokeExpr.addParameter(expr);
897                 accept(Token.RPAREN);
898                 return methodInvokeExpr;
899             }
900 
901             SQLSelect anySubQuery = createSelectParser().select();
902             SQLAnyExpr anyExpr = new SQLAnyExpr(anySubQuery);
903             accept(Token.RPAREN);
904 
905             sqlExpr = anyExpr;
906         } else {
907             sqlExpr = new SQLIdentifierExpr("ANY");
908         }
909         return sqlExpr;
910     }
911 
912     protected SQLExpr parseAliasExpr(string _alias) {
913         return new SQLIdentifierExpr(_alias);
914     }
915 
916     protected SQLExpr parseInterval() {
917         throw new ParserException("TODO. " ~ lexer.info());
918     }
919 
920     public SQLSelectParser createSelectParser() {
921         return new SQLSelectParser(this);
922     }
923 
924     public SQLExpr primaryRest(SQLExpr expr) {
925         if (expr is null) {
926             throw new Exception("expr");
927         }
928 
929         Token token = lexer.token;
930         if (token == Token.OF) {
931             if (cast(SQLIdentifierExpr)(expr) !is null) {
932                 long hashCode64 = (cast(SQLIdentifierExpr) expr).hashCode64();
933                 if (hashCode64 == FnvHash.Constants.CURRENT) {
934                     lexer.nextToken();
935                     SQLName cursorName = this.name();
936                     return new SQLCurrentOfCursorExpr(cursorName);
937                 }
938             }
939         } else if (token == Token.FOR) {
940             if (cast(SQLIdentifierExpr)(expr) !is null) {
941                 SQLIdentifierExpr idenExpr = cast(SQLIdentifierExpr) expr;
942                 if (idenExpr.hashCode64() == FnvHash.Constants.NEXTVAL) {
943                     lexer.nextToken();
944                     SQLName seqName = this.name();
945                     SQLSequenceExpr seqExpr = new SQLSequenceExpr(seqName, SQLSequenceExpr.Function.NextVal);
946                     return seqExpr;
947                 } else if (idenExpr.hashCode64() == FnvHash.Constants.CURRVAL) {
948                     lexer.nextToken();
949                     SQLName seqName = this.name();
950                     SQLSequenceExpr seqExpr = new SQLSequenceExpr(seqName, SQLSequenceExpr.Function.CurrVal);
951                     return seqExpr;
952                 } else if (idenExpr.hashCode64() == FnvHash.Constants.PREVVAL) {
953                     lexer.nextToken();
954                     SQLName seqName = this.name();
955                     SQLSequenceExpr seqExpr = new SQLSequenceExpr(seqName, SQLSequenceExpr.Function.PrevVal);
956                     return seqExpr;
957                 }
958             }
959         }
960 
961         if (token == Token.DOT) {
962             lexer.nextToken();
963 
964             if (cast(SQLCharExpr)(expr) !is null) {
965                 string text = (cast(SQLCharExpr) expr).getText().value();
966                 expr = new SQLIdentifierExpr(text);
967             }
968 
969             expr = dotRest(expr);
970             return primaryRest(expr);
971         } else if (lexer.identifierEquals(FnvHash.Constants.SETS) //
972                 && typeid(expr) == typeid(SQLIdentifierExpr) // 
973                 && "GROUPING".equalsIgnoreCase((cast(SQLIdentifierExpr) expr).getName())) {
974             SQLGroupingSetExpr groupingSets = new SQLGroupingSetExpr();
975             lexer.nextToken();
976 
977             accept(Token.LPAREN);
978 
979             for (; ; ) {
980                 SQLExpr item;
981                 if (lexer.token == Token.LPAREN) {
982                     lexer.nextToken();
983 
984                     SQLListExpr listExpr = new SQLListExpr();
985                     this.exprList(listExpr.getItems(), listExpr);
986                     item = listExpr;
987 
988                     accept(Token.RPAREN);
989                 } else {
990                     item = this.expr();
991                 }
992 
993                 item.setParent(groupingSets);
994                 groupingSets.addParameter(item);
995 
996                 if (lexer.token == Token.RPAREN) {
997                     break;
998                 }
999 
1000                 accept(Token.COMMA);
1001             }
1002 
1003             this.exprList(groupingSets.getParameters(), groupingSets);
1004 
1005             accept(Token.RPAREN);
1006 
1007             return groupingSets;
1008         } else {
1009             if (lexer.token == Token.LPAREN) {
1010                 return methodRest(expr, true);
1011             }
1012         }
1013 
1014         return expr;
1015     }
1016 
1017     protected SQLExpr parseExtract() {
1018         throw new ParserException("not supported.");
1019     }
1020 
1021     protected SQLExpr parsePosition() {
1022         throw new ParserException("not supported.");
1023     }
1024 
1025     protected SQLExpr parseMatch() {
1026         throw new ParserException("not supported.");
1027     }
1028 
1029     protected SQLExpr methodRest(SQLExpr expr, bool acceptLPAREN) {
1030         if (acceptLPAREN) {
1031             accept(Token.LPAREN);
1032         }
1033 
1034         bool distinct = false;
1035         if (lexer.token == Token.DISTINCT) {
1036             lexer.nextToken();
1037             distinct = true;
1038         }
1039 
1040         string methodName = null;
1041         string aggMethodName = null;
1042         SQLMethodInvokeExpr methodInvokeExpr;
1043         SQLExpr owner = null;
1044         string trimOption = null;
1045 
1046         long hash_lower = 0L;
1047         if (cast(SQLIdentifierExpr)(expr) !is null) {
1048             SQLIdentifierExpr identifierExpr = cast(SQLIdentifierExpr) expr;
1049             methodName = identifierExpr.getName();
1050             hash_lower = identifierExpr.nameHashCode64();
1051 
1052             if (hash_lower == FnvHash.Constants.TRIM) {
1053                 if (lexer.identifierEquals(FnvHash.Constants.LEADING)) {
1054                     trimOption = lexer.stringVal();
1055                     lexer.nextToken();
1056                 } else if (lexer.identifierEquals(FnvHash.Constants.BOTH)) {
1057                     trimOption = lexer.stringVal();
1058                     lexer.nextToken();
1059                 } else if (lexer.identifierEquals(FnvHash.Constants.TRAILING)) {
1060                     trimOption = lexer.stringVal();
1061                     lexer.nextToken();
1062                 }
1063             } else if (hash_lower == FnvHash.Constants.MATCH
1064                     && DBType.MYSQL.name == (dbType)) {
1065                 return parseMatch();
1066             } else if (hash_lower == FnvHash.Constants.EXTRACT
1067                     && DBType.MYSQL.name == (dbType)) {
1068                 return parseExtract();
1069             } else if (hash_lower == FnvHash.Constants.POSITION
1070                     && DBType.MYSQL.name == (dbType)) {
1071                 return parsePosition();
1072             } else if (hash_lower == FnvHash.Constants.INT4 && DBType.POSTGRESQL.name == (dbType)) {
1073                 PGTypeCastExpr castExpr = new PGTypeCastExpr();
1074                 castExpr.setExpr(this.expr());
1075                 castExpr.setDataType(new SQLDataTypeImpl(methodName));
1076                 accept(Token.RPAREN);
1077                 return castExpr;
1078             } else if (hash_lower == FnvHash.Constants.VARBIT && DBType.POSTGRESQL.name == (dbType)) {
1079                 PGTypeCastExpr castExpr = new PGTypeCastExpr();
1080                 SQLExpr len = this.primary();
1081                 castExpr.setDataType(new SQLDataTypeImpl(methodName, len));
1082                 accept(Token.RPAREN);
1083                 castExpr.setExpr(this.expr());
1084                 return castExpr;
1085             }
1086             aggMethodName = getAggreateFunction(hash_lower);
1087         } else if (cast(SQLPropertyExpr)(expr) !is null) {
1088             methodName = (cast(Object)(expr)).toString();
1089             aggMethodName = SQLUtils.normalize(methodName);
1090             hash_lower = FnvHash.fnv1a_64_lower(aggMethodName);
1091             aggMethodName = getAggreateFunction(hash_lower);
1092 
1093             owner = (cast(SQLPropertyExpr) expr).getOwner();
1094         } else if (cast(SQLDefaultExpr)(expr) !is null) {
1095             methodName = "DEFAULT";
1096         } else if (cast(SQLCharExpr)(expr) !is null) {
1097             methodName = (cast(SQLCharExpr) expr).getText().value();
1098         }
1099 
1100         if (aggMethodName !is null) {
1101             SQLAggregateExpr aggregateExpr = parseAggregateExpr(aggMethodName);
1102             if (distinct) {
1103                 aggregateExpr.setOption(SQLAggregateOption.DISTINCT);
1104             }
1105 
1106 
1107             return aggregateExpr;
1108         }
1109 
1110         methodInvokeExpr = new SQLMethodInvokeExpr(methodName, hash_lower);
1111         if (owner !is null) {
1112             methodInvokeExpr.setOwner(owner);
1113         }
1114         if (trimOption !is null) {
1115             methodInvokeExpr.setTrimOption(trimOption);
1116         }
1117 
1118         Token token = lexer.token;
1119         if (token != Token.RPAREN && token != Token.FROM) {
1120             exprList(methodInvokeExpr.getParameters(), methodInvokeExpr);
1121         }
1122 
1123         if (hash_lower == FnvHash.Constants.EXIST
1124                 && methodInvokeExpr.getParameters().size() == 1
1125                 && methodInvokeExpr.getParameters().get(0) !is null) {
1126             throw new ParserException("exists syntax error.");
1127         }
1128 
1129         if (lexer.token == Token.FROM) {
1130             lexer.nextToken();
1131             SQLExpr from = this.expr();
1132             methodInvokeExpr.setFrom(from);
1133 
1134             if (lexer.token == Token.FOR) {
1135                 lexer.nextToken();
1136                 SQLExpr forExpr = this.expr();
1137                 methodInvokeExpr.setFor(forExpr);
1138             }
1139         }
1140 
1141         if (lexer.token == Token.USING || lexer.identifierEquals(FnvHash.Constants.USING)) {
1142             lexer.nextToken();
1143             SQLExpr using;
1144             if (lexer.token == Token.STAR) {
1145                 lexer.nextToken();
1146                 using = new SQLAllColumnExpr();
1147             } else if (lexer.token == Token.BINARY) {
1148                 using = new SQLIdentifierExpr(lexer.stringVal());
1149                 lexer.nextToken();
1150             } else {
1151                 using = this.primary();
1152             }
1153             methodInvokeExpr.setUsing(using);
1154         }
1155 
1156         SQLAggregateExpr aggregateExpr = null;
1157         if (lexer.token == Token.ORDER) {
1158             lexer.nextToken();
1159             accept(Token.BY);
1160 
1161             aggregateExpr = new SQLAggregateExpr(methodName);
1162             aggregateExpr.getArguments().addAll(methodInvokeExpr.getParameters());
1163 
1164             SQLOrderBy orderBy = new SQLOrderBy();
1165             this.orderBy(orderBy.getItems(), orderBy);
1166             aggregateExpr.setWithinGroup(orderBy);
1167         }
1168 
1169         accept(Token.RPAREN);
1170 
1171         if (lexer.token == Token.OVER) {
1172             if (aggregateExpr is null) {
1173                 aggregateExpr = new SQLAggregateExpr(methodName);
1174                 aggregateExpr.getArguments().addAll(methodInvokeExpr.getParameters());
1175             }
1176             over(aggregateExpr);
1177         }
1178 
1179         if (aggregateExpr !is null) {
1180             return primaryRest(aggregateExpr);
1181         }
1182 
1183         return primaryRest(methodInvokeExpr);
1184 
1185         //throw new ParserException("not support token:" ~ lexer.token ~ ", " ~ lexer.info());
1186     }
1187 
1188     protected SQLExpr dotRest(SQLExpr expr) {
1189         if (lexer.token == Token.STAR) {
1190             lexer.nextToken();
1191             expr = new SQLPropertyExpr(expr, "*");
1192         } else {
1193             string name;
1194             long hash_lower = 0L;
1195 
1196             if (lexer.token == Token.IDENTIFIER) {
1197                 name = lexer.stringVal();
1198                 hash_lower = lexer.hash_lower;
1199                 lexer.nextToken();
1200             } else if (lexer.token == Token.LITERAL_CHARS
1201                     || lexer.token == Token.LITERAL_ALIAS) {
1202                 name = lexer.stringVal();
1203                 lexer.nextToken();
1204             } else if (lexer.getKeywods().containsValue(lexer.token)) {
1205                 name = lexer.stringVal();
1206                 lexer.nextToken();
1207             } else {
1208                 throw new ParserException("error : " ~ lexer.info());
1209             }
1210 
1211             if (lexer.token == Token.LPAREN) {
1212                 bool aggregate = hash_lower == FnvHash.Constants.WM_CONCAT
1213                         && cast(SQLIdentifierExpr)(expr) !is null
1214                         && (cast(SQLIdentifierExpr) expr).nameHashCode64() == FnvHash.Constants.WMSYS;
1215                 expr = methodRest(expr, name, aggregate);
1216             } else {
1217                 expr = new SQLPropertyExpr(expr, name, hash_lower);
1218             }
1219         }
1220 
1221         expr = primaryRest(expr);
1222         return expr;
1223     }
1224 
1225     private SQLExpr methodRest(SQLExpr expr, string name, bool aggregate) {
1226         lexer.nextToken();
1227 
1228         if (lexer.token == Token.DISTINCT) {
1229             lexer.nextToken();
1230 
1231             string aggreateMethodName = (cast(Object)(expr)).toString() ~ "." ~ name;
1232             SQLAggregateExpr aggregateExpr = new SQLAggregateExpr(aggreateMethodName, SQLAggregateOption.DISTINCT);
1233 
1234             if (lexer.token == Token.RPAREN) {
1235                 lexer.nextToken();
1236             } else {
1237                 if (lexer.token == Token.PLUS) {
1238                     aggregateExpr.getArguments().add(new SQLIdentifierExpr("~"));
1239                     lexer.nextToken();
1240                 } else {
1241                     exprList(aggregateExpr.getArguments(), aggregateExpr);
1242                 }
1243                 accept(Token.RPAREN);
1244             }
1245             expr = aggregateExpr;
1246         } else if (aggregate) {
1247             SQLAggregateExpr methodInvokeExpr = new SQLAggregateExpr(name);
1248             methodInvokeExpr.setMethodName((cast(Object)(expr)).toString() ~ "." ~ name);
1249             if (lexer.token == Token.RPAREN) {
1250                 lexer.nextToken();
1251             } else {
1252                 if (lexer.token == Token.PLUS) {
1253                     methodInvokeExpr.addArgument(new SQLIdentifierExpr("~"));
1254                     lexer.nextToken();
1255                 } else {
1256                     exprList(methodInvokeExpr.getArguments(), methodInvokeExpr);
1257                 }
1258                 accept(Token.RPAREN);
1259             }
1260 
1261             if (lexer.token == Token.OVER) {
1262                 over(methodInvokeExpr);
1263             }
1264 
1265             expr = methodInvokeExpr;
1266         } else {
1267             SQLMethodInvokeExpr methodInvokeExpr = new SQLMethodInvokeExpr(name);
1268             methodInvokeExpr.setOwner(expr);
1269             if (lexer.token == Token.RPAREN) {
1270                 lexer.nextToken();
1271             } else {
1272                 if (lexer.token == Token.PLUS) {
1273                     methodInvokeExpr.addParameter(new SQLIdentifierExpr("~"));
1274                     lexer.nextToken();
1275                 } else {
1276                     exprList(methodInvokeExpr.getParameters(), methodInvokeExpr);
1277                 }
1278                 accept(Token.RPAREN);
1279             }
1280             expr = methodInvokeExpr;
1281         }
1282         return expr;
1283     }
1284 
1285     public  SQLExpr groupComparisionRest(SQLExpr expr) {
1286         return expr;
1287     }
1288 
1289     public  void names(Collection!(SQLName) exprCol) {
1290         names(exprCol, null);
1291     }
1292 
1293     public  void names(Collection!(SQLName) exprCol, SQLObject parent) {
1294         if (lexer.token == Token.RBRACE) {
1295             return;
1296         }
1297 
1298         if (lexer.token == Token.EOF) {
1299             return;
1300         }
1301 
1302         SQLName name = name();
1303         name.setParent(parent);
1304         exprCol.add(name);
1305 
1306         while (lexer.token == Token.COMMA) {
1307             lexer.nextToken();
1308 
1309             name = this.name();
1310             name.setParent(parent);
1311             exprCol.add(name);
1312         }
1313     }
1314 
1315     //@Deprecated
1316     public  void exprList(Collection!(SQLExpr) exprCol) {
1317         exprList(exprCol, null);
1318     }
1319 
1320     public  void exprList(Collection!(SQLExpr) exprCol, SQLObject parent) {
1321         if (lexer.token == Token.RPAREN || lexer.token == Token.RBRACKET) {
1322             return;
1323         }
1324 
1325         if (lexer.token == Token.EOF) {
1326             return;
1327         }
1328 
1329         SQLExpr expr = expr();
1330         expr.setParent(parent);
1331         exprCol.add(expr);
1332 
1333         while (lexer.token == Token.COMMA) {
1334             lexer.nextToken();
1335             expr = this.expr();
1336             expr.setParent(parent);
1337             exprCol.add(expr);
1338         }
1339     }
1340 
1341     public SQLName name() {
1342         string identName;
1343         long hash = 0;
1344         if (lexer.token == Token.LITERAL_ALIAS) {
1345             identName = lexer.stringVal();
1346             lexer.nextToken();
1347         } else if (lexer.token == Token.IDENTIFIER) {
1348             identName = lexer.stringVal();
1349 
1350             char c0 = charAt(identName, 0);
1351             if (c0 != '[') {
1352                 hash = lexer.hash_lower();
1353             }
1354             lexer.nextToken();
1355         } else if (lexer.token == Token.LITERAL_CHARS) {
1356             identName = '\'' ~ lexer.stringVal() ~ '\'';
1357             lexer.nextToken();
1358         } else if (lexer.token == Token.VARIANT) {
1359             identName = lexer.stringVal();
1360             lexer.nextToken();
1361         } else {
1362             switch (lexer.token) {
1363                 case Token.MODEL:
1364                 case Token.PCTFREE:
1365                 case Token.INITRANS:
1366                 case Token.MAXTRANS:
1367                 case Token.SEGMENT:
1368                 case Token.CREATION:
1369                 case Token.IMMEDIATE:
1370                 case Token.DEFERRED:
1371                 case Token.STORAGE:
1372                 case Token.NEXT:
1373                 case Token.MINEXTENTS:
1374                 case Token.MAXEXTENTS:
1375                 case Token.MAXSIZE:
1376                 case Token.PCTINCREASE:
1377                 case Token.FLASH_CACHE:
1378                 case Token.CELL_FLASH_CACHE:
1379                 case Token.NONE:
1380                 case Token.LOB:
1381                 case Token.STORE:
1382                 case Token.ROW:
1383                 case Token.CHUNK:
1384                 case Token.CACHE:
1385                 case Token.NOCACHE:
1386                 case Token.LOGGING:
1387                 case Token.NOCOMPRESS:
1388                 case Token.KEEP_DUPLICATES:
1389                 case Token.EXCEPTIONS:
1390                 case Token.PURGE:
1391                 case Token.INITIALLY:
1392                 case Token.END:
1393                 case Token.COMMENT:
1394                 case Token.ENABLE:
1395                 case Token.DISABLE:
1396                 case Token.SEQUENCE:
1397                 case Token.USER:
1398                 case Token.ANALYZE:
1399                 case Token.OPTIMIZE:
1400                 case Token.GRANT:
1401                 case Token.REVOKE:
1402                     // binary有很多含义,lexer识别了这个token,实际上应该当做普通IDENTIFIER
1403                 case Token.BINARY:
1404                 case Token.OVER:
1405                 case Token.ORDER:
1406                 case Token.DO:
1407                 case Token.JOIN:
1408                 case Token.TYPE:
1409                 case Token.FUNCTION:
1410                 case Token.KEY:
1411                 case Token.SCHEMA:
1412                 case Token.INTERVAL:
1413                 case Token.EXPLAIN:
1414                 case Token.PARTITION:
1415                 case Token.SET:
1416                     identName = lexer.stringVal();
1417                     lexer.nextToken();
1418                     break;
1419                 default:
1420                     throw new ParserException("error " ~ lexer.info());
1421             }
1422         }
1423 
1424         SQLName name = new SQLIdentifierExpr(identName, hash);
1425 
1426         name = nameRest(name);
1427 
1428         return name;
1429     }
1430 
1431     public SQLName nameRest(SQLName name) {
1432         if (lexer.token == Token.DOT) {
1433             lexer.nextToken();
1434 
1435             if (lexer.token == Token.KEY) {
1436                 name = new SQLPropertyExpr(name, "KEY");
1437                 lexer.nextToken();
1438                 return name;
1439             }
1440 
1441             if (lexer.token != Token.LITERAL_ALIAS && lexer.token != Token.IDENTIFIER
1442                 && (!lexer.getKeywods().containsValue(lexer.token))) {
1443                 throw new ParserException("error, " ~ lexer.info());
1444             }
1445 
1446             if (lexer.token == Token.LITERAL_ALIAS) {
1447                 name = new SQLPropertyExpr(name, lexer.stringVal());
1448             } else {
1449                 name = new SQLPropertyExpr(name, lexer.stringVal());
1450             }
1451             lexer.nextToken();
1452             name = nameRest(name);
1453         }
1454 
1455         return name;
1456     }
1457 
1458     public bool isAggreateFunction(string word) {
1459         long hash_lower = FnvHash.fnv1a_64_lower(word);
1460         return isAggreateFunction(hash_lower);
1461     }
1462 
1463     protected bool isAggreateFunction(long hash_lower) {
1464         return search(aggregateFunctionHashCodes, hash_lower) >= 0;
1465     }
1466 
1467     protected string getAggreateFunction(long hash_lower) {
1468         int index = search(aggregateFunctionHashCodes, hash_lower);
1469         if (index < 0) {
1470             return null;
1471         }
1472         return aggregateFunctions[index];
1473     }
1474 
1475     protected SQLAggregateExpr parseAggregateExpr(string methodName) {
1476         SQLAggregateExpr aggregateExpr;
1477         if (lexer.token == Token.ALL) {
1478             aggregateExpr = new SQLAggregateExpr(methodName, SQLAggregateOption.ALL);
1479             lexer.nextToken();
1480         } else if (lexer.token == Token.DISTINCT) {
1481             aggregateExpr = new SQLAggregateExpr(methodName, SQLAggregateOption.DISTINCT);
1482             lexer.nextToken();
1483         } else if (lexer.identifierEquals(FnvHash.Constants.DEDUPLICATION)) { // just for nut
1484             aggregateExpr = new SQLAggregateExpr(methodName, SQLAggregateOption.DEDUPLICATION);
1485             lexer.nextToken();
1486         } else {
1487             aggregateExpr = new SQLAggregateExpr(methodName);
1488         }
1489 
1490         exprList(aggregateExpr.getArguments(), aggregateExpr);
1491 
1492         if (lexer.token != Token.RPAREN) {
1493             parseAggregateExprRest(aggregateExpr);
1494         }
1495 
1496         accept(Token.RPAREN);
1497 
1498         if (lexer.identifierEquals(FnvHash.Constants.FILTER)) {
1499             filter(aggregateExpr);
1500         }
1501 
1502         if (lexer.token == Token.OVER) {
1503             over(aggregateExpr);
1504         }
1505 
1506         return aggregateExpr;
1507     }
1508 
1509     protected void filter(SQLAggregateExpr aggregateExpr) {
1510 
1511     }
1512 
1513     public void over(SQLAggregateExpr aggregateExpr) {
1514         lexer.nextToken();
1515 
1516         if (lexer.token != Token.LPAREN) {
1517             SQLName overRef = this.name();
1518             aggregateExpr.setOverRef(overRef);
1519             return;
1520         }
1521 
1522         SQLOver Sover = new SQLOver();
1523         over(Sover);
1524         aggregateExpr.setOver(Sover);
1525     }
1526 
1527     public void over(SQLOver over) {
1528         lexer.nextToken();
1529 
1530         if (lexer.token == Token.PARTITION || lexer.identifierEquals("PARTITION")) {
1531             lexer.nextToken();
1532             accept(Token.BY);
1533 
1534             if (lexer.token == (Token.LPAREN)) {
1535                 lexer.nextToken();
1536                 exprList(over.getPartitionBy(), over);
1537                 accept(Token.RPAREN);
1538             } else {
1539                 exprList(over.getPartitionBy(), over);
1540             }
1541         }
1542 
1543         over.setOrderBy(parseOrderBy());
1544 
1545         if (lexer.token == Token.OF) {
1546             lexer.nextToken();
1547             SQLName of = this.name();
1548             over.setOf(of);
1549         }
1550 
1551         SQLOver.WindowingType windowingType;
1552         bool is_set =false;
1553         if (lexer.identifierEquals(FnvHash.Constants.ROWS) || lexer.token == Token.ROWS) {
1554             windowingType = SQLOver.WindowingType.ROWS;
1555             is_set =true;
1556 
1557         } else if (lexer.identifierEquals(FnvHash.Constants.RANGE)) {
1558             windowingType = SQLOver.WindowingType.RANGE;
1559             is_set =true;
1560         }
1561 
1562         if (is_set) {
1563             over.setWindowingType(windowingType);
1564             lexer.nextToken();
1565 
1566             if (lexer.token == Token.BETWEEN) {
1567                 lexer.nextToken();
1568                 SQLExpr rowsBegin = this.primary();
1569                 over.setWindowingBetweenBegin(rowsBegin);
1570 
1571                 if (lexer.identifierEquals(FnvHash.Constants.PRECEDING)) {
1572                     over.setWindowingBetweenBeginPreceding(true);
1573                     lexer.nextToken();
1574                 } else if (lexer.identifierEquals(FnvHash.Constants.FOLLOWING)) {
1575                     over.setWindowingBetweenBeginFollowing(true);
1576                     lexer.nextToken();
1577                 }
1578 
1579                 accept(Token.AND);
1580 
1581                 SQLExpr betweenEnd;
1582                 if (lexer.identifierEquals(FnvHash.Constants.CURRENT) || lexer.token == Token.CURRENT) {
1583                     lexer.nextToken();
1584                     if (lexer.identifierEquals(FnvHash.Constants.ROW)) {
1585                         lexer.nextToken();
1586                     } else {
1587                         accept(Token.ROW);
1588                     }
1589                     betweenEnd = new SQLIdentifierExpr("CURRENT ROW");
1590                 } else {
1591                     betweenEnd = this.primary();
1592                 }
1593                 over.setWindowingBetweenEnd(betweenEnd);
1594 
1595                 if (lexer.identifierEquals(FnvHash.Constants.PRECEDING)) {
1596                     over.setWindowingBetweenEndPreceding(true);
1597                     lexer.nextToken();
1598                 } else if (lexer.identifierEquals(FnvHash.Constants.FOLLOWING)) {
1599                     over.setWindowingBetweenEndFollowing(true);
1600                     lexer.nextToken();
1601                 }
1602 
1603             } else {
1604 
1605                 if (lexer.identifierEquals(FnvHash.Constants.CURRENT)) {
1606                     lexer.nextToken();
1607                     if (lexer.identifierEquals(FnvHash.Constants.ROW)) {
1608                         lexer.nextToken();
1609                     } else {
1610                         accept(Token.ROW);
1611                     }
1612                     over.setWindowing(new SQLIdentifierExpr("CURRENT ROW"));
1613                 } else  if (lexer.identifierEquals(FnvHash.Constants.UNBOUNDED)) {
1614                     lexer.nextToken();
1615                     over.setWindowing(new SQLIdentifierExpr("UNBOUNDED"));
1616 
1617                     if (lexer.identifierEquals(FnvHash.Constants.PRECEDING)) {
1618                         over.setWindowingPreceding(true);
1619                         lexer.nextToken();
1620                     } else if (lexer.identifierEquals("FOLLOWING")) {
1621                         over.setWindowingFollowing(true);
1622                         lexer.nextToken();
1623                     }
1624                 } else {
1625                     SQLIntegerExpr rowsExpr = cast(SQLIntegerExpr) this.primary();
1626                     over.setWindowing(rowsExpr);
1627 
1628                     if (lexer.identifierEquals(FnvHash.Constants.PRECEDING)) {
1629                         over.setWindowingPreceding(true);
1630                         lexer.nextToken();
1631                     } else if (lexer.identifierEquals(FnvHash.Constants.FOLLOWING)) {
1632                         over.setWindowingFollowing(true);
1633                         lexer.nextToken();
1634                     }
1635                 }
1636             }
1637         }
1638 
1639         accept(Token.RPAREN);
1640     }
1641 
1642     protected SQLAggregateExpr parseAggregateExprRest(SQLAggregateExpr aggregateExpr) {
1643         return aggregateExpr;
1644     }
1645 
1646     public SQLOrderBy parseOrderBy() {
1647         if (lexer.token == Token.ORDER) {
1648             SQLOrderBy SorderBy = new SQLOrderBy();
1649 
1650             lexer.nextToken();
1651             
1652             if (lexer.identifierEquals(FnvHash.Constants.SIBLINGS)) {
1653                 lexer.nextToken();
1654                 SorderBy.setSibings(true);
1655             }
1656 
1657             accept(Token.BY);
1658 
1659             orderBy(SorderBy.getItems(), SorderBy);
1660 
1661             return SorderBy;
1662         }
1663 
1664         return null;
1665     }
1666 
1667     public void orderBy(List!(SQLSelectOrderByItem) items, SQLObject parent) {
1668         SQLSelectOrderByItem item = parseSelectOrderByItem();
1669         item.setParent(parent);
1670         items.add(item);
1671         while (lexer.token == Token.COMMA) {
1672             lexer.nextToken();
1673             item = parseSelectOrderByItem();
1674             item.setParent(parent);
1675             items.add(item);
1676         }
1677     }
1678 
1679     public SQLSelectOrderByItem parseSelectOrderByItem() {
1680         SQLSelectOrderByItem item = new SQLSelectOrderByItem();
1681 
1682         item.setExpr(this.expr());
1683 
1684         if (lexer.token == Token.ASC) {
1685             lexer.nextToken();
1686             item.setType(SQLOrderingSpecification.ASC);
1687         } else if (lexer.token == Token.DESC) {
1688             lexer.nextToken();
1689             item.setType(SQLOrderingSpecification.DESC);
1690         }
1691 
1692         if (lexer.identifierEquals(FnvHash.Constants.NULLS)) {
1693             lexer.nextToken();
1694             if (lexer.identifierEquals(FnvHash.Constants.FIRST)) {
1695                 lexer.nextToken();
1696                 item.setNullsOrderType(SQLSelectOrderByItem.NullsOrderType.NullsFirst);
1697             } else if (lexer.identifierEquals(FnvHash.Constants.LAST)) {
1698                 lexer.nextToken();
1699                 item.setNullsOrderType(SQLSelectOrderByItem.NullsOrderType.NullsLast);
1700             } else {
1701                 throw new ParserException("TODO " ~ lexer.info());
1702             }
1703         }
1704 
1705         return item;
1706     }
1707 
1708     public SQLUpdateSetItem parseUpdateSetItem() {
1709         SQLUpdateSetItem item = new SQLUpdateSetItem();
1710 
1711         if (lexer.token == (Token.LPAREN)) {
1712             lexer.nextToken();
1713             SQLListExpr list = new SQLListExpr();
1714             this.exprList(list.getItems(), list);
1715             accept(Token.RPAREN);
1716             item.setColumn(list);
1717         } else {
1718             string identName;
1719             long hash;
1720 
1721             Token token = lexer.token();
1722             if (token == Token.IDENTIFIER) {
1723                 identName = lexer.stringVal();
1724                 hash = lexer.hash_lower();
1725             } else if (token == Token.LITERAL_CHARS) {
1726                 identName = '\'' ~ lexer.stringVal() ~ '\'';
1727                 hash = 0;
1728             } else {
1729                 identName = lexer.stringVal();
1730                 hash = 0;
1731             }
1732             lexer.nextTokenEq();
1733             SQLExpr expr = new SQLIdentifierExpr(identName, hash);
1734             while (lexer.token() == Token.DOT) {
1735                 lexer.nextToken();
1736                 string propertyName = lexer.stringVal();
1737                 lexer.nextTokenEq();
1738                 expr = new SQLPropertyExpr(expr, propertyName);
1739             }
1740 
1741             item.setColumn(expr);
1742         }
1743         if (lexer.token == Token.COLONEQ) {
1744             lexer.nextTokenValue();
1745         } else if (lexer.token == Token.EQ) {
1746             lexer.nextTokenValue();
1747         } else {
1748             throw new ParserException("syntax error, expect EQ, actual " ~ lexer.token ~ " "
1749                     ~ lexer.info());
1750         }
1751 
1752         item.setValue(this.expr());
1753         return item;
1754     }
1755 
1756     public  SQLExpr bitAnd() {
1757         SQLExpr expr = shift();
1758         return bitAndRest(expr);
1759     }
1760 
1761     public  SQLExpr bitAndRest(SQLExpr expr) {
1762         while (lexer.token == Token.AMP) {
1763             lexer.nextToken();
1764             SQLExpr rightExp = shift();
1765             expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.BitwiseAnd, rightExp, getDbType());
1766         }
1767         return expr;
1768     }
1769 
1770     public  SQLExpr bitOr() {
1771         SQLExpr expr = bitAnd();
1772         return bitOrRest(expr);
1773     }
1774 
1775     public  SQLExpr bitOrRest(SQLExpr expr) {
1776         while (lexer.token == Token.BAR) {
1777             lexer.nextToken();
1778             SQLBinaryOperator op = SQLBinaryOperator.BitwiseOr;
1779             if (lexer.token == Token.BAR) {
1780                 lexer.nextToken();
1781                 op = SQLBinaryOperator.Concat;
1782             }
1783             SQLExpr rightExp = bitAnd();
1784             expr = new SQLBinaryOpExpr(expr, op, rightExp, getDbType());
1785             expr = bitAndRest(expr);
1786         }
1787         return expr;
1788     }
1789 
1790     public  SQLExpr inRest(SQLExpr expr) {
1791         if (lexer.token == Token.IN) {
1792             lexer.nextTokenLParen();
1793 
1794             SQLInListExpr inListExpr = new SQLInListExpr(expr);
1795             List!(SQLExpr) targetList = inListExpr.getTargetList();
1796             if (lexer.token == Token.LPAREN) {
1797                 lexer.nextTokenValue();
1798 
1799                 if (lexer.token == Token.WITH) {
1800                     SQLSelect select = this.createSelectParser().select();
1801                     SQLInSubQueryExpr queryExpr = new SQLInSubQueryExpr(select);
1802                     queryExpr.setExpr(expr);
1803                     accept(Token.RPAREN);
1804                     return queryExpr;
1805                 }
1806 
1807                 for (;;) {
1808                     SQLExpr item;
1809                     if (lexer.token == Token.LITERAL_INT) {
1810                         item = new SQLIntegerExpr(lexer.integerValue());
1811                         lexer.nextToken();
1812                         if (lexer.token != Token.COMMA && lexer.token != Token.RPAREN) {
1813                             item = this.primaryRest(item);
1814                             item = this.exprRest(item);
1815                         }
1816                     } else {
1817                         item = this.expr();
1818                     }
1819 
1820                     item.setParent(inListExpr);
1821                     targetList.add(item);
1822                     if (lexer.token == Token.COMMA) {
1823                         lexer.nextTokenValue();
1824                         continue;
1825                     }
1826                     break;
1827                 }
1828 
1829                 accept(Token.RPAREN);
1830             } else {
1831                 SQLExpr itemExpr = primary();
1832                 itemExpr.setParent(inListExpr);
1833                 targetList.add(itemExpr);
1834             }
1835 
1836             expr = inListExpr;
1837 
1838             if (targetList.size() == 1) {
1839                 SQLExpr targetExpr = targetList.get(0);
1840                 if (cast(SQLQueryExpr)(targetExpr) !is null) {
1841                     SQLInSubQueryExpr inSubQueryExpr = new SQLInSubQueryExpr();
1842                     inSubQueryExpr.setExpr(inListExpr.getExpr());
1843                     inSubQueryExpr.setSubQuery((cast(SQLQueryExpr) targetExpr).getSubQuery());
1844                     expr = inSubQueryExpr;
1845                 }
1846             }
1847         } else if (lexer.token == Token.CONTAINS) {
1848             lexer.nextTokenLParen();
1849 
1850             SQLContainsExpr containsExpr = new SQLContainsExpr(expr);
1851             List!(SQLExpr) targetList = containsExpr.getTargetList();
1852             if (lexer.token == Token.LPAREN) {
1853                 lexer.nextTokenValue();
1854 
1855                 if (lexer.token == Token.WITH) {
1856                     SQLSelect select = this.createSelectParser().select();
1857                     SQLInSubQueryExpr queryExpr = new SQLInSubQueryExpr(select);
1858                     queryExpr.setExpr(expr);
1859                     accept(Token.RPAREN);
1860                     return queryExpr;
1861                 }
1862 
1863                 for (;;) {
1864                     SQLExpr item;
1865                     if (lexer.token == Token.LITERAL_INT) {
1866                         item = new SQLIntegerExpr(lexer.integerValue());
1867                         lexer.nextToken();
1868                         if (lexer.token != Token.COMMA && lexer.token != Token.RPAREN) {
1869                             item = this.primaryRest(item);
1870                             item = this.exprRest(item);
1871                         }
1872                     } else {
1873                         item = this.expr();
1874                     }
1875 
1876                     item.setParent(containsExpr);
1877                     targetList.add(item);
1878                     if (lexer.token == Token.COMMA) {
1879                         lexer.nextTokenValue();
1880                         continue;
1881                     }
1882                     break;
1883                 }
1884 
1885                 accept(Token.RPAREN);
1886             } else {
1887                 SQLExpr itemExpr = primary();
1888                 itemExpr.setParent(containsExpr);
1889                 targetList.add(itemExpr);
1890             }
1891 
1892             expr = containsExpr;
1893         }
1894 
1895         return expr;
1896     }
1897 
1898     public  SQLExpr additive() {
1899         SQLExpr expr = multiplicative();
1900 
1901         if (lexer.token == Token.PLUS
1902                 || lexer.token == Token.BARBAR
1903                 || lexer.token == Token.CONCAT
1904                 || lexer.token == Token.SUB) {
1905             expr = additiveRest(expr);
1906         }
1907 
1908         return expr;
1909     }
1910 
1911     public SQLExpr additiveRest(SQLExpr expr) {
1912         Token token = lexer.token;
1913         if (token == Token.PLUS) {
1914             lexer.nextToken();
1915             SQLExpr rightExp = multiplicative();
1916 
1917             expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Add, rightExp, dbType);
1918             expr = additiveRest(expr);
1919         } else if ((token == Token.BARBAR || token == Token.CONCAT)
1920                 && (isEnabled(SQLParserFeature.PipesAsConcat) || !(DBType.MYSQL.name == (dbType)))) {
1921             lexer.nextToken();
1922             SQLExpr rightExp = multiplicative();
1923             expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Concat, rightExp, dbType);
1924             expr = additiveRest(expr);
1925         } else if (token == Token.SUB) {
1926             lexer.nextToken();
1927             SQLExpr rightExp = multiplicative();
1928 
1929             expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Subtract, rightExp, dbType);
1930             expr = additiveRest(expr);
1931         }
1932 
1933         return expr;
1934     }
1935 
1936     public  SQLExpr shift() {
1937         SQLExpr expr = additive();
1938         return shiftRest(expr);
1939     }
1940 
1941     public SQLExpr shiftRest(SQLExpr expr) {
1942         if (lexer.token == Token.LTLT) {
1943             lexer.nextToken();
1944             SQLExpr rightExp = additive();
1945 
1946             expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.LeftShift, rightExp, dbType);
1947             expr = shiftRest(expr);
1948         } else if (lexer.token == Token.GTGT) {
1949             lexer.nextToken();
1950             SQLExpr rightExp = additive();
1951 
1952             expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.RightShift, rightExp, dbType);
1953             expr = shiftRest(expr);
1954         }
1955 
1956         return expr;
1957     }
1958 
1959     public SQLExpr and() {
1960         SQLExpr expr = relational();
1961         if (lexer.token == Token.AND || lexer.token == Token.AMPAMP) {
1962             expr = andRest(expr);
1963         }
1964         return expr;
1965     }
1966 
1967     public SQLExpr andRest(SQLExpr expr) {
1968         for (;;) {
1969             Token token = lexer.token;
1970             if (token == Token.AND) {
1971                 if (lexer.isKeepComments() && lexer.hasComment()) {
1972                     expr.addAfterComment(lexer.readAndResetComments());
1973                 }
1974 
1975                 lexer.nextToken();
1976 
1977                 SQLExpr rightExp = relational();
1978 
1979                 if (lexer.token == Token.AND
1980                         && lexer.isEnabled(SQLParserFeature.EnableSQLBinaryOpExprGroup)) {
1981 
1982                     SQLBinaryOpExprGroup group = new SQLBinaryOpExprGroup(SQLBinaryOperator.BooleanAnd, dbType);
1983                     group.add(expr);
1984                     group.add(rightExp);
1985 
1986                     if (lexer.isKeepComments() && lexer.hasComment()) {
1987                         rightExp.addAfterComment(lexer.readAndResetComments());
1988                     }
1989 
1990                     for (;;) {
1991                         lexer.nextToken();
1992                         SQLExpr more = relational();
1993                         group.add(more);
1994 
1995                         if (lexer.token == Token.AND) {
1996                             if (lexer.isKeepComments() && lexer.hasComment()) {
1997                                 more.addAfterComment(lexer.readAndResetComments());
1998                             }
1999 
2000                             continue;
2001                         }
2002                         break;
2003                     }
2004 
2005                     expr = group;
2006                 } else {
2007                     expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.BooleanAnd, rightExp, dbType);
2008                 }
2009             } else if (token == Token.AMPAMP) {
2010                 if (lexer.isKeepComments() && lexer.hasComment()) {
2011                     expr.addAfterComment(lexer.readAndResetComments());
2012                 }
2013 
2014                 lexer.nextToken();
2015 
2016                 SQLExpr rightExp = relational();
2017 
2018                 SQLBinaryOperator operator = DBType.POSTGRESQL.name == (dbType)
2019                         ? SQLBinaryOperator.PG_And
2020                         : SQLBinaryOperator.BooleanAnd;
2021 
2022                 expr = new SQLBinaryOpExpr(expr, operator, rightExp, dbType);
2023             } else {
2024                 break;
2025             }
2026         }
2027 
2028         return expr;
2029     }
2030 
2031 
2032     public SQLExpr xor() {
2033         SQLExpr expr = and();
2034         if (lexer.token == Token.XOR) {
2035             expr = xorRest(expr);
2036         }
2037         return expr;
2038     }
2039 
2040     public SQLExpr xorRest(SQLExpr expr) {
2041         for (;;) {
2042             if (lexer.token == Token.XOR) {
2043                 lexer.nextToken();
2044                 SQLExpr rightExp = and();
2045 
2046                 expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.BooleanXor, rightExp, dbType);
2047             } else {
2048                 break;
2049             }
2050         }
2051 
2052         return expr;
2053     }
2054 
2055     public SQLExpr or() {
2056         SQLExpr expr = xor();
2057         if (lexer.token == Token.OR || lexer.token == Token.BARBAR) {
2058             expr = orRest(expr);
2059         }
2060         return expr;
2061     }
2062 
2063     public SQLExpr orRest(SQLExpr expr) {
2064         for (;;) {
2065             if (lexer.token == Token.OR) {
2066                 lexer.nextToken();
2067                 SQLExpr rightExp = xor();
2068 
2069                 if (lexer.token == Token.OR
2070                         && lexer.isEnabled(SQLParserFeature.EnableSQLBinaryOpExprGroup)) {
2071 
2072                     SQLBinaryOpExprGroup group = new SQLBinaryOpExprGroup(SQLBinaryOperator.BooleanOr, dbType);
2073                     group.add(expr);
2074                     group.add(rightExp);
2075 
2076                     if (lexer.isKeepComments() && lexer.hasComment()) {
2077                         rightExp.addAfterComment(lexer.readAndResetComments());
2078                     }
2079 
2080                     for (;;) {
2081                         lexer.nextToken();
2082                         SQLExpr more = xor();
2083                         group.add(more);
2084                         if (lexer.token == Token.OR) {
2085                             if (lexer.isKeepComments() && lexer.hasComment()) {
2086                                 more.addAfterComment(lexer.readAndResetComments());
2087                             }
2088 
2089                             continue;
2090                         }
2091                         break;
2092                     }
2093 
2094                     expr = group;
2095                 } else {
2096                     expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.BooleanOr, rightExp, dbType);
2097                 }
2098             } else  if (lexer.token == Token.BARBAR) {
2099                 lexer.nextToken();
2100                 SQLExpr rightExp = xor();
2101 
2102                 SQLBinaryOperator op = DBType.MYSQL.name == (dbType) && !isEnabled(SQLParserFeature.PipesAsConcat)
2103                         ? SQLBinaryOperator.BooleanOr
2104                         : SQLBinaryOperator.Concat;
2105 
2106                 expr = new SQLBinaryOpExpr(expr, op, rightExp, dbType);
2107             } else {
2108                 break;
2109             }
2110         }
2111 
2112         return expr;
2113     }
2114 
2115     public SQLExpr relational() {
2116         SQLExpr expr = bitOr();
2117 
2118         return relationalRest(expr);
2119     }
2120 
2121     public SQLExpr relationalRest(SQLExpr expr) {
2122         SQLExpr rightExp;
2123 
2124         Token token = lexer.token;
2125 
2126         switch (token) {
2127             case Token.EQ:{
2128                 lexer.nextToken();
2129                 try {
2130                     rightExp = bitOr();
2131                 } catch (ParserException e) {
2132                     throw new ParserException("EOF, " ~ expr.stringof ~ "=", e);
2133                 }
2134 
2135                 if (lexer.token == Token.COLONEQ) {
2136                     lexer.nextToken();
2137                     SQLExpr colonExpr = this.expr();
2138                     rightExp = new SQLBinaryOpExpr(rightExp, SQLBinaryOperator.Assignment, colonExpr, dbType);
2139                 }
2140 
2141                 expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Equality, rightExp, dbType);
2142             }
2143             break;
2144             case Token.IS: {
2145                 lexer.nextTokenNotOrNull();
2146 
2147                 SQLBinaryOperator op;
2148                 if (lexer.token == Token.NOT) {
2149                     op = SQLBinaryOperator.IsNot;
2150                     lexer.nextTokenNotOrNull();
2151                 } else {
2152                     op = SQLBinaryOperator.Is;
2153                 }
2154                 rightExp = primary();
2155                 expr = new SQLBinaryOpExpr(expr, op, rightExp, dbType);
2156             }
2157             break;
2158             case Token.EQGT: {
2159                 lexer.nextToken();
2160                 rightExp = this.expr();
2161                 string argumentName = (cast(SQLIdentifierExpr) expr).getName();
2162                // expr = new OracleArgumentExpr(argumentName, rightExp);
2163                 implementationMissing(false);
2164             }
2165             break;
2166             case Token.BANGEQ:
2167             case Token.CARETEQ: {
2168                 lexer.nextToken();
2169                 rightExp = bitOr();
2170                 expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.NotEqual, rightExp, dbType);
2171             }
2172             break;
2173             case Token.COLONEQ:{
2174                 lexer.nextToken();
2175                 rightExp = this.expr();
2176                 expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Assignment, rightExp, dbType);
2177             }
2178             break;
2179             case Token.LT:{
2180                 SQLBinaryOperator op = SQLBinaryOperator.LessThan;
2181 
2182                 lexer.nextToken();
2183                 if (lexer.token == Token.EQ) {
2184                     lexer.nextToken();
2185                     op = SQLBinaryOperator.LessThanOrEqual;
2186                 }
2187 
2188                 rightExp = bitOr();
2189                 expr = new SQLBinaryOpExpr(expr, op, rightExp, getDbType());
2190             }
2191             break;
2192             case Token.LTEQ: {
2193                 lexer.nextToken();
2194                 rightExp = bitOr();
2195 
2196                 // rightExp = relationalRest(rightExp);
2197 
2198                 expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.LessThanOrEqual, rightExp, getDbType());
2199             }
2200             break;
2201             case Token.LTEQGT: {
2202                 lexer.nextToken();
2203                 rightExp = bitOr();
2204 
2205                 expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.LessThanOrEqualOrGreaterThan, rightExp, getDbType());
2206             }
2207             break;
2208             case Token.GT: {
2209                 SQLBinaryOperator op = SQLBinaryOperator.GreaterThan;
2210 
2211                 lexer.nextToken();
2212 
2213                 if (lexer.token == Token.EQ) {
2214                     lexer.nextToken();
2215                     op = SQLBinaryOperator.GreaterThanOrEqual;
2216                 }
2217 
2218                 rightExp = bitOr();
2219 
2220                 expr = new SQLBinaryOpExpr(expr, op, rightExp, getDbType());
2221             }
2222             break;
2223             case Token.GTEQ:{
2224                 lexer.nextToken();
2225                 rightExp = bitOr();
2226 
2227                 expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.GreaterThanOrEqual, rightExp, getDbType());
2228             }
2229             break;
2230             case Token.BANGLT:{
2231                 lexer.nextToken();
2232                 rightExp = bitOr();
2233 
2234                 expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.NotLessThan, rightExp, getDbType());
2235             }
2236             break;
2237             case Token.BANGGT:
2238                 lexer.nextToken();
2239                 rightExp = bitOr();
2240 
2241                 expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.NotGreaterThan, rightExp, getDbType());
2242                 break;
2243             case Token.LTGT:
2244                 lexer.nextToken();
2245                 rightExp = bitOr();
2246                 expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.LessThanOrGreater, rightExp, getDbType());
2247                 break;
2248             case Token.LIKE:
2249                 lexer.nextTokenValue();
2250                 rightExp = bitOr();
2251 
2252                 if (typeid(rightExp) == typeid(SQLIdentifierExpr)) {
2253                     string name = (cast(SQLIdentifierExpr) rightExp).getName();
2254                     int length = cast(int)(name.length);
2255                     if(length > 1 && charAt(name, 0) == charAt(name, length -1 )) {
2256                         rightExp = new SQLCharExpr(name.substring(1, length - 1));
2257                     }
2258                 }
2259 
2260                 // rightExp = relationalRest(rightExp);
2261 
2262                 expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Like, rightExp, getDbType());
2263 
2264                 if (lexer.token == Token.ESCAPE) {
2265                     lexer.nextToken();
2266                     rightExp = primary();
2267                     expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Escape, rightExp, getDbType());
2268                 }
2269                 break;
2270             case Token.ILIKE:
2271                 lexer.nextToken();
2272                 rightExp = bitOr();
2273 
2274                 expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.ILike, rightExp, getDbType());
2275                 break;
2276             case Token.MONKEYS_AT_AT:
2277                 lexer.nextToken();
2278                 rightExp = bitOr();
2279 
2280                 expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.AT_AT, rightExp, getDbType());
2281                 break;
2282             case Token.MONKEYS_AT_GT:
2283                 lexer.nextToken();
2284                 rightExp = bitOr();
2285 
2286                 expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Array_Contains, rightExp, getDbType());
2287                 break;
2288             case Token.LT_MONKEYS_AT:
2289                 lexer.nextToken();
2290                 rightExp = bitOr();
2291 
2292                 rightExp = relationalRest(rightExp);
2293 
2294                 expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Array_ContainedBy, rightExp, getDbType());
2295                 break;
2296             case Token.NOT:
2297                 lexer.nextToken();
2298                 expr = notRationalRest(expr);
2299                 break;
2300             case Token.BETWEEN:
2301                 lexer.nextToken();
2302                 SQLExpr beginExpr = relational();
2303                 accept(Token.AND);
2304                 SQLExpr endExpr = relational();
2305                 expr = new SQLBetweenExpr(expr, beginExpr, endExpr);
2306                 break;
2307             case Token.IN:
2308             case Token.CONTAINS:
2309                 expr = inRest(expr);
2310                 break;
2311             case Token.EQEQ:
2312                 /* if (DBType.ODPS.name == (dbType)) {
2313                     lexer.nextToken();
2314                     try {
2315                         rightExp = bitOr();
2316                     } catch (ParserException e) {
2317                         throw new ParserException("EOF, " ~ expr.stringof ~ "=", e);
2318                     }
2319 
2320                     if (lexer.token == Token.COLONEQ) {
2321                         lexer.nextToken();
2322                         SQLExpr colonExpr = this.expr();
2323                         rightExp = new SQLBinaryOpExpr(rightExp, SQLBinaryOperator.Assignment, colonExpr, dbType);
2324                     }
2325 
2326                     expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Equality, rightExp, dbType);
2327                 } else */ {
2328                     return expr;
2329                 }
2330             case Token.TILDE:
2331                 if (DBType.POSTGRESQL == (lexer.dbType)) {
2332                     lexer.nextToken();
2333 
2334                     rightExp = relational();
2335 
2336                     rightExp = relationalRest(rightExp);
2337 
2338                     expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.POSIX_Regular_Match, rightExp, getDbType());
2339                 } else {
2340                     return expr;
2341                 }
2342                 break;
2343             case Token.TILDE_STAR:
2344                 if (DBType.POSTGRESQL.name == (lexer.dbType)) {
2345                     lexer.nextToken();
2346                     rightExp = relational();
2347                     expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.POSIX_Regular_Match_Insensitive, rightExp, getDbType());
2348                 } else {
2349                     return expr;
2350                 }
2351                 break;
2352             case Token.BANG_TILDE:
2353                 if (DBType.POSTGRESQL.name == (lexer.dbType)) {
2354                     lexer.nextToken();
2355                     rightExp = relational();
2356                     expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.POSIX_Regular_Not_Match, rightExp, getDbType());
2357                 } else {
2358                     return expr;
2359                 }
2360                 break;
2361             case Token.BANG_TILDE_STAR:
2362                 if (DBType.POSTGRESQL.name == (lexer.dbType)) {
2363                     lexer.nextToken();
2364                     rightExp = relational();
2365                     expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.POSIX_Regular_Not_Match_POSIX_Regular_Match_Insensitive, rightExp, getDbType());
2366                 } else {
2367                     return expr;
2368                 }
2369                 break;
2370             case Token.TILDE_EQ:
2371                 if (DBType.POSTGRESQL.name == (lexer.dbType)) {
2372                     lexer.nextToken();
2373                     rightExp = relational();
2374                     expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.SAME_AS, rightExp, getDbType());
2375                 } else {
2376                     return expr;
2377                 }
2378                 break;
2379             case Token.RLIKE:
2380                 lexer.nextToken();
2381                 rightExp = relational();
2382                 expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.RLike, rightExp, getDbType());
2383                 break;
2384             case Token.IDENTIFIER:
2385                 long hash = lexer.hash_lower;
2386                 if (hash == FnvHash.Constants.SOUNDS) {
2387                     lexer.nextToken();
2388                     accept(Token.LIKE);
2389 
2390                     rightExp = relational();
2391 
2392                     expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.SoudsLike, rightExp, getDbType());
2393                 } else if (hash == FnvHash.Constants.REGEXP) {
2394                     lexer.nextToken();
2395                     rightExp = relational();
2396 
2397                     return new SQLBinaryOpExpr(expr, SQLBinaryOperator.RegExp, rightExp, DBType.MYSQL.name);
2398 
2399                 } else if (hash == FnvHash.Constants.SIMILAR && DBType.POSTGRESQL.name == (lexer.dbType)) {
2400                     lexer.nextToken();
2401                     accept(Token.TO);
2402 
2403                     rightExp = relational();
2404 
2405                     expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.SIMILAR_TO, rightExp, getDbType());
2406                 } else {
2407                     return expr;
2408                 }
2409                 break;
2410             default:
2411                 break;
2412         }
2413 
2414         switch (lexer.token) {
2415             case Token.BETWEEN:
2416             case Token.IS:
2417             case Token.EQ:
2418             case Token.IN:
2419             case Token.CONTAINS:
2420             case Token.BANG_TILDE_STAR:
2421             case Token.TILDE_EQ:
2422             case Token.LT:
2423             case Token.LTEQ:
2424             case Token.LTEQGT:
2425             case Token.GT:
2426             case Token.GTEQ:
2427             case Token.LTGT:
2428             case Token.BANGEQ:
2429             case Token.LIKE:
2430             case Token.NOT:
2431                 expr = relationalRest(expr);
2432                 break;
2433             default:
2434                 break;
2435         }
2436 
2437         return expr;
2438     }
2439 
2440     public SQLExpr notRationalRest(SQLExpr expr) {
2441         SQLExpr rightExp;
2442         switch (lexer.token) {
2443             case Token.LIKE:
2444                 lexer.nextTokenValue();
2445                  rightExp = bitOr();
2446 
2447                 expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.NotLike, rightExp, getDbType());
2448 
2449                 if (lexer.token == Token.ESCAPE) {
2450                     lexer.nextToken();
2451                     rightExp = bitOr();
2452                     expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Escape, rightExp, getDbType());
2453                 }
2454                 break;
2455             case Token.IN:
2456                 lexer.nextToken();
2457 
2458                 SQLInListExpr inListExpr = new SQLInListExpr(expr, true);
2459                 if (lexer.token == Token.LPAREN) {
2460                     lexer.nextToken();
2461 
2462                     exprList(inListExpr.getTargetList(), inListExpr);
2463                     expr = inListExpr;
2464 
2465                     accept(Token.RPAREN);
2466                 } else {
2467                     SQLExpr valueExpr = this.primary();
2468                     valueExpr.setParent(inListExpr);
2469                     inListExpr.getTargetList().add(valueExpr);
2470                     expr = inListExpr;
2471                 }
2472 
2473                 if (inListExpr.getTargetList().size() == 1) {
2474                     SQLExpr targetExpr = inListExpr.getTargetList().get(0);
2475                     if (cast(SQLQueryExpr)(targetExpr) !is null) {
2476                         SQLInSubQueryExpr inSubQueryExpr = new SQLInSubQueryExpr();
2477                         inSubQueryExpr.setNot(true);
2478                         inSubQueryExpr.setExpr(inListExpr.getExpr());
2479                         inSubQueryExpr.setSubQuery((cast(SQLQueryExpr) targetExpr).getSubQuery());
2480                         expr = inSubQueryExpr;
2481                     }
2482                 }
2483 
2484                 break;
2485             case Token.CONTAINS:
2486                 lexer.nextToken();
2487 
2488                 SQLContainsExpr containsExpr = new SQLContainsExpr(expr, true);
2489                 if (lexer.token == Token.LPAREN) {
2490                     lexer.nextToken();
2491 
2492                     exprList(containsExpr.getTargetList(), containsExpr);
2493                     expr = containsExpr;
2494 
2495                     accept(Token.RPAREN);
2496                 } else {
2497                     SQLExpr valueExpr = this.primary();
2498                     valueExpr.setParent(containsExpr);
2499                     containsExpr.getTargetList().add(valueExpr);
2500                     expr = containsExpr;
2501                 }
2502 
2503                 if (containsExpr.getTargetList().size() == 1) {
2504                     SQLExpr targetExpr = containsExpr.getTargetList().get(0);
2505                     if (cast(SQLQueryExpr)(targetExpr) !is null) {
2506                         SQLInSubQueryExpr inSubQueryExpr = new SQLInSubQueryExpr();
2507                         inSubQueryExpr.setNot(true);
2508                         inSubQueryExpr.setExpr(containsExpr.getExpr());
2509                         inSubQueryExpr.setSubQuery((cast(SQLQueryExpr) targetExpr).getSubQuery());
2510                         expr = inSubQueryExpr;
2511                     }
2512                 }
2513 
2514                 break;
2515             case Token.BETWEEN:
2516                 lexer.nextToken();
2517                 SQLExpr beginExpr = relational();
2518                 accept(Token.AND);
2519                 SQLExpr endExpr = relational();
2520 
2521                 expr = new SQLBetweenExpr(expr, true, beginExpr, endExpr);
2522                 break;
2523             case Token.ILIKE:
2524                 lexer.nextToken();
2525                 rightExp = bitOr();
2526 
2527                 return new SQLBinaryOpExpr(expr, SQLBinaryOperator.NotILike, rightExp, getDbType());
2528             case Token.LPAREN:
2529                 expr = this.primary();
2530                 break;
2531             case Token.RLIKE:
2532                 lexer.nextToken();
2533                 rightExp = bitOr();
2534                 expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.NotRLike, rightExp, getDbType());
2535                 break;
2536             case Token.IDENTIFIER:
2537                 long hash = lexer.hash_lower;
2538                 if (hash == FnvHash.Constants.REGEXP) {
2539                     lexer.nextToken();
2540                     rightExp = bitOr();
2541                     expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.NotRegExp, rightExp, getDbType());
2542                 }
2543                 break;
2544             default:
2545                 throw new ParserException("TODO " ~ lexer.info());
2546         }
2547 
2548         return expr;
2549     }
2550 
2551     public SQLDataType parseDataType() {
2552         return parseDataType(true);
2553     }
2554 
2555     public SQLDataType parseDataType(bool restrict) {
2556         Token token = lexer.token;
2557         if (token == Token.DEFAULT || token == Token.NOT || token == Token.NULL) {
2558             return null;
2559         }
2560 
2561         SQLName typeExpr = name();
2562         string typeName = (cast(Object)(typeExpr)).toString();
2563 
2564         version(HUNT_SQL_PARSER_DEBUG) warningf("typename: %s", typeName);
2565         
2566         if ("long".equalsIgnoreCase(typeName) // 
2567                 && lexer.identifierEquals("byte") //
2568                 && DBType.MYSQL.name == (getDbType()) //
2569                 ) {
2570             typeName ~= (' ' ~ lexer.stringVal());
2571             lexer.nextToken();
2572         } else if ("double".equalsIgnoreCase(typeName)
2573                 && DBType.POSTGRESQL.name == (getDbType()) //
2574                 ) {
2575             typeName ~= (' ' ~ lexer.stringVal());
2576             lexer.nextToken();
2577         }
2578 
2579         if (isCharType(typeName)) {
2580             SQLCharacterDataType charType = new SQLCharacterDataType(typeName);
2581 
2582             if (lexer.token == Token.LPAREN) {
2583                 lexer.nextToken();
2584                 SQLExpr arg = this.expr();
2585                 arg.setParent(charType);
2586                 charType.addArgument(arg);
2587                 accept(Token.RPAREN);
2588             }
2589 
2590             charType = cast(SQLCharacterDataType) parseCharTypeRest(charType);
2591 
2592             if (lexer.token == Token.HINT) {
2593                 List!(SQLCommentHint) hints = this.parseHints();
2594                 charType.setHints(hints);
2595             }
2596 
2597             return charType;
2598         }
2599 
2600         if ("character".equalsIgnoreCase(typeName) && "varying".equalsIgnoreCase(lexer.stringVal())) {
2601             typeName ~= ' ' ~ lexer.stringVal();
2602             lexer.nextToken();
2603         }
2604 
2605         SQLDataTypeImpl dataType = new SQLDataTypeImpl(typeName);
2606         dataType.setDbType(dbType);
2607 
2608         version(HUNT_SQL_PARSER_DEBUG) infof("token: %s, value: %s", lexer.token, cast(string)lexer.token);
2609 
2610         // FIXME: Needing refactor or cleanup -@zhangxueping at 2020-08-05T18:03:58+08:00
2611         // 
2612         // if (lexer.token == Token.LPAREN) {
2613         //     lexer.nextToken();
2614         //     SQLExpr arg = this.expr();
2615         //     arg.setParent(dataType);
2616         //     dataType.addArgument(arg);
2617         //     accept(Token.RPAREN);
2618         // }
2619 
2620         return parseDataTypeRest(dataType);
2621     }
2622 
2623     protected SQLDataType parseDataTypeRest(SQLDataType dataType) {
2624         if (lexer.token == Token.LPAREN) {
2625             lexer.nextToken();
2626             exprList(dataType.getArguments(), dataType);
2627             accept(Token.RPAREN);
2628         }
2629         
2630         if (lexer.identifierEquals(FnvHash.Constants.PRECISION)
2631                 && dataType.nameHashCode64() == FnvHash.Constants.DOUBLE) {
2632             lexer.nextToken();
2633             dataType.setName("DOUBLE PRECISION");
2634         }
2635 
2636         if (FnvHash.Constants.TIMESTAMP == dataType.nameHashCode64()) {
2637             if (lexer.identifierEquals(FnvHash.Constants.WITHOUT)) {
2638                 lexer.nextToken();
2639                 acceptIdentifier("TIME");
2640                 acceptIdentifier("ZONE");
2641                 dataType.setWithTimeZone(Boolean.FALSE);
2642             } else if (lexer.token == Token.WITH) {
2643                 lexer.nextToken();
2644                 acceptIdentifier("TIME");
2645                 acceptIdentifier("ZONE");
2646                 dataType.setWithTimeZone(Boolean.TRUE);
2647             }
2648         }
2649 
2650         return dataType;
2651     }
2652 
2653     protected bool isCharType(string dataTypeName) {
2654         long hash = FnvHash.hashCode64(dataTypeName);
2655         return isCharType(hash);
2656     }
2657 
2658 
2659     protected bool isCharType(long hash) {
2660         return hash == FnvHash.Constants.CHAR
2661                 || hash == FnvHash.Constants.VARCHAR
2662                 || hash == FnvHash.Constants.NCHAR
2663                 || hash == FnvHash.Constants.NVARCHAR
2664                 || hash == FnvHash.Constants.TINYTEXT
2665                 || hash == FnvHash.Constants.TEXT
2666                 || hash == FnvHash.Constants.MEDIUMTEXT
2667                 || hash == FnvHash.Constants.LONGTEXT
2668                 ;
2669     }
2670 
2671     protected SQLDataType parseCharTypeRest(SQLCharacterDataType charType) {
2672         if (lexer.token == Token.BINARY) {
2673             charType.setHasBinary(true);
2674             lexer.nextToken();
2675         }
2676 
2677         if (lexer.identifierEquals(FnvHash.Constants.CHARACTER)) {
2678             lexer.nextToken();
2679 
2680             accept(Token.SET);
2681 
2682             if (lexer.token != Token.IDENTIFIER
2683                     && lexer.token != Token.LITERAL_CHARS
2684                     && lexer.token != Token.BINARY) {
2685                 throw new ParserException(lexer.info());
2686             }
2687             charType.setCharSetName(lexer.stringVal());
2688             lexer.nextToken();
2689         } else  if (lexer.identifierEquals(FnvHash.Constants.CHARSET)) {
2690             lexer.nextToken();
2691 
2692             if (lexer.token != Token.IDENTIFIER
2693                     && lexer.token != Token.LITERAL_CHARS
2694                     && lexer.token != Token.BINARY) {
2695                 throw new ParserException(lexer.info());
2696             }
2697             charType.setCharSetName(lexer.stringVal());
2698             lexer.nextToken();
2699         }
2700 
2701         if (lexer.token == Token.BINARY) {
2702             charType.setHasBinary(true);
2703             lexer.nextToken();
2704         }
2705 
2706         if (lexer.identifierEquals(FnvHash.Constants.COLLATE)) {
2707             lexer.nextToken();
2708 
2709             if (lexer.token == Token.LITERAL_ALIAS) {
2710                 charType.setCollate(lexer.stringVal());
2711             } else if (lexer.token == Token.IDENTIFIER) {
2712                 charType.setCollate(lexer.stringVal());
2713             } else {
2714                 throw new ParserException();
2715             }
2716 
2717             lexer.nextToken();
2718         }
2719 
2720         return charType;
2721     }
2722 
2723     override public void accept(Token token) {
2724         if (lexer.token == token) {
2725             lexer.nextToken();
2726         } else {
2727             throw new ParserException("syntax error, expect:{" ~ token ~ "}, actual:{" ~ lexer.token ~ "}, "
2728                                       ~ lexer.info());
2729         }
2730     }
2731 
2732     public SQLColumnDefinition parseColumn() {
2733         SQLColumnDefinition column = createColumnDefinition();
2734         column.setName(name());
2735 
2736          Token token = lexer.token;
2737         if (token != Token.SET //
2738                 && token != Token.DROP
2739                 && token != Token.PRIMARY
2740                 && token != Token.RPAREN) {
2741             column.setDataType(parseDataType());
2742         }
2743         return parseColumnRest(column);
2744     }
2745 
2746     public SQLColumnDefinition createColumnDefinition() {
2747         SQLColumnDefinition column = new SQLColumnDefinition();
2748         column.setDbType(dbType);
2749         return column;
2750     }
2751 
2752     public SQLColumnDefinition parseColumnRest(SQLColumnDefinition column) {
2753         if (lexer.token == Token.DEFAULT) {
2754             lexer.nextToken();
2755             column.setDefaultExpr(bitOr());
2756             return parseColumnRest(column);
2757         }
2758 
2759         if (lexer.token == Token.NOT) {
2760             lexer.nextToken();
2761             accept(Token.NULL);
2762             SQLNotNullConstraint notNull = new SQLNotNullConstraint();
2763             if (lexer.token == Token.HINT) {
2764                 List!(SQLCommentHint) hints = this.parseHints();
2765                 notNull.setHints(hints);
2766             }
2767             column.addConstraint(notNull);
2768             return parseColumnRest(column);
2769         }
2770 
2771         if (lexer.token == Token.NULL) {
2772             lexer.nextToken();
2773             column.getConstraints().add(new SQLNullConstraint());
2774             return parseColumnRest(column);
2775         }
2776 
2777         if (lexer.token == Token.PRIMARY) {
2778             lexer.nextToken();
2779             accept(Token.KEY);
2780             column.addConstraint(new SQLColumnPrimaryKey());
2781             return parseColumnRest(column);
2782         }
2783 
2784         if (lexer.token == Token.UNIQUE) {
2785             lexer.nextToken();
2786             if (lexer.token == Token.KEY) {
2787                 lexer.nextToken();
2788             }
2789             column.addConstraint(new SQLColumnUniqueKey());
2790             return parseColumnRest(column);
2791         }
2792 
2793         if (lexer.token == Token.KEY) {
2794             lexer.nextToken();
2795             column.addConstraint(new SQLColumnUniqueKey());
2796             return parseColumnRest(column);
2797         }
2798 
2799         if (lexer.token == Token.REFERENCES) {
2800             SQLColumnReference _ref = parseReference();
2801             column.addConstraint(_ref);
2802             return parseColumnRest(column);
2803         }
2804 
2805         if (lexer.token == Token.CONSTRAINT) {
2806             lexer.nextToken();
2807 
2808             SQLName name = this.name();
2809 
2810             if (lexer.token == Token.PRIMARY) {
2811                 lexer.nextToken();
2812                 accept(Token.KEY);
2813                 SQLColumnPrimaryKey pk = new SQLColumnPrimaryKey();
2814                 pk.setName(name);
2815                 column.addConstraint(pk);
2816                 return parseColumnRest(column);
2817             }
2818 
2819             if (lexer.token == Token.UNIQUE) {
2820                 lexer.nextToken();
2821                 SQLColumnUniqueKey uk = new SQLColumnUniqueKey();
2822                 uk.setName(name);
2823 
2824                 column.addConstraint(uk);
2825                 return parseColumnRest(column);
2826             }
2827 
2828             if (lexer.token == Token.REFERENCES) {
2829                 SQLColumnReference _ref = parseReference();
2830                 _ref.setName(name);
2831                 column.addConstraint(_ref);
2832                 return parseColumnRest(column);
2833             }
2834 
2835             if (lexer.token == Token.NOT) {
2836                 lexer.nextToken();
2837                 accept(Token.NULL);
2838                 SQLNotNullConstraint notNull = new SQLNotNullConstraint();
2839                 notNull.setName(name);
2840                 column.addConstraint(notNull);
2841                 return parseColumnRest(column);
2842             }
2843 
2844             if (lexer.token == Token.CHECK) {
2845                 SQLColumnCheck check = parseColumnCheck();
2846                 check.setName(name);
2847                 check.setParent(column);
2848                 column.addConstraint(check);
2849                 return parseColumnRest(column);
2850             }
2851 
2852             if (lexer.token == Token.DEFAULT) {
2853                 lexer.nextToken();
2854                 SQLExpr expr = this.expr();
2855                 column.setDefaultExpr(expr);
2856                 return parseColumnRest(column);
2857             }
2858 
2859             throw new ParserException("TODO : " ~ lexer.info());
2860         }
2861 
2862         if (lexer.token == Token.CHECK) {
2863             SQLColumnCheck check = parseColumnCheck();
2864             column.addConstraint(check);
2865             return parseColumnRest(column);
2866         }
2867 
2868         if (lexer.token == Token.COMMENT) {
2869             lexer.nextToken();
2870 
2871             if (lexer.token == Token.LITERAL_ALIAS) {
2872                 string _alias = lexer.stringVal();
2873                 if (_alias.length > 2 && charAt(_alias, 0) == '"' && charAt(_alias, _alias.length - 1) == '"') {
2874                     _alias = _alias.substring(1, cast(int)(_alias.length - 1));
2875                 }
2876                 column.setComment(_alias);
2877                 lexer.nextToken();
2878             } else {
2879                 column.setComment(primary());
2880             }
2881             return parseColumnRest(column);
2882         }
2883 
2884         if (lexer.identifierEquals(FnvHash.Constants.AUTO_INCREMENT)) {
2885             lexer.nextToken();
2886             column.setAutoIncrement(true);
2887             return parseColumnRest(column);
2888         }
2889 
2890         return column;
2891     }
2892 
2893     private SQLColumnReference parseReference() {
2894         SQLColumnReference fk = new SQLColumnReference();
2895 
2896         lexer.nextToken();
2897         fk.setTable(this.name());
2898         accept(Token.LPAREN);
2899         this.names(fk.getColumns(), fk);
2900         accept(Token.RPAREN);
2901 
2902         if (lexer.identifierEquals(FnvHash.Constants.MATCH)) {
2903             lexer.nextToken();
2904             if (lexer.identifierEquals("FULL") || lexer.token() == Token.FULL) {
2905                 fk.setReferenceMatch(SQLForeignKeyImpl.Match.FULL);
2906                 lexer.nextToken();
2907             } else if (lexer.identifierEquals(FnvHash.Constants.PARTIAL)) {
2908                 fk.setReferenceMatch(SQLForeignKeyImpl.Match.PARTIAL);
2909                 lexer.nextToken();
2910             } else if (lexer.identifierEquals(FnvHash.Constants.SIMPLE)) {
2911                 fk.setReferenceMatch(SQLForeignKeyImpl.Match.SIMPLE);
2912                 lexer.nextToken();
2913             } else {
2914                 throw new ParserException("TODO : " ~ lexer.info());
2915             }
2916         }
2917 
2918         while (lexer.token() == Token.ON) {
2919             lexer.nextToken();
2920 
2921             if (lexer.token() == Token.DELETE) {
2922                 lexer.nextToken();
2923 
2924                 SQLForeignKeyImpl.Option option = parseReferenceOption();
2925                 fk.setOnDelete(option);
2926             } else if (lexer.token() == Token.UPDATE) {
2927                 lexer.nextToken();
2928 
2929                 SQLForeignKeyImpl.Option option = parseReferenceOption();
2930                 fk.setOnUpdate(option);
2931             } else {
2932                 throw new ParserException("syntax error, expect DELETE or UPDATE, actual " ~ lexer.token() ~ " "
2933                         ~ lexer.info());
2934             }
2935         }
2936 
2937         return fk;
2938     }
2939 
2940     protected SQLForeignKeyImpl.Option parseReferenceOption() {
2941         SQLForeignKeyImpl.Option option;
2942         if (lexer.token() == Token.RESTRICT || lexer.identifierEquals(FnvHash.Constants.RESTRICT)) {
2943             option = SQLForeignKeyImpl.Option.RESTRICT;
2944             lexer.nextToken();
2945         } else if (lexer.identifierEquals(FnvHash.Constants.CASCADE)) {
2946             option = SQLForeignKeyImpl.Option.CASCADE;
2947             lexer.nextToken();
2948         } else if (lexer.token() == Token.SET) {
2949             lexer.nextToken();
2950             accept(Token.NULL);
2951             option = SQLForeignKeyImpl.Option.SET_NULL;
2952         } else if (lexer.identifierEquals(FnvHash.Constants.NO)) {
2953             lexer.nextToken();
2954             if (lexer.identifierEquals(FnvHash.Constants.ACTION)) {
2955                 option = SQLForeignKeyImpl.Option.NO_ACTION;
2956                 lexer.nextToken();
2957             } else {
2958                 throw new ParserException("syntax error, expect ACTION, actual " ~ lexer.token() ~ " "
2959                         ~ lexer.info());
2960             }
2961         } else {
2962             throw new ParserException("syntax error, expect ACTION, actual " ~ lexer.token() ~ " "
2963                     ~ lexer.info());
2964         }
2965 
2966         return option;
2967     }
2968 
2969     protected SQLColumnCheck parseColumnCheck() {
2970         lexer.nextToken();
2971         SQLExpr expr = this.expr();
2972         SQLColumnCheck check = new SQLColumnCheck(expr);
2973 
2974         if (lexer.token == Token.DISABLE) {
2975             lexer.nextToken();
2976             check.setEnable(Boolean.FALSE);
2977         } else if (lexer.token == Token.ENABLE) {
2978             lexer.nextToken();
2979             check.setEnable(Boolean.TRUE);
2980         } else if (lexer.identifierEquals(FnvHash.Constants.VALIDATE)) {
2981             lexer.nextToken();
2982             check.setValidate(Boolean.TRUE);
2983         } else if (lexer.identifierEquals(FnvHash.Constants.NOVALIDATE)) {
2984             lexer.nextToken();
2985             check.setValidate(Boolean.FALSE);
2986         } else if (lexer.identifierEquals(FnvHash.Constants.RELY)) {
2987             lexer.nextToken();
2988             check.setRely(Boolean.TRUE);
2989         } else if (lexer.identifierEquals(FnvHash.Constants.NORELY)) {
2990             lexer.nextToken();
2991             check.setRely(Boolean.FALSE);
2992         }
2993         return check;
2994     }
2995 
2996     public SQLPrimaryKey parsePrimaryKey() {
2997         accept(Token.PRIMARY);
2998         accept(Token.KEY);
2999 
3000         SQLPrimaryKeyImpl pk = new SQLPrimaryKeyImpl();
3001 
3002         if (lexer.identifierEquals(FnvHash.Constants.CLUSTERED)) {
3003             lexer.nextToken();
3004             pk.setClustered(true);
3005         }
3006 
3007         accept(Token.LPAREN);
3008         orderBy(pk.getColumns(), pk);
3009         accept(Token.RPAREN);
3010 
3011         return pk;
3012     }
3013 
3014     public SQLUnique parseUnique() {
3015         accept(Token.UNIQUE);
3016 
3017         SQLUnique unique = new SQLUnique();
3018         accept(Token.LPAREN);
3019         orderBy(unique.getColumns(), unique);
3020         accept(Token.RPAREN);
3021 
3022         if (lexer.token == Token.DISABLE) {
3023             lexer.nextToken();
3024             unique.setEnable(Boolean.FALSE);
3025         } else if (lexer.token == Token.ENABLE) {
3026             lexer.nextToken();
3027             unique.setEnable(Boolean.TRUE);
3028         } else if (lexer.identifierEquals(FnvHash.Constants.VALIDATE)) {
3029             lexer.nextToken();
3030             unique.setValidate(Boolean.TRUE);
3031         } else if (lexer.identifierEquals(FnvHash.Constants.NOVALIDATE)) {
3032             lexer.nextToken();
3033             unique.setValidate(Boolean.FALSE);
3034         } else if (lexer.identifierEquals(FnvHash.Constants.RELY)) {
3035             lexer.nextToken();
3036             unique.setRely(Boolean.TRUE);
3037         } else if (lexer.identifierEquals(FnvHash.Constants.NORELY)) {
3038             lexer.nextToken();
3039             unique.setRely(Boolean.FALSE);
3040         }
3041 
3042         return unique;
3043     }
3044 
3045     public SQLAssignItem parseAssignItem() {
3046         SQLAssignItem item = new SQLAssignItem();
3047 
3048         SQLExpr var = primary();
3049 
3050         if (cast(SQLIdentifierExpr)(var) !is null) {
3051             var = new SQLVariantRefExpr((cast(SQLIdentifierExpr) var).getName());
3052         }
3053         item.setTarget(var);
3054         if (lexer.token == Token.COLONEQ) {
3055             lexer.nextToken();
3056         } else if (lexer.token == Token.TRUE || lexer.identifierEquals(FnvHash.Constants.TRUE)) {
3057             lexer.nextToken();
3058             item.setValue(new SQLBooleanExpr(true));
3059             return item;
3060         } else if (lexer.token == Token.ON) {
3061             lexer.nextToken();
3062             item.setValue(new SQLIdentifierExpr("ON"));
3063             return item;
3064         } else {
3065             if (lexer.token == Token.EQ) {
3066                 lexer.nextToken();
3067             }  else {
3068                 accept(Token.EQ);
3069             }
3070         }
3071 
3072         if (lexer.token == Token.ON) {
3073             item.setValue(new SQLIdentifierExpr(lexer.stringVal()));
3074             lexer.nextToken();
3075         } else {
3076             if (lexer.token == Token.ALL) {
3077                 item.setValue(new SQLIdentifierExpr(lexer.stringVal()));
3078                 lexer.nextToken();
3079             } else {
3080                 SQLExpr expr = this.expr();
3081 
3082                 if (lexer.token == Token.COMMA && DBType.POSTGRESQL.name == (dbType)) {
3083                     SQLListExpr listExpr = new SQLListExpr();
3084                     listExpr.addItem(expr);
3085                     expr.setParent(listExpr);
3086                     do {
3087                         lexer.nextToken();
3088                         SQLExpr listItem = this.expr();
3089                         listItem.setParent(listExpr);
3090                         listExpr.addItem(listItem);
3091                     } while (lexer.token == Token.COMMA);
3092                     item.setValue(listExpr);
3093                 } else {
3094                     item.setValue(expr);
3095                 }
3096             }
3097         }
3098 
3099         return item;
3100     }
3101 
3102     public List!(SQLCommentHint) parseHints() {
3103         List!(SQLCommentHint) hints = new ArrayList!(SQLCommentHint)();
3104         parseHints!(SQLCommentHint)((hints));
3105         return hints;
3106     }
3107 
3108     //@SuppressWarnings({ "unchecked", "rawtypes" })
3109     public void parseHints(T)(List!(T) hints) {
3110         if (lexer.token == Token.HINT) {
3111             SQLCommentHint hint = new SQLCommentHint(lexer.stringVal());
3112 
3113             if (lexer.commentCount > 0) {
3114                 hint.addBeforeComment(lexer.comments);
3115             }
3116 
3117             hints.add(hint);
3118             lexer.nextToken();
3119         }
3120     }
3121 
3122     public SQLConstraint parseConstaint() {
3123         SQLName name = null;
3124 
3125         if (lexer.token == Token.CONSTRAINT) {
3126             lexer.nextToken();
3127             name = this.name();
3128         }
3129 
3130         SQLConstraint constraint;
3131         if (lexer.token == Token.PRIMARY) {
3132             constraint = parsePrimaryKey();
3133         } else if (lexer.token == Token.UNIQUE) {
3134             constraint = parseUnique();
3135         } else if (lexer.token == Token.KEY) {
3136             constraint = parseUnique();
3137         } else if (lexer.token == Token.FOREIGN) {
3138             constraint = parseForeignKey();
3139         } else if (lexer.token == Token.CHECK) {
3140             constraint = parseCheck();
3141         } else {
3142             throw new ParserException("TODO : " ~ lexer.info());
3143         }
3144 
3145         constraint.setName(name);
3146 
3147         return constraint;
3148     }
3149 
3150     public SQLCheck parseCheck() {
3151         accept(Token.CHECK);
3152         SQLCheck check = createCheck();
3153         accept(Token.LPAREN);
3154         check.setExpr(this.expr());
3155         accept(Token.RPAREN);
3156         return check;
3157     }
3158 
3159     protected SQLCheck createCheck() {
3160         return new SQLCheck();
3161     }
3162 
3163     public SQLForeignKeyConstraint parseForeignKey() {
3164         accept(Token.FOREIGN);
3165         accept(Token.KEY);
3166 
3167         SQLForeignKeyImpl fk = createForeignKey();
3168 
3169         accept(Token.LPAREN);
3170         this.names(fk.getReferencingColumns(), fk);
3171         accept(Token.RPAREN);
3172 
3173         accept(Token.REFERENCES);
3174 
3175         fk.setReferencedTableName(this.name());
3176 
3177         if (lexer.token == Token.LPAREN) {
3178             lexer.nextToken();
3179             this.names(fk.getReferencedColumns(), fk);
3180             accept(Token.RPAREN);
3181         }
3182 
3183         if (lexer.token == Token.ON) {
3184             lexer.nextToken();
3185             accept(Token.DELETE);
3186             if (lexer.identifierEquals(FnvHash.Constants.CASCADE)) {
3187                 lexer.nextToken();
3188                 fk.setOnDeleteCascade(true);
3189             } else {
3190                 accept(Token.SET);
3191                 accept(Token.NULL);
3192                 fk.setOnDeleteSetNull(true);
3193             }
3194         }
3195 
3196         return fk;
3197     }
3198 
3199     protected SQLForeignKeyImpl createForeignKey() {
3200         return new SQLForeignKeyImpl();
3201     }
3202 
3203     public SQLSelectItem parseSelectItem() {
3204         SQLExpr expr;
3205         bool connectByRoot = false;
3206         Token token = lexer.token;
3207         if (token == Token.IDENTIFIER) {
3208             string ident = lexer.stringVal();
3209             long hash_lower = lexer.hash_lower();
3210             lexer.nextTokenComma();
3211 
3212             if (hash_lower == FnvHash.Constants.CONNECT_BY_ROOT) {
3213                 connectByRoot = lexer.token != Token.LPAREN;
3214                 if (connectByRoot) {
3215                     expr = new SQLIdentifierExpr(lexer.stringVal());
3216                     lexer.nextToken();
3217                 } else {
3218                     expr = new SQLIdentifierExpr(ident);
3219                 }
3220             } else if (FnvHash.Constants.DATE == hash_lower
3221                     && lexer.token == Token.LITERAL_CHARS
3222                     && (DBType.ORACLE.name == (getDbType())
3223                     || DBType.POSTGRESQL.name == (getDbType()))) {
3224                 string literal = lexer.stringVal();
3225                 lexer.nextToken();
3226 
3227                 SQLDateExpr dateExpr = new SQLDateExpr();
3228                 dateExpr.setLiteral(new String(literal));
3229 
3230                 expr = dateExpr;
3231             } else {
3232                 expr = new SQLIdentifierExpr(ident, hash_lower);
3233             }
3234 
3235             token = lexer.token;
3236 
3237             if (token == Token.DOT) {
3238                 lexer.nextTokenIdent();
3239                 string name;
3240                 long name_hash_lower;
3241 
3242                 if (lexer.token == Token.STAR) {
3243                     name = "*";
3244                     name_hash_lower = FnvHash.Constants.STAR;
3245                 } else {
3246                     name = lexer.stringVal();
3247                     name_hash_lower = lexer.hash_lower();
3248                 }
3249 
3250                 lexer.nextTokenComma();
3251 
3252                 token = lexer.token;
3253                 if (token == Token.LPAREN) {
3254                     bool aggregate = hash_lower == FnvHash.Constants.WMSYS && name_hash_lower == FnvHash.Constants.WM_CONCAT;
3255                     expr = methodRest(expr, name, aggregate);
3256                     token = lexer.token;
3257                 } else {
3258                     if (name_hash_lower == FnvHash.Constants.NEXTVAL) {
3259                         expr = new SQLSequenceExpr(cast(SQLIdentifierExpr) expr, SQLSequenceExpr.Function.NextVal);
3260                     } else if (name_hash_lower == FnvHash.Constants.CURRVAL) {
3261                         expr = new SQLSequenceExpr(cast(SQLIdentifierExpr) expr, SQLSequenceExpr.Function.CurrVal);
3262                     } else if (name_hash_lower == FnvHash.Constants.PREVVAL) {
3263                         expr = new SQLSequenceExpr(cast(SQLIdentifierExpr) expr, SQLSequenceExpr.Function.PrevVal);
3264                     } else {
3265                         expr = new SQLPropertyExpr(expr, name, name_hash_lower);
3266                     }
3267                 }
3268             }
3269 
3270             if (token == Token.COMMA) {
3271                 return new SQLSelectItem(expr, null, connectByRoot);
3272             }
3273 
3274             if (token == Token.AS) {
3275                 lexer.nextToken();
3276                 string as = null;
3277                 if (lexer.token != Token.COMMA && lexer.token != Token.FROM) {
3278                     as = lexer.stringVal();
3279 
3280                     lexer.nextTokenComma();
3281 
3282                     if (lexer.token == Token.DOT) {
3283                         lexer.nextToken();
3284                         as ~= '.' ~ lexer.stringVal();
3285                         lexer.nextToken();
3286                     }
3287                 }
3288 
3289                 return new SQLSelectItem(expr, as, connectByRoot);
3290             }
3291 
3292             if (token == Token.LITERAL_ALIAS) {
3293                 string as = lexer.stringVal();
3294                 lexer.nextTokenComma();
3295                 return new SQLSelectItem(expr, as, connectByRoot);
3296             }
3297 
3298             if ((token == Token.IDENTIFIER && hash_lower != FnvHash.Constants.CURRENT)
3299                     || token == Token.MODEL) {
3300                 string as;
3301                 if (lexer.hash_lower == FnvHash.Constants.FORCE && DBType.MYSQL.name == (dbType)) {
3302                     string force = lexer.stringVal();
3303 
3304                     Lexer.SavePoint savePoint = lexer.mark();
3305                     lexer.nextToken();
3306 
3307                     if (lexer.token == Token.PARTITION) {
3308                         lexer.reset(savePoint);
3309                         as = null;
3310                     } else {
3311                         as = force;
3312                         lexer.nextTokenComma();
3313                     }
3314                 } else {
3315                     as = lexer.stringVal();
3316                     lexer.nextTokenComma();
3317                 }
3318                 return new SQLSelectItem(expr, as, connectByRoot);
3319             }
3320 
3321             if (token == Token.LPAREN) {
3322                 lexer.nextToken();
3323                 expr = this.methodRest(expr, false);
3324             } else {
3325                 expr = this.primaryRest(expr);
3326             }
3327             expr = this.exprRest(expr);
3328         } else if (token == Token.STAR) {
3329             expr = new SQLAllColumnExpr();
3330             lexer.nextToken();
3331             return new SQLSelectItem(expr, null, connectByRoot);
3332         } else if (token == Token.DO || token == Token.JOIN) {
3333             expr = this.name();
3334             expr = this.exprRest(expr);
3335         } else {
3336             expr = this.expr();
3337         }
3338 
3339          string _alias;
3340         switch (lexer.token) {
3341             case Token.FULL:
3342             case Token.MODEL:
3343             case Token.TABLESPACE:
3344                 _alias = lexer.stringVal();
3345                 lexer.nextToken();
3346                 break;
3347             default:
3348                 _alias = as();
3349                 break;
3350         }
3351 
3352         SQLSelectItem selectItem = new SQLSelectItem(expr, _alias, connectByRoot);
3353         if (lexer.token == Token.HINT && !lexer.isEnabled(SQLParserFeature.StrictForWall)) {
3354             string comment = "/*" ~ lexer.stringVal() ~ "*/";
3355             selectItem.addAfterComment(comment);
3356             lexer.nextToken();
3357         }
3358 
3359         return selectItem;
3360     }
3361 
3362     public SQLExpr parseGroupingSet() {
3363         string tmp = lexer.stringVal();
3364         acceptIdentifier("GROUPING");
3365         
3366         SQLGroupingSetExpr expr = new SQLGroupingSetExpr();
3367         
3368         if (lexer.token == Token.SET || lexer.identifierEquals(FnvHash.Constants.SET)) {
3369             lexer.nextToken();
3370         } else {
3371             return new SQLIdentifierExpr(tmp);
3372         }
3373 
3374         accept(Token.LPAREN);
3375 
3376         this.exprList(expr.getParameters(), expr);
3377 
3378         accept(Token.RPAREN);
3379 
3380         return expr;
3381     }
3382 
3383     protected SQLPartition parsePartition() {
3384         throw new ParserException("TODO");
3385     }
3386 
3387     public  SQLPartitionBy parsePartitionBy() {
3388         throw new ParserException("TODO");
3389     }
3390     
3391     public SQLPartitionValue parsePartitionValues() {
3392         if (lexer.token != Token.VALUES) {
3393             return null;
3394         }
3395         lexer.nextToken();
3396 
3397         SQLPartitionValue values = null;
3398 
3399         if (lexer.token == Token.IN) {
3400             lexer.nextToken();
3401             values = new SQLPartitionValue(SQLPartitionValue.Operator.In);
3402 
3403             accept(Token.LPAREN);
3404             this.exprList(values.getItems(), values);
3405             accept(Token.RPAREN);
3406         } else if (lexer.identifierEquals(FnvHash.Constants.LESS)) {
3407             lexer.nextToken();
3408             acceptIdentifier("THAN");
3409 
3410             values = new SQLPartitionValue(SQLPartitionValue.Operator.LessThan);
3411 
3412             if (lexer.identifierEquals(FnvHash.Constants.MAXVALUE)) {
3413                 SQLIdentifierExpr maxValue = new SQLIdentifierExpr(lexer.stringVal());
3414                 lexer.nextToken();
3415                 maxValue.setParent(values);
3416                 values.addItem(maxValue);
3417             } else {
3418                 accept(Token.LPAREN);
3419                 this.exprList(values.getItems(), values);
3420                 accept(Token.RPAREN);
3421             }
3422         } else if (lexer.token == Token.LPAREN) {
3423             values = new SQLPartitionValue(SQLPartitionValue.Operator.List);
3424             lexer.nextToken();
3425             this.exprList(values.getItems(), values);
3426             accept(Token.RPAREN);
3427         }
3428 
3429         return values;
3430     }
3431     
3432     protected static bool isIdent(SQLExpr expr, string name) {
3433         if (cast(SQLIdentifierExpr)(expr) !is null) {
3434             SQLIdentifierExpr identExpr = cast(SQLIdentifierExpr) expr;
3435             return identExpr.getName().equalsIgnoreCase(name);
3436         }
3437         return false;
3438     }
3439 
3440     public SQLLimit parseLimit() {
3441         if (lexer.token == Token.LIMIT) {
3442             lexer.nextTokenValue();
3443 
3444             SQLLimit limit = new SQLLimit();
3445 
3446             SQLExpr temp;
3447             if (lexer.token == Token.LITERAL_INT) {
3448                 temp = new SQLIntegerExpr(lexer.integerValue());
3449                 lexer.nextTokenComma();
3450                 if (lexer.token != Token.COMMA && lexer.token != Token.EOF && lexer.token != Token.IDENTIFIER) {
3451                     temp = this.primaryRest(temp);
3452                     temp = this.exprRest(temp);
3453                 }
3454             } else {
3455                 temp = this.expr();
3456             }
3457 
3458             if (lexer.token == (Token.COMMA)) {
3459                 limit.setOffset(temp);
3460                 lexer.nextTokenValue();
3461 
3462                 SQLExpr rowCount;
3463                 if (lexer.token == Token.LITERAL_INT) {
3464                     rowCount = new SQLIntegerExpr(lexer.integerValue());
3465                     lexer.nextToken();
3466                     if (lexer.token != Token.EOF && lexer.token != Token.IDENTIFIER) {
3467                         rowCount = this.primaryRest(rowCount);
3468                         rowCount = this.exprRest(rowCount);
3469                     }
3470                 } else {
3471                     rowCount = this.expr();
3472                 }
3473 
3474                 limit.setRowCount(rowCount);
3475             } else if (lexer.identifierEquals(FnvHash.Constants.OFFSET)) {
3476                 limit.setRowCount(temp);
3477                 lexer.nextToken();
3478                 limit.setOffset(this.expr());
3479             } else {
3480                 limit.setRowCount(temp);
3481             }
3482             return limit;
3483         }
3484 
3485         return null;
3486     }
3487 }