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.dialect.mysql.parser.MySqlSelectIntoParser;
17
18
19 import hunt.collection;
20
21 import hunt.sql.ast.SQLExpr;
22 import hunt.sql.ast.SQLSetQuantifier;
23 import hunt.sql.ast.expr.SQLIdentifierExpr;
24 import hunt.sql.ast.expr.SQLLiteralExpr;
25 import hunt.sql.ast.expr.SQLVariantRefExpr;
26 import hunt.sql.ast.statement.SQLSelect;
27 import hunt.sql.ast.statement.SQLSelectQuery;
28 import hunt.sql.ast.statement.SQLSelectQueryBlock;
29 import hunt.sql.ast.statement.SQLTableSource;
30 import hunt.sql.ast.statement.SQLUnionQuery;
31 import hunt.sql.dialect.mysql.ast.MySqlForceIndexHint;
32 import hunt.sql.dialect.mysql.ast.MySqlIgnoreIndexHint;
33 import hunt.sql.dialect.mysql.ast.MySqlIndexHint;
34 import hunt.sql.dialect.mysql.ast.MySqlIndexHintImpl;
35 import hunt.sql.dialect.mysql.ast.MySqlUseIndexHint;
36 import hunt.sql.dialect.mysql.ast.clause.MySqlSelectIntoStatement;
37 import hunt.sql.dialect.mysql.ast.expr.MySqlOutFileExpr;
38 import hunt.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock;
39 import hunt.sql.parser.ParserException;
40 import hunt.sql.parser.SQLExprParser;
41 import hunt.sql.parser.SQLSelectParser;
42 import hunt.sql.parser.Token;
43 import hunt.sql.dialect.mysql.parser.MySqlExprParser;
44 import hunt.sql.ast.SQLObject;
45 import hunt.Boolean;
46 import hunt.sql.ast.SQLCommentHint;
47
48 public class MySqlSelectIntoParser : SQLSelectParser {
49 private List!(SQLExpr) argsList;
50
51 public this(SQLExprParser exprParser){
52 super(exprParser);
53 }
54
55 public this(string sql){
56 this(new MySqlExprParser(sql));
57 }
58
59 public MySqlSelectIntoStatement parseSelectInto()
60 {
61 SQLSelect select=select();
62 MySqlSelectIntoStatement stmt=new MySqlSelectIntoStatement();
63 stmt.setSelect(select);
64 stmt.setVarList(argsList);
65 return stmt;
66
67 }
68
69 override
70 public SQLSelectQuery query() {
71 if (lexer.token() == (Token.LPAREN)) {
72 lexer.nextToken();
73
74 SQLSelectQuery select = query();
75 accept(Token.RPAREN);
76
77 return queryRest(select);
78 }
79
80 MySqlSelectQueryBlock queryBlock = new MySqlSelectQueryBlock();
81
82 if (lexer.token() == Token.SELECT) {
83 lexer.nextToken();
84
85 if (lexer.token() == Token.HINT) {
86 this.exprParser.parseHints!(SQLCommentHint)((queryBlock.getHints()));
87 }
88
89 if (lexer.token() == Token.COMMENT) {
90 lexer.nextToken();
91 }
92
93 if (lexer.token() == (Token.DISTINCT)) {
94 queryBlock.setDistionOption(SQLSetQuantifier.DISTINCT);
95 lexer.nextToken();
96 } else if (lexer.identifierEquals("DISTINCTROW")) {
97 queryBlock.setDistionOption(SQLSetQuantifier.DISTINCTROW);
98 lexer.nextToken();
99 } else if (lexer.token() == (Token.ALL)) {
100 queryBlock.setDistionOption(SQLSetQuantifier.ALL);
101 lexer.nextToken();
102 }
103
104 if (lexer.identifierEquals("HIGH_PRIORITY")) {
105 queryBlock.setHignPriority(true);
106 lexer.nextToken();
107 }
108
109 if (lexer.identifierEquals("STRAIGHT_JOIN")) {
110 queryBlock.setStraightJoin(true);
111 lexer.nextToken();
112 }
113
114 if (lexer.identifierEquals("SQL_SMALL_RESULT")) {
115 queryBlock.setSmallResult(true);
116 lexer.nextToken();
117 }
118
119 if (lexer.identifierEquals("SQL_BIG_RESULT")) {
120 queryBlock.setBigResult(true);
121 lexer.nextToken();
122 }
123
124 if (lexer.identifierEquals("SQL_BUFFER_RESULT")) {
125 queryBlock.setBufferResult(true);
126 lexer.nextToken();
127 }
128
129 if (lexer.identifierEquals("SQL_CACHE")) {
130 queryBlock.setCache(new Boolean(true));
131 lexer.nextToken();
132 }
133
134 if (lexer.identifierEquals("SQL_NO_CACHE")) {
135 queryBlock.setCache(new Boolean(false));
136 lexer.nextToken();
137 }
138
139 if (lexer.identifierEquals("SQL_CALC_FOUND_ROWS")) {
140 queryBlock.setCalcFoundRows(true);
141 lexer.nextToken();
142 }
143
144 parseSelectList(queryBlock);
145
146 argsList=parseIntoArgs();
147 }
148
149 parseFrom(queryBlock);
150
151 parseWhere(queryBlock);
152
153 parseGroupBy(queryBlock);
154
155 queryBlock.setOrderBy(this.exprParser.parseOrderBy());
156
157 if (lexer.token() == Token.LIMIT) {
158 queryBlock.setLimit(this.exprParser.parseLimit());
159 }
160
161 if (lexer.token() == Token.PROCEDURE) {
162 lexer.nextToken();
163 throw new ParserException("TODO. " ~ lexer.info());
164 }
165
166 parseInto(queryBlock);
167
168 if (lexer.token() == Token.FOR) {
169 lexer.nextToken();
170 accept(Token.UPDATE);
171
172 queryBlock.setForUpdate(true);
173 }
174
175 if (lexer.token() == Token.LOCK) {
176 lexer.nextToken();
177 accept(Token.IN);
178 acceptIdentifier("SHARE");
179 acceptIdentifier("MODE");
180 queryBlock.setLockInShareMode(true);
181 }
182
183 return queryRest(queryBlock);
184 }
185 /**
186 * parser the select into arguments
187 * @return
188 */
189 protected List!(SQLExpr) parseIntoArgs() {
190
191 List!(SQLExpr) args=new ArrayList!(SQLExpr)();
192 if (lexer.token() == (Token.INTO)) {
193 accept(Token.INTO);
194 //lexer.nextToken();
195 for (;;) {
196 SQLExpr var = exprParser.primary();
197 if (cast(SQLIdentifierExpr)(var) !is null) {
198 var = new SQLVariantRefExpr(
199 (cast(SQLIdentifierExpr) var).getName());
200 }
201 args.add(var);
202 if (lexer.token() == Token.COMMA) {
203 accept(Token.COMMA);
204 continue;
205 }
206 else
207 {
208 break;
209 }
210 }
211 }
212 return args;
213 }
214
215
216 protected void parseInto(SQLSelectQueryBlock queryBlock) {
217 if (lexer.token() == (Token.INTO)) {
218 lexer.nextToken();
219
220 if (lexer.identifierEquals("OUTFILE")) {
221 lexer.nextToken();
222
223 MySqlOutFileExpr outFile = new MySqlOutFileExpr();
224 outFile.setFile(expr());
225
226 queryBlock.setInto(outFile);
227
228 if (lexer.identifierEquals("FIELDS") || lexer.identifierEquals("COLUMNS")) {
229 lexer.nextToken();
230
231 if (lexer.identifierEquals("TERMINATED")) {
232 lexer.nextToken();
233 accept(Token.BY);
234 }
235 outFile.setColumnsTerminatedBy(cast(SQLLiteralExpr) expr());
236
237 if (lexer.identifierEquals("OPTIONALLY")) {
238 lexer.nextToken();
239 outFile.setColumnsEnclosedOptionally(true);
240 }
241
242 if (lexer.identifierEquals("ENCLOSED")) {
243 lexer.nextToken();
244 accept(Token.BY);
245 outFile.setColumnsEnclosedBy(cast(SQLLiteralExpr) expr());
246 }
247
248 if (lexer.identifierEquals("ESCAPED")) {
249 lexer.nextToken();
250 accept(Token.BY);
251 outFile.setColumnsEscaped(cast(SQLLiteralExpr) expr());
252 }
253 }
254
255 if (lexer.identifierEquals("LINES")) {
256 lexer.nextToken();
257
258 if (lexer.identifierEquals("STARTING")) {
259 lexer.nextToken();
260 accept(Token.BY);
261 outFile.setLinesStartingBy(cast(SQLLiteralExpr) expr());
262 } else {
263 lexer.identifierEquals("TERMINATED");
264 lexer.nextToken();
265 accept(Token.BY);
266 outFile.setLinesTerminatedBy(cast(SQLLiteralExpr) expr());
267 }
268 }
269 } else {
270 queryBlock.setInto(this.exprParser.name());
271 }
272 }
273 }
274
275 override protected SQLTableSource parseTableSourceRest(SQLTableSource tableSource) {
276 if (lexer.identifierEquals("USING")) {
277 return tableSource;
278 }
279
280 parseIndexHintList(tableSource);
281
282 return super.parseTableSourceRest(tableSource);
283 }
284
285 private void parseIndexHintList(SQLTableSource tableSource) {
286 if (lexer.token() == Token.USE) {
287 lexer.nextToken();
288 MySqlUseIndexHint hint = new MySqlUseIndexHint();
289 parseIndexHint(hint);
290 tableSource.getHints().add(hint);
291 parseIndexHintList(tableSource);
292 }
293
294 if (lexer.identifierEquals("IGNORE")) {
295 lexer.nextToken();
296 MySqlIgnoreIndexHint hint = new MySqlIgnoreIndexHint();
297 parseIndexHint(hint);
298 tableSource.getHints().add(hint);
299 parseIndexHintList(tableSource);
300 }
301
302 if (lexer.identifierEquals("FORCE")) {
303 lexer.nextToken();
304 MySqlForceIndexHint hint = new MySqlForceIndexHint();
305 parseIndexHint(hint);
306 tableSource.getHints().add(hint);
307 parseIndexHintList(tableSource);
308 }
309 }
310
311 private void parseIndexHint(MySqlIndexHintImpl hint) {
312 if (lexer.token() == Token.INDEX) {
313 lexer.nextToken();
314 } else {
315 accept(Token.KEY);
316 }
317
318 if (lexer.token() == Token.FOR) {
319 lexer.nextToken();
320
321 if (lexer.token() == Token.JOIN) {
322 lexer.nextToken();
323 hint.setOption(MySqlIndexHint.Option.JOIN);
324 } else if (lexer.token() == Token.ORDER) {
325 lexer.nextToken();
326 accept(Token.BY);
327 hint.setOption(MySqlIndexHint.Option.ORDER_BY);
328 } else {
329 accept(Token.GROUP);
330 accept(Token.BY);
331 hint.setOption(MySqlIndexHint.Option.GROUP_BY);
332 }
333 }
334
335 accept(Token.LPAREN);
336 if (lexer.token() == Token.PRIMARY) {
337 lexer.nextToken();
338 hint.getIndexList().add(new SQLIdentifierExpr("PRIMARY"));
339 } else {
340 this.exprParser.names(hint.getIndexList());
341 }
342 accept(Token.RPAREN);
343 }
344
345 override public SQLUnionQuery unionRest(SQLUnionQuery union_p) {
346 if (lexer.token() == Token.LIMIT) {
347 union_p.setLimit(this.exprParser.parseLimit());
348 }
349 return super.unionRest(union_p);
350 }
351
352 public MySqlExprParser getExprParser() {
353 return cast(MySqlExprParser) exprParser;
354 }
355 }