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.SQLStatementParser;
17 
18 import hunt.collection;
19 
20 import hunt.sql.ast;
21 import hunt.sql.ast.expr;
22 import hunt.sql.ast.statement;
23 import hunt.sql.ast.statement.SQLCreateTriggerStatement;
24 // import hunt.sql.dialect.hive.ast.HiveInsert;
25 // import hunt.sql.dialect.hive.ast.HiveInsertStatement;
26 import hunt.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock;
27 import hunt.sql.dialect.mysql.parser.MySqlExprParser;
28 // import hunt.sql.dialect.oracle.parser.OracleExprParser;
29 import hunt.sql.util.FnvHash;
30 import hunt.sql.util.DBType;
31 import hunt.sql.parser.SQLParser;
32 import hunt.sql.parser.SQLExprParser;
33 import hunt.sql.parser.SQLSelectListCache;
34 import hunt.sql.parser.SQLCreateTableParser;
35 import hunt.sql.parser.SQLSelectParser;
36 import hunt.sql.ast.statement.SQLInsertStatement;
37 import hunt.sql.parser.InsertColumnsCache;
38 import hunt.sql.parser.Lexer;
39 import hunt.sql.parser.Token;
40 import hunt.String;
41 import hunt.sql.parser.ParserException;
42 //import hunt.lang;
43 import hunt.sql.parser.SQLParserFeature;
44 import hunt.text;
45 import hunt.Boolean;
46 import hunt.Integer;
47 
48 public class SQLStatementParser : SQLParser {
49 
50     protected SQLExprParser      exprParser;
51     protected bool            parseCompleteValues = true;
52     protected int                parseValuesSize     = 3;
53     protected SQLSelectListCache selectListCache     = null;
54     protected InsertColumnsCache insertColumnsCache  = null;
55 
56     public this(string sql){
57         import std.stdio;
58         this(sql, null);
59     }
60 
61     public this(string sql, string dbType){
62         this(new SQLExprParser(sql, dbType));
63     }
64 
65     public this(SQLExprParser exprParser){
66         super(exprParser.getLexer(), exprParser.getDbType());
67         this.exprParser = exprParser;
68     }
69 
70     protected this(Lexer lexer, string dbType){
71         super(lexer, dbType);
72     }
73 
74     public bool isKeepComments() {
75         return lexer.isKeepComments();
76     }
77 
78     public void setKeepComments(bool keepComments) {
79         this.lexer.setKeepComments(keepComments);
80     }
81 
82     public SQLExprParser getExprParser() {
83         return exprParser;
84     }
85 
86     public List!(SQLStatement) parseStatementList() {
87         List!(SQLStatement) statementList = new ArrayList!(SQLStatement)();
88         parseStatementList(statementList, -1, null);
89         return statementList;
90     }
91 
92     public List!(SQLStatement) parseStatementList(SQLObject parent) {
93         List!(SQLStatement) statementList = new ArrayList!(SQLStatement)();
94         parseStatementList(statementList, -1, parent);
95         return statementList;
96     }
97 
98     public void parseStatementList(List!(SQLStatement) statementList) {
99         parseStatementList(statementList, -1, null);
100     }
101 
102     public void parseStatementList(List!(SQLStatement) statementList, int max) {
103         parseStatementList(statementList, max, null);
104     }
105 
106     public void parseStatementList(List!(SQLStatement) statementList, int max, SQLObject parent) {
107         import std.stdio;
108         // writeln("#####");
109         if ("select @@session.tx_read_only" == (lexer.text)
110                 && lexer.token == Token.SELECT) {
111             SQLSelect select = new SQLSelect();
112             MySqlSelectQueryBlock queryBlock = new MySqlSelectQueryBlock();
113             queryBlock.addSelectItem(new SQLPropertyExpr(new SQLVariantRefExpr("@@session"), "tx_read_only"));
114             select.setQuery(queryBlock);
115 
116             SQLSelectStatement stmt = new SQLSelectStatement(select);
117             statementList.add(stmt);
118 
119             lexer.reset(29, '\u001A', Token.EOF);
120             return;
121         }
122 
123         for (;;) {
124             // writeln("token : ",lexer.token);
125             if (max != -1) {
126                 if (statementList.size() >= max) {
127                     return;
128                 }
129             }
130 
131             switch (lexer.token) {
132                 case Token.EOF:
133                 case Token.END:
134                 case Token.UNTIL:
135                 case Token.ELSE:
136                 case Token.WHEN:
137                     if (lexer.isKeepComments() && lexer.hasComment() && statementList.size() > 0) {
138                         SQLStatement stmt = statementList.get(statementList.size() - 1);
139                         stmt.addAfterComment(lexer.readAndResetComments());
140                     }
141                     return;
142                 case Token.SEMI: {
143                     int line0 = lexer.getLine();
144                     lexer.nextToken();
145                     int line1 = lexer.getLine();
146 
147                     if(statementList.size() > 0) {
148                         SQLStatement lastStmt = statementList.get(statementList.size() - 1);
149                         lastStmt.setAfterSemi(true);
150 
151                         if (lexer.isKeepComments()) {
152                             SQLStatement stmt = statementList.get(statementList.size() - 1);
153                             if (line1 - line0 <= 1) {
154                                 stmt.addAfterComment(lexer.readAndResetComments());
155                             }
156                         }
157                     }
158 
159                     continue;
160                 }
161                 case Token.WITH: {
162                     SQLStatement stmt = parseWith();
163                     stmt.setParent(parent);
164                     statementList.add(stmt);
165                     continue;
166                 }
167                 case Token.SELECT: {
168                     SQLStatement stmt = parseSelect();
169                     stmt.setParent(parent);
170                     statementList.add(stmt);
171                     continue;
172                 }
173                 case Token.UPDATE: {
174                     SQLStatement stmt = parseUpdateStatement();
175                     stmt.setParent(parent);
176                     statementList.add(stmt);
177                     continue;
178                 }
179                 case Token.CREATE: {
180                     SQLStatement stmt = parseCreate();
181                     stmt.setParent(parent);
182                     statementList.add(stmt);
183                     continue;
184                 }
185                 case Token.INSERT: {
186                     SQLStatement stmt = parseInsert();
187                     stmt.setParent(parent);
188                     statementList.add(stmt);
189                     continue;
190                 }
191                 case Token.DELETE: {
192                     SQLStatement stmt = parseDeleteStatement();
193                     stmt.setParent(parent);
194                     statementList.add(stmt);
195                     continue;
196                 }
197                 case Token.EXPLAIN: {
198                     SQLStatement stmt = parseExplain();
199                     stmt.setParent(parent);
200                     statementList.add(stmt);
201                     continue;
202                 }
203                 case Token.SET: {
204                     SQLStatement stmt = parseSet();
205                     stmt.setParent(parent);
206                     statementList.add(stmt);
207                     continue;
208                 }
209                 case Token.ALTER: {
210                     SQLStatement stmt = parseAlter();
211                     stmt.setParent(parent);
212                     statementList.add(stmt);
213                     continue;
214                 }
215                 case Token.TRUNCATE: {
216                     SQLStatement stmt = parseTruncate();
217                     stmt.setParent(parent);
218                     statementList.add(stmt);
219                     continue;
220                 }
221                 case Token.USE: {
222                     SQLStatement stmt = parseUse();
223                     stmt.setParent(parent);
224                     statementList.add(stmt);
225                     continue;
226                 }
227                 case Token.GRANT: {
228                     SQLStatement stmt = parseGrant();
229                     stmt.setParent(parent);
230                     statementList.add(stmt);
231                     continue;
232                 }
233                 case Token.REVOKE: {
234                     SQLStatement stmt = parseRevoke();
235                     stmt.setParent(parent);
236                     statementList.add(stmt);
237                     continue;
238                 }
239                 case Token.SHOW: {
240                     SQLStatement stmt = parseShow();
241                     stmt.setParent(parent);
242                     statementList.add(stmt);
243                     continue;
244                 }
245                 case Token.MERGE: {
246                     SQLStatement stmt = parseMerge();
247                     stmt.setParent(parent);
248                     statementList.add(stmt);
249                     continue;
250                 }
251                 case Token.REPEAT: {
252                     SQLStatement stmt = parseRepeat();
253                     stmt.setParent(parent);
254                     statementList.add(stmt);
255                     continue;
256                 }
257                 case Token.DECLARE: {
258                     SQLStatement stmt = parseDeclare();
259                     stmt.setParent(parent);
260                     statementList.add(stmt);
261                     continue;
262                 }
263                 case Token.WHILE: {
264                     SQLStatement stmt = parseWhile();
265                     stmt.setParent(parent);
266                     statementList.add(stmt);
267                     continue;
268                 }
269                 case Token.IF: {
270                     SQLStatement stmt = parseIf();
271                     stmt.setParent(parent);
272                     statementList.add(stmt);
273                     continue;
274                 }
275                 case Token.CASE: {
276                     SQLStatement stmt = parseCase();
277                     stmt.setParent(parent);
278                     statementList.add(stmt);
279                     continue;
280                 }
281                 case Token.OPEN: {
282                     SQLStatement stmt = parseOpen();
283                     stmt.setParent(parent);
284                     statementList.add(stmt);
285                     continue;
286                 }
287                 case Token.FETCH: {
288                     SQLStatement stmt = parseFetch();
289                     stmt.setParent(parent);
290                     statementList.add(stmt);
291                     continue;
292                 }
293                 case Token.DROP: {
294                     SQLStatement stmt = parseDrop();
295                     stmt.setParent(parent);
296                     statementList.add(stmt);
297                     continue;
298                 }
299                 case Token.COMMENT: {
300                     if(DBType.MYSQL.opEquals(this.dbType)){//mysql 关键字 comment 没有这个语法,oracle才有
301                         return;
302                     }
303                     SQLStatement stmt = parseComment();
304                     stmt.setParent(parent);
305                     statementList.add(stmt);
306                     continue;
307                 }
308                 case Token.KILL: {
309                     SQLStatement stmt = parseKill();
310                     stmt.setParent(parent);
311                     statementList.add(stmt);
312                     continue;
313                 }
314                 case Token.CLOSE: {
315                     SQLStatement stmt = parseClose();
316                     stmt.setParent(parent);
317                     statementList.add(stmt);
318                     continue;
319                 }
320                 case Token.RETURN: {
321                     SQLStatement stmt = parseReturn();
322                     stmt.setParent(parent);
323                     statementList.add(stmt);
324                     continue;
325                 }
326                 case Token.UPSERT: {
327                     SQLStatement stmt = parseUpsert();
328                     stmt.setParent(parent);
329                     statementList.add(stmt);
330                     continue;
331                 }
332                 case Token.LEAVE: {
333                     SQLStatement stmt = parseLeave();
334                     stmt.setParent(parent);
335                     statementList.add(stmt);
336                     continue;
337                 }
338                 default:
339                     break;
340             }
341 
342             if (lexer.token == Token.LBRACE || lexer.identifierEquals("CALL")) {
343                 SQLCallStatement stmt = parseCall();
344                 statementList.add(stmt);
345                 continue;
346             }
347 
348 
349             if (lexer.identifierEquals("UPSERT")) {
350                 SQLStatement stmt = parseUpsert();
351                 statementList.add(stmt);
352                 continue;
353             }
354 
355             if (lexer.identifierEquals("RENAME")) {
356                 SQLStatement stmt = parseRename();
357                 statementList.add(stmt);
358                 continue;
359             }
360 
361             if (lexer.identifierEquals(FnvHash.Constants.RELEASE)) {
362                 SQLStatement stmt = parseReleaseSavePoint();
363                 statementList.add(stmt);
364                 continue;
365             }
366 
367             if (lexer.identifierEquals(FnvHash.Constants.SAVEPOINT)) {
368                 SQLStatement stmt = parseSavePoint();
369                 statementList.add(stmt);
370                 continue;
371             }
372 
373             if (lexer.identifierEquals(FnvHash.Constants.ROLLBACK)) {
374                 SQLRollbackStatement stmt = parseRollback();
375                 statementList.add(stmt);
376 
377                 if (cast(SQLBlockStatement)(parent) !is null
378                         && DBType.MYSQL.opEquals(dbType)) {
379                     return;
380                 }
381 
382                 continue;
383             }
384 
385             if (lexer.identifierEquals(FnvHash.Constants.MERGE)) {
386                 SQLStatement stmt = parseMerge();
387                 stmt.setParent(parent);
388                 statementList.add(stmt);
389                 continue;
390             }
391 
392             if (lexer.identifierEquals("DUMP")) {
393                 SQLStatement stmt = parseDump();
394                 statementList.add(stmt);
395 
396                 continue;
397             }
398 
399             if (lexer.identifierEquals(FnvHash.Constants.COMMIT)) {
400                 SQLStatement stmt = parseCommit();
401 
402                 statementList.add(stmt);
403 
404                 if (cast(SQLBlockStatement)(parent) !is null
405                         && DBType.MYSQL.opEquals(dbType)) {
406                     return;
407                 }
408 
409                 continue;
410             }
411 
412             if (lexer.identifierEquals("RETURN")) {
413                 SQLStatement stmt = parseReturn();
414                 statementList.add(stmt);
415                 continue;
416             }
417 
418             if (lexer.token == Token.LPAREN) {
419                 char markChar = lexer.current();
420                 int markBp = lexer.bp();
421 
422                 do {
423                     lexer.nextToken();
424                 } while (lexer.token == Token.LPAREN);
425 
426                 if (lexer.token == Token.SELECT) {
427                     lexer.reset(markBp, markChar, Token.LPAREN);
428                     SQLStatement stmt = parseSelect();
429                     statementList.add(stmt);
430                     continue;
431                 } else {
432                     throw new ParserException("TODO " ~ lexer.info());
433                 }
434             }
435 
436             int size = statementList.size();
437             if (parseStatementListDialect(statementList)) {
438                 if (parent !is null) {
439                     for (int i = size; i < statementList.size(); ++i) {
440                         SQLStatement dialectStmt = statementList.get(i);
441                         dialectStmt.setParent(parent);
442                     }
443                 }
444 
445                 continue;
446             }
447 
448             // throw new ParserException("syntax error, " ~ lexer.token ~ " "
449             // + lexer.stringVal() ~ ", pos "
450             // + lexer.pos());
451             //throw new ParserException("not supported." ~ lexer.info());
452             printError(lexer.token);
453         }
454     }
455 
456     public SQLStatement parseDump() {
457         SQLDumpStatement stmt = new SQLDumpStatement();
458         acceptIdentifier("DUMP");
459         acceptIdentifier("DATA");
460 
461         if (lexer.identifierEquals(FnvHash.Constants.OVERWRITE)) {
462             lexer.nextToken();
463             stmt.setOverwrite(true);
464         }
465 
466         if (lexer.token == Token.INTO) {
467             lexer.nextToken();
468             stmt.setInto(this.exprParser.expr());
469         }
470 
471         SQLSelect select = createSQLSelectParser().select();
472         stmt.setSelect(select);
473         return stmt;
474     }
475 
476 
477     public SQLStatement parseDrop() {
478         List!(string) beforeComments = null;
479         if (lexer.isKeepComments() && lexer.hasComment()) {
480             beforeComments = lexer.readAndResetComments();
481         }
482 
483         lexer.nextToken();
484 
485          SQLStatement stmt;
486 
487         List!(SQLCommentHint) hints = null;
488         if (lexer.token == Token.HINT) {
489             hints = this.exprParser.parseHints();
490         }
491 
492         if (lexer.token == Token.TABLE || lexer.identifierEquals("TEMPORARY")) {
493             SQLDropTableStatement dropTable = parseDropTable(false);
494             if (hints !is null) {
495                 dropTable.setHints(hints);
496             }
497             stmt = dropTable;
498         } else if (lexer.token == Token.USER) {
499             stmt = parseDropUser();
500         } else if (lexer.token == Token.INDEX) {
501             stmt = parseDropIndex();
502         } else if (lexer.token == Token.VIEW) {
503             stmt = parseDropView(false);
504         } else if (lexer.token == Token.TRIGGER) {
505             stmt = parseDropTrigger(false);
506         } else if (lexer.token == Token.DATABASE || lexer.token == Token.SCHEMA) {
507             stmt = parseDropDatabase(false);
508         } else if (lexer.token == Token.FUNCTION) {
509             stmt = parseDropFunction(false);
510         } else if (lexer.token == Token.TABLESPACE) {
511             stmt = parseDropTablespace(false);
512 
513         } else if (lexer.token == Token.PROCEDURE) {
514             stmt = parseDropProcedure(false);
515 
516         } else if (lexer.token == Token.SEQUENCE) {
517             stmt = parseDropSequence(false);
518 
519         } else if (lexer.identifierEquals(FnvHash.Constants.EVENT)) {
520             stmt = parseDropEvent();
521 
522         } else if (lexer.identifierEquals(FnvHash.Constants.LOGFILE)) {
523             stmt = parseDropLogFileGroup();
524 
525         } else if (lexer.identifierEquals(FnvHash.Constants.SERVER)) {
526             stmt = parseDropServer();
527 
528         } else {
529             throw new ParserException("TODO " ~ lexer.info());
530         }
531 
532         if (beforeComments !is null) {
533             stmt.addBeforeComment(beforeComments);
534         }
535         return stmt;
536     }
537 
538     protected SQLStatement parseDropServer() {
539         if (lexer.token == Token.DROP) {
540             lexer.nextToken();
541         }
542 
543         acceptIdentifier("SERVER");
544 
545         SQLDropServerStatement stmt = new SQLDropServerStatement();
546         stmt.setDbType(dbType);
547 
548         if (lexer.token == Token.IF) {
549             lexer.nextToken();
550             accept(Token.EXISTS);
551             stmt.setIfExists(true);
552         }
553 
554         SQLName name = this.exprParser.name();
555         stmt.setName(name);
556 
557         return stmt;
558     }
559 
560     protected SQLStatement parseDropLogFileGroup() {
561         if (lexer.token == Token.DROP) {
562             lexer.nextToken();
563         }
564 
565         acceptIdentifier("LOGFILE");
566         accept(Token.GROUP);
567 
568         SQLDropLogFileGroupStatement stmt = new SQLDropLogFileGroupStatement();
569         stmt.setDbType(dbType);
570 
571         SQLName name = this.exprParser.name();
572         stmt.setName(name);
573 
574         if (lexer.identifierEquals(FnvHash.Constants.ENGINE)) {
575             lexer.nextToken();
576             if (lexer.token == Token.EQ) {
577                 lexer.nextToken();
578             }
579             SQLExpr engine = this.exprParser.primary();
580             stmt.setEngine(engine);
581         }
582 
583         return stmt;
584     }
585 
586     protected SQLStatement parseDropEvent() {
587         if (lexer.token == Token.DROP) {
588             lexer.nextToken();
589         }
590 
591         acceptIdentifier("EVENT");
592 
593         SQLDropEventStatement stmt = new SQLDropEventStatement();
594         stmt.setDbType(dbType);
595 
596         if (lexer.token == Token.IF) {
597             lexer.nextToken();
598             accept(Token.EXISTS);
599             stmt.setIfExists(true);
600         }
601 
602         SQLName name = this.exprParser.name();
603         stmt.setName(name);
604 
605         return stmt;
606     }
607 
608     protected SQLStatement parseAlterFunction() {
609         throw new ParserException("TODO " ~ lexer.info());
610     }
611 
612     public SQLStatement parseKill() {
613         throw new ParserException("not supported. " ~ lexer.info());
614     }
615 
616     public SQLStatement parseCase() {
617         throw new ParserException("not supported. " ~ lexer.info());
618     }
619 
620     public SQLStatement parseIf() {
621         throw new ParserException("not supported. " ~ lexer.info());
622     }
623 
624     public SQLStatement parseWhile() {
625         throw new ParserException("not supported. " ~ lexer.info());
626     }
627 
628     public SQLStatement parseDeclare() {
629         throw new ParserException("not supported. " ~ lexer.info());
630     }
631 
632     public SQLStatement parseRepeat() {
633         throw new ParserException("not supported. " ~ lexer.info());
634     }
635 
636     public SQLStatement parseLeave() {
637         throw new ParserException("not supported. " ~ lexer.info());
638     }
639 
640     public SQLStatement parseReturn() {
641         if (lexer.token == Token.RETURN
642                 || lexer.identifierEquals("RETURN")) {
643             lexer.nextToken();
644         }
645 
646         SQLReturnStatement stmt = new SQLReturnStatement();
647         if (lexer.token != Token.SEMI) {
648             SQLExpr expr = this.exprParser.expr();
649             stmt.setExpr(expr);
650         }
651 
652         if (lexer.token == Token.SEMI) {
653             lexer.nextToken();
654             stmt.setAfterSemi(true);
655         }
656 
657         return stmt;
658     }
659 
660     public SQLStatement parseUpsert() {
661         SQLInsertStatement insertStatement = new SQLInsertStatement();
662 
663         if (lexer.token == Token.UPSERT || lexer.identifierEquals("UPSERT")) {
664             lexer.nextToken();
665             insertStatement.setUpsert(true);
666         }
667 
668         parseInsert0(insertStatement);
669         return insertStatement;
670     }
671 
672     public SQLRollbackStatement parseRollback() {
673         lexer.nextToken();
674 
675         if (lexer.identifierEquals("WORK")) {
676             lexer.nextToken();
677         }
678 
679         SQLRollbackStatement stmt = new SQLRollbackStatement(getDbType());
680 
681         if (lexer.token == Token.TO) {
682             lexer.nextToken();
683 
684             if (lexer.identifierEquals("SAVEPOINT") || lexer.token == Token.SAVEPOINT) {
685                 lexer.nextToken();
686             }
687 
688             stmt.setTo(this.exprParser.name());
689         }
690         return stmt;
691     }
692 
693     public SQLStatement parseCommit() {
694         throw new ParserException("TODO " ~ lexer.info());
695     }
696 
697     public SQLStatement parseShow() {
698         throw new ParserException("TODO " ~ lexer.info());
699     }
700 
701     public SQLUseStatement parseUse() {
702         accept(Token.USE);
703         SQLUseStatement stmt = new SQLUseStatement(getDbType());
704         stmt.setDatabase(this.exprParser.name());
705         return stmt;
706     }
707 
708     public SQLGrantStatement parseGrant() {
709         accept(Token.GRANT);
710         SQLGrantStatement stmt = new SQLGrantStatement(getDbType());
711 
712         parsePrivileages(stmt.getPrivileges(), stmt);
713 
714         if (lexer.token == Token.ON) {
715             lexer.nextToken();
716 
717             if (lexer.token == Token.PROCEDURE) {
718                 lexer.nextToken();
719                 stmt.setObjectType(SQLObjectType.PROCEDURE);
720             } else if (lexer.token == Token.FUNCTION) {
721                 lexer.nextToken();
722                 stmt.setObjectType(SQLObjectType.FUNCTION);
723             } else if (lexer.token == Token.TABLE) {
724                 lexer.nextToken();
725                 stmt.setObjectType(SQLObjectType.TABLE);
726             } else if (lexer.token == Token.USER) {
727                 lexer.nextToken();
728                 stmt.setObjectType(SQLObjectType.USER);
729             } else if (lexer.token == Token.DATABASE) {
730                 lexer.nextToken();
731                 stmt.setObjectType(SQLObjectType.DATABASE);
732             }
733 
734             if (stmt.getObjectType().name.length != 0 && lexer.token == Token.COLONCOLON) {
735                 lexer.nextToken(); // sql server
736             }
737 
738             SQLExpr expr;
739             if (lexer.token == Token.DOT) {
740                 expr = new SQLAllColumnExpr();
741                 lexer.nextToken();
742             } else {
743                 expr = this.exprParser.expr();
744             }
745 
746             if (stmt.getObjectType() == SQLObjectType.TABLE || stmt.getObjectType().name.length == 0) {
747                 stmt.setOn(new SQLExprTableSource(expr));
748             } else {
749                 stmt.setOn(expr);
750             }
751         }
752 
753         if (lexer.token == Token.TO) {
754             lexer.nextToken();
755             stmt.setTo(this.exprParser.expr());
756         }
757 
758         if (lexer.token == Token.WITH) {
759             lexer.nextToken();
760 
761             if (lexer.token == Token.GRANT) {
762                 lexer.nextToken();
763                 acceptIdentifier("OPTION");
764             }
765 
766             for (;;) {
767                 if (lexer.identifierEquals("MAX_QUERIES_PER_HOUR")) {
768                     lexer.nextToken();
769                     stmt.setMaxQueriesPerHour(this.exprParser.primary());
770                     continue;
771                 }
772 
773                 if (lexer.identifierEquals("MAX_UPDATES_PER_HOUR")) {
774                     lexer.nextToken();
775                     stmt.setMaxUpdatesPerHour(this.exprParser.primary());
776                     continue;
777                 }
778 
779                 if (lexer.identifierEquals("MAX_CONNECTIONS_PER_HOUR")) {
780                     lexer.nextToken();
781                     stmt.setMaxConnectionsPerHour(this.exprParser.primary());
782                     continue;
783                 }
784 
785                 if (lexer.identifierEquals("MAX_USER_CONNECTIONS")) {
786                     lexer.nextToken();
787                     stmt.setMaxUserConnections(this.exprParser.primary());
788                     continue;
789                 }
790 
791                 break;
792             }
793         }
794 
795         if (lexer.identifierEquals("ADMIN")) {
796             lexer.nextToken();
797             acceptIdentifier("OPTION");
798             stmt.setAdminOption(true);
799         }
800 
801         if (lexer.token == Token.IDENTIFIED) {
802             lexer.nextToken();
803             accept(Token.BY);
804 
805             if (lexer.identifierEquals("PASSWORD")) {
806                 lexer.nextToken();
807                 string password = lexer.stringVal();
808                 accept(Token.LITERAL_CHARS);
809                 stmt.setIdentifiedByPassword(password);
810             } else {
811                 stmt.setIdentifiedBy(this.exprParser.expr());
812             }
813         }
814 
815         if (lexer.token == Token.WITH) {
816             lexer.nextToken();
817             if (lexer.token == Token.GRANT) {
818                 lexer.nextToken();
819                 acceptIdentifier("OPTION");
820                 stmt.setWithGrantOption(true);
821             }
822         }
823 
824         return stmt;
825     }
826 
827     protected void parsePrivileages(List!(SQLExpr) privileges, SQLObject parent) {
828         for (;;) {
829             string privilege = null;
830             if (lexer.token == Token.ALL) {
831                 lexer.nextToken();
832                 if (lexer.identifierEquals("PRIVILEGES")) {
833                     privilege = "ALL PRIVILEGES";
834                     lexer.nextToken();
835                 } else {
836                     privilege = "ALL";
837                 }
838             } else if (lexer.token == Token.SELECT) {
839                 privilege = "SELECT";
840                 lexer.nextToken();
841             } else if (lexer.token == Token.UPDATE) {
842                 privilege = "UPDATE";
843                 lexer.nextToken();
844             } else if (lexer.token == Token.DELETE) {
845                 privilege = "DELETE";
846                 lexer.nextToken();
847             } else if (lexer.token == Token.INSERT) {
848                 privilege = "INSERT";
849                 lexer.nextToken();
850             } else if (lexer.token == Token.INDEX) {
851                 lexer.nextToken();
852                 privilege = "INDEX";
853             } else if (lexer.token == Token.TRIGGER) {
854                 lexer.nextToken();
855                 privilege = "TRIGGER";
856             } else if (lexer.token == Token.REFERENCES) {
857                 privilege = "REFERENCES";
858                 lexer.nextToken();
859             } else if (lexer.token == Token.CREATE) {
860                 lexer.nextToken();
861 
862                 if (lexer.token == Token.TABLE) {
863                     privilege = "CREATE TABLE";
864                     lexer.nextToken();
865                 } else if (lexer.token == Token.SESSION) {
866                     privilege = "CREATE SESSION";
867                     lexer.nextToken();
868                 } else if (lexer.token == Token.TABLESPACE) {
869                     privilege = "CREATE TABLESPACE";
870                     lexer.nextToken();
871                 } else if (lexer.token == Token.USER) {
872                     privilege = "CREATE USER";
873                     lexer.nextToken();
874                 } else if (lexer.token == Token.VIEW) {
875                     privilege = "CREATE VIEW";
876                     lexer.nextToken();
877                 } else if (lexer.token == Token.PROCEDURE) {
878                     privilege = "CREATE PROCEDURE";
879                     lexer.nextToken();
880                 } else if (lexer.token == Token.SEQUENCE) {
881                     privilege = "CREATE SEQUENCE";
882                     lexer.nextToken();
883                 } else if (lexer.token == Token.ANY) {
884                     lexer.nextToken();
885 
886                     if (lexer.token == Token.TABLE) {
887                         lexer.nextToken();
888                         privilege = "CREATE ANY TABLE";
889                     } else if (lexer.identifierEquals("MATERIALIZED")) {
890                         lexer.nextToken();
891                         accept(Token.VIEW);
892                         privilege = "CREATE ANY MATERIALIZED VIEW";
893                     } else {
894                         throw new ParserException("TODO : " ~ lexer.token ~ " " ~ lexer.stringVal());
895                     }
896                 } else if (lexer.identifierEquals("SYNONYM")) {
897                     privilege = "CREATE SYNONYM";
898                     lexer.nextToken();
899                 } else if (lexer.identifierEquals("ROUTINE")) {
900                     privilege = "CREATE ROUTINE";
901                     lexer.nextToken();
902                 } else if (lexer.identifierEquals("TEMPORARY")) {
903                     lexer.nextToken();
904                     accept(Token.TABLE);
905                     privilege = "CREATE TEMPORARY TABLE";
906                 } else if (lexer.token == Token.ON) {
907                     privilege = "CREATE";
908                 } else {
909                     throw new ParserException("TODO : " ~ lexer.token ~ " " ~ lexer.stringVal());
910                 }
911             } else if (lexer.token == Token.ALTER) {
912                 lexer.nextToken();
913                 if (lexer.token == Token.TABLE) {
914                     privilege = "ALTER TABLE";
915                     lexer.nextToken();
916                 } else if (lexer.token == Token.SESSION) {
917                     privilege = "ALTER SESSION";
918                     lexer.nextToken();
919                 } else if (lexer.identifierEquals(FnvHash.Constants.ROUTINE)) {
920                     privilege = "ALTER ROUTINE";
921                     lexer.nextToken();
922                 } else if (lexer.token == Token.ANY) {
923                     lexer.nextToken();
924 
925                     if (lexer.token == Token.TABLE) {
926                         lexer.nextToken();
927                         privilege = "ALTER ANY TABLE";
928                     } else if (lexer.identifierEquals("MATERIALIZED")) {
929                         lexer.nextToken();
930                         accept(Token.VIEW);
931                         privilege = "ALTER ANY MATERIALIZED VIEW";
932                     } else {
933                         throw new ParserException("TODO : " ~ lexer.token ~ " " ~ lexer.stringVal());
934                     }
935                 } else if (lexer.token == Token.ON) {
936                     privilege = "ALTER";
937                 } else {
938                     throw new ParserException("TODO : " ~ lexer.token ~ " " ~ lexer.stringVal());
939                 }
940             } else if (lexer.token == Token.DROP) {
941                 lexer.nextToken();
942                 if (lexer.token == Token.DROP) {
943                     privilege = "DROP TABLE";
944                     lexer.nextToken();
945                 } else if (lexer.token == Token.SESSION) {
946                     privilege = "DROP SESSION";
947                     lexer.nextToken();
948                 } else if (lexer.token == Token.ANY) {
949                     lexer.nextToken();
950 
951                     if (lexer.token == Token.TABLE) {
952                         lexer.nextToken();
953                         privilege = "DROP ANY TABLE";
954                     } else if (lexer.identifierEquals("MATERIALIZED")) {
955                         lexer.nextToken();
956                         accept(Token.VIEW);
957                         privilege = "DROP ANY MATERIALIZED VIEW";
958                     } else {
959                         throw new ParserException("TODO : " ~ lexer.token ~ " " ~ lexer.stringVal());
960                     }
961                 } else {
962                     privilege = "DROP";
963                 }
964             } else if (lexer.identifierEquals("USAGE")) {
965                 privilege = "USAGE";
966                 lexer.nextToken();
967             } else if (lexer.identifierEquals("EXECUTE")) {
968                 privilege = "EXECUTE";
969                 lexer.nextToken();
970             } else if (lexer.identifierEquals("PROXY")) {
971                 privilege = "PROXY";
972                 lexer.nextToken();
973             } else if (lexer.identifierEquals("QUERY")) {
974                 lexer.nextToken();
975                 acceptIdentifier("REWRITE");
976                 privilege = "QUERY REWRITE";
977             } else if (lexer.identifierEquals("GLOBAL")) {
978                 lexer.nextToken();
979                 acceptIdentifier("QUERY");
980                 acceptIdentifier("REWRITE");
981                 privilege = "GLOBAL QUERY REWRITE";
982             } else if (lexer.identifierEquals("INHERIT")) {
983                 lexer.nextToken();
984                 acceptIdentifier("PRIVILEGES");
985                 privilege = "INHERIT PRIVILEGES";
986             } else if (lexer.identifierEquals("EVENT")) {
987                 lexer.nextToken();
988                 privilege = "EVENT";
989             } else if (lexer.identifierEquals("FILE")) {
990                 lexer.nextToken();
991                 privilege = "FILE";
992             } else if (lexer.token == Token.GRANT) {
993                 lexer.nextToken();
994                 acceptIdentifier("OPTION");
995                 privilege = "GRANT OPTION";
996             } else if (lexer.token == Token.LOCK) {
997                 lexer.nextToken();
998                 acceptIdentifier("TABLES");
999                 privilege = "LOCK TABLES";
1000             } else if (lexer.identifierEquals("PROCESS")) {
1001                 lexer.nextToken();
1002                 privilege = "PROCESS";
1003             } else if (lexer.identifierEquals("RELOAD")) {
1004                 lexer.nextToken();
1005                 privilege = "RELOAD";
1006             } else if (lexer.identifierEquals("RESOURCE")) {
1007                 lexer.nextToken();
1008                 privilege = "RESOURCE";
1009             } else if (lexer.token == Token.CONNECT) {
1010                 lexer.nextToken();
1011                 privilege = "CONNECT";
1012             } else if (lexer.identifierEquals("REPLICATION")) {
1013                 lexer.nextToken();
1014                 if (lexer.identifierEquals("SLAVE")) {
1015                     lexer.nextToken();
1016                     privilege = "REPLICATION SLAVE";
1017                 } else {
1018                     acceptIdentifier("CLIENT");
1019                     privilege = "REPLICATION CLIENT";
1020                 }
1021             } else if (lexer.token == Token.SHOW) {
1022                 lexer.nextToken();
1023 
1024                 if (lexer.token == Token.VIEW) {
1025                     lexer.nextToken();
1026                     privilege = "SHOW VIEW";
1027                 } else {
1028                     acceptIdentifier("DATABASES");
1029                     privilege = "SHOW DATABASES";
1030                 }
1031             } else if (lexer.identifierEquals("SHUTDOWN")) {
1032                 lexer.nextToken();
1033                 privilege = "SHUTDOWN";
1034             } else if (lexer.identifierEquals("SUPER")) {
1035                 lexer.nextToken();
1036                 privilege = "SUPER";
1037 
1038             } else if (lexer.identifierEquals("CONTROL")) { // sqlserver
1039                 lexer.nextToken();
1040                 privilege = "CONTROL";
1041             } else if (lexer.identifierEquals("IMPERSONATE")) { // sqlserver
1042                 lexer.nextToken();
1043                 privilege = "IMPERSONATE";
1044             }
1045 
1046             if (privilege !is null) {
1047                 SQLExpr expr = new SQLIdentifierExpr(privilege);
1048 
1049                 if (lexer.token == Token.LPAREN) {
1050                     expr = this.exprParser.primaryRest(expr);
1051                 }
1052 
1053                 expr.setParent(parent);
1054                 privileges.add(expr);
1055             }
1056 
1057             if (lexer.token == Token.COMMA) {
1058                 lexer.nextToken();
1059                 continue;
1060             }
1061             break;
1062         }
1063     }
1064 
1065     public SQLRevokeStatement parseRevoke() {
1066         accept(Token.REVOKE);
1067 
1068         SQLRevokeStatement stmt = new SQLRevokeStatement(getDbType());
1069 
1070         parsePrivileages(stmt.getPrivileges(), stmt);
1071 
1072         if (lexer.token == Token.ON) {
1073             lexer.nextToken();
1074 
1075             if (lexer.token == Token.PROCEDURE) {
1076                 lexer.nextToken();
1077                 stmt.setObjectType(SQLObjectType.PROCEDURE);
1078             } else if (lexer.token == Token.FUNCTION) {
1079                 lexer.nextToken();
1080                 stmt.setObjectType(SQLObjectType.FUNCTION);
1081             } else if (lexer.token == Token.TABLE) {
1082                 lexer.nextToken();
1083                 stmt.setObjectType(SQLObjectType.TABLE);
1084             } else if (lexer.token == Token.USER) {
1085                 lexer.nextToken();
1086                 stmt.setObjectType(SQLObjectType.USER);
1087             }
1088 
1089             SQLExpr expr = this.exprParser.expr();
1090             if (stmt.getObjectType() == SQLObjectType.TABLE || stmt.getObjectType().name.length == 0) {
1091                 stmt.setOn(new SQLExprTableSource(expr));
1092             } else {
1093                 stmt.setOn(expr);
1094             }
1095         }
1096 
1097         if (lexer.token == Token.FROM) {
1098             lexer.nextToken();
1099             stmt.setFrom(this.exprParser.expr());
1100         }
1101 
1102         return stmt;
1103     }
1104 
1105     public SQLStatement parseSavePoint() {
1106         acceptIdentifier("SAVEPOINT");
1107         SQLSavePointStatement stmt = new SQLSavePointStatement(getDbType());
1108         stmt.setName(this.exprParser.name());
1109         return stmt;
1110     }
1111 
1112     public SQLStatement parseReleaseSavePoint() {
1113         acceptIdentifier("RELEASE");
1114         acceptIdentifier("SAVEPOINT");
1115         SQLReleaseSavePointStatement stmt = new SQLReleaseSavePointStatement(getDbType());
1116         stmt.setName(this.exprParser.name());
1117         return stmt;
1118     }
1119 
1120     public SQLStatement parseAlter() {
1121         accept(Token.ALTER);
1122 
1123         if (lexer.token == Token.TABLE) {
1124             lexer.nextToken();
1125 
1126             SQLAlterTableStatement stmt = new SQLAlterTableStatement(getDbType());
1127             stmt.setName(this.exprParser.name());
1128 
1129             for (;;) {
1130                 if (lexer.token == Token.DROP) {
1131                     parseAlterDrop(stmt);
1132                 } else if (lexer.identifierEquals("ADD")) {
1133                     lexer.nextToken();
1134 
1135                     bool ifNotExists = false;
1136 
1137                     if (lexer.token == Token.IF) {
1138                         lexer.nextToken();
1139                         accept(Token.NOT);
1140                         accept(Token.EXISTS);
1141                         ifNotExists = true;
1142                     }
1143 
1144                     if (lexer.token == Token.PRIMARY) {
1145                         SQLPrimaryKey primaryKey = this.exprParser.parsePrimaryKey();
1146                         SQLAlterTableAddConstraint item = new SQLAlterTableAddConstraint(primaryKey);
1147                         stmt.addItem(item);
1148                     } else if (lexer.token == Token.IDENTIFIER) {
1149                         SQLAlterTableAddColumn item = parseAlterTableAddColumn();
1150                         stmt.addItem(item);
1151                     } else if (lexer.token == Token.COLUMN) {
1152                         lexer.nextToken();
1153                         SQLAlterTableAddColumn item = parseAlterTableAddColumn();
1154                         stmt.addItem(item);
1155                     } else if (lexer.token == Token.CHECK) {
1156                         SQLCheck check = this.exprParser.parseCheck();
1157                         SQLAlterTableAddConstraint item = new SQLAlterTableAddConstraint(check);
1158                         stmt.addItem(item);
1159                     } else if (lexer.token == Token.CONSTRAINT) {
1160                         SQLConstraint constraint = this.exprParser.parseConstaint();
1161                         SQLAlterTableAddConstraint item = new SQLAlterTableAddConstraint(constraint);
1162                         stmt.addItem(item);
1163                     } else if (lexer.token == Token.FOREIGN) {
1164                         SQLConstraint constraint = this.exprParser.parseForeignKey();
1165                         SQLAlterTableAddConstraint item = new SQLAlterTableAddConstraint(constraint);
1166                         stmt.addItem(item);
1167                     } else if (lexer.token == Token.PARTITION) {
1168                         lexer.nextToken();
1169                         SQLAlterTableAddPartition addPartition = new SQLAlterTableAddPartition();
1170 
1171                         addPartition.setIfNotExists(ifNotExists);
1172 
1173                         accept(Token.LPAREN);
1174 
1175                         parseAssignItems(cast(List!SQLAssignItem)(addPartition.getPartitions()), cast(SQLObject)addPartition);
1176 
1177                         accept(Token.RPAREN);
1178 
1179                         stmt.addItem(addPartition);
1180                     } else {
1181                         throw new ParserException("TODO " ~ lexer.info());
1182                     }
1183                 } else if (lexer.token == Token.DISABLE) {
1184                     lexer.nextToken();
1185 
1186                     if (lexer.token == Token.CONSTRAINT) {
1187                         lexer.nextToken();
1188                         SQLAlterTableDisableConstraint item = new SQLAlterTableDisableConstraint();
1189                         item.setConstraintName(this.exprParser.name());
1190                         stmt.addItem(item);
1191                     } else if (lexer.identifierEquals("LIFECYCLE")) {
1192                         lexer.nextToken();
1193                         SQLAlterTableDisableLifecycle item = new SQLAlterTableDisableLifecycle();
1194                         stmt.addItem(item);
1195                     } else {
1196                         acceptIdentifier("KEYS");
1197                         SQLAlterTableDisableKeys item = new SQLAlterTableDisableKeys();
1198                         stmt.addItem(item);
1199                     }
1200                 } else if (lexer.token == Token.ENABLE) {
1201                     lexer.nextToken();
1202                     if (lexer.token == Token.CONSTRAINT) {
1203                         lexer.nextToken();
1204                         SQLAlterTableEnableConstraint item = new SQLAlterTableEnableConstraint();
1205                         item.setConstraintName(this.exprParser.name());
1206                         stmt.addItem(item);
1207                     } else if (lexer.identifierEquals("LIFECYCLE")) {
1208                         lexer.nextToken();
1209                         SQLAlterTableEnableLifecycle item = new SQLAlterTableEnableLifecycle();
1210                         stmt.addItem(item);
1211                     } else {
1212                         acceptIdentifier("KEYS");
1213                         SQLAlterTableEnableKeys item = new SQLAlterTableEnableKeys();
1214                         stmt.addItem(item);
1215                     }
1216                 } else if (lexer.token == Token.ALTER) {
1217                     lexer.nextToken();
1218                     if (lexer.token == Token.COLUMN) {
1219                         SQLAlterTableAlterColumn alterColumn = parseAlterColumn();
1220                         stmt.addItem(alterColumn);
1221                     } else if (lexer.token == Token.LITERAL_ALIAS) {
1222                         SQLAlterTableAlterColumn alterColumn = parseAlterColumn();
1223                         stmt.addItem(alterColumn);
1224                     } else {
1225                         throw new ParserException("TODO " ~ lexer.info());
1226                     }
1227                 } else if (lexer.identifierEquals("CHANGE")) {
1228                     lexer.nextToken();
1229                     accept(Token.COLUMN);
1230                     SQLName columnName = this.exprParser.name();
1231 
1232                     if (lexer.identifierEquals("RENAME")) {
1233                         lexer.nextToken();
1234                         accept(Token.TO);
1235                         SQLName toName = this.exprParser.name();
1236                         SQLAlterTableRenameColumn renameColumn = new SQLAlterTableRenameColumn();
1237 
1238                         renameColumn.setColumn(columnName);
1239                         renameColumn.setTo(toName);
1240 
1241                         stmt.addItem(renameColumn);
1242                     } else if (lexer.token == Token.COMMENT) {
1243                         lexer.nextToken();
1244 
1245                         SQLExpr comment;
1246                         if (lexer.token == Token.LITERAL_ALIAS) {
1247                             string _alias = lexer.stringVal();
1248                             if (_alias.length > 2 && charAt(_alias, 0) == '"' && charAt(_alias, _alias.length - 1) == '"') {
1249                                 _alias = _alias.substring(1, cast(int)(_alias.length - 1));
1250                             }
1251                             comment = new SQLCharExpr(_alias);
1252                             lexer.nextToken();
1253                         } else {
1254                             comment = this.exprParser.primary();
1255                         }
1256 
1257                         SQLColumnDefinition column = new SQLColumnDefinition();
1258                         column.setDbType(dbType);
1259                         column.setName(columnName);
1260                         column.setComment(comment);
1261 
1262                         SQLAlterTableAlterColumn changeColumn = new SQLAlterTableAlterColumn();
1263 
1264                         changeColumn.setColumn(column);
1265 
1266                         stmt.addItem(changeColumn);
1267                     } else {
1268                         SQLColumnDefinition column = this.exprParser.parseColumn();
1269 
1270                         SQLAlterTableAlterColumn alterColumn = new SQLAlterTableAlterColumn();
1271                         alterColumn.setColumn(column);
1272                         alterColumn.setOriginColumn(columnName);
1273                         stmt.addItem(alterColumn);
1274                     }
1275                 } else if (lexer.token == Token.WITH) {
1276                     lexer.nextToken();
1277                     acceptIdentifier("NOCHECK");
1278                     acceptIdentifier("ADD");
1279                     SQLConstraint check = this.exprParser.parseConstaint();
1280 
1281                     SQLAlterTableAddConstraint addCheck = new SQLAlterTableAddConstraint();
1282                     addCheck.setWithNoCheck(true);
1283                     addCheck.setConstraint(check);
1284                     stmt.addItem(addCheck);
1285                 } else if (lexer.identifierEquals("RENAME")) {
1286                     stmt.addItem(parseAlterTableRename());
1287                 } else if (lexer.token == Token.SET) {
1288                     lexer.nextToken();
1289 
1290                     if (lexer.token == Token.COMMENT) {
1291                         lexer.nextToken();
1292                         SQLAlterTableSetComment setComment = new SQLAlterTableSetComment();
1293                         setComment.setComment(this.exprParser.primary());
1294                         stmt.addItem(setComment);
1295                     } else if (lexer.identifierEquals("LIFECYCLE")) {
1296                         lexer.nextToken();
1297                         SQLAlterTableSetLifecycle setLifecycle = new SQLAlterTableSetLifecycle();
1298                         setLifecycle.setLifecycle(this.exprParser.primary());
1299                         stmt.addItem(setLifecycle);
1300                     } else {
1301                         throw new ParserException("TODO " ~ lexer.info());
1302                     }
1303                 } else if (lexer.token == Token.PARTITION) {
1304                     lexer.nextToken();
1305 
1306                     SQLAlterTableRenamePartition renamePartition = new SQLAlterTableRenamePartition();
1307 
1308                     accept(Token.LPAREN);
1309 
1310                     parseAssignItems(renamePartition.getPartition(), renamePartition);
1311 
1312                     accept(Token.RPAREN);
1313 
1314                     if (lexer.token == Token.ENABLE) {
1315                         lexer.nextToken();
1316                         if (lexer.identifierEquals("LIFECYCLE")) {
1317                             lexer.nextToken();
1318                         }
1319 
1320                         SQLAlterTableEnableLifecycle enableLifeCycle = new SQLAlterTableEnableLifecycle();
1321                         foreach(SQLAssignItem condition ; renamePartition.getPartition()) {
1322                             enableLifeCycle.getPartition().add(condition);
1323                             condition.setParent(enableLifeCycle);
1324                         }
1325                         stmt.addItem(enableLifeCycle);
1326 
1327                         continue;
1328                     }
1329 
1330                     if (lexer.token == Token.DISABLE) {
1331                         lexer.nextToken();
1332                         if (lexer.identifierEquals("LIFECYCLE")) {
1333                             lexer.nextToken();
1334                         }
1335 
1336                         SQLAlterTableDisableLifecycle disableLifeCycle = new SQLAlterTableDisableLifecycle();
1337                         foreach(SQLAssignItem condition ; renamePartition.getPartition()) {
1338                             disableLifeCycle.getPartition().add(condition);
1339                             condition.setParent(disableLifeCycle);
1340                         }
1341                         stmt.addItem(disableLifeCycle);
1342 
1343                         continue;
1344                     }
1345 
1346                     acceptIdentifier("RENAME");
1347                     accept(Token.TO);
1348                     accept(Token.PARTITION);
1349 
1350                     accept(Token.LPAREN);
1351 
1352                     parseAssignItems(renamePartition.getTo(), renamePartition);
1353 
1354                     accept(Token.RPAREN);
1355 
1356                     stmt.addItem(renamePartition);
1357                 } else if (lexer.identifierEquals("TOUCH")) {
1358                     lexer.nextToken();
1359                     SQLAlterTableTouch item = new SQLAlterTableTouch();
1360 
1361                     if (lexer.token == Token.PARTITION) {
1362                         lexer.nextToken();
1363 
1364                         accept(Token.LPAREN);
1365                         parseAssignItems(item.getPartition(), item);
1366                         accept(Token.RPAREN);
1367                     }
1368 
1369                     stmt.addItem(item);
1370                 } else if (DBType.ODPS.opEquals(dbType) && lexer.identifierEquals("MERGE")) {
1371                     lexer.nextToken();
1372                     acceptIdentifier("SMALLFILES");
1373                     stmt.setMergeSmallFiles(true);
1374                 } else {
1375                     break;
1376                 }
1377             }
1378 
1379             return stmt;
1380         } else if (lexer.token == Token.VIEW) {
1381             lexer.nextToken();
1382             SQLName viewName = this.exprParser.name();
1383 
1384             if (lexer.identifierEquals("RENAME")) {
1385                 lexer.nextToken();
1386                 accept(Token.TO);
1387 
1388                 SQLAlterViewRenameStatement stmt = new SQLAlterViewRenameStatement();
1389                 stmt.setName(viewName);
1390 
1391                 SQLName newName = this.exprParser.name();
1392 
1393                 stmt.setTo(newName);
1394 
1395                 return stmt;
1396             }
1397             throw new ParserException("TODO " ~ lexer.info());
1398         }
1399         throw new ParserException("TODO " ~ lexer.info());
1400     }
1401 
1402     protected SQLAlterTableItem parseAlterTableRename() {
1403         acceptIdentifier("RENAME");
1404 
1405         if (lexer.token == Token.COLUMN) {
1406             lexer.nextToken();
1407             SQLAlterTableRenameColumn renameColumn = new SQLAlterTableRenameColumn();
1408             renameColumn.setColumn(this.exprParser.name());
1409             accept(Token.TO);
1410             renameColumn.setTo(this.exprParser.name());
1411             return renameColumn;
1412         }
1413 
1414         if (lexer.token == Token.TO) {
1415             lexer.nextToken();
1416             SQLAlterTableRename item = new SQLAlterTableRename();
1417             item.setTo(this.exprParser.name());
1418             return item;
1419         }
1420 
1421         throw new ParserException("TODO " ~ lexer.info());
1422     }
1423 
1424     protected SQLAlterTableAlterColumn parseAlterColumn() {
1425         lexer.nextToken();
1426         SQLColumnDefinition column = this.exprParser.parseColumn();
1427 
1428         SQLAlterTableAlterColumn alterColumn = new SQLAlterTableAlterColumn();
1429         alterColumn.setColumn(column);
1430         return alterColumn;
1431     }
1432 
1433     public void parseAlterDrop(SQLAlterTableStatement stmt) {
1434         lexer.nextToken();
1435 
1436         bool ifExists = false;
1437 
1438         if (lexer.token == Token.IF) {
1439             lexer.nextToken();
1440 
1441             accept(Token.EXISTS);
1442             ifExists = true;
1443         }
1444 
1445         if (lexer.token == Token.CONSTRAINT) {
1446             lexer.nextToken();
1447             SQLAlterTableDropConstraint item = new SQLAlterTableDropConstraint();
1448             item.setConstraintName(this.exprParser.name());
1449             stmt.addItem(item);
1450         } else if (lexer.token == Token.COLUMN) {
1451             lexer.nextToken();
1452             SQLAlterTableDropColumnItem item = new SQLAlterTableDropColumnItem();
1453             this.exprParser.names(item.getColumns());
1454 
1455             if (lexer.token == Token.CASCADE) {
1456                 item.setCascade(true);
1457                 lexer.nextToken();
1458             }
1459 
1460             stmt.addItem(item);
1461         } else if (lexer.token == Token.LITERAL_ALIAS) {
1462             SQLAlterTableDropColumnItem item = new SQLAlterTableDropColumnItem();
1463             this.exprParser.names(item.getColumns());
1464 
1465             if (lexer.token == Token.CASCADE) {
1466                 item.setCascade(true);
1467                 lexer.nextToken();
1468             }
1469 
1470             stmt.addItem(item);
1471         } else if (lexer.token == Token.PARTITION) {
1472             SQLAlterTableDropPartition dropPartition = parseAlterTableDropPartition(ifExists);
1473 
1474             stmt.addItem(dropPartition);
1475         } else if (lexer.token == Token.INDEX) {
1476             lexer.nextToken();
1477             SQLName indexName = this.exprParser.name();
1478             SQLAlterTableDropIndex item = new SQLAlterTableDropIndex();
1479             item.setIndexName(indexName);
1480             stmt.addItem(item);
1481         } else if (lexer.token() == Token.PRIMARY) {
1482             lexer.nextToken();
1483             accept(Token.KEY);
1484             SQLAlterTableDropPrimaryKey item = new SQLAlterTableDropPrimaryKey();
1485             stmt.addItem(item);
1486         } else {
1487             throw new ParserException("TODO " ~ lexer.info());
1488         }
1489     }
1490 
1491     protected SQLAlterTableDropPartition parseAlterTableDropPartition(bool ifExists) {
1492         lexer.nextToken();
1493         SQLAlterTableDropPartition dropPartition = new SQLAlterTableDropPartition();
1494 
1495         dropPartition.setIfExists(ifExists);
1496 
1497         if (lexer.token == Token.LPAREN) {
1498             accept(Token.LPAREN);
1499 
1500             parseAssignItems(cast(List!SQLAssignItem)(dropPartition.getPartitions()), cast(SQLObject)dropPartition);
1501 
1502             accept(Token.RPAREN);
1503             
1504             if (lexer.identifierEquals("PURGE")) {
1505                 lexer.nextToken();
1506                 dropPartition.setPurge(true);
1507             }
1508         } else {
1509             SQLName partition = this.exprParser.name();
1510             dropPartition.addPartition(partition);
1511         }
1512 
1513     
1514         return dropPartition;
1515     }
1516 
1517     public SQLStatement parseRename() {
1518         throw new ParserException("TODO " ~ lexer.info());
1519     }
1520 
1521     protected SQLDropTableStatement parseDropTable(bool acceptDrop) {
1522         if (acceptDrop) {
1523             accept(Token.DROP);
1524         }
1525 
1526         SQLDropTableStatement stmt = new SQLDropTableStatement(getDbType());
1527 
1528         if (lexer.identifierEquals("TEMPORARY")) {
1529             lexer.nextToken();
1530             stmt.setTemporary(true);
1531         }
1532 
1533         accept(Token.TABLE);
1534 
1535         if (lexer.token == Token.IF) {
1536             lexer.nextToken();
1537             accept(Token.EXISTS);
1538             stmt.setIfExists(true);
1539         }
1540 
1541         for (;;) {
1542             SQLName name = this.exprParser.name();
1543             stmt.addPartition(new SQLExprTableSource(name));
1544             if (lexer.token == Token.COMMA) {
1545                 lexer.nextToken();
1546                 continue;
1547             }
1548             break;
1549         }
1550 
1551         for (;;) {
1552             if (lexer.identifierEquals("RESTRICT")) {
1553                 lexer.nextToken();
1554                 stmt.setRestrict(true);
1555                 continue;
1556             }
1557 
1558             if (lexer.identifierEquals("CASCADE")) {
1559                 lexer.nextToken();
1560                 stmt.setCascade(true);
1561 
1562                 if (lexer.identifierEquals("CONSTRAINTS")) { // for oracle
1563                     lexer.nextToken();
1564                 }
1565 
1566                 continue;
1567             }
1568 
1569             if (lexer.token == Token.PURGE || lexer.identifierEquals("PURGE")) {
1570                 lexer.nextToken();
1571                 stmt.setPurge(true);
1572                 continue;
1573             }
1574 
1575             break;
1576         }
1577 
1578         return stmt;
1579     }
1580 
1581     protected SQLDropSequenceStatement parseDropSequence(bool acceptDrop) {
1582         if (acceptDrop) {
1583             accept(Token.DROP);
1584         }
1585 
1586         lexer.nextToken();
1587 
1588         SQLName name = this.exprParser.name();
1589 
1590         SQLDropSequenceStatement stmt = new SQLDropSequenceStatement(getDbType());
1591         stmt.setName(name);
1592         return stmt;
1593     }
1594 
1595     protected SQLDropTriggerStatement parseDropTrigger(bool acceptDrop) {
1596         if (acceptDrop) {
1597             accept(Token.DROP);
1598         }
1599 
1600         lexer.nextToken();
1601         SQLDropTriggerStatement stmt = new SQLDropTriggerStatement(getDbType());
1602 
1603         if (lexer.token == Token.IF) {
1604             lexer.nextToken();
1605             accept(Token.EXISTS);
1606             stmt.setIfExists(true);
1607         }
1608 
1609         SQLName name = this.exprParser.name();
1610 
1611 
1612         stmt.setName(name);
1613         return stmt;
1614     }
1615 
1616     protected SQLDropViewStatement parseDropView(bool acceptDrop) {
1617         if (acceptDrop) {
1618             accept(Token.DROP);
1619         }
1620 
1621         SQLDropViewStatement stmt = new SQLDropViewStatement(getDbType());
1622 
1623         accept(Token.VIEW);
1624 
1625         if (lexer.token == Token.IF) {
1626             lexer.nextToken();
1627             accept(Token.EXISTS);
1628             stmt.setIfExists(true);
1629         }
1630 
1631         for (;;) {
1632             SQLName name = this.exprParser.name();
1633             stmt.addPartition(new SQLExprTableSource(name));
1634             if (lexer.token == Token.COMMA) {
1635                 lexer.nextToken();
1636                 continue;
1637             }
1638             break;
1639         }
1640 
1641         if (lexer.identifierEquals("RESTRICT")) {
1642             lexer.nextToken();
1643             stmt.setRestrict(true);
1644         } else if (lexer.identifierEquals("CASCADE")) {
1645             lexer.nextToken();
1646 
1647             if (lexer.identifierEquals("CONSTRAINTS")) { // for oracle
1648                 lexer.nextToken();
1649             }
1650 
1651             stmt.setCascade(true);
1652         }
1653 
1654         return stmt;
1655     }
1656 
1657     protected SQLDropDatabaseStatement parseDropDatabase(bool acceptDrop) {
1658         if (acceptDrop) {
1659             accept(Token.DROP);
1660         }
1661 
1662         SQLDropDatabaseStatement stmt = new SQLDropDatabaseStatement(getDbType());
1663 
1664         if (lexer.token == Token.SCHEMA) {
1665             lexer.nextToken();
1666         } else {
1667             accept(Token.DATABASE);
1668         }
1669 
1670         if (lexer.token == Token.IF) {
1671             lexer.nextToken();
1672             accept(Token.EXISTS);
1673             stmt.setIfExists(true);
1674         }
1675 
1676         SQLName name = this.exprParser.name();
1677         stmt.setDatabase(name);
1678 
1679         return stmt;
1680     }
1681 
1682     protected SQLDropFunctionStatement parseDropFunction(bool acceptDrop) {
1683         if (acceptDrop) {
1684             accept(Token.DROP);
1685         }
1686 
1687         SQLDropFunctionStatement stmt = new SQLDropFunctionStatement(getDbType());
1688 
1689         accept(Token.FUNCTION);
1690 
1691         if (lexer.token == Token.IF) {
1692             lexer.nextToken();
1693             accept(Token.EXISTS);
1694             stmt.setIfExists(true);
1695         }
1696 
1697         SQLName name = this.exprParser.name();
1698         stmt.setName(name);
1699 
1700         return stmt;
1701     }
1702 
1703     protected SQLDropTableSpaceStatement parseDropTablespace(bool acceptDrop) {
1704         SQLDropTableSpaceStatement stmt = new SQLDropTableSpaceStatement(getDbType());
1705 
1706         if (lexer.isKeepComments() && lexer.hasComment()) {
1707             stmt.addBeforeComment(lexer.readAndResetComments());
1708         }
1709 
1710         if (acceptDrop) {
1711             accept(Token.DROP);
1712         }
1713 
1714         accept(Token.TABLESPACE);
1715 
1716         if (lexer.token == Token.IF) {
1717             lexer.nextToken();
1718             accept(Token.EXISTS);
1719             stmt.setIfExists(true);
1720         }
1721 
1722         SQLName name = this.exprParser.name();
1723         stmt.setName(name);
1724 
1725         if (lexer.identifierEquals(FnvHash.Constants.ENGINE)) {
1726             lexer.nextToken();
1727             if (lexer.token == Token.EQ) {
1728                 lexer.nextToken();
1729             }
1730             SQLExpr engine = this.exprParser.primary();
1731             stmt.setEngine(engine);
1732         }
1733 
1734         return stmt;
1735     }
1736 
1737     protected SQLDropProcedureStatement parseDropProcedure(bool acceptDrop) {
1738         if (acceptDrop) {
1739             accept(Token.DROP);
1740         }
1741 
1742         SQLDropProcedureStatement stmt = new SQLDropProcedureStatement(getDbType());
1743 
1744         accept(Token.PROCEDURE);
1745 
1746         if (lexer.token == Token.IF) {
1747             lexer.nextToken();
1748             accept(Token.EXISTS);
1749             stmt.setIfExists(true);
1750         }
1751 
1752         SQLName name = this.exprParser.name();
1753         stmt.setName(name);
1754 
1755         return stmt;
1756     }
1757 
1758     public SQLStatement parseTruncate() {
1759         accept(Token.TRUNCATE);
1760         if (lexer.token == Token.TABLE) {
1761             lexer.nextToken();
1762         }
1763         SQLTruncateStatement stmt = new SQLTruncateStatement(getDbType());
1764 
1765         if (lexer.token == Token.ONLY) {
1766             lexer.nextToken();
1767             stmt.setOnly(true);
1768         }
1769 
1770         for (;;) {
1771             SQLName name = this.exprParser.name();
1772             stmt.addTableSource(name);
1773 
1774             if (lexer.token == Token.COMMA) {
1775                 lexer.nextToken();
1776                 continue;
1777             }
1778 
1779             break;
1780         }
1781 
1782         for (;;) {
1783             if (lexer.token == Token.PURGE) {
1784                 lexer.nextToken();
1785 
1786                 if (lexer.identifierEquals("SNAPSHOT")) {
1787                     lexer.nextToken();
1788                     acceptIdentifier("LOG");
1789                     stmt.setPurgeSnapshotLog(true);
1790                 } else {
1791                     throw new ParserException("TODO : " ~ lexer.token ~ " " ~ lexer.stringVal());
1792                 }
1793                 continue;
1794             }
1795 
1796             if (lexer.token == Token.RESTART) {
1797                 lexer.nextToken();
1798                 accept(Token.IDENTITY);
1799                 stmt.setRestartIdentity(Boolean.TRUE);
1800                 continue;
1801             } else if (lexer.token == Token.SHARE) {
1802                 lexer.nextToken();
1803                 accept(Token.IDENTITY);
1804                 stmt.setRestartIdentity(Boolean.FALSE);
1805                 continue;
1806             }
1807 
1808             if (lexer.token == Token.CASCADE) {
1809                 lexer.nextToken();
1810                 stmt.setCascade(Boolean.TRUE);
1811                 continue;
1812             } else if (lexer.token == Token.RESTRICT) {
1813                 lexer.nextToken();
1814                 stmt.setCascade(Boolean.FALSE);
1815                 continue;
1816             }
1817             
1818             if (lexer.token == Token.DROP) {
1819                 lexer.nextToken();
1820                 acceptIdentifier("STORAGE");
1821                 stmt.setDropStorage(true);
1822                 continue;
1823             }
1824             
1825             if (lexer.identifierEquals("REUSE")) {
1826                 lexer.nextToken();
1827                 acceptIdentifier("STORAGE");
1828                 stmt.setReuseStorage(true);
1829                 continue;
1830             }
1831             
1832             if (lexer.identifierEquals("IGNORE")) {
1833                 lexer.nextToken();
1834                 accept(Token.DELETE);
1835                 acceptIdentifier("TRIGGERS");
1836                 stmt.setIgnoreDeleteTriggers(true);
1837                 continue;
1838             }
1839             
1840             if (lexer.identifierEquals("RESTRICT")) {
1841                 lexer.nextToken();
1842                 accept(Token.WHEN);
1843                 accept(Token.DELETE);
1844                 acceptIdentifier("TRIGGERS");
1845                 stmt.setRestrictWhenDeleteTriggers(true);
1846                 continue;
1847             }
1848             
1849             if (lexer.token == Token.CONTINUE) {
1850                 lexer.nextToken();
1851                 accept(Token.IDENTITY);
1852                 continue;
1853             }
1854             
1855             if (lexer.identifierEquals("IMMEDIATE")) {
1856                 lexer.nextToken();
1857                 stmt.setImmediate(true);
1858                 continue;
1859             }
1860 
1861             break;
1862         }
1863 
1864         return stmt;
1865     }
1866 
1867     public SQLStatement parseInsert() {
1868         SQLInsertStatement stmt = new SQLInsertStatement();
1869 
1870         if (lexer.token == Token.INSERT) {
1871             accept(Token.INSERT);
1872         }
1873 
1874         parseInsert0(stmt);
1875         return stmt;
1876     }
1877 
1878     protected void parseInsert0(SQLInsertInto insertStatement) {
1879         parseInsert0(insertStatement, true);
1880     }
1881 
1882     protected void parseInsert0_hinits(SQLInsertInto insertStatement) {
1883 
1884     }
1885 
1886     protected void parseInsert0(SQLInsertInto insertStatement, bool acceptSubQuery) {
1887         if (lexer.token == Token.INTO) {
1888             lexer.nextToken();
1889 
1890             SQLName tableName = this.exprParser.name();
1891             insertStatement.setTableName(tableName);
1892 
1893             if (lexer.token == Token.LITERAL_ALIAS) {
1894                 insertStatement.setAlias(tableAlias());
1895             }
1896 
1897             parseInsert0_hinits(insertStatement);
1898 
1899             if (lexer.token == Token.IDENTIFIER) {
1900                 insertStatement.setAlias(lexer.stringVal());
1901                 lexer.nextToken();
1902             }
1903         }
1904 
1905         if (lexer.token == (Token.LPAREN)) {
1906             lexer.nextToken();
1907             parseInsertColumns(insertStatement);
1908             accept(Token.RPAREN);
1909         }
1910 
1911         if (lexer.token == Token.VALUES) {
1912             lexer.nextToken();
1913             for (;;) {
1914                 if (lexer.token == Token.LPAREN) {
1915                     lexer.nextToken();
1916 
1917                     ValuesClause values = new ValuesClause();
1918                     this.exprParser.exprList(values.getValues(), values);
1919                     insertStatement.addValueCause(values);
1920                     accept(Token.RPAREN);
1921                 } else { // oracle
1922                     ValuesClause values = new ValuesClause();
1923                     SQLExpr value = this.exprParser.expr();
1924                     values.addValue(value);
1925                     insertStatement.addValueCause(values);
1926                 }
1927                 
1928                 if (lexer.token == Token.COMMA) {
1929                     lexer.nextToken();
1930                     continue;
1931                 } else {
1932                     break;
1933                 }
1934             }
1935         } else if (acceptSubQuery && (lexer.token == Token.SELECT || lexer.token == Token.LPAREN)) {
1936             SQLSelect select = this.createSQLSelectParser().select();
1937             insertStatement.setQuery(select);
1938         }
1939     }
1940 
1941     protected void parseInsertColumns(SQLInsertInto insert) {
1942         this.exprParser.exprList(insert.getColumns(), insert);
1943     }
1944 
1945     public bool parseStatementListDialect(List!(SQLStatement) statementList) {
1946         return false;
1947     }
1948 
1949     public SQLDropUserStatement parseDropUser() {
1950         accept(Token.USER);
1951 
1952         SQLDropUserStatement stmt = new SQLDropUserStatement(getDbType());
1953         for (;;) {
1954             SQLExpr expr = this.exprParser.expr();
1955             stmt.addUser(expr);
1956             if (lexer.token == Token.COMMA) {
1957                 lexer.nextToken();
1958                 continue;
1959             }
1960             break;
1961         }
1962 
1963         return stmt;
1964     }
1965 
1966     public SQLStatement parseDropIndex() {
1967         accept(Token.INDEX);
1968         SQLDropIndexStatement stmt = new SQLDropIndexStatement(getDbType());
1969         stmt.setIndexName(this.exprParser.name());
1970 
1971         if (lexer.token == Token.ON) {
1972             lexer.nextToken();
1973             stmt.setTableName(this.exprParser.name());
1974         }
1975 
1976         if (lexer.identifierEquals(FnvHash.Constants.ALGORITHM)) {
1977             lexer.nextToken();
1978             if (lexer.token == Token.EQ) {
1979                 lexer.nextToken();
1980             }
1981             SQLExpr algorithm = this.exprParser.primary();
1982             stmt.setAlgorithm(algorithm);
1983         }
1984 
1985         if (lexer.token == Token.LOCK) {
1986             lexer.nextToken();
1987             if (lexer.token == Token.EQ) {
1988                 lexer.nextToken();
1989             }
1990             SQLExpr option = this.exprParser.primary();
1991             stmt.setLockOption(option);
1992         }
1993         // for mysql
1994         return stmt;
1995     }
1996 
1997     public SQLCallStatement parseCall() {
1998 
1999         bool brace = false;
2000         if (lexer.token == Token.LBRACE) {
2001             lexer.nextToken();
2002             brace = true;
2003         }
2004 
2005         SQLCallStatement stmt = new SQLCallStatement(getDbType());
2006 
2007         if (lexer.token == Token.QUES) {
2008             lexer.nextToken();
2009             accept(Token.EQ);
2010             stmt.setOutParameter(new SQLVariantRefExpr("?"));
2011         }
2012 
2013         acceptIdentifier("CALL");
2014 
2015         stmt.setProcedureName(exprParser.name());
2016 
2017         if (lexer.token == Token.LPAREN) {
2018             lexer.nextToken();
2019             exprParser.exprList(stmt.getParameters(), stmt);
2020             accept(Token.RPAREN);
2021         }
2022 
2023         if (brace) {
2024             accept(Token.RBRACE);
2025             stmt.setBrace(true);
2026         }
2027 
2028         return stmt;
2029     }
2030 
2031     public SQLStatement parseSet() {
2032         accept(Token.SET);
2033         SQLSetStatement stmt = new SQLSetStatement(getDbType());
2034 
2035         parseAssignItems(stmt.getItems(), stmt);
2036 
2037         return stmt;
2038     }
2039 
2040     public void parseAssignItems(List!(SQLAssignItem) items, SQLObject parent) {
2041         for (;;) {
2042             SQLAssignItem item = exprParser.parseAssignItem();
2043             item.setParent(parent);
2044             items.add(item);
2045 
2046             if (lexer.token == Token.COMMA) {
2047                 lexer.nextToken();
2048                 continue;
2049             } else {
2050                 break;
2051             }
2052         }
2053     }
2054 
2055     public SQLStatement parseCreatePackage() {
2056         throw new ParserException("TODO " ~ lexer.info());
2057     }
2058 
2059     public SQLStatement parseCreate() {
2060         char markChar = lexer.current();
2061         int markBp = lexer.bp();
2062         
2063         List!(string) comments = null;
2064         if (lexer.isKeepComments() && lexer.hasComment()) {
2065             comments = lexer.readAndResetComments();
2066         }
2067 
2068         accept(Token.CREATE);
2069 
2070         Token token = lexer.token;
2071 
2072         if (token == Token.TABLE || lexer.identifierEquals("GLOBAL")) {
2073             SQLCreateTableParser createTableParser = getSQLCreateTableParser();
2074             SQLCreateTableStatement stmt = createTableParser.parseCreateTable(false);
2075             
2076             if (comments !is null) {
2077                 stmt.addBeforeComment(comments);
2078             }
2079             
2080             return stmt;
2081         } else if (token == Token.INDEX //
2082                    || token == Token.UNIQUE //
2083                    || lexer.identifierEquals("NONCLUSTERED") // sql server
2084         ) {
2085             return parseCreateIndex(false);
2086         } else if (lexer.token == Token.SEQUENCE) {
2087             return parseCreateSequence(false);
2088         } else if (token == Token.OR) {
2089             lexer.nextToken();
2090             accept(Token.REPLACE);
2091 
2092             if (lexer.identifierEquals("FORCE")) {
2093                 lexer.nextToken();
2094             }
2095             if (lexer.token == Token.PROCEDURE) {
2096                 lexer.reset(markBp, markChar, Token.CREATE);
2097                 return parseCreateProcedure();
2098             }
2099 
2100             if (lexer.token == Token.VIEW) {
2101                 lexer.reset(markBp, markChar, Token.CREATE);
2102                 return parseCreateView();
2103             }
2104 
2105             if (lexer.token == Token.TRIGGER) {
2106                 lexer.reset(markBp, markChar, Token.CREATE);
2107                 return parseCreateTrigger();
2108             }
2109 
2110             if (lexer.token == Token.FUNCTION) {
2111                 lexer.reset(markBp, markChar, Token.CREATE);
2112                 return parseCreateFunction();
2113             }
2114 
2115             if (lexer.identifierEquals(FnvHash.Constants.PACKAGE)) {
2116                 lexer.reset(markBp, markChar, Token.CREATE);
2117                 return parseCreatePackage();
2118             }
2119 
2120             if (lexer.identifierEquals(FnvHash.Constants.TYPE)) {
2121                 lexer.reset(markBp, markChar, Token.CREATE);
2122                 return parseCreateType();
2123             }
2124 
2125             if (lexer.identifierEquals(FnvHash.Constants.PUBLIC)) {
2126                 lexer.reset(markBp, markChar, Token.CREATE);
2127                 return parseCreateSynonym();
2128             }
2129 
2130             if (lexer.identifierEquals(FnvHash.Constants.SYNONYM)) {
2131                 lexer.reset(markBp, markChar, Token.CREATE);
2132                 return parseCreateSynonym();
2133             }
2134 
2135             // lexer.reset(mark_bp, mark_ch, Token.CREATE);
2136             throw new ParserException("TODO " ~ lexer.info());
2137         } else if (token == Token.DATABASE) {
2138             lexer.nextToken();
2139             if (lexer.identifierEquals("LINK")) {
2140                 lexer.reset(markBp, markChar, Token.CREATE);
2141                 return parseCreateDbLink();
2142             }
2143 
2144             lexer.reset(markBp, markChar, Token.CREATE);
2145             return parseCreateDatabase();
2146         } else if (lexer.token == Token.USER) {
2147             lexer.reset(markBp, markChar, Token.CREATE);
2148             return parseCreateUser();
2149         } else if (lexer.identifierEquals(FnvHash.Constants.PUBLIC)) {
2150             lexer.nextToken();
2151             if (lexer.identifierEquals("SYNONYM")) {
2152                 lexer.reset(markBp, markChar, Token.CREATE);
2153                 return parseCreateSynonym();
2154             } else {
2155                 lexer.reset(markBp, markChar, Token.CREATE);
2156                 return parseCreateDbLink();
2157             }
2158         } else if (lexer.identifierEquals("SHARE")) {
2159             lexer.reset(markBp, markChar, Token.CREATE);
2160             return parseCreateDbLink();
2161         } else if (lexer.identifierEquals("SYNONYM")) {
2162             lexer.reset(markBp, markChar, Token.CREATE);
2163             return parseCreateSynonym();
2164         } else if (token == Token.VIEW) {
2165             return parseCreateView();
2166         } else if (token == Token.TRIGGER) {
2167             lexer.reset(markBp, markChar, Token.CREATE);
2168             return parseCreateTrigger();
2169         } else if (token == Token.PROCEDURE) {
2170             SQLCreateProcedureStatement stmt = parseCreateProcedure();
2171             stmt.setCreate(true);
2172             return stmt;
2173         } else if (token == Token.FUNCTION) {
2174             lexer.reset(markBp, markChar, Token.CREATE);
2175             SQLStatement stmt = this.parseCreateFunction();
2176             return stmt;
2177         } else if (lexer.identifierEquals(FnvHash.Constants.BITMAP)) {
2178             lexer.reset(markBp, markChar, Token.CREATE);
2179             return parseCreateIndex(true);
2180         } else if (lexer.identifierEquals(FnvHash.Constants.MATERIALIZED)) {
2181             lexer.reset(markBp, markChar, Token.CREATE);
2182             return parseCreateMaterializedView();
2183         } else if (lexer.identifierEquals(FnvHash.Constants.TYPE)) {
2184             lexer.reset(markBp, markChar, Token.CREATE);
2185             return parseCreateType();
2186         }
2187 
2188         throw new ParserException("TODO " ~ lexer.token);
2189     }
2190 
2191     public SQLStatement parseCreateType() {
2192         throw new ParserException("TODO " ~ lexer.token);
2193     }
2194 
2195     public SQLStatement parseCreateUser() {
2196         accept(Token.CREATE);
2197         accept(Token.USER);
2198 
2199         SQLCreateUserStatement stmt = new SQLCreateUserStatement();
2200         stmt.setUser(this.exprParser.name());
2201 
2202         accept(Token.IDENTIFIED);
2203         accept(Token.BY);
2204         stmt.setPassword(this.exprParser.primary());
2205 
2206         return stmt;
2207     }
2208 
2209     public SQLCreateFunctionStatement parseCreateFunction() {
2210         throw new ParserException("TODO " ~ lexer.token);
2211     }
2212 
2213     public SQLStatement parseCreateMaterializedView() {
2214         accept(Token.CREATE);
2215         acceptIdentifier("MATERIALIZED");
2216         accept(Token.VIEW);
2217 
2218         SQLCreateMaterializedViewStatement stmt = new SQLCreateMaterializedViewStatement();
2219         stmt.setName(this.exprParser.name());
2220 
2221         if (lexer.token == Token.PARTITION) {
2222             SQLPartitionBy partitionBy = this.exprParser.parsePartitionBy();
2223             stmt.setPartitionBy(partitionBy);
2224         }
2225 
2226         for (;;) {
2227             // if (cast(OracleExprParser)(exprParser) !is null) {
2228             //     ((OracleExprParser) exprParser).parseSegmentAttributes(stmt);
2229             // }
2230 
2231             if (lexer.identifierEquals("REFRESH")) {
2232                 lexer.nextToken();
2233 
2234                 for (; ; ) {
2235                     if (lexer.identifierEquals("FAST")) {
2236                         lexer.nextToken();
2237                         stmt.setRefreshFast(true);
2238                     } else if (lexer.identifierEquals("COMPLETE")) {
2239                         lexer.nextToken();
2240                         stmt.setRefreshComlete(true);
2241                     } else if (lexer.identifierEquals("FORCE")) {
2242                         lexer.nextToken();
2243                         stmt.setRefreshForce(true);
2244                     } else if (lexer.token == Token.ON) {
2245                         lexer.nextToken();
2246                         if (lexer.token == Token.COMMIT) {
2247                             lexer.nextToken();
2248                             stmt.setRefreshOnCommit(true);
2249                         } else {
2250                             acceptIdentifier("DEMAND");
2251                             stmt.setRefreshOnDemand(true);
2252                         }
2253                     } else {
2254                         break;
2255                     }
2256                 }
2257             } else if (lexer.identifierEquals(FnvHash.Constants.BUILD)) {
2258                 lexer.nextToken();
2259 
2260                 if (lexer.identifierEquals("IMMEDIATE") || lexer.token == Token.IMMEDIATE) {
2261                     lexer.nextToken();
2262                     stmt.setBuildImmediate(true);
2263                 } else {
2264                     accept(Token.DEFERRED);
2265                     stmt.setBuildDeferred(true);
2266                 }
2267             } else if (lexer.identifierEquals(FnvHash.Constants.PARALLEL)) {
2268                 lexer.nextToken();
2269                 stmt.setParallel(true);
2270                 if (lexer.token == Token.LITERAL_INT) {
2271                     stmt.setParallelValue(cast(Integer)(lexer.integerValue()));
2272                     lexer.nextToken();
2273                 }
2274             } else if (lexer.identifierEquals(FnvHash.Constants.NOCACHE) || lexer.token == Token.NOCACHE) {
2275                 lexer.nextToken();
2276                 stmt.setCache(false);
2277             } else if (lexer.identifierEquals(FnvHash.Constants.NOPARALLEL)) {
2278                 lexer.nextToken();
2279                 stmt.setParallel(false);
2280             } else if (lexer.token == Token.WITH) {
2281                 lexer.nextToken();
2282                 acceptIdentifier("ROWID");
2283                 stmt.setWithRowId(true);
2284             } else {
2285                 break;
2286             }
2287         }
2288 
2289         if (lexer.token == Token.ENABLE) {
2290             lexer.nextToken();
2291             acceptIdentifier("QUERY");
2292             acceptIdentifier("REWRITE");
2293             stmt.setEnableQueryRewrite(true);
2294         }
2295 
2296         accept(Token.AS);
2297         SQLSelect select = this.createSQLSelectParser().select();
2298         stmt.setQuery(select);
2299 
2300         return stmt;
2301     }
2302 
2303 
2304     public SQLStatement parseCreateDbLink() {
2305         throw new ParserException("TODO " ~ lexer.token);
2306     }
2307 
2308     public SQLStatement parseCreateSynonym() {
2309         throw new ParserException("TODO " ~ lexer.token);
2310     }
2311 
2312     public SQLStatement parseCreateTrigger() {
2313         SQLCreateTriggerStatement stmt = new SQLCreateTriggerStatement(getDbType());
2314 
2315         if (lexer.token == Token.CREATE) {
2316             lexer.nextToken();
2317 
2318             if (lexer.token == Token.OR) {
2319                 lexer.nextToken();
2320                 accept(Token.REPLACE);
2321 
2322                 stmt.setOrReplace(true);
2323             }
2324         }
2325 
2326         if (lexer.identifierEquals(FnvHash.Constants.DEFINER)) {
2327             lexer.nextToken();
2328             accept(Token.EQ);
2329             SQLName definer = (cast(MySqlExprParser) this.exprParser).userName();
2330             stmt.setDefiner(definer);
2331 
2332             if (lexer.token() == Token.LPAREN) {
2333                 lexer.nextToken();
2334                 accept(Token.RPAREN);
2335             }
2336         }
2337 
2338         accept(Token.TRIGGER);
2339 
2340 
2341         stmt.setName(this.exprParser.name());
2342 
2343         if (lexer.identifierEquals(FnvHash.Constants.BEFORE)) {
2344             stmt.setTriggerType(SQLCreateTriggerStatement.TriggerType.BEFORE);
2345             lexer.nextToken();
2346         } else if (lexer.identifierEquals(FnvHash.Constants.AFTER)) {
2347             stmt.setTriggerType(SQLCreateTriggerStatement.TriggerType.AFTER);
2348             lexer.nextToken();
2349         } else if (lexer.identifierEquals(FnvHash.Constants.INSTEAD)) {
2350             lexer.nextToken();
2351             accept(Token.OF);
2352             stmt.setTriggerType(SQLCreateTriggerStatement.TriggerType.INSTEAD_OF);
2353         }
2354 
2355         for (;;) {
2356             if (lexer.token == Token.INSERT) {
2357                 lexer.nextToken();
2358                 stmt.setInsert(true);
2359             } else if (lexer.token == Token.UPDATE) {
2360                 lexer.nextToken();
2361                 stmt.setUpdate(true);
2362 
2363                 if (lexer.token == Token.OF) {
2364                     lexer.nextToken();
2365                     this.exprParser.names(stmt.getUpdateOfColumns(), stmt);
2366                 }
2367             } else if (lexer.token == Token.DELETE) {
2368                 lexer.nextToken();
2369                 stmt.setDelete(true);
2370             }
2371 
2372             if (lexer.token == Token.COMMA
2373                     || lexer.token == Token.OR) {
2374                 lexer.nextToken();
2375                 continue;
2376             }
2377 
2378             break;
2379         }
2380 
2381         accept(Token.ON);
2382         stmt.setOn(this.exprParser.name());
2383 
2384         if (lexer.token == Token.FOR) {
2385             lexer.nextToken();
2386             acceptIdentifier("EACH");
2387             accept(Token.ROW);
2388             stmt.setForEachRow(true);
2389         }
2390 
2391         if (lexer.token == Token.WHEN) {
2392             lexer.nextToken();
2393             SQLExpr condition = this.exprParser.expr();
2394             stmt.setWhen(condition);
2395         }
2396 
2397         List!(SQLStatement) body = this.parseStatementList();
2398         if (body is null || body.isEmpty()) {
2399             throw new ParserException("syntax error");
2400         }
2401         stmt.setBody(body.get(0));
2402         return stmt;
2403     }
2404 
2405     public SQLStatement parseBlock() {
2406         throw new ParserException("TODO " ~ lexer.token);
2407     }
2408 
2409     public SQLStatement parseCreateDatabase() {
2410         if (lexer.token == Token.CREATE) {
2411             lexer.nextToken();
2412         }
2413 
2414         accept(Token.DATABASE);
2415 
2416         SQLCreateDatabaseStatement stmt = new SQLCreateDatabaseStatement(getDbType());
2417         stmt.setName(this.exprParser.name());
2418         return stmt;
2419     }
2420 
2421     public SQLCreateProcedureStatement parseCreateProcedure() {
2422         throw new ParserException("TODO " ~ lexer.token);
2423     }
2424 
2425     public SQLStatement parseCreateSequence(bool acceptCreate) {
2426         throw new ParserException("TODO " ~ lexer.token);
2427     }
2428 
2429     public SQLStatement parseCreateIndex(bool acceptCreate) {
2430         if (acceptCreate) {
2431             accept(Token.CREATE);
2432         }
2433 
2434         SQLCreateIndexStatement stmt = new SQLCreateIndexStatement(getDbType());
2435         if (lexer.token == Token.UNIQUE) {
2436             lexer.nextToken();
2437             if (lexer.identifierEquals("CLUSTERED")) {
2438                 lexer.nextToken();
2439                 stmt.setType("UNIQUE CLUSTERED");
2440             } else {
2441                 stmt.setType("UNIQUE");
2442             }
2443         } else if (lexer.identifierEquals("FULLTEXT")) {
2444             stmt.setType("FULLTEXT");
2445             lexer.nextToken();
2446         } else if (lexer.identifierEquals("NONCLUSTERED")) {
2447             stmt.setType("NONCLUSTERED");
2448             lexer.nextToken();
2449         }
2450 
2451         accept(Token.INDEX);
2452 
2453         stmt.setName(this.exprParser.name());
2454 
2455         accept(Token.ON);
2456 
2457         stmt.setTable(this.exprParser.name());
2458 
2459         accept(Token.LPAREN);
2460 
2461         for (;;) {
2462             SQLSelectOrderByItem item = this.exprParser.parseSelectOrderByItem();
2463             item.setParent(stmt);
2464             stmt.addItem(item);
2465             if (lexer.token == Token.COMMA) {
2466                 lexer.nextToken();
2467                 continue;
2468             }
2469             break;
2470         }
2471         accept(Token.RPAREN);
2472 
2473         return stmt;
2474     }
2475 
2476     public SQLCreateTableParser getSQLCreateTableParser() {
2477         return new SQLCreateTableParser(this.exprParser);
2478     }
2479 
2480     public SQLStatement parseSelect() {
2481         SQLSelectParser selectParser = createSQLSelectParser();
2482         SQLSelect select = selectParser.select();
2483         return new SQLSelectStatement(select,getDbType());
2484     }
2485 
2486     public SQLSelectParser createSQLSelectParser() {
2487         return new SQLSelectParser(this.exprParser, selectListCache);
2488     }
2489 
2490     public SQLUpdateStatement parseUpdateStatement() {
2491         SQLUpdateStatement udpateStatement = createUpdateStatement();
2492 
2493         if (lexer.token == Token.UPDATE) {
2494             lexer.nextToken();
2495 
2496             SQLTableSource tableSource = this.exprParser.createSelectParser().parseTableSource();
2497             udpateStatement.setTableSource(tableSource);
2498         }
2499 
2500         parseUpdateSet(udpateStatement);
2501 
2502         if (lexer.token == (Token.WHERE)) {
2503             lexer.nextToken();
2504             udpateStatement.setWhere(this.exprParser.expr());
2505         }
2506 
2507         return udpateStatement;
2508     }
2509 
2510     protected void parseUpdateSet(SQLUpdateStatement update) {
2511         accept(Token.SET);
2512 
2513         for (;;) {
2514             SQLUpdateSetItem item = this.exprParser.parseUpdateSetItem();
2515             update.addItem(item);
2516 
2517             if (lexer.token != Token.COMMA) {
2518                 break;
2519             }
2520 
2521             lexer.nextToken();
2522         }
2523     }
2524 
2525     protected SQLUpdateStatement createUpdateStatement() {
2526         return new SQLUpdateStatement(getDbType());
2527     }
2528 
2529     public SQLDeleteStatement parseDeleteStatement() {
2530         SQLDeleteStatement deleteStatement = new SQLDeleteStatement(getDbType());
2531 
2532         if (lexer.token == Token.DELETE) {
2533             lexer.nextToken();
2534             if (lexer.token == (Token.FROM)) {
2535                 lexer.nextToken();
2536             }
2537 
2538             if (lexer.token == Token.COMMENT) {
2539                 lexer.nextToken();
2540             }
2541 
2542             SQLName tableName = exprParser.name();
2543 
2544             deleteStatement.setTableName(tableName);
2545 
2546             if (lexer.token == Token.FROM) {
2547                 lexer.nextToken();
2548                 SQLTableSource tableSource = createSQLSelectParser().parseTableSource();
2549                 deleteStatement.setFrom(tableSource);
2550             }
2551         }
2552 
2553         if (lexer.token == (Token.WHERE)) {
2554             lexer.nextToken();
2555             SQLExpr where = this.exprParser.expr();
2556             deleteStatement.setWhere(where);
2557         }
2558 
2559         return deleteStatement;
2560     }
2561 
2562     public SQLCreateTableStatement parseCreateTable() {
2563         // SQLCreateTableParser parser = new SQLCreateTableParser(this.lexer);
2564         // return parser.parseCreateTable();
2565         throw new ParserException("TODO");
2566     }
2567 
2568     public SQLCreateViewStatement parseCreateView() {
2569         SQLCreateViewStatement createView = new SQLCreateViewStatement(getDbType());
2570 
2571         if (lexer.token == Token.CREATE) {
2572             lexer.nextToken();
2573         }
2574 
2575         if (lexer.token == Token.OR) {
2576             lexer.nextToken();
2577             accept(Token.REPLACE);
2578             createView.setOrReplace(true);
2579         }
2580 
2581         if (lexer.identifierEquals("ALGORITHM")) {
2582             lexer.nextToken();
2583             accept(Token.EQ);
2584             string algorithm = lexer.stringVal();
2585             createView.setAlgorithm(algorithm);
2586             lexer.nextToken();
2587         }
2588 
2589         if (lexer.identifierEquals(FnvHash.Constants.DEFINER)) {
2590             lexer.nextToken();
2591             accept(Token.EQ);
2592             SQLName definer = cast(SQLName) (cast(MySqlExprParser) this.exprParser).userName();
2593             createView.setDefiner(definer);
2594         }
2595 
2596         if (lexer.identifierEquals(FnvHash.Constants.SQL)) {
2597             lexer.nextToken();
2598             acceptIdentifier("SECURITY");
2599             string sqlSecurity = lexer.stringVal();
2600             createView.setSqlSecurity(sqlSecurity);
2601             lexer.nextToken();
2602         }
2603 
2604         if (lexer.identifierEquals("FORCE")) {
2605             lexer.nextToken();
2606             createView.setForce(true);
2607         }
2608 
2609         this.accept(Token.VIEW);
2610 
2611         if (lexer.token == Token.IF || lexer.identifierEquals("IF")) {
2612             lexer.nextToken();
2613             accept(Token.NOT);
2614             accept(Token.EXISTS);
2615             createView.setIfNotExists(true);
2616         }
2617 
2618         createView.setName(exprParser.name());
2619 
2620         if (lexer.token == Token.LPAREN) {
2621             lexer.nextToken();
2622 
2623             for (;;) {
2624 
2625                 if (lexer.token == Token.CONSTRAINT) {
2626                     SQLTableConstraint constraint = cast(SQLTableConstraint) this.exprParser.parseConstaint();
2627                     createView.addColumn(constraint);
2628                 } else {
2629                     SQLColumnDefinition column = new SQLColumnDefinition();
2630                     column.setDbType(dbType);
2631                     SQLName expr = this.exprParser.name();
2632                     column.setName(expr);
2633 
2634                     this.exprParser.parseColumnRest(column);
2635 
2636                     if (lexer.token == Token.COMMENT) {
2637                         lexer.nextToken();
2638 
2639                         SQLExpr comment;
2640                         if (lexer.token == Token.LITERAL_ALIAS) {
2641                             string _alias = lexer.stringVal();
2642                             if (_alias.length > 2 && charAt(_alias, 0) == '"' && charAt(_alias, _alias.length - 1) == '"') {
2643                                 _alias = _alias.substring(1, _alias.length - 1);
2644                             }
2645                             comment = new SQLCharExpr(_alias);
2646                             lexer.nextToken();
2647                         } else {
2648                             comment = this.exprParser.primary();
2649                         }
2650                         column.setComment(comment);
2651                     }
2652 
2653                     column.setParent(createView);
2654                     createView.addColumn(column);
2655                 }
2656 
2657                 if (lexer.token == Token.COMMA) {
2658                     lexer.nextToken();
2659                 } else {
2660                     break;
2661                 }
2662             }
2663 
2664             accept(Token.RPAREN);
2665         }
2666 
2667         if (lexer.token == Token.COMMENT) {
2668             lexer.nextToken();
2669             SQLCharExpr comment = cast(SQLCharExpr) exprParser.primary();
2670             createView.setComment(comment);
2671         }
2672 
2673         this.accept(Token.AS);
2674 
2675         SQLSelectParser selectParser = this.createSQLSelectParser();
2676         createView.setSubQuery(selectParser.select());
2677 
2678         if (lexer.token == Token.WITH) {
2679             lexer.nextToken();
2680 
2681             if (lexer.identifierEquals("CASCADED")) {
2682                 createView.setWithCascaded(true);
2683                 lexer.nextToken();
2684             } else if (lexer.identifierEquals("LOCAL")){
2685                 createView.setWithLocal(true);
2686                 lexer.nextToken();
2687             } else if (lexer.identifierEquals("READ")) {
2688                 lexer.nextToken();
2689                 accept(Token.ONLY);
2690                 createView.setWithReadOnly(true);
2691             }
2692 
2693             if (lexer.token == Token.CHECK) {
2694                 lexer.nextToken();
2695                 acceptIdentifier("OPTION");
2696                 createView.setWithCheckOption(true);
2697             }
2698         }
2699 
2700         return createView;
2701     }
2702 
2703     public SQLCommentStatement parseComment() {
2704         accept(Token.COMMENT);
2705         SQLCommentStatement stmt = new SQLCommentStatement();
2706 
2707         accept(Token.ON);
2708 
2709         if (lexer.token == Token.TABLE) {
2710             stmt.setType(SQLCommentStatement.Type.TABLE);
2711             lexer.nextToken();
2712         } else if (lexer.token == Token.COLUMN) {
2713             stmt.setType(SQLCommentStatement.Type.COLUMN);
2714             lexer.nextToken();
2715         }
2716 
2717         stmt.setOn(this.exprParser.name());
2718 
2719         accept(Token.IS);
2720         stmt.setComment(this.exprParser.expr());
2721 
2722         return stmt;
2723     }
2724 
2725     protected SQLAlterTableAddColumn parseAlterTableAddColumn() {
2726         bool odps = DBType.ODPS.opEquals(dbType);
2727 
2728         if (odps) {
2729             acceptIdentifier("COLUMNS");
2730             accept(Token.LPAREN);
2731         }
2732 
2733         SQLAlterTableAddColumn item = new SQLAlterTableAddColumn();
2734 
2735         for (;;) {
2736             SQLColumnDefinition columnDef = this.exprParser.parseColumn();
2737             item.addColumn(columnDef);
2738             if (lexer.token == Token.COMMA) {
2739                 lexer.nextToken();
2740                 if (lexer.identifierEquals("ADD")) {
2741                     break;
2742                 }
2743                 continue;
2744             }
2745             break;
2746         }
2747 
2748         if (odps) {
2749             accept(Token.RPAREN);
2750         }
2751         return item;
2752     }
2753     
2754     public SQLStatement parseStatement() {
2755         if (lexer.token == Token.SELECT) {
2756             return this.parseSelect();
2757         }
2758 
2759         if (lexer.token == Token.INSERT) {
2760             return this.parseInsert();
2761         }
2762 
2763 
2764         if (lexer.token == Token.UPDATE) {
2765             return this.parseUpdateStatement();
2766         }
2767 
2768         if (lexer.token == Token.DELETE) {
2769             return this.parseDeleteStatement();
2770         }
2771 
2772         List!(SQLStatement) list = new ArrayList!(SQLStatement)(1);
2773         this.parseStatementList(list, 1, null);
2774         return list.get(0);
2775     }
2776     
2777     /**
2778     * @param tryBest  - 为true去解析并忽略之后的错误
2779     *  强制建议除非明确知道可以忽略才传tryBest=true,
2780     *  不然会忽略语法错误,且截断sql,导致update和delete无where条件下执行!!!
2781     */
2782     public SQLStatement parseStatement(  bool tryBest) {
2783         List!(SQLStatement) list = new ArrayList!(SQLStatement)();
2784         this.parseStatementList(list, 1, null);
2785         if (tryBest) {
2786             if (lexer.token != Token.EOF) {
2787                 throw new ParserException("sql syntax error, no terminated. " ~ lexer.token);
2788             }
2789         }
2790         return list.get(0);
2791     }
2792 
2793     public SQLExplainStatement parseExplain() {
2794         accept(Token.EXPLAIN);
2795         if (lexer.identifierEquals("PLAN")) {
2796             lexer.nextToken();
2797         }
2798 
2799         if (lexer.token == Token.FOR) {
2800             lexer.nextToken();
2801         }
2802 
2803         SQLExplainStatement explain = new SQLExplainStatement(getDbType());
2804 
2805         if (lexer.token == Token.HINT) {
2806             explain.setHints(this.exprParser.parseHints());
2807         }
2808 
2809         if (DBType.MYSQL.opEquals(dbType)) {
2810             if (lexer.identifierEquals("FORMAT")
2811                     || lexer.identifierEquals("EXTENDED")
2812                     || lexer.identifierEquals("PARTITIONS")) {
2813                 explain.setType(lexer.stringVal);
2814                 lexer.nextToken();
2815             }
2816         }
2817 
2818         explain.setStatement(parseStatement());
2819 
2820         return explain;
2821     }
2822 
2823     protected SQLAlterTableAddIndex parseAlterTableAddIndex() {
2824         SQLAlterTableAddIndex item = new SQLAlterTableAddIndex();
2825 
2826         if (lexer.token == Token.FULLTEXT) {
2827             lexer.nextToken();
2828             item.setType("FULLTEXT");
2829         } else if (lexer.identifierEquals(FnvHash.Constants.SPATIAL)) {
2830             lexer.nextToken();
2831             item.setType("SPATIAL");
2832         }
2833 
2834         if (lexer.token == Token.UNIQUE) {
2835             item.setUnique(true);
2836             lexer.nextToken();
2837             if (lexer.token == Token.INDEX) {
2838                 lexer.nextToken();
2839             } else if (lexer.token == Token.KEY) {
2840                 item.setKey(true);
2841                 lexer.nextToken();
2842             }
2843         } else {
2844             if (lexer.token == Token.INDEX) {
2845                 accept(Token.INDEX);
2846             } else if (lexer.token == Token.KEY) {
2847                 item.setKey(true);
2848                 accept(Token.KEY);
2849             }
2850         }
2851 
2852         if (lexer.token == Token.LPAREN) {
2853             lexer.nextToken();
2854         } else {
2855             item.setName(this.exprParser.name());
2856 
2857             if (DBType.MYSQL.opEquals(dbType)) {
2858                 if (lexer.identifierEquals("USING")) {
2859                     lexer.nextToken();
2860                     string indexType = lexer.stringVal;
2861                     item.setType(indexType);
2862                     accept(Token.IDENTIFIER);
2863                 }
2864             }
2865 
2866             accept(Token.LPAREN);
2867         }
2868 
2869         for (;;) {
2870             SQLSelectOrderByItem column = this.exprParser.parseSelectOrderByItem();
2871             item.addItem(column);
2872             if (lexer.token == Token.COMMA) {
2873                 lexer.nextToken();
2874                 continue;
2875             }
2876             break;
2877         }
2878         accept(Token.RPAREN);
2879 
2880         if (DBType.MYSQL.opEquals(dbType)) {
2881             if (lexer.identifierEquals(FnvHash.Constants.USING)) {
2882                 lexer.nextToken();
2883                 string indexType = lexer.stringVal;
2884                 item.setType(indexType);
2885                 accept(Token.IDENTIFIER);
2886             }
2887         }
2888 
2889         if (lexer.token == Token.COMMENT) {
2890             lexer.nextToken();
2891             SQLExpr comment = this.exprParser.primary();
2892             item.setComment(comment);
2893         }
2894         return item;
2895     }
2896 
2897     /**
2898      * parse cursor open statement
2899      * 
2900      * @return
2901      */
2902     public SQLOpenStatement parseOpen() {
2903         SQLOpenStatement stmt = new SQLOpenStatement();
2904         accept(Token.OPEN);
2905         stmt.setCursorName(exprParser.name());
2906 
2907         if (lexer.token == Token.LPAREN) {
2908             lexer.nextToken();
2909             this.exprParser.names(stmt.getColumns(), stmt);
2910             accept(Token.RPAREN);
2911         }
2912 
2913         if (lexer.token == Token.FOR) {
2914             lexer.nextToken();
2915             if (lexer.token == Token.SELECT) {
2916                 SQLSelectParser selectParser = createSQLSelectParser();
2917                 SQLSelect select = selectParser.select();
2918                 SQLQueryExpr queryExpr = new SQLQueryExpr(select);
2919                 stmt.setFor(queryExpr);
2920             } else {
2921                 throw new ParserException("TODO " ~ lexer.info());
2922             }
2923         }
2924         accept(Token.SEMI);
2925         stmt.setAfterSemi(true);
2926         return stmt;
2927     }
2928 
2929     public SQLFetchStatement parseFetch() {
2930         accept(Token.FETCH);
2931 
2932         SQLFetchStatement stmt = new SQLFetchStatement();
2933         stmt.setCursorName(this.exprParser.name());
2934 
2935         if (lexer.identifierEquals("BULK")) {
2936             lexer.nextToken();
2937             acceptIdentifier("COLLECT");
2938             stmt.setBulkCollect(true);
2939         }
2940 
2941         accept(Token.INTO);
2942         for (;;) {
2943             stmt.getInto().add(this.exprParser.name());
2944             if (lexer.token == Token.COMMA) {
2945                 lexer.nextToken();
2946                 continue;
2947             }
2948 
2949             break;
2950         }
2951 
2952         return stmt;
2953     }
2954 
2955     public SQLStatement parseClose() {
2956         SQLCloseStatement stmt = new SQLCloseStatement();
2957         accept(Token.CLOSE);
2958         stmt.setCursorName(exprParser.name());
2959         accept(Token.SEMI);
2960         stmt.setAfterSemi(true);
2961         return stmt;
2962     }
2963 
2964     public bool isParseCompleteValues() {
2965         return parseCompleteValues;
2966     }
2967 
2968     public void setParseCompleteValues(bool parseCompleteValues) {
2969         this.parseCompleteValues = parseCompleteValues;
2970     }
2971 
2972     public int getParseValuesSize() {
2973         return parseValuesSize;
2974     }
2975 
2976     public void setParseValuesSize(int parseValuesSize) {
2977         this.parseValuesSize = parseValuesSize;
2978     }
2979     
2980     public SQLStatement parseMerge() {
2981         accept(Token.MERGE);
2982 
2983         SQLMergeStatement stmt = new SQLMergeStatement();
2984         stmt.setDbType(dbType);
2985 
2986         parseHints((stmt.getHints()));
2987 
2988         accept(Token.INTO);
2989         
2990         if (lexer.token == Token.LPAREN) {
2991             lexer.nextToken();
2992             SQLSelect select = this.createSQLSelectParser().select();
2993             SQLSubqueryTableSource tableSource = new SQLSubqueryTableSource(select);
2994             stmt.setInto(tableSource);
2995             accept(Token.RPAREN);
2996         } else {
2997             stmt.setInto(exprParser.name());
2998         }
2999         
3000         stmt.getInto().setAlias(tableAlias());
3001 
3002         accept(Token.USING);
3003 
3004         SQLTableSource using = this.createSQLSelectParser().parseTableSource();
3005         stmt.setUsing(using);
3006 
3007         accept(Token.ON);
3008         stmt.setOn(exprParser.expr());
3009 
3010         for (;;) {
3011             bool insertFlag = false;
3012             if (lexer.token == Token.WHEN) {
3013                 lexer.nextToken();
3014                 if (lexer.token == Token.MATCHED) {
3015                     SQLMergeStatement.MergeUpdateClause updateClause = new SQLMergeStatement.MergeUpdateClause();
3016                     lexer.nextToken();
3017                     accept(Token.THEN);
3018                     accept(Token.UPDATE);
3019                     accept(Token.SET);
3020 
3021                     for (; ; ) {
3022                         SQLUpdateSetItem item = this.exprParser.parseUpdateSetItem();
3023 
3024                         updateClause.addItem(item);
3025                         item.setParent(updateClause);
3026 
3027                         if (lexer.token == (Token.COMMA)) {
3028                             lexer.nextToken();
3029                             continue;
3030                         }
3031 
3032                         break;
3033                     }
3034 
3035                     if (lexer.token == Token.WHERE) {
3036                         lexer.nextToken();
3037                         updateClause.setWhere(exprParser.expr());
3038                     }
3039 
3040                     if (lexer.token == Token.DELETE) {
3041                         lexer.nextToken();
3042                         accept(Token.WHERE);
3043                         updateClause.setWhere(exprParser.expr());
3044                     }
3045 
3046                     stmt.setUpdateClause(updateClause);
3047                 } else if (lexer.token == Token.NOT) {
3048                     lexer.nextToken();
3049                     insertFlag = true;
3050                 }
3051             }
3052 
3053             if (!insertFlag) {
3054                 if (lexer.token == Token.WHEN) {
3055                     lexer.nextToken();
3056                 }
3057 
3058                 if (lexer.token == Token.NOT) {
3059                     lexer.nextToken();
3060                     insertFlag = true;
3061                 }
3062             }
3063 
3064             if (insertFlag) {
3065                 SQLMergeStatement.MergeInsertClause insertClause = new SQLMergeStatement.MergeInsertClause();
3066 
3067                 accept(Token.MATCHED);
3068                 accept(Token.THEN);
3069                 accept(Token.INSERT);
3070 
3071                 if (lexer.token == Token.LPAREN) {
3072                     accept(Token.LPAREN);
3073                     exprParser.exprList(insertClause.getColumns(), insertClause);
3074                     accept(Token.RPAREN);
3075                 }
3076                 accept(Token.VALUES);
3077                 accept(Token.LPAREN);
3078                 exprParser.exprList(insertClause.getValues(), insertClause);
3079                 accept(Token.RPAREN);
3080 
3081                 if (lexer.token == Token.WHERE) {
3082                     lexer.nextToken();
3083                     insertClause.setWhere(exprParser.expr());
3084                 }
3085 
3086                 stmt.setInsertClause(insertClause);
3087             }
3088 
3089             if (lexer.token == Token.WHEN) {
3090                 continue;
3091             }
3092 
3093             break;
3094         }
3095 
3096         SQLErrorLoggingClause errorClause = parseErrorLoggingClause();
3097         stmt.setErrorLoggingClause(errorClause);
3098 
3099         return stmt;
3100     }
3101     
3102     protected SQLErrorLoggingClause parseErrorLoggingClause() {
3103         if (lexer.identifierEquals("LOG")) {
3104             SQLErrorLoggingClause errorClause = new SQLErrorLoggingClause();
3105 
3106             lexer.nextToken();
3107             accept(Token.ERRORS);
3108             if (lexer.token == Token.INTO) {
3109                 lexer.nextToken();
3110                 errorClause.setInto(exprParser.name());
3111             }
3112 
3113             if (lexer.token == Token.LPAREN) {
3114                 lexer.nextToken();
3115                 errorClause.setSimpleExpression(exprParser.expr());
3116                 accept(Token.RPAREN);
3117             }
3118 
3119             if (lexer.token == Token.REJECT) {
3120                 lexer.nextToken();
3121                 accept(Token.LIMIT);
3122                 errorClause.setLimit(exprParser.expr());
3123             }
3124 
3125             return errorClause;
3126         }
3127         return null;
3128     }
3129     
3130     public void parseHints(List!(SQLHint) hints) {
3131         this.getExprParser().parseHints!(SQLHint)((hints));
3132     }
3133 
3134     public SQLStatement parseDescribe() {
3135         if (lexer.token == Token.DESC || lexer.identifierEquals("DESCRIBE")) {
3136             lexer.nextToken();
3137         } else {
3138             throw new ParserException("expect DESC, actual " ~ lexer.token);
3139         }
3140 
3141         SQLDescribeStatement stmt = new SQLDescribeStatement();
3142         stmt.setDbType(dbType);
3143 
3144         if (lexer.identifierEquals("ROLE")) {
3145             lexer.nextToken();
3146             stmt.setObjectType(SQLObjectType.ROLE);
3147         } else if (lexer.identifierEquals("PACKAGE")) {
3148             lexer.nextToken();
3149             stmt.setObjectType(SQLObjectType.PACKAGE);
3150         } else if (lexer.identifierEquals("INSTANCE")) {
3151             lexer.nextToken();
3152             stmt.setObjectType(SQLObjectType.INSTANCE);
3153         }
3154         stmt.setObject(this.exprParser.name());
3155 
3156         Token token = lexer.token;
3157         if (token == Token.PARTITION) {
3158             lexer.nextToken();
3159             this.accept(Token.LPAREN);
3160             for (;;) {
3161                 stmt.getPartition().add(this.exprParser.expr());
3162                 if (lexer.token == Token.COMMA) {
3163                     lexer.nextToken();
3164                     continue;
3165                 }
3166                 if (lexer.token == Token.RPAREN) {
3167                     lexer.nextToken();
3168                     break;
3169                 }
3170             }
3171         } else if (token == Token.IDENTIFIER) {
3172             SQLName column = this.exprParser.name();
3173             stmt.setColumn(column);
3174         }
3175         return stmt;
3176     }
3177 
3178     public SQLWithSubqueryClause parseWithQuery() {
3179         accept(Token.WITH);
3180 
3181         SQLWithSubqueryClause withQueryClause = new SQLWithSubqueryClause();
3182 
3183         if (lexer.token == Token.RECURSIVE || lexer.identifierEquals("RECURSIVE")) {
3184             lexer.nextToken();
3185             withQueryClause.setRecursive(true);
3186         }
3187 
3188         for (;;) {
3189             SQLWithSubqueryClause.Entry entry = new SQLWithSubqueryClause.Entry();
3190             entry.setParent(withQueryClause);
3191 
3192             string _alias = this.lexer.stringVal();
3193             lexer.nextToken();
3194             entry.setAlias(_alias);
3195 
3196             if (lexer.token == Token.LPAREN) {
3197                 lexer.nextToken();
3198                 exprParser.names(entry.getColumns());
3199                 accept(Token.RPAREN);
3200             }
3201 
3202             accept(Token.AS);
3203             accept(Token.LPAREN);
3204 
3205             switch (lexer.token) {
3206                 case Token.VALUES:
3207                 case Token.SELECT:
3208                     entry.setSubQuery(
3209                             this.createSQLSelectParser()
3210                                     .select());
3211                     break;
3212                 case Token.INSERT:
3213                     entry.setReturningStatement(
3214                             this.parseInsert()
3215                     );
3216                     break;
3217                 case Token.UPDATE:
3218                     entry.setReturningStatement(
3219                             this.parseUpdateStatement()
3220                     );
3221                     break;
3222                 case Token.DELETE:
3223                     entry.setReturningStatement(
3224                             this.parseDeleteStatement()
3225                     );
3226                     break;
3227                 default:
3228                     break;
3229             }
3230 
3231             accept(Token.RPAREN);
3232 
3233             withQueryClause.addEntry(entry);
3234 
3235             if (lexer.token == Token.COMMA) {
3236                 lexer.nextToken();
3237                 continue;
3238             }
3239 
3240             break;
3241         }
3242 
3243         return withQueryClause;
3244     }
3245 
3246     public SQLStatement parseWith() {
3247         SQLWithSubqueryClause _with = this.parseWithQuery();
3248 
3249         if (lexer.token == Token.SELECT) {
3250             SQLSelectParser selectParser = createSQLSelectParser();
3251             SQLSelect select = selectParser.select();
3252             select.setWithSubQuery(_with);
3253             return new SQLSelectStatement(select, dbType);
3254         }
3255 
3256         throw new ParserException("TODO. " ~ lexer.info());
3257     }
3258 
3259     protected void parseValueClause(List!(ValuesClause) valueClauseList, int columnSize, SQLObject parent) {
3260          bool optimizedForParameterized = lexer.isEnabled(SQLParserFeature.OptimizedForForParameterizedSkipValue);
3261 
3262         for (int i = 0; ; ++i) {
3263             int startPos = lexer.pos() - 1;
3264 
3265             if (lexer.token() != Token.LPAREN) {
3266                 throw new ParserException("syntax error, expect ')', " ~ lexer.info());
3267             }
3268             lexer.nextTokenValue();
3269 
3270             if (lexer.token() != Token.RPAREN) {
3271                 List!(SQLExpr) valueExprList;
3272                 if (columnSize > 0) {
3273                     valueExprList = new ArrayList!(SQLExpr)(columnSize);
3274                 } else {
3275                     valueExprList = new ArrayList!(SQLExpr)();
3276                 }
3277                 ValuesClause values = new ValuesClause(valueExprList);
3278                 values.setParent(parent);
3279 
3280                 for (; ; ) {
3281                     SQLExpr expr;
3282                     if (lexer.token() == Token.LITERAL_INT) {
3283                         if (optimizedForParameterized) {
3284                             expr = new SQLVariantRefExpr("?");
3285                             values.incrementReplaceCount();
3286                         } else {
3287                             expr = new SQLIntegerExpr(lexer.integerValue());
3288                         }
3289                         lexer.nextTokenCommaValue();
3290 
3291                         if (lexer.token != Token.COMMA && lexer.token != Token.RPAREN) {
3292                             expr = this.exprParser.exprRest(expr);
3293                         }
3294                     } else if (lexer.token() == Token.LITERAL_CHARS) {
3295                         if (optimizedForParameterized) {
3296                             expr = new SQLVariantRefExpr("?");
3297                             values.incrementReplaceCount();
3298                         } else {
3299                             expr = new SQLCharExpr(lexer.stringVal());
3300                         }
3301                         lexer.nextTokenCommaValue();
3302                         if (lexer.token != Token.COMMA && lexer.token != Token.RPAREN) {
3303                             expr = this.exprParser.exprRest(expr);
3304                         }
3305                     } else if (lexer.token() == Token.LITERAL_NCHARS) {
3306                         if (optimizedForParameterized) {
3307                             expr = new SQLVariantRefExpr("?");
3308                             values.incrementReplaceCount();
3309                         } else {
3310                             expr = new SQLNCharExpr(lexer.stringVal());
3311                         }
3312                         lexer.nextTokenCommaValue();
3313                         if (lexer.token != Token.COMMA && lexer.token != Token.RPAREN) {
3314                             expr = this.exprParser.exprRest(expr);
3315                         }
3316                     } else if (lexer.token == Token.NULL) {
3317                         if (optimizedForParameterized) {
3318                             expr = new SQLVariantRefExpr("?");
3319                             values.incrementReplaceCount();
3320                         } else {
3321                             expr = new SQLNullExpr();
3322                         }
3323                         lexer.nextTokenCommaValue();
3324                         if (lexer.token != Token.COMMA && lexer.token != Token.RPAREN) {
3325                             expr = this.exprParser.exprRest(expr);
3326                         }
3327                     } else {
3328                         expr = exprParser.expr();
3329                     }
3330 
3331                     if (lexer.token() == Token.COMMA) {
3332                         valueExprList.add(expr);
3333                         expr.setParent(values);
3334                         lexer.nextTokenValue();
3335                         continue;
3336                     } else if (lexer.token() == Token.RPAREN) {
3337                         valueExprList.add(expr);
3338                         expr.setParent(values);
3339                         break;
3340                     } else {
3341                         expr = this.exprParser.primaryRest(expr);
3342                         if (lexer.token() != Token.COMMA && lexer.token() != Token.RPAREN) {
3343                             expr = this.exprParser.exprRest(expr);
3344                         }
3345 
3346                         valueExprList.add(expr);
3347                         if (lexer.token() == Token.COMMA) {
3348                             lexer.nextTokenValue();
3349                             continue;
3350                         } else {
3351                             break;
3352                         }
3353                     }
3354                 }
3355 
3356                 if (lexer.isEnabled(SQLParserFeature.KeepInsertValueClauseOriginalString)) {
3357                     int endPos = lexer.pos();
3358                     string orginalString = lexer.subString(startPos, endPos - startPos);
3359                     values.setOriginalString(orginalString);
3360                 }
3361 
3362                 valueClauseList.add(values);
3363             } else {
3364                 ValuesClause values = new ValuesClause(new ArrayList!(SQLExpr)(0));
3365                 valueClauseList.add(values);
3366             }
3367 
3368             if (lexer.token() != Token.RPAREN) {
3369                 throw new ParserException("syntax error. " ~ lexer.info());
3370             }
3371 
3372             if (!parseCompleteValues && valueClauseList.size() >= parseValuesSize) {
3373                 lexer.skipToEOF();
3374                 break;
3375             }
3376 
3377             lexer.nextTokenComma();
3378             if (lexer.token() == Token.COMMA) {
3379                 lexer.nextTokenLParen();
3380                 continue;
3381             } else {
3382                 break;
3383             }
3384         }
3385     }
3386 
3387     // protected HiveInsertStatement parseHiveInsertStmt() {
3388     //     HiveInsertStatement insert = new HiveInsertStatement();
3389 
3390     //     if (lexer.isKeepComments() && lexer.hasComment()) {
3391     //         insert.addBeforeComment(lexer.readAndResetComments());
3392     //     }
3393 
3394     //     SQLSelectParser selectParser = createSQLSelectParser();
3395 
3396     //     accept(Token.INSERT);
3397 
3398     //     if (lexer.token() == Token.INTO) {
3399     //         lexer.nextToken();
3400     //     } else {
3401     //         accept(Token.OVERWRITE);
3402     //         insert.setOverwrite(true);
3403     //     }
3404 
3405     //     accept(Token.TABLE);
3406     //     insert.setTableSource(this.exprParser.name());
3407 
3408     //     if (lexer.token() == Token.PARTITION) {
3409     //         lexer.nextToken();
3410     //         accept(Token.LPAREN);
3411     //         for (;;) {
3412     //             SQLAssignItem ptExpr = new SQLAssignItem();
3413     //             ptExpr.setTarget(this.exprParser.name());
3414     //             if (lexer.token() == Token.EQ) {
3415     //                 lexer.nextToken();
3416     //                 SQLExpr ptValue = this.exprParser.expr();
3417     //                 ptExpr.setValue(ptValue);
3418     //             }
3419     //             insert.addPartition(ptExpr);
3420     //             if (!(lexer.token() == (Token.COMMA))) {
3421     //                 break;
3422     //             } else {
3423     //                 lexer.nextToken();
3424     //             }
3425     //         }
3426     //         accept(Token.RPAREN);
3427     //     }
3428 
3429     //     if (lexer.token() == Token.VALUES) {
3430     //         lexer.nextToken();
3431 
3432     //         for (;;) {
3433     //             if (lexer.token() == Token.LPAREN) {
3434     //                 lexer.nextToken();
3435 
3436     //                 ValuesClause values = new ValuesClause();
3437     //                 this.exprParser.exprList(values.getValues(), values);
3438     //                 insert.addValueCause(values);
3439     //                 accept(Token.RPAREN);
3440     //             }
3441 
3442     //             if (lexer.token() == Token.COMMA) {
3443     //                 lexer.nextToken();
3444     //                 continue;
3445     //             } else {
3446     //                 break;
3447     //             }
3448     //         }
3449     //     } else {
3450     //         SQLSelect query = selectParser.select();
3451     //         insert.setQuery(query);
3452     //     }
3453 
3454     //     return insert;
3455     // }
3456 
3457     // protected HiveInsert parseHiveInsert() {
3458     //     HiveInsert insert = new HiveInsert();
3459 
3460     //     if (lexer.isKeepComments() && lexer.hasComment()) {
3461     //         insert.addBeforeComment(lexer.readAndResetComments());
3462     //     }
3463 
3464     //     SQLSelectParser selectParser = createSQLSelectParser();
3465 
3466     //     accept(Token.INSERT);
3467 
3468     //     if (lexer.token() == Token.INTO) {
3469     //         lexer.nextToken();
3470     //     } else {
3471     //         accept(Token.OVERWRITE);
3472     //         insert.setOverwrite(true);
3473     //     }
3474 
3475     //     accept(Token.TABLE);
3476     //     insert.setTableSource(this.exprParser.name());
3477 
3478     //     if (lexer.token() == Token.PARTITION) {
3479     //         lexer.nextToken();
3480     //         accept(Token.LPAREN);
3481     //         for (;;) {
3482     //             SQLAssignItem ptExpr = new SQLAssignItem();
3483     //             ptExpr.setTarget(this.exprParser.name());
3484     //             if (lexer.token() == Token.EQ) {
3485     //                 lexer.nextToken();
3486     //                 SQLExpr ptValue = this.exprParser.expr();
3487     //                 ptExpr.setValue(ptValue);
3488     //             }
3489     //             insert.addPartition(ptExpr);
3490     //             if (!(lexer.token() == (Token.COMMA))) {
3491     //                 break;
3492     //             } else {
3493     //                 lexer.nextToken();
3494     //             }
3495     //         }
3496     //         accept(Token.RPAREN);
3497     //     }
3498 
3499     //     if (lexer.token() == Token.VALUES) {
3500     //         lexer.nextToken();
3501 
3502     //         for (;;) {
3503     //             if (lexer.token() == Token.LPAREN) {
3504     //                 lexer.nextToken();
3505 
3506     //                 ValuesClause values = new ValuesClause();
3507     //                 this.exprParser.exprList(values.getValues(), values);
3508     //                 insert.addValueCause(values);
3509     //                 accept(Token.RPAREN);
3510     //             }
3511 
3512     //             if (lexer.token() == Token.COMMA) {
3513     //                 lexer.nextToken();
3514     //                 continue;
3515     //             } else {
3516     //                 break;
3517     //             }
3518     //         }
3519     //     } else {
3520     //         SQLSelect query = selectParser.select();
3521     //         insert.setQuery(query);
3522     //     }
3523 
3524     //     return insert;
3525     // }
3526 
3527     public SQLSelectListCache getSelectListCache() {
3528         return selectListCache;
3529     }
3530 
3531     public void setSelectListCache(SQLSelectListCache selectListCache) {
3532         this.selectListCache = selectListCache;
3533     }
3534 }