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.PagerUtils; 17 18 import hunt.collection; 19 20 import std.exception; 21 import hunt.sql.ast; 22 import hunt.sql.ast.expr; 23 import hunt.sql.ast.statement; 24 // import hunt.sql.dialect.db2.ast.stmt.DB2SelectQueryBlock; 25 import hunt.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock; 26 import hunt.sql.dialect.mysql.visitor.MySqlASTVisitorAdapter; 27 // import hunt.sql.dialect.odps.ast.OdpsSelectQueryBlock; 28 // import hunt.sql.dialect.oracle.ast.stmt.OracleSelectQueryBlock; 29 // import hunt.sql.dialect.oracle.visitor.OracleASTVisitorAdapter; 30 import hunt.sql.dialect.postgresql.ast.stmt.PGSelectQueryBlock; 31 // import hunt.sql.dialect.sqlserver.ast.SQLServerSelectQueryBlock; 32 // import hunt.sql.dialect.sqlserver.ast.SQLServerTop; 33 import hunt.sql.visitor.SQLASTVisitor; 34 import hunt.sql.util.DBType; 35 import hunt.sql.util.DBType; 36 import hunt.sql.SQLUtils; 37 import hunt.Integer; 38 import hunt.sql.visitor.SQLASTVisitorAdapter; 39 40 public class PagerUtils { 41 42 public static string count(string sql, string dbType) { 43 List!(SQLStatement) stmtList = SQLUtils.parseStatements(sql, dbType); 44 45 if (stmtList.size() != 1) { 46 throw new Exception("sql not support count : " ~ sql); 47 } 48 49 SQLStatement stmt = stmtList.get(0); 50 51 if (!(cast(SQLSelectStatement)(stmt) !is null)) { 52 throw new Exception("sql not support count : " ~ sql); 53 } 54 55 SQLSelectStatement selectStmt = cast(SQLSelectStatement) stmt; 56 return count(selectStmt.getSelect(), dbType); 57 } 58 59 public static string limit(string sql, string dbType, int offset, int count) { 60 List!(SQLStatement) stmtList = SQLUtils.parseStatements(sql, dbType); 61 62 if (stmtList.size() != 1) { 63 throw new Exception("sql not support count : " ~ sql); 64 } 65 66 SQLStatement stmt = stmtList.get(0); 67 68 if (!(cast(SQLSelectStatement)(stmt) !is null)) { 69 throw new Exception("sql not support count : " ~ sql); 70 } 71 72 SQLSelectStatement selectStmt = cast(SQLSelectStatement) stmt; 73 74 return limit(selectStmt.getSelect(), dbType, offset, count); 75 } 76 77 public static string limit(SQLSelect select, string dbType, int offset, int count) { 78 limit(select, dbType, offset, count, false); 79 80 return SQLUtils.toSQLString(select, dbType); 81 } 82 83 public static bool limit(SQLSelect select, string dbType, int offset, int count, bool check) { 84 SQLSelectQuery query = select.getQuery(); 85 86 // if (DBType.ORACLE.opEquals(dbType)) { 87 // return limitOracle(select, dbType, offset, count, check); 88 // } 89 90 // if (DBType.DB2.opEquals(dbType)) { 91 // return limitDB2(select, dbType, offset, count, check); 92 // } 93 94 // if (DBType.SQL_SERVER.opEquals(dbType) || DBType.JTDS.opEquals(dbType)) { 95 // return limitSQLServer(select, dbType, offset, count, check); 96 // } 97 98 return limitQueryBlock(select, dbType, offset, count, check); 99 } 100 101 private static bool limitQueryBlock(SQLSelect select, string dbType, int offset, int count, bool check) { 102 SQLSelectQuery query = select.getQuery(); 103 if (cast(SQLUnionQuery)(query) !is null) { 104 SQLUnionQuery union_p = cast(SQLUnionQuery) query; 105 return limitUnion(union_p, dbType, offset, count, check); 106 } 107 108 SQLSelectQueryBlock queryBlock = cast(SQLSelectQueryBlock) query; 109 if (DBType.MYSQL.opEquals(dbType) || // 110 DBType.MARIADB.opEquals(dbType) /*|| // 111 DBType.H2.opEquals(dbType) */) { 112 return limitMySqlQueryBlock(queryBlock, dbType, offset, count, check); 113 } 114 115 if (DBType.POSTGRESQL.opEquals(dbType)) { 116 return limitPostgreSQLQueryBlock(cast(PGSelectQueryBlock) queryBlock, dbType, offset, count, check); 117 } 118 throw new Exception("limitQueryBlock"); 119 } 120 121 private static bool limitPostgreSQLQueryBlock(PGSelectQueryBlock queryBlock, string dbType, int offset, int count, bool check) { 122 SQLLimit limit = queryBlock.getLimit(); 123 if (limit !is null) { 124 if (offset > 0) { 125 limit.setOffset(new SQLIntegerExpr(offset)); 126 } 127 128 if (check && cast(SQLNumericLiteralExpr)limit.getRowCount() !is null) { 129 int rowCount = (cast(SQLNumericLiteralExpr) limit.getRowCount()).getNumber().intValue(); 130 if (rowCount <= count && offset <= 0) { 131 return false; 132 } 133 } 134 135 limit.setRowCount(new SQLIntegerExpr(count)); 136 } 137 138 limit = new SQLLimit(); 139 if (offset > 0) { 140 limit.setOffset(new SQLIntegerExpr(offset)); 141 } 142 limit.setRowCount(new SQLIntegerExpr(count)); 143 queryBlock.setLimit(limit); 144 return true; 145 } 146 147 // private static bool limitDB2(SQLSelect select, string dbType, int offset, int count, bool check) { 148 // SQLSelectQuery query = select.getQuery(); 149 150 // SQLBinaryOpExpr gt = new SQLBinaryOpExpr(new SQLIdentifierExpr("ROWNUM"), // 151 // SQLBinaryOperator.GreaterThan, // 152 // new SQLNumberExpr(offset), // 153 // DBType.DB2); 154 // SQLBinaryOpExpr lteq = new SQLBinaryOpExpr(new SQLIdentifierExpr("ROWNUM"), // 155 // SQLBinaryOperator.LessThanOrEqual, // 156 // new SQLNumberExpr(count + offset), // 157 // DBType.DB2); 158 // SQLBinaryOpExpr pageCondition = new SQLBinaryOpExpr(gt, SQLBinaryOperator.BooleanAnd, lteq, DBType.DB2); 159 160 // if (cast(SQLSelectQueryBlock)(query) !is null) { 161 // DB2SelectQueryBlock queryBlock = cast(DB2SelectQueryBlock) query; 162 // if (offset <= 0) { 163 // SQLExpr first = queryBlock.getFirst(); 164 // if (check && first !is null && cast(SQLNumericLiteralExpr)(first) !is null) { 165 // int rowCount = (cast(SQLNumericLiteralExpr) first).getNumber().intValue(); 166 // if (rowCount < count) { 167 // return false; 168 // } 169 // } 170 // queryBlock.setFirst(new SQLIntegerExpr(count)); 171 // return true; 172 // } 173 174 // SQLAggregateExpr aggregateExpr = new SQLAggregateExpr("ROW_NUMBER"); 175 // SQLOrderBy orderBy = select.getOrderBy(); 176 177 // if (orderBy is null && cast(SQLSelectQueryBlock)select.getQuery() !is null) { 178 // SQLSelectQueryBlock selectQueryBlcok = cast(SQLSelectQueryBlock) select.getQuery(); 179 // orderBy = selectQueryBlcok.getOrderBy(); 180 // selectQueryBlcok.setOrderBy(null); 181 // } else { 182 // select.setOrderBy(null); 183 // } 184 185 // aggregateExpr.setOver(new SQLOver(orderBy)); 186 187 // queryBlock.getSelectList().add(new SQLSelectItem(aggregateExpr, "ROWNUM")); 188 189 // DB2SelectQueryBlock countQueryBlock = new DB2SelectQueryBlock(); 190 // countQueryBlock.getSelectList().add(new SQLSelectItem(new SQLAllColumnExpr())); 191 192 // countQueryBlock.setFrom(new SQLSubqueryTableSource(select.clone(), "XX")); 193 194 // countQueryBlock.setWhere(pageCondition); 195 196 // select.setQuery(countQueryBlock); 197 198 // return true; 199 // } 200 201 // DB2SelectQueryBlock countQueryBlock = new DB2SelectQueryBlock(); 202 // countQueryBlock.getSelectList().add(new SQLSelectItem(new SQLPropertyExpr(new SQLIdentifierExpr("XX"), "*"))); 203 // SQLAggregateExpr aggregateExpr = new SQLAggregateExpr("ROW_NUMBER"); 204 // SQLOrderBy orderBy = select.getOrderBy(); 205 // aggregateExpr.setOver(new SQLOver(orderBy)); 206 // select.setOrderBy(null); 207 // countQueryBlock.getSelectList().add(new SQLSelectItem(aggregateExpr, "ROWNUM")); 208 209 // countQueryBlock.setFrom(new SQLSubqueryTableSource(select.clone(), "XX")); 210 211 // if (offset <= 0) { 212 // select.setQuery(countQueryBlock); 213 // return true; 214 // } 215 216 // DB2SelectQueryBlock offsetQueryBlock = new DB2SelectQueryBlock(); 217 // offsetQueryBlock.getSelectList().add(new SQLSelectItem(new SQLAllColumnExpr())); 218 // offsetQueryBlock.setFrom(new SQLSubqueryTableSource(new SQLSelect(countQueryBlock), "XXX")); 219 // offsetQueryBlock.setWhere(pageCondition); 220 221 // select.setQuery(offsetQueryBlock); 222 223 // return true; 224 // } 225 226 // private static bool limitSQLServer(SQLSelect select, string dbType, int offset, int count, bool check) { 227 // SQLSelectQuery query = select.getQuery(); 228 229 // SQLBinaryOpExpr gt = new SQLBinaryOpExpr(new SQLIdentifierExpr("ROWNUM"), // 230 // SQLBinaryOperator.GreaterThan, // 231 // new SQLNumberExpr(offset), // 232 // DBType.SQL_SERVER); 233 // SQLBinaryOpExpr lteq = new SQLBinaryOpExpr(new SQLIdentifierExpr("ROWNUM"), // 234 // SQLBinaryOperator.LessThanOrEqual, // 235 // new SQLNumberExpr(count + offset), // 236 // DBType.SQL_SERVER); 237 // SQLBinaryOpExpr pageCondition = new SQLBinaryOpExpr(gt, SQLBinaryOperator.BooleanAnd, lteq, 238 // DBType.SQL_SERVER); 239 240 // if (cast(SQLSelectQueryBlock)(query) !is null) { 241 // SQLServerSelectQueryBlock queryBlock = cast(SQLServerSelectQueryBlock) query; 242 // if (offset <= 0) { 243 // SQLServerTop top = queryBlock.getTop(); 244 // if (check && top !is null && !top.isPercent() && cast(SQLNumericLiteralExpr)top.getExpr() !is null) { 245 // int rowCount = (cast(SQLNumericLiteralExpr) top.getExpr()).getNumber().intValue(); 246 // if (rowCount <= count) { 247 // return false; 248 // } 249 // } 250 // queryBlock.setTop(new SQLServerTop(new SQLNumberExpr(count))); 251 // return true; 252 // } 253 254 // SQLAggregateExpr aggregateExpr = new SQLAggregateExpr("ROW_NUMBER"); 255 // SQLOrderBy orderBy = select.getOrderBy(); 256 // aggregateExpr.setOver(new SQLOver(orderBy)); 257 // select.setOrderBy(null); 258 259 // queryBlock.getSelectList().add(new SQLSelectItem(aggregateExpr, "ROWNUM")); 260 261 // SQLServerSelectQueryBlock countQueryBlock = new SQLServerSelectQueryBlock(); 262 // countQueryBlock.getSelectList().add(new SQLSelectItem(new SQLAllColumnExpr())); 263 264 // countQueryBlock.setFrom(new SQLSubqueryTableSource(select.clone(), "XX")); 265 266 // countQueryBlock.setWhere(pageCondition); 267 268 // select.setQuery(countQueryBlock); 269 270 // return true; 271 // } 272 273 // SQLServerSelectQueryBlock countQueryBlock = new SQLServerSelectQueryBlock(); 274 // countQueryBlock.getSelectList().add(new SQLSelectItem(new SQLPropertyExpr(new SQLIdentifierExpr("XX"), "*"))); 275 276 // countQueryBlock.setFrom(new SQLSubqueryTableSource(select.clone(), "XX")); 277 278 // if (offset <= 0) { 279 // countQueryBlock.setTop(new SQLServerTop(new SQLNumberExpr(count))); 280 281 // select.setQuery(countQueryBlock); 282 // return true; 283 // } 284 285 // SQLAggregateExpr aggregateExpr = new SQLAggregateExpr("ROW_NUMBER"); 286 // SQLOrderBy orderBy = select.getOrderBy(); 287 // aggregateExpr.setOver(new SQLOver(orderBy)); 288 // select.setOrderBy(null); 289 // countQueryBlock.getSelectList().add(new SQLSelectItem(aggregateExpr, "ROWNUM")); 290 291 // SQLServerSelectQueryBlock offsetQueryBlock = new SQLServerSelectQueryBlock(); 292 // offsetQueryBlock.getSelectList().add(new SQLSelectItem(new SQLAllColumnExpr())); 293 // offsetQueryBlock.setFrom(new SQLSubqueryTableSource(new SQLSelect(countQueryBlock), "XXX")); 294 // offsetQueryBlock.setWhere(pageCondition); 295 296 // select.setQuery(offsetQueryBlock); 297 298 // return true; 299 // } 300 301 // private static bool limitOracle(SQLSelect select, string dbType, int offset, int count, bool check) { 302 // SQLSelectQuery query = select.getQuery(); 303 304 // if (cast(SQLSelectQueryBlock)(query) !is null) { 305 // OracleSelectQueryBlock queryBlock = cast(OracleSelectQueryBlock) query; 306 // SQLOrderBy orderBy = select.getOrderBy(); 307 // if (orderBy is null && queryBlock.getOrderBy() !is null) { 308 // orderBy = queryBlock.getOrderBy(); 309 // } 310 311 // if (queryBlock.getGroupBy() is null 312 // && orderBy is null && offset <= 0) { 313 314 // SQLExpr where = queryBlock.getWhere(); 315 // if (check && cast(SQLBinaryOpExpr)(where) !is null) { 316 // SQLBinaryOpExpr binaryOpWhere = cast(SQLBinaryOpExpr) where; 317 // if (binaryOpWhere.getOperator() == SQLBinaryOperator.LessThanOrEqual) { 318 // SQLExpr left = binaryOpWhere.getLeft(); 319 // SQLExpr right = binaryOpWhere.getRight(); 320 // if (cast(SQLIdentifierExpr)(left) !is null 321 // && (cast(SQLIdentifierExpr) left).getName().equalsIgnoreCase("ROWNUM") 322 // && cast(SQLNumericLiteralExpr)(right) !is null) { 323 // int rowCount = (cast(SQLNumericLiteralExpr) right).getNumber().intValue(); 324 // if (rowCount <= count) { 325 // return false; 326 // } 327 // } 328 // } 329 // } 330 331 // SQLExpr condition = new SQLBinaryOpExpr(new SQLIdentifierExpr("ROWNUM"), // 332 // SQLBinaryOperator.LessThanOrEqual, // 333 // new SQLNumberExpr(count), // 334 // DBType.ORACLE); 335 // if (queryBlock.getWhere() is null) { 336 // queryBlock.setWhere(condition); 337 // } else { 338 // queryBlock.setWhere(new SQLBinaryOpExpr(queryBlock.getWhere(), // 339 // SQLBinaryOperator.BooleanAnd, // 340 // condition, // 341 // DBType.ORACLE)); 342 // } 343 344 // return true; 345 // } 346 // } 347 348 // OracleSelectQueryBlock countQueryBlock = new OracleSelectQueryBlock(); 349 // countQueryBlock.getSelectList().add(new SQLSelectItem(new SQLPropertyExpr(new SQLIdentifierExpr("XX"), "*"))); 350 // countQueryBlock.getSelectList().add(new SQLSelectItem(new SQLIdentifierExpr("ROWNUM"), "RN")); 351 352 // countQueryBlock.setFrom(new SQLSubqueryTableSource(select.clone(), "XX")); 353 // countQueryBlock.setWhere(new SQLBinaryOpExpr(new SQLIdentifierExpr("ROWNUM"), // 354 // SQLBinaryOperator.LessThanOrEqual, // 355 // new SQLNumberExpr(count + offset), // 356 // DBType.ORACLE)); 357 358 // select.setOrderBy(null); 359 // if (offset <= 0) { 360 // select.setQuery(countQueryBlock); 361 // return true; 362 // } 363 364 // OracleSelectQueryBlock offsetQueryBlock = new OracleSelectQueryBlock(); 365 // offsetQueryBlock.getSelectList().add(new SQLSelectItem(new SQLAllColumnExpr())); 366 // offsetQueryBlock.setFrom(new SQLSubqueryTableSource(new SQLSelect(countQueryBlock), "XXX")); 367 // offsetQueryBlock.setWhere(new SQLBinaryOpExpr(new SQLIdentifierExpr("RN"), // 368 // SQLBinaryOperator.GreaterThan, // 369 // new SQLNumberExpr(offset), // 370 // DBType.ORACLE)); 371 372 // select.setQuery(offsetQueryBlock); 373 // return true; 374 // } 375 376 private static bool limitMySqlQueryBlock(SQLSelectQueryBlock queryBlock, string dbType, int offset, int count, bool check) { 377 SQLLimit limit = queryBlock.getLimit(); 378 if (limit !is null) { 379 if (offset > 0) { 380 limit.setOffset(new SQLIntegerExpr(offset)); 381 } 382 383 if (check && cast(SQLNumericLiteralExpr)limit.getRowCount() !is null) { 384 int rowCount = (cast(SQLNumericLiteralExpr) limit.getRowCount()).getNumber().intValue(); 385 if (rowCount <= count && offset <= 0) { 386 return false; 387 } 388 } else if (check && cast(SQLVariantRefExpr)limit.getRowCount() !is null) { 389 return false; 390 } 391 392 limit.setRowCount(new SQLIntegerExpr(count)); 393 } 394 395 if (limit is null) { 396 limit = new SQLLimit(); 397 if (offset > 0) { 398 limit.setOffset(new SQLIntegerExpr(offset)); 399 } 400 limit.setRowCount(new SQLIntegerExpr(count)); 401 queryBlock.setLimit(limit); 402 } 403 404 return true; 405 } 406 407 private static bool limitUnion(SQLUnionQuery queryBlock, string dbType, int offset, int count, bool check) { 408 SQLLimit limit = queryBlock.getLimit(); 409 if (limit !is null) { 410 if (offset > 0) { 411 limit.setOffset(new SQLIntegerExpr(offset)); 412 } 413 414 if (check && cast(SQLNumericLiteralExpr)limit.getRowCount() !is null) { 415 int rowCount = (cast(SQLNumericLiteralExpr) limit.getRowCount()).getNumber().intValue(); 416 if (rowCount <= count && offset <= 0) { 417 return false; 418 } 419 } else if (check && cast(SQLVariantRefExpr)limit.getRowCount() !is null) { 420 return false; 421 } 422 423 limit.setRowCount(new SQLIntegerExpr(count)); 424 } 425 426 if (limit is null) { 427 limit = new SQLLimit(); 428 if (offset > 0) { 429 limit.setOffset(new SQLIntegerExpr(offset)); 430 } 431 limit.setRowCount(new SQLIntegerExpr(count)); 432 queryBlock.setLimit(limit); 433 } 434 435 return true; 436 } 437 438 private static string count(SQLSelect select, string dbType) { 439 if (select.getOrderBy() !is null) { 440 select.setOrderBy(null); 441 } 442 443 SQLSelectQuery query = select.getQuery(); 444 clearOrderBy(query); 445 446 if (cast(SQLSelectQueryBlock)(query) !is null) { 447 SQLSelectItem countItem = createCountItem(dbType); 448 449 SQLSelectQueryBlock queryBlock = cast(SQLSelectQueryBlock) query; 450 List!(SQLSelectItem) selectList = queryBlock.getSelectList(); 451 452 if (queryBlock.getGroupBy() !is null 453 && queryBlock.getGroupBy().getItems().size() > 0) { 454 return createCountUseSubQuery(select, dbType); 455 } 456 457 int option = queryBlock.getDistionOption(); 458 if (option == SQLSetQuantifier.DISTINCT 459 && selectList.size() >= 1) { 460 SQLAggregateExpr countExpr = new SQLAggregateExpr("COUNT", SQLAggregateOption.DISTINCT); 461 for (int i = 0; i < selectList.size(); ++i) { 462 countExpr.addArgument(selectList.get(i).getExpr()); 463 } 464 selectList.clear(); 465 queryBlock.setDistionOption(0); 466 queryBlock.addSelectItem(countExpr); 467 } else { 468 selectList.clear(); 469 selectList.add(countItem); 470 } 471 return SQLUtils.toSQLString(select, dbType); 472 } else if (cast(SQLUnionQuery)(query) !is null) { 473 return createCountUseSubQuery(select, dbType); 474 } 475 476 throw new Exception("IllegalState"); 477 } 478 479 private static string createCountUseSubQuery(SQLSelect select, string dbType) { 480 SQLSelectQueryBlock countSelectQuery = createQueryBlock(dbType); 481 482 SQLSelectItem countItem = createCountItem(dbType); 483 countSelectQuery.getSelectList().add(countItem); 484 485 SQLSubqueryTableSource fromSubquery = new SQLSubqueryTableSource(select); 486 fromSubquery.setAlias("ALIAS_COUNT"); 487 countSelectQuery.setFrom(fromSubquery); 488 489 SQLSelect countSelect = new SQLSelect(countSelectQuery); 490 SQLSelectStatement countStmt = new SQLSelectStatement(countSelect, dbType); 491 492 return SQLUtils.toSQLString(countStmt, dbType); 493 } 494 495 private static SQLSelectQueryBlock createQueryBlock(string dbType) { 496 if (DBType.MYSQL.opEquals(dbType) 497 || DBType.MARIADB.opEquals(dbType) 498 /* || DBType.ALIYUN_ADS.opEquals(dbType) */) { 499 return new MySqlSelectQueryBlock(); 500 } 501 502 if (DBType.MARIADB.opEquals(dbType)) { 503 return new MySqlSelectQueryBlock(); 504 } 505 506 // if (DBType.H2.opEquals(dbType)) { 507 // return new MySqlSelectQueryBlock(); 508 // } 509 510 // if (DBType.ORACLE.opEquals(dbType)) { 511 // return new OracleSelectQueryBlock(); 512 // } 513 514 if (DBType.POSTGRESQL.opEquals(dbType)) { 515 return new PGSelectQueryBlock(); 516 } 517 518 // if (DBType.SQL_SERVER.opEquals(dbType) || DBType.JTDS.opEquals(dbType)) { 519 // return new SQLServerSelectQueryBlock(); 520 // } 521 522 // if (DBType.DB2.opEquals(dbType)) { 523 // return new DB2SelectQueryBlock(); 524 // } 525 526 return new SQLSelectQueryBlock(); 527 } 528 529 private static SQLSelectItem createCountItem(string dbType) { 530 SQLAggregateExpr countExpr = new SQLAggregateExpr("COUNT"); 531 532 countExpr.addArgument(new SQLAllColumnExpr()); 533 534 SQLSelectItem countItem = new SQLSelectItem(countExpr); 535 return countItem; 536 } 537 538 private static void clearOrderBy(SQLSelectQuery query) { 539 if (cast(SQLSelectQueryBlock)(query) !is null) { 540 SQLSelectQueryBlock queryBlock = cast(SQLSelectQueryBlock) query; 541 if (queryBlock.getOrderBy() !is null) { 542 queryBlock.setOrderBy(null); 543 } 544 return; 545 } 546 547 if (cast(SQLUnionQuery)(query) !is null) { 548 SQLUnionQuery union_p = cast(SQLUnionQuery) query; 549 if (union_p.getOrderBy() !is null) { 550 union_p.setOrderBy(null); 551 } 552 clearOrderBy(union_p.getLeft()); 553 clearOrderBy(union_p.getRight()); 554 } 555 } 556 557 /** 558 * 559 * @param sql 560 * @param dbType 561 * @return if not exists limit, return -1; 562 */ 563 public static int getLimit(string sql, string dbType) { 564 List!(SQLStatement) stmtList = SQLUtils.parseStatements(sql, dbType); 565 566 if (stmtList.size() != 1) { 567 return -1; 568 } 569 570 SQLStatement stmt = stmtList.get(0); 571 572 if (cast(SQLSelectStatement)(stmt) !is null) { 573 SQLSelectStatement selectStmt = cast(SQLSelectStatement) stmt; 574 SQLSelectQuery query = selectStmt.getSelect().getQuery(); 575 if (cast(SQLSelectQueryBlock)(query) !is null) { 576 if (cast(MySqlSelectQueryBlock)(query) !is null) { 577 SQLLimit limit = (cast(MySqlSelectQueryBlock) query).getLimit(); 578 579 if (limit is null) { 580 return -1; 581 } 582 583 SQLExpr rowCountExpr = limit.getRowCount(); 584 585 if (cast(SQLNumericLiteralExpr)(rowCountExpr) !is null) { 586 int rowCount = (cast(SQLNumericLiteralExpr) rowCountExpr).getNumber().intValue(); 587 return rowCount; 588 } 589 590 return Integer.MAX_VALUE; 591 } 592 593 // if (cast(OdpsSelectQueryBlock)(query) !is null) { 594 // SQLLimit limit = (cast(OdpsSelectQueryBlock) query).getLimit(); 595 // SQLExpr rowCountExpr = limit !is null ? limit.getRowCount() : null; 596 597 // if (cast(SQLNumericLiteralExpr)(rowCountExpr) !is null) { 598 // int rowCount = (cast(SQLNumericLiteralExpr) rowCountExpr).getNumber().intValue(); 599 // return rowCount; 600 // } 601 602 // return Integer.MAX_VALUE; 603 // } 604 605 return -1; 606 } 607 } 608 609 return -1; 610 } 611 612 public static bool hasUnorderedLimit(string sql, string dbType) { 613 List!(SQLStatement) stmtList = SQLUtils.parseStatements(sql, dbType); 614 615 if (DBType.MYSQL.opEquals(dbType)) { 616 617 MySqlUnorderedLimitDetectVisitor visitor = new MySqlUnorderedLimitDetectVisitor(); 618 619 foreach(SQLStatement stmt ; stmtList) { 620 stmt.accept(visitor); 621 } 622 623 return visitor.unorderedLimitCount > 0; 624 } 625 626 // if (DBType.ORACLE.opEquals(dbType)) { 627 628 // OracleUnorderedLimitDetectVisitor visitor = new OracleUnorderedLimitDetectVisitor(); 629 630 // foreach(SQLStatement stmt ; stmtList) { 631 // stmt.accept(visitor); 632 // } 633 634 // return visitor.unorderedLimitCount > 0; 635 // } 636 637 throw new Exception("not supported. dbType : " ~ dbType); 638 } 639 640 private static class MySqlUnorderedLimitDetectVisitor : MySqlASTVisitorAdapter { 641 public int unorderedLimitCount; 642 // alias endVisit = SQLASTVisitorAdapter.endVisit; 643 // alias visit = SQLASTVisitorAdapter.visit; 644 645 alias endVisit = MySqlASTVisitorAdapter.endVisit; 646 alias visit = MySqlASTVisitorAdapter.visit; 647 648 override 649 public bool visit(MySqlSelectQueryBlock x) { 650 SQLOrderBy orderBy = x.getOrderBy(); 651 SQLLimit limit = x.getLimit(); 652 653 if (limit !is null && (orderBy is null || orderBy.getItems().size() == 0)) { 654 bool subQueryHasOrderBy = false; 655 SQLTableSource from = x.getFrom(); 656 if (cast(SQLSubqueryTableSource)(from) !is null) { 657 SQLSubqueryTableSource subqueryTabSrc = cast(SQLSubqueryTableSource) from; 658 SQLSelect select = subqueryTabSrc.getSelect(); 659 if (cast(SQLSelectQueryBlock)select.getQuery() !is null) { 660 SQLSelectQueryBlock subquery = cast(SQLSelectQueryBlock) select.getQuery(); 661 if (subquery.getOrderBy() !is null && subquery.getOrderBy().getItems().size() > 0) { 662 subQueryHasOrderBy = true; 663 } 664 } 665 } 666 667 if (!subQueryHasOrderBy) { 668 unorderedLimitCount++; 669 } 670 } 671 return true; 672 } 673 } 674 675 // private static class OracleUnorderedLimitDetectVisitor : OracleASTVisitorAdapter { 676 // public int unorderedLimitCount; 677 678 // public bool visit(SQLBinaryOpExpr x) { 679 // SQLExpr left = x.getLeft(); 680 // SQLExpr right = x.getRight(); 681 682 // bool rownum = false; 683 // if (cast(SQLIdentifierExpr)(left) !is null 684 // && (cast(SQLIdentifierExpr) left).getName().equalsIgnoreCase("ROWNUM") 685 // && cast(SQLLiteralExpr)(right) !is null) { 686 // rownum = true; 687 // } else if (cast(SQLIdentifierExpr)(right) !is null 688 // && (cast(SQLIdentifierExpr) right).getName().equalsIgnoreCase("ROWNUM") 689 // && cast(SQLLiteralExpr)(left) !is null) { 690 // rownum = true; 691 // } 692 693 // OracleSelectQueryBlock selectQuery = null; 694 // if (rownum) { 695 // for (SQLObject parent = x.getParent(); parent !is null; parent = parent.getParent()) { 696 // if (cast(SQLSelectQuery)(parent) !is null) { 697 // if (cast(OracleSelectQueryBlock)(parent) !is null) { 698 // OracleSelectQueryBlock queryBlock = cast(OracleSelectQueryBlock) parent; 699 // SQLTableSource from = queryBlock.getFrom(); 700 // if (cast(SQLExprTableSource)(from) !is null) { 701 // selectQuery = queryBlock; 702 // } else if (cast(SQLSubqueryTableSource)(from) !is null) { 703 // SQLSelect subSelect = (cast(SQLSubqueryTableSource) from).getSelect(); 704 // if (cast(OracleSelectQueryBlock)subSelect.getQuery() !is null) { 705 // selectQuery = cast(OracleSelectQueryBlock) subSelect.getQuery(); 706 // } 707 // } 708 // } 709 // break; 710 // } 711 // } 712 // } 713 714 715 // if (selectQuery !is null) { 716 // SQLOrderBy orderBy = selectQuery.getOrderBy(); 717 718 // SQLObject parent = selectQuery.getParent(); 719 // if (orderBy is null && cast(SQLSelect)(parent) !is null) { 720 // SQLSelect select = cast(SQLSelect) parent; 721 // orderBy = select.getOrderBy(); 722 // } 723 724 // if (orderBy is null || orderBy.getItems().size() == 0) { 725 // unorderedLimitCount++; 726 // } 727 // } 728 729 // return true; 730 // } 731 732 // override 733 // public bool visit(OracleSelectQueryBlock queryBlock) { 734 // bool isExprTableSrc = cast(SQLExprTableSource)queryBlock.getFrom() !is null; 735 736 // if (!isExprTableSrc) { 737 // return true; 738 // } 739 740 // bool rownum = false; 741 // foreach(SQLSelectItem item ; queryBlock.getSelectList()) { 742 // SQLExpr itemExpr = item.getExpr(); 743 // if (cast(SQLIdentifierExpr)(itemExpr) !is null) { 744 // if ((cast(SQLIdentifierExpr) itemExpr).getName().equalsIgnoreCase("ROWNUM")) { 745 // rownum = true; 746 // break; 747 // } 748 // } 749 // } 750 751 // if (!rownum) { 752 // return true; 753 // } 754 755 // SQLObject parent = queryBlock.getParent(); 756 // if (!(cast(SQLSelect)(parent) !is null)) { 757 // return true; 758 // } 759 760 // SQLSelect select = cast(SQLSelect) parent; 761 762 // if (select.getOrderBy() is null || select.getOrderBy().getItems().size() == 0) { 763 // unorderedLimitCount++; 764 // } 765 766 // return false; 767 // } 768 // } 769 }