From 3a7d001b930e5d6f6aa04668e28391a7ebeca18b Mon Sep 17 00:00:00 2001 From: wenshao Date: Sun, 7 Jun 2015 22:36:33 +0800 Subject: [PATCH] new feature : sql builder --- pom.xml | 6 +- .../java/com/alibaba/druid/sql/SQLUtils.java | 43 +++- .../com/alibaba/druid/sql/ast/SQLOrderBy.java | 12 +- .../sql/ast/statement/SQLExprTableSource.java | 5 + .../ast/statement/SQLSelectQueryBlock.java | 5 + .../sql/ast/statement/SQLUpdateStatement.java | 5 + .../alibaba/druid/sql/builder/SQLBuilder.java | 6 + .../druid/sql/builder/SQLBuilderFactory.java | 39 ++++ .../druid/sql/builder/SQLDeleteBuilder.java | 18 ++ .../druid/sql/builder/SQLSelectBuilder.java | 36 +++ .../druid/sql/builder/SQLUpdateBuilder.java | 20 ++ .../druid/sql/builder/UpdateBuilder.java | 18 ++ .../sql/builder/impl/SQLBuilderImpl.java | 8 + .../builder/impl/SQLDeleteBuilderImpl.java | 94 ++++++++ .../builder/impl/SQLSelectBuilderImpl.java | 217 ++++++++++++++++++ .../builder/impl/SQLUpdateBuilderImpl.java | 105 +++++++++ .../impl/dialect/MySqlSelectBuilderImpl.java | 23 ++ .../impl/dialect/OracleSelectBuilderImpl.java | 26 +++ .../impl/dialect/PGSelectBuilderImpl.java | 22 ++ .../dialect/SQLServerSelectBuilderImpl.java | 21 ++ .../mysql/parser/MySqlStatementParser.java | 21 +- .../dialect/odps/parser/OdpsExprParser.java | 53 +++++ .../dialect/odps/parser/OdpsSelectParser.java | 52 ----- .../sql/dialect/oracle/ast/OracleOrderBy.java | 5 + .../oracle/parser/OracleStatementParser.java | 6 +- .../sqlserver/parser/SQLServerExprParser.java | 2 +- .../druid/sql/parser/SQLExprParser.java | 47 ++++ .../druid/sql/parser/SQLSelectParser.java | 30 +-- .../druid/sql/parser/SQLStatementParser.java | 16 +- .../bvt/sql/builder/BuilderDeleteTest.java | 26 +++ .../bvt/sql/builder/BuilderSelectTest.java | 32 +++ .../bvt/sql/builder/BuilderUpdateTest.java | 27 +++ 32 files changed, 921 insertions(+), 125 deletions(-) create mode 100644 src/main/java/com/alibaba/druid/sql/builder/SQLBuilder.java create mode 100644 src/main/java/com/alibaba/druid/sql/builder/SQLBuilderFactory.java create mode 100644 src/main/java/com/alibaba/druid/sql/builder/SQLDeleteBuilder.java create mode 100644 src/main/java/com/alibaba/druid/sql/builder/SQLSelectBuilder.java create mode 100644 src/main/java/com/alibaba/druid/sql/builder/SQLUpdateBuilder.java create mode 100644 src/main/java/com/alibaba/druid/sql/builder/UpdateBuilder.java create mode 100644 src/main/java/com/alibaba/druid/sql/builder/impl/SQLBuilderImpl.java create mode 100644 src/main/java/com/alibaba/druid/sql/builder/impl/SQLDeleteBuilderImpl.java create mode 100644 src/main/java/com/alibaba/druid/sql/builder/impl/SQLSelectBuilderImpl.java create mode 100644 src/main/java/com/alibaba/druid/sql/builder/impl/SQLUpdateBuilderImpl.java create mode 100644 src/main/java/com/alibaba/druid/sql/builder/impl/dialect/MySqlSelectBuilderImpl.java create mode 100644 src/main/java/com/alibaba/druid/sql/builder/impl/dialect/OracleSelectBuilderImpl.java create mode 100644 src/main/java/com/alibaba/druid/sql/builder/impl/dialect/PGSelectBuilderImpl.java create mode 100644 src/main/java/com/alibaba/druid/sql/builder/impl/dialect/SQLServerSelectBuilderImpl.java create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/builder/BuilderDeleteTest.java create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/builder/BuilderSelectTest.java create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/builder/BuilderUpdateTest.java diff --git a/pom.xml b/pom.xml index f7fb32ded1..42227a9377 100644 --- a/pom.xml +++ b/pom.xml @@ -407,7 +407,7 @@ org.mybatis mybatis-spring - 1.1.1 + 1.2.2 provided true @@ -446,7 +446,7 @@ mysql mysql-connector-java - 5.1.24 + 5.1.35 provided @@ -568,7 +568,7 @@ org.nutz nutz - 1.b.47 + 1.b.52 test diff --git a/src/main/java/com/alibaba/druid/sql/SQLUtils.java b/src/main/java/com/alibaba/druid/sql/SQLUtils.java index d8ac7edfaa..68acc9f166 100644 --- a/src/main/java/com/alibaba/druid/sql/SQLUtils.java +++ b/src/main/java/com/alibaba/druid/sql/SQLUtils.java @@ -26,9 +26,11 @@ import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr; import com.alibaba.druid.sql.ast.expr.SQLBinaryOperator; import com.alibaba.druid.sql.ast.statement.SQLDeleteStatement; import com.alibaba.druid.sql.ast.statement.SQLSelectItem; +import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem; import com.alibaba.druid.sql.ast.statement.SQLSelectQuery; import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; import com.alibaba.druid.sql.ast.statement.SQLSelectStatement; +import com.alibaba.druid.sql.ast.statement.SQLUpdateSetItem; import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement; import com.alibaba.druid.sql.dialect.db2.visitor.DB2OutputVisitor; import com.alibaba.druid.sql.dialect.db2.visitor.DB2SchemaStatVisitor; @@ -175,6 +177,39 @@ public class SQLUtils { return expr; } + + public static SQLSelectOrderByItem toOrderByItem(String sql, String dbType) { + SQLExprParser parser = SQLParserUtils.createExprParser(sql, dbType); + SQLSelectOrderByItem orderByItem = parser.parseSelectOrderByItem(); + + if (parser.getLexer().token() != Token.EOF) { + throw new ParserException("illegal sql expr : " + sql); + } + + return orderByItem; + } + + public static SQLUpdateSetItem toUpdateSetItem(String sql, String dbType) { + SQLExprParser parser = SQLParserUtils.createExprParser(sql, dbType); + SQLUpdateSetItem updateSetItem = parser.parseUpdateSetItem(); + + if (parser.getLexer().token() != Token.EOF) { + throw new ParserException("illegal sql expr : " + sql); + } + + return updateSetItem; + } + + public static SQLSelectItem toSelectItem(String sql, String dbType) { + SQLExprParser parser = SQLParserUtils.createExprParser(sql, dbType); + SQLSelectItem selectItem = parser.parseSelectItem(); + + if (parser.getLexer().token() != Token.EOF) { + throw new ParserException("illegal sql expr : " + sql); + } + + return selectItem; + } public static List toStatementList(String sql, String dbType) { SQLStatementParser parser = SQLParserUtils.createSQLStatementParser(sql, dbType); @@ -406,7 +441,7 @@ public class SQLUtils { SQLSelectQuery query = ((SQLSelectStatement) stmt).getSelect().getQuery(); if (query instanceof SQLSelectQueryBlock) { SQLSelectQueryBlock queryBlock = (SQLSelectQueryBlock) query; - SQLExpr newCondition = buildNewCondition(op, condition, left, queryBlock.getWhere()); + SQLExpr newCondition = buildCondition(op, condition, left, queryBlock.getWhere()); queryBlock.setWhere(newCondition); } else { throw new IllegalArgumentException("add condition not support " + stmt.getClass().getName()); @@ -418,7 +453,7 @@ public class SQLUtils { if (stmt instanceof SQLDeleteStatement) { SQLDeleteStatement delete = (SQLDeleteStatement) stmt; - SQLExpr newCondition = buildNewCondition(op, condition, left, delete.getWhere()); + SQLExpr newCondition = buildCondition(op, condition, left, delete.getWhere()); delete.setWhere(newCondition); return; @@ -427,7 +462,7 @@ public class SQLUtils { if (stmt instanceof SQLUpdateStatement) { SQLUpdateStatement update = (SQLUpdateStatement) stmt; - SQLExpr newCondition = buildNewCondition(op, condition, left, update.getWhere()); + SQLExpr newCondition = buildCondition(op, condition, left, update.getWhere()); update.setWhere(newCondition); return; @@ -436,7 +471,7 @@ public class SQLUtils { throw new IllegalArgumentException("add condition not support " + stmt.getClass().getName()); } - protected static SQLExpr buildNewCondition(SQLBinaryOperator op, SQLExpr condition, boolean left, SQLExpr where) { + public static SQLExpr buildCondition(SQLBinaryOperator op, SQLExpr condition, boolean left, SQLExpr where) { if (where == null) { return condition; } diff --git a/src/main/java/com/alibaba/druid/sql/ast/SQLOrderBy.java b/src/main/java/com/alibaba/druid/sql/ast/SQLOrderBy.java index d0720a961c..8200a7b842 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/SQLOrderBy.java +++ b/src/main/java/com/alibaba/druid/sql/ast/SQLOrderBy.java @@ -31,8 +31,7 @@ public class SQLOrderBy extends SQLObjectImpl { public SQLOrderBy(SQLExpr expr){ SQLSelectOrderByItem item = new SQLSelectOrderByItem(expr); - item.setParent(this); - this.items.add(item); + addItem(item); } public void addItem(SQLSelectOrderByItem item) { @@ -71,5 +70,14 @@ public class SQLOrderBy extends SQLObjectImpl { return items.equals(other.items); } + public void addItem(SQLExpr expr, SQLOrderingSpecification type) { + SQLSelectOrderByItem item = createItem(); + item.setExpr(expr); + item.setType(type); + addItem(item); + } + protected SQLSelectOrderByItem createItem() { + return new SQLSelectOrderByItem(); + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLExprTableSource.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLExprTableSource.java index eb0cbb76ad..37fc8776f2 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLExprTableSource.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLExprTableSource.java @@ -27,7 +27,12 @@ public class SQLExprTableSource extends SQLTableSourceImpl { } public SQLExprTableSource(SQLExpr expr){ + this(expr, null); + } + + public SQLExprTableSource(SQLExpr expr, String alias){ this.setExpr(expr); + this.setAlias(alias); } public SQLExpr getExpr() { diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectQueryBlock.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectQueryBlock.java index 79331a3e0e..7c2831b068 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectQueryBlock.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectQueryBlock.java @@ -82,6 +82,11 @@ public class SQLSelectQueryBlock extends SQLObjectImpl implements SQLSelectQuery public List getSelectList() { return this.selectList; } + + public void addSelectItem(SQLSelectItem item) { + this.selectList.add(item); + item.setParent(this); + } public SQLTableSource getFrom() { return this.from; diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLUpdateStatement.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLUpdateStatement.java index 8abdcfc828..ff930a2893 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLUpdateStatement.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLUpdateStatement.java @@ -75,6 +75,11 @@ public class SQLUpdateStatement extends SQLStatementImpl { public List getItems() { return items; } + + public void addItem(SQLUpdateSetItem item) { + this.items.add(item); + item.setParent(this); + } @Override public void output(StringBuffer buf) { diff --git a/src/main/java/com/alibaba/druid/sql/builder/SQLBuilder.java b/src/main/java/com/alibaba/druid/sql/builder/SQLBuilder.java new file mode 100644 index 0000000000..0f7cd19215 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/builder/SQLBuilder.java @@ -0,0 +1,6 @@ +package com.alibaba.druid.sql.builder; + + +public interface SQLBuilder { + +} diff --git a/src/main/java/com/alibaba/druid/sql/builder/SQLBuilderFactory.java b/src/main/java/com/alibaba/druid/sql/builder/SQLBuilderFactory.java new file mode 100644 index 0000000000..b49451d3e1 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/builder/SQLBuilderFactory.java @@ -0,0 +1,39 @@ +package com.alibaba.druid.sql.builder; + +import com.alibaba.druid.sql.builder.impl.SQLDeleteBuilderImpl; +import com.alibaba.druid.sql.builder.impl.SQLSelectBuilderImpl; +import com.alibaba.druid.sql.builder.impl.SQLUpdateBuilderImpl; +import com.alibaba.druid.sql.builder.impl.dialect.MySqlSelectBuilderImpl; +import com.alibaba.druid.sql.builder.impl.dialect.PGSelectBuilderImpl; +import com.alibaba.druid.util.JdbcConstants; + + +public class SQLBuilderFactory { + public static SQLSelectBuilder createSelectSQLBuilder(String dbType) { + if (JdbcConstants.MYSQL.equals(dbType)) { + return new MySqlSelectBuilderImpl(); + } + + if (JdbcConstants.POSTGRESQL.equals(dbType)) { + return new PGSelectBuilderImpl(); + } + + if (JdbcConstants.SQL_SERVER.equals(dbType)) { + return new PGSelectBuilderImpl(); + } + + if (JdbcConstants.ORACLE.equals(dbType)) { + return new PGSelectBuilderImpl(); + } + + return new SQLSelectBuilderImpl(dbType); + } + + public static SQLDeleteBuilder createDeleteBuilder(String dbType) { + return new SQLDeleteBuilderImpl(dbType); + } + + public static SQLUpdateBuilder createUpdateBuilder(String dbType) { + return new SQLUpdateBuilderImpl(dbType); + } +} diff --git a/src/main/java/com/alibaba/druid/sql/builder/SQLDeleteBuilder.java b/src/main/java/com/alibaba/druid/sql/builder/SQLDeleteBuilder.java new file mode 100644 index 0000000000..01fc38e6ea --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/builder/SQLDeleteBuilder.java @@ -0,0 +1,18 @@ +package com.alibaba.druid.sql.builder; + + +public interface SQLDeleteBuilder { + SQLDeleteBuilder from(String table); + + SQLDeleteBuilder from(String table, String alias); + + SQLDeleteBuilder limit(int rowCount); + + SQLDeleteBuilder limit(int rowCount, int offset); + + SQLDeleteBuilder where(String sql); + + SQLDeleteBuilder whereAnd(String sql); + + SQLDeleteBuilder whereOr(String sql); +} diff --git a/src/main/java/com/alibaba/druid/sql/builder/SQLSelectBuilder.java b/src/main/java/com/alibaba/druid/sql/builder/SQLSelectBuilder.java new file mode 100644 index 0000000000..3c12527cda --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/builder/SQLSelectBuilder.java @@ -0,0 +1,36 @@ +package com.alibaba.druid.sql.builder; + +import com.alibaba.druid.sql.ast.statement.SQLSelectStatement; + +public interface SQLSelectBuilder { + + SQLSelectStatement getSQLSelectStatement(); + + SQLSelectBuilder select(String... column); + + SQLSelectBuilder selectWithAlias(String column, String alias); + + SQLSelectBuilder from(String table); + + SQLSelectBuilder from(String table, String alias); + + SQLSelectBuilder orderBy(String... columns); + + SQLSelectBuilder groupBy(String expr); + + SQLSelectBuilder having(String expr); + + SQLSelectBuilder into(String expr); + + SQLSelectBuilder limit(int rowCount); + + SQLSelectBuilder limit(int rowCount, int offset); + + SQLSelectBuilder where(String sql); + + SQLSelectBuilder whereAnd(String sql); + + SQLSelectBuilder whereOr(String sql); + + String toString(); +} diff --git a/src/main/java/com/alibaba/druid/sql/builder/SQLUpdateBuilder.java b/src/main/java/com/alibaba/druid/sql/builder/SQLUpdateBuilder.java new file mode 100644 index 0000000000..6a2ad480a0 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/builder/SQLUpdateBuilder.java @@ -0,0 +1,20 @@ +package com.alibaba.druid.sql.builder; + + +public interface SQLUpdateBuilder { + SQLUpdateBuilder from(String table); + + SQLUpdateBuilder from(String table, String alias); + + SQLUpdateBuilder limit(int rowCount); + + SQLUpdateBuilder limit(int rowCount, int offset); + + SQLUpdateBuilder where(String sql); + + SQLUpdateBuilder whereAnd(String sql); + + SQLUpdateBuilder whereOr(String sql); + + SQLUpdateBuilder set(String... items); +} diff --git a/src/main/java/com/alibaba/druid/sql/builder/UpdateBuilder.java b/src/main/java/com/alibaba/druid/sql/builder/UpdateBuilder.java new file mode 100644 index 0000000000..9f73886360 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/builder/UpdateBuilder.java @@ -0,0 +1,18 @@ +package com.alibaba.druid.sql.builder; + + +public interface UpdateBuilder { + UpdateBuilder from(String table); + + UpdateBuilder from(String table, String alias); + + UpdateBuilder limit(int rowCount); + + UpdateBuilder limit(int rowCount, int offset); + + UpdateBuilder where(String sql); + + UpdateBuilder whereAnd(String sql); + + UpdateBuilder whereOr(String sql); +} diff --git a/src/main/java/com/alibaba/druid/sql/builder/impl/SQLBuilderImpl.java b/src/main/java/com/alibaba/druid/sql/builder/impl/SQLBuilderImpl.java new file mode 100644 index 0000000000..4e98289d7d --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/builder/impl/SQLBuilderImpl.java @@ -0,0 +1,8 @@ +package com.alibaba.druid.sql.builder.impl; + +import com.alibaba.druid.sql.builder.SQLBuilder; + + +public class SQLBuilderImpl implements SQLBuilder { + +} diff --git a/src/main/java/com/alibaba/druid/sql/builder/impl/SQLDeleteBuilderImpl.java b/src/main/java/com/alibaba/druid/sql/builder/impl/SQLDeleteBuilderImpl.java new file mode 100644 index 0000000000..d15bceafc7 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/builder/impl/SQLDeleteBuilderImpl.java @@ -0,0 +1,94 @@ +package com.alibaba.druid.sql.builder.impl; + +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLExpr; +import com.alibaba.druid.sql.ast.expr.SQLBinaryOperator; +import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; +import com.alibaba.druid.sql.ast.statement.SQLDeleteStatement; +import com.alibaba.druid.sql.ast.statement.SQLExprTableSource; +import com.alibaba.druid.sql.builder.SQLDeleteBuilder; + +public class SQLDeleteBuilderImpl implements SQLDeleteBuilder { + + private SQLDeleteStatement stmt; + private String dbType; + + public SQLDeleteBuilderImpl(String dbType){ + this.dbType = dbType; + } + + public SQLDeleteBuilderImpl(SQLDeleteStatement stmt, String dbType){ + this.stmt = stmt; + this.dbType = dbType; + } + + @Override + public SQLDeleteBuilderImpl limit(int rowCount) { + throw new UnsupportedOperationException(); + } + + @Override + public SQLDeleteBuilderImpl limit(int rowCount, int offset) { + throw new UnsupportedOperationException(); + } + + @Override + public SQLDeleteBuilder from(String table) { + return from(table, null); + } + + @Override + public SQLDeleteBuilder from(String table, String alias) { + SQLDeleteStatement delete = getSQLDeleteStatement(); + SQLExprTableSource from = new SQLExprTableSource(new SQLIdentifierExpr(table), alias); + delete.setTableSource(from); + return this; + } + + @Override + public SQLDeleteBuilder where(String expr) { + SQLDeleteStatement delete = getSQLDeleteStatement(); + + SQLExpr exprObj = SQLUtils.toSQLExpr(expr, dbType); + delete.setWhere(exprObj); + + return this; + } + + @Override + public SQLDeleteBuilder whereAnd(String expr) { + SQLDeleteStatement delete = getSQLDeleteStatement(); + + SQLExpr exprObj = SQLUtils.toSQLExpr(expr, dbType); + SQLExpr newCondition = SQLUtils.buildCondition(SQLBinaryOperator.BooleanAnd, exprObj, false, delete.getWhere()); + delete.setWhere(newCondition); + + return this; + } + + @Override + public SQLDeleteBuilder whereOr(String expr) { + SQLDeleteStatement delete = getSQLDeleteStatement(); + + SQLExpr exprObj = SQLUtils.toSQLExpr(expr, dbType); + SQLExpr newCondition = SQLUtils.buildCondition(SQLBinaryOperator.BooleanOr, exprObj, false, delete.getWhere()); + delete.setWhere(newCondition); + + return this; + } + + public SQLDeleteStatement getSQLDeleteStatement() { + if (stmt == null) { + stmt = createSQLDeleteStatement(); + } + return stmt; + } + + public SQLDeleteStatement createSQLDeleteStatement() { + return new SQLDeleteStatement(); + } + + public String toString() { + return SQLUtils.toSQLString(stmt, dbType); + } +} diff --git a/src/main/java/com/alibaba/druid/sql/builder/impl/SQLSelectBuilderImpl.java b/src/main/java/com/alibaba/druid/sql/builder/impl/SQLSelectBuilderImpl.java new file mode 100644 index 0000000000..597d79ceb3 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/builder/impl/SQLSelectBuilderImpl.java @@ -0,0 +1,217 @@ +package com.alibaba.druid.sql.builder.impl; + +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLExpr; +import com.alibaba.druid.sql.ast.SQLOrderBy; +import com.alibaba.druid.sql.ast.expr.SQLBinaryOperator; +import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; +import com.alibaba.druid.sql.ast.statement.SQLExprTableSource; +import com.alibaba.druid.sql.ast.statement.SQLSelect; +import com.alibaba.druid.sql.ast.statement.SQLSelectGroupByClause; +import com.alibaba.druid.sql.ast.statement.SQLSelectItem; +import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem; +import com.alibaba.druid.sql.ast.statement.SQLSelectQuery; +import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; +import com.alibaba.druid.sql.ast.statement.SQLSelectStatement; +import com.alibaba.druid.sql.builder.SQLSelectBuilder; + +public class SQLSelectBuilderImpl implements SQLSelectBuilder { + + private SQLSelectStatement stmt; + private String dbType; + + public SQLSelectBuilderImpl(String dbType){ + this(new SQLSelectStatement(), dbType); + } + + public SQLSelectBuilderImpl(SQLSelectStatement stmt, String dbType){ + this.stmt = stmt; + this.dbType = dbType; + } + + public SQLSelect getSQLSelect() { + if (stmt.getSelect() == null) { + stmt.setSelect(createSelect()); + } + return stmt.getSelect(); + } + + @Override + public SQLSelectStatement getSQLSelectStatement() { + return stmt; + } + + public SQLSelectBuilderImpl select(String... columns) { + SQLSelectQueryBlock queryBlock = getQueryBlock(); + + for (String column : columns) { + SQLSelectItem selectItem = SQLUtils.toSelectItem(column, dbType); + queryBlock.addSelectItem(selectItem); + } + + return this; + } + + @Override + public SQLSelectBuilderImpl selectWithAlias(String column, String alias) { + SQLSelectQueryBlock queryBlock = getQueryBlock(); + + SQLExpr columnExpr = SQLUtils.toSQLExpr(column, dbType); + SQLSelectItem selectItem = new SQLSelectItem(columnExpr, alias); + queryBlock.addSelectItem(selectItem); + + return this; + } + + @Override + public SQLSelectBuilderImpl from(String table) { + return from(table, null); + } + + @Override + public SQLSelectBuilderImpl from(String table, String alias) { + SQLSelectQueryBlock queryBlock = getQueryBlock(); + SQLExprTableSource from = new SQLExprTableSource(new SQLIdentifierExpr(table), alias); + queryBlock.setFrom(from); + + return this; + } + + @Override + public SQLSelectBuilderImpl orderBy(String... columns) { + SQLSelect select = this.getSQLSelect(); + + SQLOrderBy orderBy = select.getOrderBy(); + if (orderBy == null) { + orderBy = createOrderBy(); + select.setOrderBy(orderBy); + } + + for (String column : columns) { + SQLSelectOrderByItem orderByItem = SQLUtils.toOrderByItem(column, dbType); + orderBy.addItem(orderByItem); + } + + return this; + } + + @Override + public SQLSelectBuilderImpl groupBy(String expr) { + SQLSelectQueryBlock queryBlock = getQueryBlock(); + + SQLSelectGroupByClause groupBy = queryBlock.getGroupBy(); + if (groupBy == null) { + groupBy = createGroupBy(); + queryBlock.setGroupBy(groupBy); + } + + SQLExpr exprObj = SQLUtils.toSQLExpr(expr, dbType); + groupBy.addItem(exprObj); + + return this; + } + + @Override + public SQLSelectBuilderImpl having(String expr) { + SQLSelectQueryBlock queryBlock = getQueryBlock(); + + SQLSelectGroupByClause groupBy = queryBlock.getGroupBy(); + if (groupBy == null) { + groupBy = createGroupBy(); + queryBlock.setGroupBy(groupBy); + } + + SQLExpr exprObj = SQLUtils.toSQLExpr(expr, dbType); + groupBy.setHaving(exprObj); + + return this; + } + + @Override + public SQLSelectBuilderImpl into(String expr) { + SQLSelectQueryBlock queryBlock = getQueryBlock(); + + SQLExpr exprObj = SQLUtils.toSQLExpr(expr, dbType); + queryBlock.setInto(exprObj); + + return this; + } + + @Override + public SQLSelectBuilderImpl where(String expr) { + SQLSelectQueryBlock queryBlock = getQueryBlock(); + + SQLExpr exprObj = SQLUtils.toSQLExpr(expr, dbType); + queryBlock.setWhere(exprObj); + + return this; + } + + @Override + public SQLSelectBuilderImpl whereAnd(String expr) { + SQLSelectQueryBlock queryBlock = getQueryBlock(); + + SQLExpr exprObj = SQLUtils.toSQLExpr(expr, dbType); + SQLExpr newCondition = SQLUtils.buildCondition(SQLBinaryOperator.BooleanAnd, exprObj, false, queryBlock.getWhere()); + queryBlock.setWhere(newCondition); + + return this; + } + + @Override + public SQLSelectBuilderImpl whereOr(String expr) { + SQLSelectQueryBlock queryBlock = getQueryBlock(); + + SQLExpr exprObj = SQLUtils.toSQLExpr(expr, dbType); + SQLExpr newCondition = SQLUtils.buildCondition(SQLBinaryOperator.BooleanOr, exprObj, false, queryBlock.getWhere()); + queryBlock.setWhere(newCondition); + + return this; + } + + @Override + public SQLSelectBuilderImpl limit(int rowCount) { + throw new UnsupportedOperationException(); + } + + @Override + public SQLSelectBuilderImpl limit(int rowCount, int offset) { + throw new UnsupportedOperationException(); + } + + protected SQLSelectQueryBlock getQueryBlock() { + SQLSelect select = getSQLSelect(); + SQLSelectQuery query = select.getQuery(); + if (query == null) { + query = createSelectQueryBlock(); + select.setQuery(query); + } + + if (!(query instanceof SQLSelectQueryBlock)) { + throw new IllegalStateException("not support from, class : " + query.getClass().getName()); + } + + SQLSelectQueryBlock queryBlock = (SQLSelectQueryBlock) query; + return queryBlock; + } + + protected SQLSelect createSelect() { + return new SQLSelect(); + } + + protected SQLSelectQuery createSelectQueryBlock() { + return new SQLSelectQueryBlock(); + } + + protected SQLOrderBy createOrderBy() { + return new SQLOrderBy(); + } + + protected SQLSelectGroupByClause createGroupBy() { + return new SQLSelectGroupByClause(); + } + + public String toString() { + return SQLUtils.toSQLString(stmt, dbType); + } +} diff --git a/src/main/java/com/alibaba/druid/sql/builder/impl/SQLUpdateBuilderImpl.java b/src/main/java/com/alibaba/druid/sql/builder/impl/SQLUpdateBuilderImpl.java new file mode 100644 index 0000000000..51785b0a24 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/builder/impl/SQLUpdateBuilderImpl.java @@ -0,0 +1,105 @@ +package com.alibaba.druid.sql.builder.impl; + +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLExpr; +import com.alibaba.druid.sql.ast.expr.SQLBinaryOperator; +import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; +import com.alibaba.druid.sql.ast.statement.SQLExprTableSource; +import com.alibaba.druid.sql.ast.statement.SQLUpdateSetItem; +import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement; +import com.alibaba.druid.sql.builder.SQLUpdateBuilder; + +public class SQLUpdateBuilderImpl implements SQLUpdateBuilder { + + private SQLUpdateStatement stmt; + private String dbType; + + public SQLUpdateBuilderImpl(String dbType){ + this.dbType = dbType; + } + + public SQLUpdateBuilderImpl(SQLUpdateStatement stmt, String dbType){ + this.stmt = stmt; + this.dbType = dbType; + } + + @Override + public SQLUpdateBuilderImpl limit(int rowCount) { + throw new UnsupportedOperationException(); + } + + @Override + public SQLUpdateBuilderImpl limit(int rowCount, int offset) { + throw new UnsupportedOperationException(); + } + + @Override + public SQLUpdateBuilderImpl from(String table) { + return from(table, null); + } + + @Override + public SQLUpdateBuilderImpl from(String table, String alias) { + SQLUpdateStatement update = getSQLUpdateStatement(); + SQLExprTableSource from = new SQLExprTableSource(new SQLIdentifierExpr(table), alias); + update.setTableSource(from); + return this; + } + + @Override + public SQLUpdateBuilderImpl where(String expr) { + SQLUpdateStatement update = getSQLUpdateStatement(); + + SQLExpr exprObj = SQLUtils.toSQLExpr(expr, dbType); + update.setWhere(exprObj); + + return this; + } + + @Override + public SQLUpdateBuilderImpl whereAnd(String expr) { + SQLUpdateStatement update = getSQLUpdateStatement(); + + SQLExpr exprObj = SQLUtils.toSQLExpr(expr, dbType); + SQLExpr newCondition = SQLUtils.buildCondition(SQLBinaryOperator.BooleanAnd, exprObj, false, update.getWhere()); + update.setWhere(newCondition); + + return this; + } + + @Override + public SQLUpdateBuilderImpl whereOr(String expr) { + SQLUpdateStatement update = getSQLUpdateStatement(); + + SQLExpr exprObj = SQLUtils.toSQLExpr(expr, dbType); + SQLExpr newCondition = SQLUtils.buildCondition(SQLBinaryOperator.BooleanOr, exprObj, false, update.getWhere()); + update.setWhere(newCondition); + + return this; + } + + public SQLUpdateBuilderImpl set(String... items) { + SQLUpdateStatement update = getSQLUpdateStatement(); + for (String item : items) { + SQLUpdateSetItem updateSetItem = SQLUtils.toUpdateSetItem(item, dbType); + update.addItem(updateSetItem); + } + + return this; + } + + public SQLUpdateStatement getSQLUpdateStatement() { + if (stmt == null) { + stmt = createSQLUpdateStatement(); + } + return stmt; + } + + public SQLUpdateStatement createSQLUpdateStatement() { + return new SQLUpdateStatement(); + } + + public String toString() { + return SQLUtils.toSQLString(stmt, dbType); + } +} diff --git a/src/main/java/com/alibaba/druid/sql/builder/impl/dialect/MySqlSelectBuilderImpl.java b/src/main/java/com/alibaba/druid/sql/builder/impl/dialect/MySqlSelectBuilderImpl.java new file mode 100644 index 0000000000..cb1424bb7e --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/builder/impl/dialect/MySqlSelectBuilderImpl.java @@ -0,0 +1,23 @@ +package com.alibaba.druid.sql.builder.impl.dialect; + +import com.alibaba.druid.sql.ast.statement.SQLSelectGroupByClause; +import com.alibaba.druid.sql.ast.statement.SQLSelectQuery; +import com.alibaba.druid.sql.builder.impl.SQLSelectBuilderImpl; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectGroupBy; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock; +import com.alibaba.druid.util.JdbcConstants; + +public class MySqlSelectBuilderImpl extends SQLSelectBuilderImpl { + + public MySqlSelectBuilderImpl(){ + super(JdbcConstants.MYSQL); + } + + protected SQLSelectQuery createSelectQueryBlock() { + return new MySqlSelectQueryBlock(); + } + + protected SQLSelectGroupByClause createGroupBy() { + return new MySqlSelectGroupBy(); + } +} diff --git a/src/main/java/com/alibaba/druid/sql/builder/impl/dialect/OracleSelectBuilderImpl.java b/src/main/java/com/alibaba/druid/sql/builder/impl/dialect/OracleSelectBuilderImpl.java new file mode 100644 index 0000000000..58f0f3209f --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/builder/impl/dialect/OracleSelectBuilderImpl.java @@ -0,0 +1,26 @@ +package com.alibaba.druid.sql.builder.impl.dialect; + +import com.alibaba.druid.sql.builder.impl.SQLSelectBuilderImpl; +import com.alibaba.druid.sql.dialect.oracle.ast.OracleOrderBy; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelect; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectQueryBlock; +import com.alibaba.druid.util.JdbcConstants; + +public class OracleSelectBuilderImpl extends SQLSelectBuilderImpl { + + public OracleSelectBuilderImpl(){ + super(JdbcConstants.ORACLE); + } + + protected OracleSelectQueryBlock createSelectQueryBlock() { + return new OracleSelectQueryBlock(); + } + + protected OracleSelect createSelect() { + return new OracleSelect(); + } + + protected OracleOrderBy createOrderBy() { + return new OracleOrderBy(); + } +} diff --git a/src/main/java/com/alibaba/druid/sql/builder/impl/dialect/PGSelectBuilderImpl.java b/src/main/java/com/alibaba/druid/sql/builder/impl/dialect/PGSelectBuilderImpl.java new file mode 100644 index 0000000000..a438626399 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/builder/impl/dialect/PGSelectBuilderImpl.java @@ -0,0 +1,22 @@ +package com.alibaba.druid.sql.builder.impl.dialect; + +import com.alibaba.druid.sql.builder.impl.SQLSelectBuilderImpl; +import com.alibaba.druid.sql.dialect.postgresql.ast.PGOrderBy; +import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectQueryBlock; +import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectStatement; +import com.alibaba.druid.util.JdbcConstants; + +public class PGSelectBuilderImpl extends SQLSelectBuilderImpl { + + public PGSelectBuilderImpl(){ + super(new PGSelectStatement(), JdbcConstants.POSTGRESQL); + } + + protected PGSelectQueryBlock createSelectQueryBlock() { + return new PGSelectQueryBlock(); + } + + protected PGOrderBy createOrderBy() { + return new PGOrderBy(); + } +} diff --git a/src/main/java/com/alibaba/druid/sql/builder/impl/dialect/SQLServerSelectBuilderImpl.java b/src/main/java/com/alibaba/druid/sql/builder/impl/dialect/SQLServerSelectBuilderImpl.java new file mode 100644 index 0000000000..f4690df0b4 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/builder/impl/dialect/SQLServerSelectBuilderImpl.java @@ -0,0 +1,21 @@ +package com.alibaba.druid.sql.builder.impl.dialect; + +import com.alibaba.druid.sql.builder.impl.SQLSelectBuilderImpl; +import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerSelect; +import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerSelectQueryBlock; +import com.alibaba.druid.util.JdbcConstants; + +public class SQLServerSelectBuilderImpl extends SQLSelectBuilderImpl { + + public SQLServerSelectBuilderImpl(){ + super(JdbcConstants.SQL_SERVER); + } + + protected SQLServerSelectQueryBlock createSelectQueryBlock() { + return new SQLServerSelectQueryBlock(); + } + + protected SQLServerSelect createSelect() { + return new SQLServerSelect(); + } +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java index 56ef1e5534..96c07827e2 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java @@ -25,7 +25,6 @@ import com.alibaba.druid.sql.ast.SQLOrderBy; import com.alibaba.druid.sql.ast.SQLStatement; import com.alibaba.druid.sql.ast.expr.SQLCharExpr; import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr; -import com.alibaba.druid.sql.ast.expr.SQLListExpr; import com.alibaba.druid.sql.ast.expr.SQLLiteralExpr; import com.alibaba.druid.sql.ast.expr.SQLNCharExpr; import com.alibaba.druid.sql.ast.expr.SQLQueryExpr; @@ -2666,24 +2665,8 @@ public class MySqlStatementParser extends SQLStatementParser { accept(Token.SET); for (;;) { - SQLUpdateSetItem item = new SQLUpdateSetItem(); - - if (lexer.token() == (Token.LPAREN)) { - lexer.nextToken(); - SQLListExpr list = new SQLListExpr(); - this.exprParser.exprList(list.getItems(), list); - accept(Token.RPAREN); - item.setColumn(list); - } else { - item.setColumn(this.exprParser.primary()); - } - if (lexer.token() == Token.COLONEQ) { - lexer.nextToken(); - } else { - accept(Token.EQ); - } - item.setValue(this.exprParser.expr()); - update.getItems().add(item); + SQLUpdateSetItem item = this.exprParser.parseUpdateSetItem(); + update.addItem(item); if (lexer.token() != Token.COMMA) { break; diff --git a/src/main/java/com/alibaba/druid/sql/dialect/odps/parser/OdpsExprParser.java b/src/main/java/com/alibaba/druid/sql/dialect/odps/parser/OdpsExprParser.java index b7d9257f53..d6bc801569 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/odps/parser/OdpsExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/odps/parser/OdpsExprParser.java @@ -17,8 +17,12 @@ package com.alibaba.druid.sql.dialect.odps.parser; import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.expr.SQLCharExpr; +import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; +import com.alibaba.druid.sql.ast.statement.SQLSelectItem; +import com.alibaba.druid.sql.dialect.odps.ast.OdpsUDTFSQLSelectItem; import com.alibaba.druid.sql.parser.Lexer; import com.alibaba.druid.sql.parser.SQLExprParser; +import com.alibaba.druid.sql.parser.Token; public class OdpsExprParser extends SQLExprParser { @@ -47,4 +51,53 @@ public class OdpsExprParser extends SQLExprParser { protected SQLExpr parseAliasExpr(String alias) { return new SQLCharExpr(alias); } + + @Override + public SQLSelectItem parseSelectItem() { + SQLExpr expr; + if (lexer.token() == Token.IDENTIFIER) { + expr = new SQLIdentifierExpr(lexer.stringVal()); + lexer.nextTokenComma(); + + if (lexer.token() != Token.COMMA) { + expr = this.primaryRest(expr); + expr = this.exprRest(expr); + } + } else { + expr = expr(); + } + + if (lexer.token() == Token.AS) { + lexer.nextToken(); + + if (lexer.token() == Token.LPAREN) { + lexer.nextToken(); + + OdpsUDTFSQLSelectItem selectItem = new OdpsUDTFSQLSelectItem(); + + selectItem.setExpr(expr); + + for (;;) { + String alias = lexer.stringVal(); + lexer.nextToken(); + + selectItem.getAliasList().add(alias); + + if (lexer.token() == Token.COMMA) { + lexer.nextToken(); + continue; + } + break; + } + + accept(Token.RPAREN); + + return selectItem; + } + } + + final String alias = as(); + + return new SQLSelectItem(expr, alias); + } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/odps/parser/OdpsSelectParser.java b/src/main/java/com/alibaba/druid/sql/dialect/odps/parser/OdpsSelectParser.java index f4299db585..26ecd1a7a3 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/odps/parser/OdpsSelectParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/odps/parser/OdpsSelectParser.java @@ -15,13 +15,9 @@ */ package com.alibaba.druid.sql.dialect.odps.parser; -import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLSetQuantifier; -import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; -import com.alibaba.druid.sql.ast.statement.SQLSelectItem; import com.alibaba.druid.sql.ast.statement.SQLSelectQuery; import com.alibaba.druid.sql.dialect.odps.ast.OdpsSelectQueryBlock; -import com.alibaba.druid.sql.dialect.odps.ast.OdpsUDTFSQLSelectItem; import com.alibaba.druid.sql.parser.SQLExprParser; import com.alibaba.druid.sql.parser.SQLSelectParser; import com.alibaba.druid.sql.parser.Token; @@ -81,52 +77,4 @@ public class OdpsSelectParser extends SQLSelectParser { return queryRest(queryBlock); } - @Override - protected SQLSelectItem parseSelectItem() { - SQLExpr expr; - if (lexer.token() == Token.IDENTIFIER) { - expr = new SQLIdentifierExpr(lexer.stringVal()); - lexer.nextTokenComma(); - - if (lexer.token() != Token.COMMA) { - expr = this.exprParser.primaryRest(expr); - expr = this.exprParser.exprRest(expr); - } - } else { - expr = expr(); - } - - if (lexer.token() == Token.AS) { - lexer.nextToken(); - - if (lexer.token() == Token.LPAREN) { - lexer.nextToken(); - - OdpsUDTFSQLSelectItem selectItem = new OdpsUDTFSQLSelectItem(); - - selectItem.setExpr(expr); - - for (;;) { - String alias = lexer.stringVal(); - lexer.nextToken(); - - selectItem.getAliasList().add(alias); - - if (lexer.token() == Token.COMMA) { - lexer.nextToken(); - continue; - } - break; - } - - accept(Token.RPAREN); - - return selectItem; - } - } - - final String alias = as(); - - return new SQLSelectItem(expr, alias); - } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/OracleOrderBy.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/OracleOrderBy.java index d297606575..a3eee22fd2 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/OracleOrderBy.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/OracleOrderBy.java @@ -16,6 +16,7 @@ package com.alibaba.druid.sql.dialect.oracle.ast; import com.alibaba.druid.sql.ast.SQLOrderBy; +import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleOrderByItem; import com.alibaba.druid.sql.dialect.oracle.visitor.OracleASTVisitor; import com.alibaba.druid.sql.visitor.SQLASTVisitor; @@ -67,4 +68,8 @@ public class OracleOrderBy extends SQLOrderBy { ((OracleOrderByItem) this.items.get(i)).output(buf); } } + + protected SQLSelectOrderByItem createItem() { + return new OracleOrderByItem(); + } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleStatementParser.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleStatementParser.java index ecd2bd5fef..2c64fde35a 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleStatementParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleStatementParser.java @@ -1137,12 +1137,10 @@ public class OracleStatementParser extends SQLStatementParser { accept(Token.SET); for (;;) { - SQLUpdateSetItem item = new SQLUpdateSetItem(); - item.setColumn(this.exprParser.name()); - accept(Token.EQ); - item.setValue(this.exprParser.expr()); + SQLUpdateSetItem item = this.exprParser.parseUpdateSetItem(); updateClause.getItems().add(item); + item.setParent(updateClause); if (lexer.token() == (Token.COMMA)) { lexer.nextToken(); diff --git a/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/parser/SQLServerExprParser.java b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/parser/SQLServerExprParser.java index 69e2a97f7a..e2837e09de 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/parser/SQLServerExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/sqlserver/parser/SQLServerExprParser.java @@ -174,7 +174,7 @@ public class SQLServerExprParser extends SQLExprParser { return null; } - protected SQLSelectItem parseSelectItem() { + public SQLSelectItem parseSelectItem() { SQLExpr expr; if (lexer.token() == Token.IDENTIFIER) { expr = new SQLIdentifierExpr(lexer.stringVal()); diff --git a/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java b/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java index 52085129f2..7ae7d02a8f 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java @@ -76,8 +76,10 @@ import com.alibaba.druid.sql.ast.statement.SQLForeignKeyImpl; import com.alibaba.druid.sql.ast.statement.SQLPrimaryKey; import com.alibaba.druid.sql.ast.statement.SQLPrimaryKeyImpl; import com.alibaba.druid.sql.ast.statement.SQLSelect; +import com.alibaba.druid.sql.ast.statement.SQLSelectItem; import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem; import com.alibaba.druid.sql.ast.statement.SQLUnique; +import com.alibaba.druid.sql.ast.statement.SQLUpdateSetItem; public class SQLExprParser extends SQLParser { @@ -1001,6 +1003,28 @@ public class SQLExprParser extends SQLParser { return item; } + + public SQLUpdateSetItem parseUpdateSetItem() { + SQLUpdateSetItem item = new SQLUpdateSetItem(); + + if (lexer.token() == (Token.LPAREN)) { + lexer.nextToken(); + SQLListExpr list = new SQLListExpr(); + this.exprList(list.getItems(), list); + accept(Token.RPAREN); + item.setColumn(list); + } else { + item.setColumn(this.primary()); + } + if (lexer.token() == Token.COLONEQ) { + lexer.nextToken(); + } else { + accept(Token.EQ); + } + + item.setValue(this.expr()); + return item; + } public final SQLExpr bitAnd() { SQLExpr expr = shift(); @@ -1743,4 +1767,27 @@ public class SQLExprParser extends SQLParser { protected SQLForeignKeyConstraint createForeignKey() { return new SQLForeignKeyImpl(); } + + public SQLSelectItem parseSelectItem() { + SQLExpr expr; + boolean connectByRoot = false; + if (lexer.token() == Token.IDENTIFIER) { + if (identifierEquals("CONNECT_BY_ROOT")) { + connectByRoot = true; + lexer.nextToken(); + } + expr = new SQLIdentifierExpr(lexer.stringVal()); + lexer.nextTokenComma(); + + if (lexer.token() != Token.COMMA) { + expr = this.primaryRest(expr); + expr = this.exprRest(expr); + } + } else { + expr = expr(); + } + final String alias = as(); + + return new SQLSelectItem(expr, alias, connectByRoot); + } } diff --git a/src/main/java/com/alibaba/druid/sql/parser/SQLSelectParser.java b/src/main/java/com/alibaba/druid/sql/parser/SQLSelectParser.java index 475900cf40..898f54aa74 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLSelectParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLSelectParser.java @@ -64,7 +64,7 @@ public class SQLSelectParser extends SQLParser { select.setOrderBy(parseOrderBy()); } - while(lexer.token() == Token.HINT) { + while (lexer.token() == Token.HINT) { this.exprParser.parseHints(select.getHints()); } @@ -269,11 +269,12 @@ public class SQLSelectParser extends SQLParser { } } - protected final void parseSelectList(SQLSelectQueryBlock queryBlock) { + protected void parseSelectList(SQLSelectQueryBlock queryBlock) { final List selectList = queryBlock.getSelectList(); for (;;) { - final SQLSelectItem selectItem = parseSelectItem(); + final SQLSelectItem selectItem = this.exprParser.parseSelectItem(); selectList.add(selectItem); + selectItem.setParent(queryBlock); if (lexer.token() != Token.COMMA) { break; @@ -283,29 +284,6 @@ public class SQLSelectParser extends SQLParser { } } - protected SQLSelectItem parseSelectItem() { - SQLExpr expr; - boolean connectByRoot = false; - if (lexer.token() == Token.IDENTIFIER) { - if (identifierEquals("CONNECT_BY_ROOT")) { - connectByRoot = true; - lexer.nextToken(); - } - expr = new SQLIdentifierExpr(lexer.stringVal()); - lexer.nextTokenComma(); - - if (lexer.token() != Token.COMMA) { - expr = this.exprParser.primaryRest(expr); - expr = this.exprParser.exprRest(expr); - } - } else { - expr = expr(); - } - final String alias = as(); - - return new SQLSelectItem(expr, alias, connectByRoot); - } - public void parseFrom(SQLSelectQueryBlock queryBlock) { if (lexer.token() != Token.FROM) { return; diff --git a/src/main/java/com/alibaba/druid/sql/parser/SQLStatementParser.java b/src/main/java/com/alibaba/druid/sql/parser/SQLStatementParser.java index 1895cc0f53..6035f8eb33 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLStatementParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLStatementParser.java @@ -1539,20 +1539,8 @@ public class SQLStatementParser extends SQLParser { accept(Token.SET); for (;;) { - SQLUpdateSetItem item = new SQLUpdateSetItem(); - - if (lexer.token() == (Token.LPAREN)) { - lexer.nextToken(); - SQLListExpr list = new SQLListExpr(); - this.exprParser.exprList(list.getItems(), list); - accept(Token.RPAREN); - item.setColumn(list); - } else { - item.setColumn(this.exprParser.primary()); - } - accept(Token.EQ); - item.setValue(this.exprParser.expr()); - update.getItems().add(item); + SQLUpdateSetItem item = this.exprParser.parseUpdateSetItem(); + update.addItem(item); if (lexer.token() != Token.COMMA) { break; diff --git a/src/test/java/com/alibaba/druid/bvt/sql/builder/BuilderDeleteTest.java b/src/test/java/com/alibaba/druid/bvt/sql/builder/BuilderDeleteTest.java new file mode 100644 index 0000000000..52df54d466 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/builder/BuilderDeleteTest.java @@ -0,0 +1,26 @@ +package com.alibaba.druid.bvt.sql.builder; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.sql.builder.SQLBuilderFactory; +import com.alibaba.druid.sql.builder.SQLDeleteBuilder; +import com.alibaba.druid.util.JdbcConstants; + +public class BuilderDeleteTest extends TestCase { + + public void test_0() throws Exception { + SQLDeleteBuilder builder = SQLBuilderFactory.createDeleteBuilder(JdbcConstants.MYSQL); + + builder // + .from("mytable") // + .whereAnd("f1 > 0") // + ; + + String sql = builder.toString(); + System.out.println(sql); + Assert.assertEquals("DELETE FROM mytable" // + + "\nWHERE f1 > 0", sql); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/builder/BuilderSelectTest.java b/src/test/java/com/alibaba/druid/bvt/sql/builder/BuilderSelectTest.java new file mode 100644 index 0000000000..c63c221ad8 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/builder/BuilderSelectTest.java @@ -0,0 +1,32 @@ +package com.alibaba.druid.bvt.sql.builder; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.sql.builder.SQLBuilderFactory; +import com.alibaba.druid.sql.builder.SQLSelectBuilder; +import com.alibaba.druid.util.JdbcConstants; + +public class BuilderSelectTest extends TestCase { + + public void test_0() throws Exception { + SQLSelectBuilder builder = SQLBuilderFactory.createSelectSQLBuilder(JdbcConstants.MYSQL); + + builder.from("mytable"); + builder.select("f1", "f2", "f3 F3", "count(*) cnt"); + builder.groupBy("f1"); + builder.having("count(*) > 1"); + builder.orderBy("f1", "f2 desc"); + builder.whereAnd("f1 > 0"); + + String sql = builder.toString(); + System.out.println(sql); + Assert.assertEquals("SELECT f1, f2, f3 AS F3, COUNT(*) AS cnt" // + + "\nFROM mytable"// + + "\nWHERE f1 > 0"// + + "\nGROUP BY f1"// + + "\nHAVING COUNT(*) > 1"// + + "\nORDER BY f1, f2 DESC", sql); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/builder/BuilderUpdateTest.java b/src/test/java/com/alibaba/druid/bvt/sql/builder/BuilderUpdateTest.java new file mode 100644 index 0000000000..61f8951995 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/builder/BuilderUpdateTest.java @@ -0,0 +1,27 @@ +package com.alibaba.druid.bvt.sql.builder; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.sql.builder.SQLBuilderFactory; +import com.alibaba.druid.sql.builder.SQLUpdateBuilder; +import com.alibaba.druid.util.JdbcConstants; + +public class BuilderUpdateTest extends TestCase { + + public void test_0() throws Exception { + SQLUpdateBuilder builder = SQLBuilderFactory.createUpdateBuilder(JdbcConstants.MYSQL); + + builder // + .from("mytable") // + .whereAnd("f1 > 0") // + .set("f1 = f1 + 1", "f2 = ?"); + + String sql = builder.toString(); + System.out.println(sql); + Assert.assertEquals("UPDATE mytable" // + + "\nSET f1 = f1 + 1, f2 = ?" // + + "\nWHERE f1 > 0", sql); + } +}