From cd6140c5bf7f44e706745a8dfb0a57a6bfcbbb4f Mon Sep 17 00:00:00 2001 From: wenshao Date: Sat, 2 Feb 2013 15:53:23 +0800 Subject: [PATCH] add PagerUtils oracle support --- .../com/alibaba/druid/sql/PagerUtils.java | 107 +++++++++++++----- .../postgresql/visitor/PGOutputVisitor.java | 2 +- ...java => PagerUtilsTest_Count_MySql_0.java} | 2 +- ...java => PagerUtilsTest_Limit_mysql_0.java} | 2 +- 4 files changed, 84 insertions(+), 29 deletions(-) rename src/test/java/com/alibaba/druid/bvt/sql/{PagerUtilsTest0.java => PagerUtilsTest_Count_MySql_0.java} (97%) rename src/test/java/com/alibaba/druid/bvt/sql/{PagerUtilsTestLimit_0.java => PagerUtilsTest_Limit_mysql_0.java} (96%) diff --git a/src/main/java/com/alibaba/druid/sql/PagerUtils.java b/src/main/java/com/alibaba/druid/sql/PagerUtils.java index 4f75c76399..764543b3d4 100644 --- a/src/main/java/com/alibaba/druid/sql/PagerUtils.java +++ b/src/main/java/com/alibaba/druid/sql/PagerUtils.java @@ -17,10 +17,15 @@ package com.alibaba.druid.sql; import java.util.List; +import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLStatement; import com.alibaba.druid.sql.ast.expr.SQLAggregateExpr; import com.alibaba.druid.sql.ast.expr.SQLAllColumnExpr; +import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr; +import com.alibaba.druid.sql.ast.expr.SQLBinaryOperator; +import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; import com.alibaba.druid.sql.ast.expr.SQLNumberExpr; +import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr; import com.alibaba.druid.sql.ast.statement.SQLSelect; import com.alibaba.druid.sql.ast.statement.SQLSelectItem; import com.alibaba.druid.sql.ast.statement.SQLSelectQuery; @@ -54,7 +59,7 @@ public class PagerUtils { SQLSelectStatement selectStmt = (SQLSelectStatement) stmt; return count(selectStmt.getSelect(), dbType); } - + public static String limit(String sql, String dbType, int offset, int count) { List stmtList = SQLUtils.parseStatements(sql, dbType); @@ -69,58 +74,108 @@ public class PagerUtils { } SQLSelectStatement selectStmt = (SQLSelectStatement) stmt; - + return limit(selectStmt.getSelect(), dbType, offset, count); } - + public static String limit(SQLSelect select, String dbType, int offset, int count) { SQLSelectQuery query = select.getQuery(); - + + if (JdbcConstants.ORACLE.equals(dbType)) { + return limitOracle(select, dbType, offset, count); + } + if (query instanceof SQLSelectQueryBlock) { - return limit((SQLSelectQueryBlock) query, dbType, offset, count); + return limitQueryBlock(select, dbType, offset, count); } + throw new UnsupportedOperationException(); } - - public static String limit(SQLSelectQueryBlock queryBlock, String dbType, int offset, int count) { + + private static String limitQueryBlock(SQLSelect select, String dbType, int offset, int count) { + SQLSelectQueryBlock queryBlock = (SQLSelectQueryBlock) select.getQuery(); if (JdbcConstants.MYSQL.equals(dbType)) { - return limitMySql((MySqlSelectQueryBlock) queryBlock, dbType, offset, count); + return limitMySqlQueryBlock((MySqlSelectQueryBlock) queryBlock, dbType, offset, count); } + throw new UnsupportedOperationException(); } - - public static String limitMySql(MySqlSelectQueryBlock queryBlock, String dbType, int offset, int count) { + + private static String limitOracle(SQLSelect select, String dbType, int offset, int count) { + SQLSelectQuery query = select.getQuery(); + + if (query instanceof SQLSelectQueryBlock) { + OracleSelectQueryBlock queryBlock = (OracleSelectQueryBlock) query; + if (select.getOrderBy() == null && offset <= 0) { + SQLExpr condition = new SQLBinaryOpExpr(new SQLIdentifierExpr("ROWNUM"), // + SQLBinaryOperator.LessThanOrEqual, // + new SQLNumberExpr(count)); + if (queryBlock.getWhere() == null) { + queryBlock.setWhere(condition); + } else { + queryBlock.setWhere(new SQLBinaryOpExpr(queryBlock.getWhere(), // + SQLBinaryOperator.BooleanAnd, // + condition)); + } + + return SQLUtils.toSQLString(select, dbType); + } + } + + OracleSelectQueryBlock countQueryBlock = new OracleSelectQueryBlock(); + countQueryBlock.getSelectList().add(new SQLSelectItem(new SQLPropertyExpr(new SQLIdentifierExpr("_X"), "*"))); + countQueryBlock.getSelectList().add(new SQLSelectItem(new SQLIdentifierExpr("ROWNUM"), "_RN")); + + countQueryBlock.setFrom(new SQLSubqueryTableSource(select, "_X")); + countQueryBlock.setWhere(new SQLBinaryOpExpr(new SQLIdentifierExpr("ROWNUM"), // + SQLBinaryOperator.LessThanOrEqual, // + new SQLNumberExpr(count + offset))); + if (offset <= 0) { + return SQLUtils.toSQLString(countQueryBlock, dbType); + } + + OracleSelectQueryBlock offsetQueryBlock = new OracleSelectQueryBlock(); + offsetQueryBlock.getSelectList().add(new SQLSelectItem(new SQLAllColumnExpr())); + offsetQueryBlock.setFrom(new SQLSubqueryTableSource(new SQLSelect(countQueryBlock), "_XX")); + offsetQueryBlock.setWhere(new SQLBinaryOpExpr(new SQLIdentifierExpr("_RN"), // + SQLBinaryOperator.GreaterThan, // + new SQLNumberExpr(offset))); + + return SQLUtils.toSQLString(offsetQueryBlock, dbType); + } + + private static String limitMySqlQueryBlock(MySqlSelectQueryBlock queryBlock, String dbType, int offset, int count) { if (queryBlock.getLimit() != null) { throw new IllegalArgumentException("limit already exists."); } - + Limit limit = new Limit(); if (offset > 0) { limit.setOffset(new SQLNumberExpr(offset)); } limit.setRowCount(new SQLNumberExpr(count)); queryBlock.setLimit(limit); - + return SQLUtils.toSQLString(queryBlock, dbType); } - + private static String count(SQLSelect select, String dbType) { if (select.getOrderBy() != null) { select.setOrderBy(null); } - + SQLSelectQuery query = select.getQuery(); clearOrderBy(query); if (query instanceof SQLSelectQueryBlock) { SQLSelectItem countItem = createCountItem(dbType); - + SQLSelectQueryBlock queryBlock = (SQLSelectQueryBlock) query; - + if (queryBlock.getGroupBy() != null && queryBlock.getGroupBy().getItems().size() > 0) { - return createCountUseSubQuery(select, dbType); + return createCountUseSubQuery(select, dbType); } - + queryBlock.getSelectList().clear(); queryBlock.getSelectList().add(countItem); return SQLUtils.toSQLString(select, dbType); @@ -133,15 +188,15 @@ public class PagerUtils { private static String createCountUseSubQuery(SQLSelect select, String dbType) { SQLSelectQueryBlock countSelectQuery = createQueryBlock(dbType); - + SQLSelectItem countItem = createCountItem(dbType); countSelectQuery.getSelectList().add(countItem); - + countSelectQuery.setFrom(new SQLSubqueryTableSource(select)); - + SQLSelect countSelect = new SQLSelect(countSelectQuery); SQLSelectStatement countStmt = new SQLSelectStatement(countSelect); - + return SQLUtils.toSQLString(countStmt, dbType); } @@ -149,19 +204,19 @@ public class PagerUtils { if (JdbcConstants.MYSQL.equals(dbType)) { return new MySqlSelectQueryBlock(); } - + if (JdbcConstants.ORACLE.equals(dbType)) { return new OracleSelectQueryBlock(); } - + if (JdbcConstants.POSTGRESQL.equals(dbType)) { return new PGSelectQueryBlock(); } - + if (JdbcConstants.SQL_SERVER.equals(dbType)) { return new SQLServerSelectQueryBlock(); } - + return new SQLSelectQueryBlock(); } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGOutputVisitor.java index b9bea852e3..254d97833d 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGOutputVisitor.java @@ -197,7 +197,7 @@ public class PGOutputVisitor extends SQLASTOutputVisitor implements PGASTVisitor } if (x.getGroupBy() != null) { - print(" "); + println(); x.getGroupBy().accept(this); } diff --git a/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest0.java b/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest_Count_MySql_0.java similarity index 97% rename from src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest0.java rename to src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest_Count_MySql_0.java index d6271da251..4ca0b17534 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest0.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest_Count_MySql_0.java @@ -7,7 +7,7 @@ import org.junit.Assert; import com.alibaba.druid.sql.PagerUtils; import com.alibaba.druid.util.JdbcConstants; -public class PagerUtilsTest0 extends TestCase { +public class PagerUtilsTest_Count_MySql_0 extends TestCase { public void test_mysql_0() throws Exception { String sql = "select * from t"; diff --git a/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTestLimit_0.java b/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest_Limit_mysql_0.java similarity index 96% rename from src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTestLimit_0.java rename to src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest_Limit_mysql_0.java index 38382bc614..1363ae19f6 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTestLimit_0.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest_Limit_mysql_0.java @@ -7,7 +7,7 @@ import org.junit.Assert; import com.alibaba.druid.sql.PagerUtils; import com.alibaba.druid.util.JdbcConstants; -public class PagerUtilsTestLimit_0 extends TestCase { +public class PagerUtilsTest_Limit_mysql_0 extends TestCase { public void test_mysql_0() throws Exception { String sql = "select * from t";