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.postgresql.parser.PGSQLStatementParser; 17 18 import hunt.sql.ast.SQLExpr; 19 import hunt.sql.ast.SQLName; 20 import hunt.sql.ast.SQLStatement; 21 import hunt.sql.ast.expr; 22 import hunt.sql.ast.statement; 23 import hunt.sql.dialect.postgresql.ast.stmt.PGDeleteStatement; 24 import hunt.sql.dialect.postgresql.ast.stmt.PGInsertStatement; 25 import hunt.sql.dialect.postgresql.ast.stmt.PGSelectStatement; 26 import hunt.sql.dialect.postgresql.ast.stmt.PGShowStatement; 27 import hunt.sql.dialect.postgresql.ast.stmt.PGUpdateStatement; 28 import hunt.sql.parser; 29 import hunt.sql.dialect.postgresql.ast.stmt; 30 import hunt.sql.parser.Lexer; 31 import hunt.sql.parser.ParserException; 32 import hunt.sql.parser.SQLStatementParser; 33 import hunt.sql.parser.Token; 34 import hunt.sql.util.FnvHash; 35 import hunt.sql.util.DBType; 36 import hunt.sql.dialect.postgresql.parser.PGExprParser; 37 import hunt.sql.dialect.postgresql.parser.PGSelectParser; 38 import hunt.sql.ast.SQLObjectImpl; 39 import hunt.Boolean; 40 import hunt.String; 41 import hunt.collection; 42 import hunt.text; 43 import std.uni; 44 45 public class PGSQLStatementParser : SQLStatementParser { 46 enum string TIME_ZONE = "TIME ZONE"; 47 enum string TIME = "TIME"; 48 enum string LOCAL = "LOCAL"; 49 50 public this(PGExprParser parser) { 51 super(parser); 52 } 53 54 public this(string sql){ 55 super(new PGExprParser(sql)); 56 } 57 58 public this(string sql, SQLParserFeature[] features...){ 59 super(new PGExprParser(sql, features)); 60 } 61 62 public this(Lexer lexer){ 63 super(new PGExprParser(lexer)); 64 } 65 66 override public PGSelectParser createSQLSelectParser() { 67 return new PGSelectParser(this.exprParser, selectListCache); 68 } 69 70 override public SQLUpdateStatement parseUpdateStatement() { 71 accept(Token.UPDATE); 72 73 PGUpdateStatement udpateStatement = new PGUpdateStatement(); 74 75 SQLSelectParser selectParser = this.exprParser.createSelectParser(); 76 SQLTableSource tableSource = selectParser.parseTableSource(); 77 udpateStatement.setTableSource(tableSource); 78 79 parseUpdateSet(udpateStatement); 80 81 if (lexer.token() == Token.FROM) { 82 lexer.nextToken(); 83 SQLTableSource from = selectParser.parseTableSource(); 84 udpateStatement.setFrom(from); 85 } 86 87 if (lexer.token() == (Token.WHERE)) { 88 lexer.nextToken(); 89 udpateStatement.setWhere(this.exprParser.expr()); 90 } 91 92 if (lexer.token() == Token.RETURNING) { 93 lexer.nextToken(); 94 95 for (;;) { 96 udpateStatement.getReturning().add(this.exprParser.expr()); 97 if (lexer.token() == Token.COMMA) { 98 lexer.nextToken(); 99 continue; 100 } 101 break; 102 } 103 } 104 105 return udpateStatement; 106 } 107 108 override public PGInsertStatement parseInsert() { 109 PGInsertStatement stmt = new PGInsertStatement(); 110 111 if (lexer.token() == Token.INSERT) { 112 lexer.nextToken(); 113 accept(Token.INTO); 114 115 SQLName tableName = this.exprParser.name(); 116 stmt.setTableName(tableName); 117 118 if (lexer.token() == Token.AS) { 119 lexer.nextToken(); 120 stmt.setAlias(lexer.stringVal()); 121 lexer.nextToken(); 122 } else if (lexer.token() == Token.IDENTIFIER) { 123 stmt.setAlias(lexer.stringVal()); 124 lexer.nextToken(); 125 } 126 127 } 128 129 if (lexer.token() == Token.DEFAULT) { 130 lexer.nextToken(); 131 accept(Token.VALUES); 132 stmt.setDefaultValues(true); 133 } 134 135 if (lexer.token() == (Token.LPAREN)) { 136 lexer.nextToken(); 137 this.exprParser.exprList(stmt.getColumns(), stmt); 138 accept(Token.RPAREN); 139 } 140 141 if (lexer.token() == (Token.VALUES)) { 142 lexer.nextToken(); 143 144 for (;;) { 145 accept(Token.LPAREN); 146 ValuesClause valuesCaluse = new ValuesClause(); 147 this.exprParser.exprList(valuesCaluse.getValues(), valuesCaluse); 148 stmt.addValueCause(valuesCaluse); 149 150 accept(Token.RPAREN); 151 if (lexer.token() == Token.COMMA) { 152 lexer.nextToken(); 153 continue; 154 } 155 break; 156 } 157 } else if (lexer.token() == (Token.SELECT)) { 158 SQLQueryExpr queryExpr = cast(SQLQueryExpr) this.exprParser.expr(); 159 stmt.setQuery(queryExpr.getSubQuery()); 160 } 161 162 if (lexer.token() == Token.ON) { 163 lexer.nextToken(); 164 if (lexer.identifierEquals(FnvHash.Constants.CONFLICT)) { 165 lexer.nextToken(); 166 167 if (lexer.token() == Token.LPAREN) { 168 lexer.nextToken(); 169 List!(SQLExpr) onConflictTarget = new ArrayList!(SQLExpr)(); 170 this.exprParser.exprList(onConflictTarget, stmt); 171 stmt.setOnConflictTarget(onConflictTarget); 172 accept(Token.RPAREN); 173 } 174 175 if (lexer.token() == Token.ON) { 176 lexer.nextToken(); 177 accept(Token.CONSTRAINT); 178 SQLName constraintName = this.exprParser.name(); 179 stmt.setOnConflictConstraint(constraintName); 180 } 181 182 if (lexer.token() == Token.WHERE) { 183 lexer.nextToken(); 184 SQLExpr where = this.exprParser.expr(); 185 stmt.setOnConflictWhere(where); 186 } 187 188 if (lexer.token() == Token.DO) { 189 lexer.nextToken(); 190 191 if (lexer.identifierEquals(FnvHash.Constants.NOTHING)) { 192 lexer.nextToken(); 193 stmt.setOnConflictDoNothing(true); 194 } else { 195 accept(Token.UPDATE); 196 accept(Token.SET); 197 198 for (;;) { 199 SQLUpdateSetItem item = this.exprParser.parseUpdateSetItem(); 200 stmt.addConflicUpdateItem(item); 201 202 if (lexer.token() != Token.COMMA) { 203 break; 204 } 205 206 lexer.nextToken(); 207 } 208 } 209 } 210 } 211 } 212 213 if (lexer.token() == Token.RETURNING) { 214 lexer.nextToken(); 215 SQLExpr returning = this.exprParser.expr(); 216 217 if (lexer.token() == Token.COMMA) { 218 lexer.nextToken(); 219 SQLListExpr list = new SQLListExpr(); 220 list.addItem(returning); 221 222 this.exprParser.exprList(list.getItems(), list); 223 224 returning = list; 225 } 226 stmt.setReturning(returning); 227 } 228 return stmt; 229 } 230 231 override public PGDeleteStatement parseDeleteStatement() { 232 lexer.nextToken(); 233 PGDeleteStatement deleteStatement = new PGDeleteStatement(); 234 235 if (lexer.token() == (Token.FROM)) { 236 lexer.nextToken(); 237 } 238 if (lexer.token() == (Token.ONLY)) { 239 lexer.nextToken(); 240 deleteStatement.setOnly(true); 241 } 242 243 SQLName tableName = exprParser.name(); 244 245 deleteStatement.setTableName(tableName); 246 247 if (lexer.token() == Token.AS) { 248 accept(Token.AS); 249 } 250 if (lexer.token() == Token.IDENTIFIER) { 251 deleteStatement.setAlias(lexer.stringVal()); 252 lexer.nextToken(); 253 } 254 255 if (lexer.token() == Token.USING) { 256 lexer.nextToken(); 257 258 SQLTableSource tableSource = createSQLSelectParser().parseTableSource(); 259 deleteStatement.setUsing(tableSource); 260 } 261 262 if (lexer.token() == (Token.WHERE)) { 263 lexer.nextToken(); 264 265 if (lexer.token() == Token.CURRENT) { 266 lexer.nextToken(); 267 accept(Token.OF); 268 SQLName cursorName = this.exprParser.name(); 269 SQLExpr where = new SQLCurrentOfCursorExpr(cursorName); 270 deleteStatement.setWhere(where); 271 } else { 272 SQLExpr where = this.exprParser.expr(); 273 deleteStatement.setWhere(where); 274 } 275 } 276 277 if (lexer.token() == Token.RETURNING) { 278 lexer.nextToken(); 279 accept(Token.STAR); 280 deleteStatement.setReturning(true); 281 } 282 283 return deleteStatement; 284 } 285 286 override public bool parseStatementListDialect(List!(SQLStatement) statementList) { 287 switch (lexer.token()) { 288 case Token.BEGIN: 289 case Token.START: { 290 PGStartTransactionStatement stmt = parseBegin(); 291 statementList.add(stmt); 292 return true; 293 } 294 295 case Token.WITH: 296 statementList.add(parseWith()); 297 return true; 298 default: 299 break; 300 } 301 302 if (lexer.identifierEquals(FnvHash.Constants.CONNECT)) { 303 SQLStatement stmt = parseConnectTo(); 304 statementList.add(stmt); 305 return true; 306 } 307 308 return false; 309 } 310 311 protected PGStartTransactionStatement parseBegin() { 312 PGStartTransactionStatement stmt = new PGStartTransactionStatement(); 313 if (lexer.token() == Token.START) { 314 lexer.nextToken(); 315 acceptIdentifier("TRANSACTION"); 316 } else { 317 accept(Token.BEGIN); 318 } 319 320 return stmt; 321 } 322 323 public SQLStatement parseConnectTo() { 324 acceptIdentifier("CONNECT"); 325 accept(Token.TO); 326 327 PGConnectToStatement stmt = new PGConnectToStatement(); 328 SQLName target = this.exprParser.name(); 329 stmt.setTarget(target); 330 331 return stmt; 332 } 333 334 override public PGSelectStatement parseSelect() { 335 PGSelectParser selectParser = createSQLSelectParser(); 336 SQLSelect select = selectParser.select(); 337 return new PGSelectStatement(select); 338 } 339 340 override public SQLStatement parseWith() { 341 SQLWithSubqueryClause with_p = this.parseWithQuery(); 342 // PGWithClause with = this.parseWithClause(); 343 if (lexer.token() == Token.INSERT) { 344 PGInsertStatement stmt = this.parseInsert(); 345 stmt.setWith(with_p); 346 return stmt; 347 } 348 349 if (lexer.token() == Token.SELECT) { 350 PGSelectStatement stmt = this.parseSelect(); 351 stmt.getSelect().setWithSubQuery(with_p); 352 return stmt; 353 } 354 355 if (lexer.token() == Token.DELETE) { 356 PGDeleteStatement stmt = this.parseDeleteStatement(); 357 stmt.setWith(with_p); 358 return stmt; 359 } 360 361 if (lexer.token() == Token.UPDATE) { 362 PGUpdateStatement stmt = cast(PGUpdateStatement) this.parseUpdateStatement(); 363 stmt.setWith(with_p); 364 return stmt; 365 } 366 367 throw new ParserException("TODO. " ~ lexer.info()); 368 } 369 370 override protected SQLAlterTableAlterColumn parseAlterColumn() { 371 if (lexer.token() == Token.COLUMN) { 372 lexer.nextToken(); 373 } 374 375 SQLColumnDefinition column = this.exprParser.parseColumn(); 376 377 SQLAlterTableAlterColumn alterColumn = new SQLAlterTableAlterColumn(); 378 alterColumn.setColumn(column); 379 380 if (column.getDataType() is null && column.getConstraints().size() == 0) { 381 if (lexer.token() == Token.SET) { 382 lexer.nextToken(); 383 if (lexer.token() == Token.NOT) { 384 lexer.nextToken(); 385 accept(Token.NULL); 386 alterColumn.setSetNotNull(true); 387 } else { 388 accept(Token.DEFAULT); 389 SQLExpr defaultValue = this.exprParser.expr(); 390 alterColumn.setSetDefault(defaultValue); 391 } 392 } else if (lexer.token() == Token.DROP) { 393 lexer.nextToken(); 394 if (lexer.token() == Token.NOT) { 395 lexer.nextToken(); 396 accept(Token.NULL); 397 alterColumn.setDropNotNull(true); 398 } else { 399 accept(Token.DEFAULT); 400 alterColumn.setDropDefault(true); 401 } 402 } 403 } 404 return alterColumn; 405 } 406 407 override public SQLStatement parseShow() { 408 accept(Token.SHOW); 409 PGShowStatement stmt = new PGShowStatement(); 410 switch (lexer.token()) { 411 case Token.ALL: 412 stmt.setExpr(new SQLIdentifierExpr(Token.ALL.stringof)); //@gxc 413 lexer.nextToken(); 414 break; 415 default: 416 stmt.setExpr(this.exprParser.expr()); 417 break; 418 } 419 return stmt; 420 } 421 422 override 423 public SQLStatement parseCommit() { 424 SQLCommitStatement stmt = new SQLCommitStatement(); 425 stmt.setDbType(this.dbType); 426 lexer.nextToken(); 427 return stmt; 428 } 429 430 override 431 public SQLStatement parseSet() { 432 accept(Token.SET); 433 Token token = lexer.token(); 434 string range = ""; 435 436 SQLSetStatement.Option option = null; 437 if (token == Token.SESSION) { 438 lexer.nextToken(); 439 range = Token.SESSION.stringof;//@gxc 440 option = SQLSetStatement.Option.SESSION; 441 } else if (token == Token.IDENTIFIER && equalsIgnoreCase(LOCAL, lexer.stringVal())) { 442 range = LOCAL; 443 option = SQLSetStatement.Option.LOCAL; 444 lexer.nextToken(); 445 } 446 string parameter = lexer.stringVal(); 447 SQLExpr paramExpr; 448 List!(SQLExpr) values = new ArrayList!(SQLExpr)(); 449 if (equalsIgnoreCase(TIME, parameter)) { 450 lexer.nextToken(); 451 acceptIdentifier("ZONE"); 452 paramExpr = new SQLIdentifierExpr("TIME ZONE"); 453 string value = lexer.stringVal(); 454 if (lexer.token() == Token.IDENTIFIER) { 455 values.add(new SQLIdentifierExpr(toUpper(value))); 456 } else { 457 values.add(new SQLCharExpr(value)); 458 } 459 lexer.nextToken(); 460 // return new PGSetStatement(range, TIME_ZONE, exprs); 461 } else { 462 paramExpr = new SQLIdentifierExpr(parameter); 463 lexer.nextToken(); 464 465 while (!lexer.isEOF()) { 466 lexer.nextToken(); 467 if (lexer.token() == Token.LITERAL_CHARS) { 468 values.add(new SQLCharExpr(lexer.stringVal())); 469 } else if (lexer.token() == Token.LITERAL_INT) { 470 values.add(new SQLIdentifierExpr(lexer.numberString())); 471 } else { 472 values.add(new SQLIdentifierExpr(lexer.stringVal())); 473 } 474 // skip comma 475 lexer.nextToken(); 476 } 477 } 478 479 // value | 'value' | DEFAULT 480 481 482 483 SQLExpr valueExpr; 484 if (values.size() == 1) { 485 valueExpr = values.get(0); 486 } else { 487 SQLListExpr listExpr = new SQLListExpr(); 488 foreach(SQLExpr value ; values) { 489 listExpr.addItem(value); 490 } 491 valueExpr = listExpr; 492 } 493 SQLSetStatement stmt = new SQLSetStatement(paramExpr, valueExpr, dbType); 494 stmt.setOption(option); 495 return stmt; 496 } 497 498 override public SQLCreateSequenceStatement parseCreateSequence(bool acceptCreate) { 499 if (acceptCreate) { 500 accept(Token.CREATE); 501 } 502 503 accept(Token.SEQUENCE); 504 505 SQLCreateSequenceStatement stmt = new SQLCreateSequenceStatement(); 506 stmt.setDbType(dbType); 507 stmt.setName(this.exprParser.name()); 508 509 for (;;) { 510 if (lexer.token() == Token.START) { 511 lexer.nextToken(); 512 accept(Token.WITH); 513 stmt.setStartWith(this.exprParser.expr()); 514 continue; 515 } else if (lexer.identifierEquals("INCREMENT")) { 516 lexer.nextToken(); 517 accept(Token.BY); 518 stmt.setIncrementBy(this.exprParser.expr()); 519 continue; 520 } else if (lexer.token() == Token.CACHE || lexer.identifierEquals(FnvHash.Constants.CACHE)) { 521 lexer.nextToken(); 522 stmt.setCache(Boolean.TRUE); 523 524 if (lexer.token() == Token.LITERAL_INT) { 525 stmt.setCacheValue(this.exprParser.primary()); 526 } 527 continue; 528 } else if (lexer.token() == Token.NOCACHE) { 529 lexer.nextToken(); 530 stmt.setCache(Boolean.FALSE); 531 continue; 532 } else if (lexer.token() == Token.ORDER) { 533 lexer.nextToken(); 534 stmt.setOrder(Boolean.TRUE); 535 continue; 536 } else if (lexer.identifierEquals("NOORDER")) { 537 lexer.nextToken(); 538 stmt.setOrder(Boolean.FALSE); 539 continue; 540 } else if (lexer.identifierEquals("CYCLE")) { 541 lexer.nextToken(); 542 stmt.setCycle(Boolean.TRUE); 543 continue; 544 } else if (lexer.identifierEquals("NOCYCLE")) { 545 lexer.nextToken(); 546 stmt.setCycle(Boolean.FALSE); 547 continue; 548 } else if (lexer.identifierEquals("MINVALUE")) { 549 lexer.nextToken(); 550 stmt.setMinValue(this.exprParser.expr()); 551 continue; 552 } else if (lexer.identifierEquals("MAXVALUE")) { 553 lexer.nextToken(); 554 stmt.setMaxValue(this.exprParser.expr()); 555 continue; 556 } else if (lexer.identifierEquals("NOMAXVALUE")) { 557 lexer.nextToken(); 558 stmt.setNoMaxValue(true); 559 continue; 560 } else if (lexer.identifierEquals("NOMINVALUE")) { 561 lexer.nextToken(); 562 stmt.setNoMinValue(true); 563 continue; 564 } 565 break; 566 } 567 568 return stmt; 569 } 570 571 override public SQLStatement parseCreateIndex(bool acceptCreate) { 572 if (acceptCreate) { 573 accept(Token.CREATE); 574 } 575 576 SQLCreateIndexStatement stmt = new SQLCreateIndexStatement(getDbType()); 577 if (lexer.token() == Token.UNIQUE) { 578 lexer.nextToken(); 579 if (lexer.identifierEquals("CLUSTERED")) { 580 lexer.nextToken(); 581 stmt.setType("UNIQUE CLUSTERED"); 582 } else { 583 stmt.setType("UNIQUE"); 584 } 585 } else if (lexer.identifierEquals("FULLTEXT")) { 586 stmt.setType("FULLTEXT"); 587 lexer.nextToken(); 588 } else if (lexer.identifierEquals("NONCLUSTERED")) { 589 stmt.setType("NONCLUSTERED"); 590 lexer.nextToken(); 591 } 592 593 accept(Token.INDEX); 594 595 stmt.setName(this.exprParser.name()); 596 597 accept(Token.ON); 598 599 stmt.setTable(this.exprParser.name()); 600 601 if (lexer.token() == Token.USING) { 602 lexer.nextToken(); 603 string using = lexer.stringVal(); 604 accept(Token.IDENTIFIER); 605 stmt.setUsing(using); 606 } 607 608 accept(Token.LPAREN); 609 610 for (;;) { 611 SQLSelectOrderByItem item = this.exprParser.parseSelectOrderByItem(); 612 item.setParent(stmt); 613 stmt.addItem(item); 614 if (lexer.token() == Token.COMMA) { 615 lexer.nextToken(); 616 continue; 617 } 618 break; 619 } 620 accept(Token.RPAREN); 621 622 return stmt; 623 } 624 }