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.SQLParser;
17 
18 import hunt.sql.ast.statement.SQLCreateTableStatement;
19 // import hunt.sql.dialect.hive.stmt.HiveCreateTableStatement;
20 import hunt.sql.parser.Lexer;
21 import hunt.sql.parser.Token;
22 import hunt.sql.parser.SQLParserFeature;
23 import hunt.sql.parser.ParserException;
24 import hunt.String;
25 //import hunt.lang;
26 import hunt.text;
27 import hunt.Integer;
28 
29 public class SQLParser {
30     protected  Lexer lexer;
31     protected string      dbType;
32 
33     public this(string sql, string dbType){
34         this(new Lexer(sql, null, dbType), dbType);
35         this.lexer.nextToken();
36     }
37 
38     public this(string sql){
39         this(sql, null);
40     }
41 
42     public this(Lexer lexer){
43         this(lexer, null);
44     }
45 
46     public this(Lexer lexer, string dbType){
47         this.lexer = lexer;
48         this.dbType = dbType;
49     }
50 
51     public  Lexer getLexer() {
52         return lexer;
53     }
54 
55     public string getDbType() {
56         return dbType;
57     }
58 
59     protected bool identifierEquals(string text) {
60         return lexer.identifierEquals(text);
61     }
62 
63     protected void acceptIdentifier(string text) {
64         if (lexer.identifierEquals(text)) {
65             lexer.nextToken();
66         } else {
67             setErrorEndPos(lexer.pos());
68             throw new ParserException("syntax error, expect " ~ text ~ ", actual " ~ lexer.token ~ ", " ~ lexer.info());
69         }
70     }
71 
72     protected string tableAlias() {
73         return tableAlias(false);
74     }
75 
76     protected string tableAlias(bool must) {
77          Token token = lexer.token;
78         if (token == Token.CONNECT
79                 || token == Token.START
80                 || token == Token.SELECT
81                 || token == Token.FROM
82                 || token == Token.WHERE) {
83             if (must) {
84                 throw new ParserException("illegal _alias. " ~ lexer.info());
85             }
86             return null;
87         }
88 
89         if (token == Token.IDENTIFIER) {
90             string ident = lexer.stringVal;
91             if (equalsIgnoreCase(ident, "START") || equalsIgnoreCase(ident, "CONNECT")) {
92                 if (must) {
93                     throw new ParserException("illegal _alias. " ~ lexer.info());
94                 }
95                 return null;
96             }
97         }
98 
99         return this.as();
100     }
101 
102     protected string as() {
103         string _alias = null;
104 
105          Token token = lexer.token;
106 
107         if (token == Token.COMMA) {
108             return null;
109         }
110 
111         if (token == Token.AS) {
112             lexer.nextToken();
113             _alias = lexer.stringVal();
114             lexer.nextToken();
115 
116             if (_alias !is null) {
117                 while (lexer.token == Token.DOT) {
118                     lexer.nextToken();
119                     _alias ~= ('.' ~ lexer.token.stringof); //@gxc
120                     lexer.nextToken();
121                 }
122 
123                 return _alias;
124             }
125 
126             if (lexer.token == Token.LPAREN) {
127                 return null;
128             }
129 
130             throw new ParserException("Error : " ~ lexer.info());
131         }
132 
133         if (lexer.token == Token.LITERAL_ALIAS) {
134             _alias = lexer.stringVal();
135             lexer.nextToken();
136         } else if (lexer.token == Token.IDENTIFIER) {
137             _alias = lexer.stringVal();
138             lexer.nextToken();
139         } else if (lexer.token == Token.LITERAL_CHARS) {
140             _alias = "'" ~ lexer.stringVal() ~ "'";
141             lexer.nextToken();
142         } else {
143             switch (lexer.token) {
144                 case Token.CASE:
145                 case Token.USER:
146                 case Token.LOB:
147                 case Token.END:
148                 case Token.DEFERRED:
149                 case Token.OUTER:
150                 case Token.DO:
151                 case Token.STORE:
152                 case Token.MOD:
153                     _alias = lexer.stringVal();
154                     lexer.nextToken();
155                     break;
156                 default:
157                     break;
158             }
159         }
160 
161         switch (lexer.token) {
162             case Token.KEY:
163             case Token.INTERVAL:
164             case Token.CONSTRAINT:
165                 _alias = lexer.token.stringof;  //@gxc
166                 lexer.nextToken();
167                 return _alias;
168             default:
169                 break;
170         }
171 
172         return _alias;
173     }
174 
175     protected string alias_f() {
176         string _alias = null;
177         if (lexer.token == Token.LITERAL_ALIAS) {
178             _alias = lexer.stringVal();
179             lexer.nextToken();
180         } else if (lexer.token == Token.IDENTIFIER) {
181             _alias = lexer.stringVal();
182             lexer.nextToken();
183         } else if (lexer.token == Token.LITERAL_CHARS) {
184             _alias = "'" ~ lexer.stringVal() ~ "'";
185             lexer.nextToken();
186         } else {
187             switch (lexer.token) {
188                 case Token.KEY:
189                 case Token.INDEX:
190                 case Token.CASE:
191                 case Token.MODEL:
192                 case Token.PCTFREE:
193                 case Token.INITRANS:
194                 case Token.MAXTRANS:
195                 case Token.SEGMENT:
196                 case Token.CREATION:
197                 case Token.IMMEDIATE:
198                 case Token.DEFERRED:
199                 case Token.STORAGE:
200                 case Token.NEXT:
201                 case Token.MINEXTENTS:
202                 case Token.MAXEXTENTS:
203                 case Token.MAXSIZE:
204                 case Token.PCTINCREASE:
205                 case Token.FLASH_CACHE:
206                 case Token.CELL_FLASH_CACHE:
207                 case Token.NONE:
208                 case Token.LOB:
209                 case Token.STORE:
210                 case Token.ROW:
211                 case Token.CHUNK:
212                 case Token.CACHE:
213                 case Token.NOCACHE:
214                 case Token.LOGGING:
215                 case Token.NOCOMPRESS:
216                 case Token.KEEP_DUPLICATES:
217                 case Token.EXCEPTIONS:
218                 case Token.PURGE:
219                 case Token.INITIALLY:
220                 case Token.END:
221                 case Token.COMMENT:
222                 case Token.ENABLE:
223                 case Token.DISABLE:
224                 case Token.SEQUENCE:
225                 case Token.USER:
226                 case Token.ANALYZE:
227                 case Token.OPTIMIZE:
228                 case Token.GRANT:
229                 case Token.REVOKE:
230                 case Token.FULL:
231                 case Token.TO:
232                 case Token.NEW:
233                 case Token.INTERVAL:
234                 case Token.LOCK:
235                 case Token.LIMIT:
236                 case Token.IDENTIFIED:
237                 case Token.PASSWORD:
238                 case Token.BINARY:
239                 case Token.WINDOW:
240                 case Token.OFFSET:
241                 case Token.SHARE:
242                 case Token.START:
243                 case Token.CONNECT:
244                 case Token.MATCHED:
245                 case Token.ERRORS:
246                 case Token.REJECT:
247                 case Token.UNLIMITED:
248                 case Token.BEGIN:
249                 case Token.EXCLUSIVE:
250                 case Token.MODE:
251                 case Token.ADVISE:
252                 case Token.TYPE:
253                 case Token.CLOSE:
254                 case Token.OPEN:
255                     _alias = lexer.stringVal();
256                     lexer.nextToken();
257                     return _alias;
258                 case Token.QUES:
259                     _alias = "?";
260                     lexer.nextToken();
261                     break;
262                 default:
263                     break;
264             }
265         }
266         return _alias;
267     }
268 
269     protected void printError(Token token) {
270         string arround;
271         if (lexer._mark >= 0 && (lexer.text.length > lexer._mark + 30)) {
272             if (lexer._mark - 5 > 0) {
273                 arround = lexer.text.substring(lexer._mark - 5, lexer._mark + 30);
274             } else {
275                 arround = lexer.text.substring(lexer._mark, lexer._mark + 30);
276             }
277 
278         } else if (lexer._mark >= 0) {
279             if (lexer._mark - 5 > 0) {
280                 arround = lexer.text.substring(lexer._mark - 5);
281             } else {
282                 arround = lexer.text.substring(lexer._mark);
283             }
284         } else {
285             arround = lexer.text;
286         }
287 
288         // throw new
289         // ParserException("syntax error, error arround:'"~arround~"',expect "
290         // ~ token ~ ", actual " ~ lexer.token ~ " "
291         // ~ lexer.stringVal() ~ ", pos " ~ this.lexer.pos());
292         throw new ParserException("syntax error, error in :<" ~ arround ~ ">, expect: <" ~ token ~ 
293             ">, actual: <" ~ lexer.token ~ ">, " ~ lexer.info());
294     }
295 
296     public void accept(Token token) {
297         if (lexer.token == token) {
298             lexer.nextToken();
299         } else {
300             setErrorEndPos(lexer.pos());
301             printError(token);
302         }
303     }
304 
305     public int acceptInteger() {
306         if (lexer.token == Token.LITERAL_INT) {
307             int intVal = (cast(Integer) lexer.integerValue()).intValue();
308             lexer.nextToken();
309             return intVal;
310         } else {
311             throw new ParserException("syntax error, expect: <int>, actual: <" ~ lexer.token ~ ">, "
312                     ~ lexer.info());
313         }
314     }
315 
316     public void match(Token token) {
317         if (lexer.token != token) {
318             throw new ParserException("syntax error, expect: <" ~ token ~ ">, actual: <" ~ lexer.token ~ ">, "
319                                       ~ lexer.info());
320         }
321     }
322 
323     private int errorEndPos = -1;
324 
325     protected void setErrorEndPos(int errPos) {
326         if (errPos > errorEndPos) {
327             errorEndPos = errPos;
328         }
329     }
330 
331     public void config(SQLParserFeature feature, bool state) {
332         this.lexer.config(feature, state);
333     }
334 
335     public  bool isEnabled(SQLParserFeature feature) {
336         return lexer.isEnabled(feature);
337     }
338 
339     protected SQLCreateTableStatement newCreateStatement() {
340         return new SQLCreateTableStatement(getDbType());
341     }
342 }