diff --git a/src/main/java/com/alibaba/druid/sql/SQLUtils.java b/src/main/java/com/alibaba/druid/sql/SQLUtils.java index b5347e57bd..d65b3b3281 100644 --- a/src/main/java/com/alibaba/druid/sql/SQLUtils.java +++ b/src/main/java/com/alibaba/druid/sql/SQLUtils.java @@ -18,10 +18,7 @@ package com.alibaba.druid.sql; import java.util.List; import java.util.Map; -import com.alibaba.druid.sql.ast.SQLExpr; -import com.alibaba.druid.sql.ast.SQLObject; -import com.alibaba.druid.sql.ast.SQLReplaceable; -import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.ast.*; import com.alibaba.druid.sql.ast.expr.*; import com.alibaba.druid.sql.ast.statement.*; import com.alibaba.druid.sql.dialect.db2.visitor.DB2OutputVisitor; @@ -803,6 +800,10 @@ public class SQLUtils { return name; } + public static boolean nameEquals(SQLName a, SQLName b) { + return nameEquals(a.getSimpleName(), b.getSimpleName()); + } + public static boolean nameEquals(String a, String b) { if (a == b) { return true; diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBinaryOpExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBinaryOpExpr.java index 5eb73c3c06..72d61a3b06 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBinaryOpExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBinaryOpExpr.java @@ -417,4 +417,16 @@ public class SQLBinaryOpExpr extends SQLExprImpl implements SQLReplaceable, Seri return null; } + + public boolean contains(SQLExpr item) { + if (item instanceof SQLBinaryOpExpr) { + if (this.equalsIgoreOrder((SQLBinaryOpExpr) item)) { + return true; + } + + return left.equals(item) || right.equals(item); + } + + return false; + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLIdentifierExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLIdentifierExpr.java index acbd8f5e5d..1b1a70b798 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLIdentifierExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLIdentifierExpr.java @@ -18,6 +18,7 @@ package com.alibaba.druid.sql.ast.expr; import com.alibaba.druid.sql.SQLUtils; import com.alibaba.druid.sql.ast.SQLExprImpl; import com.alibaba.druid.sql.ast.SQLName; +import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition; import com.alibaba.druid.sql.visitor.SQLASTVisitor; public class SQLIdentifierExpr extends SQLExprImpl implements SQLName { @@ -27,6 +28,8 @@ public class SQLIdentifierExpr extends SQLExprImpl implements SQLName { private transient String lowerName; private transient Boolean parameter; + private transient SQLColumnDefinition resolvedColumn; + public SQLIdentifierExpr(){ } @@ -136,4 +139,12 @@ public class SQLIdentifierExpr extends SQLExprImpl implements SQLName { public String normalizedName() { return SQLUtils.normalize(name); } + + public SQLColumnDefinition getResolvedColumn() { + return resolvedColumn; + } + + public void setResolvedColumn(SQLColumnDefinition resolvedColumn) { + this.resolvedColumn = resolvedColumn; + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLPropertyExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLPropertyExpr.java index 5037e4e7be..a39017b207 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLPropertyExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLPropertyExpr.java @@ -19,6 +19,7 @@ import com.alibaba.druid.sql.SQLUtils; import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLExprImpl; import com.alibaba.druid.sql.ast.SQLName; +import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition; import com.alibaba.druid.sql.parser.ParserException; import com.alibaba.druid.sql.visitor.SQLASTVisitor; @@ -27,6 +28,8 @@ public class SQLPropertyExpr extends SQLExprImpl implements SQLName { private SQLExpr owner; private String name; + private transient SQLColumnDefinition resolvedColumn; + public SQLPropertyExpr(String owner, String name){ this(new SQLIdentifierExpr(owner), name); } @@ -153,4 +156,12 @@ public class SQLPropertyExpr extends SQLExprImpl implements SQLName { return ownerName + '.' + SQLUtils.normalize(name); } + + public SQLColumnDefinition getResolvedColumn() { + return resolvedColumn; + } + + public void setResolvedColumn(SQLColumnDefinition resolvedColumn) { + this.resolvedColumn = resolvedColumn; + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLColumnDefinition.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLColumnDefinition.java index 6ea265fd5a..58f8cc076b 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLColumnDefinition.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLColumnDefinition.java @@ -366,4 +366,14 @@ public class SQLColumnDefinition extends SQLObjectImpl implements SQLTableElemen identExpr.setName(columnName); } } + + public boolean containsNotNullConstaint() { + for (SQLColumnConstraint constraint : this.constraints) { + if (constraint instanceof SQLNotNullConstraint) { + return true; + } + } + + return false; + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLCreateTableStatement.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLCreateTableStatement.java index eef2647e81..d9b617d30c 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLCreateTableStatement.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLCreateTableStatement.java @@ -15,18 +15,20 @@ */ package com.alibaba.druid.sql.ast.statement; +import java.io.IOException; import java.util.*; import com.alibaba.druid.sql.SQLUtils; import com.alibaba.druid.sql.ast.*; import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr; +import com.alibaba.druid.sql.dialect.mysql.ast.MySqlKey; +import com.alibaba.druid.sql.dialect.mysql.ast.MySqlUnique; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlTableIndex; import com.alibaba.druid.sql.visitor.SQLASTVisitor; -import com.alibaba.druid.util.JdbcConstants; +import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlShowColumnOutpuVisitor; import com.alibaba.druid.util.ListDG; import com.alibaba.druid.util.lang.Consumer; -import org.apache.ibatis.jdbc.SQL; public class SQLCreateTableStatement extends SQLStatementImpl implements SQLDDLStatement { @@ -192,6 +194,73 @@ public class SQLCreateTableStatement extends SQLStatementImpl implements SQLDDLS return null; } + public boolean isPrimaryColumn(String columnName) { + SQLPrimaryKey pk = this.findPrimaryKey(); + if (pk == null) { + return false; + } + + return pk.containsColumn(columnName); + } + + /** + * only for show columns + */ + public boolean isMUL(String columnName) { + for (SQLTableElement element : this.tableElementList) { + if (element instanceof MySqlUnique) { + MySqlUnique unique = (MySqlUnique) element; + + SQLExpr column = unique.getColumns().get(0); + if (column instanceof SQLIdentifierExpr + && SQLUtils.nameEquals(columnName, ((SQLIdentifierExpr) column).getName())) { + return unique.columns.size() > 1; + } + } else if (element instanceof MySqlKey) { + MySqlKey unique = (MySqlKey) element; + + SQLExpr column = unique.getColumns().get(0); + if (column instanceof SQLIdentifierExpr + && SQLUtils.nameEquals(columnName, ((SQLIdentifierExpr) column).getName())) { + return true; + } + } + } + return false; + } + + /** + * only for show columns + */ + public boolean isUNI(String columnName) { + for (SQLTableElement element : this.tableElementList) { + if (element instanceof MySqlUnique) { + MySqlUnique unique = (MySqlUnique) element; + + SQLExpr column = unique.getColumns().get(0); + if (column instanceof SQLIdentifierExpr + && SQLUtils.nameEquals(columnName, ((SQLIdentifierExpr) column).getName())) { + return unique.columns.size() == 1; + } + } + } + return false; + } + + public MySqlUnique findUnique(String columnName) { + for (SQLTableElement element : this.tableElementList) { + if (element instanceof MySqlUnique) { + MySqlUnique unique = (MySqlUnique) element; + + if (unique.containsColumn(columnName)) { + return unique; + } + } + } + + return null; + } + public SQLTableElement findIndex(String columnName) { for (SQLTableElement element : tableElementList) { List keyColumns = null; @@ -418,7 +487,6 @@ public class SQLCreateTableStatement extends SQLStatementImpl implements SQLDDLS } } } - } public void simplify() { @@ -453,4 +521,83 @@ public class SQLCreateTableStatement extends SQLStatementImpl implements SQLDDLS } } } + + public boolean apply(SQLAlterTableStatement alter) { + if (!SQLUtils.nameEquals(alter.getName(), this.getName())) { + return false; + } + + int applyCount = 0; + for (SQLAlterTableItem item : alter.getItems()) { + if (item instanceof SQLAlterTableDropColumnItem) { + if (apply((SQLAlterTableDropColumnItem) item)) { + applyCount++; + } + } else if (item instanceof SQLAlterTableAddColumn) { + if (apply((SQLAlterTableAddColumn) item)) { + applyCount++; + } + } + } + + return applyCount > 0; + } + + private boolean apply(SQLAlterTableDropColumnItem item) { + for (SQLName column : item.getColumns()) { + String columnName = column.getSimpleName(); + for (int i = tableElementList.size() - 1; i >= 0; --i) { + SQLTableElement e = tableElementList.get(i); + if (e instanceof SQLColumnDefinition) { + if (SQLUtils.nameEquals(columnName, ((SQLColumnDefinition) e).getName().getSimpleName())) { + tableElementList.remove(i); + } + } + } + } + return true; + } + + private boolean apply(SQLAlterTableAddColumn item) { + int startIndex = tableElementList.size(); + if (item.isFirst()) { + startIndex = 0; + } + + int afterIndex = columnIndexOf(item.getAfterColumn()); + if (afterIndex != -1) { + startIndex = afterIndex + 1; + } + + int beforeIndex = columnIndexOf(item.getFirstColumn()); + if (beforeIndex != -1) { + startIndex = beforeIndex; + } + + for (int i = 0; i < item.getColumns().size(); i++) { + SQLColumnDefinition column = item.getColumns().get(i); + tableElementList.add(i + startIndex, column); + column.setParent(this); + } + + return true; + } + + private int columnIndexOf(SQLName column) { + if (column == null) { + return -1; + } + + String columnName = column.getSimpleName(); + for (int i = tableElementList.size() - 1; i >= 0; --i) { + SQLTableElement e = tableElementList.get(i); + if (e instanceof SQLColumnDefinition) { + if (SQLUtils.nameEquals(columnName, ((SQLColumnDefinition) e).getName().getSimpleName())) { + return i; + } + } + } + + return -1; + } } 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 b046e6871b..cc476ac0de 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 @@ -21,6 +21,8 @@ import java.util.List; import com.alibaba.druid.sql.SQLUtils; import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLName; +import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; +import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr; import com.alibaba.druid.sql.repository.SchemaObject; import com.alibaba.druid.sql.visitor.SQLASTVisitor; @@ -150,4 +152,23 @@ public class SQLExprTableSource extends SQLTableSourceImpl { public void setSchemaObject(SchemaObject schemaObject) { this.schemaObject = schemaObject; } + + public boolean containsAlias(String alias) { + if (SQLUtils.nameEquals(this.alias, alias)) { + return true; + } + + String name = null; + if (expr instanceof SQLIdentifierExpr) { + name = ((SQLIdentifierExpr) expr).getName(); + } else if (expr instanceof SQLPropertyExpr) { + name = ((SQLPropertyExpr) expr).getName(); + } + + if (name != null && SQLUtils.nameEquals(name, alias)) { + return true; + } + + return false; + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLJoinTableSource.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLJoinTableSource.java index b0056b54eb..2f3df40074 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLJoinTableSource.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLJoinTableSource.java @@ -18,9 +18,13 @@ package com.alibaba.druid.sql.ast.statement; import java.util.ArrayList; import java.util.List; +import com.alibaba.druid.sql.SQLUtils; import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLReplaceable; +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.SQLPropertyExpr; import com.alibaba.druid.sql.visitor.SQLASTVisitor; public class SQLJoinTableSource extends SQLTableSourceImpl implements SQLReplaceable { @@ -121,6 +125,33 @@ public class SQLJoinTableSource extends SQLTableSourceImpl implements SQLReplace this.condition = condition; } + public void addConditionn(SQLExpr condition) { + this.condition = SQLBinaryOpExpr.and(this.condition, condition); + } + + public void addConditionnIfAbsent(SQLExpr condition) { + if (this.containsCondition(condition)) { + return; + } + this.condition = SQLBinaryOpExpr.and(this.condition, condition); + } + + public boolean containsCondition(SQLExpr condition) { + if (this.condition == null) { + return false; + } + + if (this.condition.equals(condition)) { + return false; + } + + if (this.condition instanceof SQLBinaryOpExpr) { + return ((SQLBinaryOpExpr) this.condition).contains(condition); + } + + return false; + } + public List getUsing() { return this.using; } @@ -247,6 +278,9 @@ public class SQLJoinTableSource extends SQLTableSourceImpl implements SQLReplace * a inner_join (b inner_join c) -< a inner_join b innre_join c */ public void rearrangement() { + if (joinType != JoinType.COMMA && joinType != JoinType.INNER_JOIN) { + return; + } if (right instanceof SQLJoinTableSource) { SQLJoinTableSource rightJoin = (SQLJoinTableSource) right; @@ -259,10 +293,79 @@ public class SQLJoinTableSource extends SQLTableSourceImpl implements SQLReplace setLeft(rightJoin); rightJoin.setLeft(a); rightJoin.setRight(b); - rightJoin.setCondition(on_ab); + + + boolean on_ab_match = false; + if (on_ab instanceof SQLBinaryOpExpr) { + SQLBinaryOpExpr on_ab_binaryOpExpr = (SQLBinaryOpExpr) on_ab; + if (on_ab_binaryOpExpr.getLeft() instanceof SQLPropertyExpr + && on_ab_binaryOpExpr.getRight() instanceof SQLPropertyExpr) { + String leftOwnerName = ((SQLPropertyExpr) on_ab_binaryOpExpr.getLeft()).getOwnernName(); + String rightOwnerName = ((SQLPropertyExpr) on_ab_binaryOpExpr.getRight()).getOwnernName(); + + if (rightJoin.containsAlias(leftOwnerName) && rightJoin.containsAlias(rightOwnerName)) { + on_ab_match = true; + } + } + } + + if (on_ab_match) { + rightJoin.setCondition(on_ab); + } else { + rightJoin.setCondition(null); + on_bc = SQLBinaryOpExpr.and(on_bc, on_ab); + } setRight(c); setCondition(on_bc); } } + + public boolean contains(SQLTableSource tableSource, SQLExpr conditionn) { + if (right.equals(tableSource)) { + if (this.condition == conditionn) { + return true; + } + + return this.condition != null && this.condition.equals(conditionn); + } + + if (left instanceof SQLJoinTableSource) { + return ((SQLJoinTableSource) left).contains(tableSource, conditionn); + } + + return false; + } + + public SQLJoinTableSource findJoin(SQLTableSource tableSource, JoinType joinType) { + if (right.equals(tableSource)) { + if (this.joinType == joinType) { + return this; + } + return null; + } + + if (left instanceof SQLJoinTableSource) { + return ((SQLJoinTableSource) left).findJoin(tableSource, joinType); + } + + return null; + } + + public boolean containsAlias(String alias) { + if (SQLUtils.nameEquals(this.alias, alias)) { + return true; + } + + if (left != null && left.containsAlias(alias)) { + return true; + } + + if (right != null && right.containsAlias(alias)) { + return true; + } + + return false; + } + } 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 a3987ab66b..fa63725bc1 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 @@ -162,6 +162,26 @@ public class SQLSelectQueryBlock extends SQLObjectImpl implements SQLSelectQuery this.from = from; } + public void setFrom(SQLSelectQueryBlock queryBlock, String alias) { + if (queryBlock == null) { + this.from = null; + return; + } + + this.setFrom(new SQLSelect(queryBlock), alias); + } + + public void setFrom(SQLSelect select, String alias) { + if (select == null) { + this.from = null; + return; + } + + SQLSubqueryTableSource from = new SQLSubqueryTableSource(select); + from.setAlias(alias); + this.setFrom(from); + } + public void setFrom(String tableName, String alias) { SQLExprTableSource from; if (tableName == null || tableName.length() == 0) { @@ -436,6 +456,10 @@ public class SQLSelectQueryBlock extends SQLObjectImpl implements SQLSelectQuery return findTableSource(join.getRight(), alias); } + if (from instanceof SQLExprTableSource && from.containsAlias(alias)) { + return from; + } + return null; } @@ -481,4 +505,32 @@ public class SQLSelectQueryBlock extends SQLObjectImpl implements SQLSelectQuery setLimit(limit); } + + public int selectIndexOf(SQLExpr expr) { + String ident = null; + if (expr instanceof SQLIdentifierExpr) { + ident = ((SQLIdentifierExpr) expr).getName(); + } + + for (int i = 0; i < selectList.size(); i++) { + SQLSelectItem selectItem = selectList.get(i); + if (ident != null && SQLUtils.nameEquals(ident, selectItem.alias)) { + return i; + } + + SQLExpr selectItemExpr = selectItem.getExpr(); + if (selectItemExpr instanceof SQLName) { + String name = ((SQLName) selectItemExpr).getSimpleName(); + if (SQLUtils.nameEquals(ident, name)) { + return i; + } + } + + if (expr.equals(selectItemExpr)) { + return i; + } + } + + return -1; + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLTableSource.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLTableSource.java index 7d832681f0..8fe61bc508 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLTableSource.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLTableSource.java @@ -32,6 +32,7 @@ public interface SQLTableSource extends SQLObject { SQLTableSource clone(); String computeAlias(); + boolean containsAlias(String alias); SQLExpr getFlashback(); void setFlashback(SQLExpr flashback); diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLTableSourceImpl.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLTableSourceImpl.java index b61053acee..2d9cd90263 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLTableSourceImpl.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLTableSourceImpl.java @@ -18,6 +18,7 @@ package com.alibaba.druid.sql.ast.statement; import java.util.ArrayList; import java.util.List; +import com.alibaba.druid.sql.SQLUtils; import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLHint; import com.alibaba.druid.sql.ast.SQLObjectImpl; @@ -84,4 +85,13 @@ public abstract class SQLTableSourceImpl extends SQLObjectImpl implements SQLTab } this.flashback = flashback; } + + + public boolean containsAlias(String alias) { + if (SQLUtils.nameEquals(this.alias, alias)) { + return true; + } + + return false; + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLUnique.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLUnique.java index 23d0c2d248..089bb5f033 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLUnique.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLUnique.java @@ -52,6 +52,17 @@ public class SQLUnique extends SQLConstraintImpl implements SQLUniqueConstraint, visitor.endVisit(this); } + public boolean containsColumn(String column) { + for (SQLExpr expr : columns) { + if (expr instanceof SQLIdentifierExpr) { + if (SQLUtils.nameEquals(((SQLIdentifierExpr) expr).getName(), column)) { + return true; + } + } + } + return false; + } + public void cloneTo(SQLUnique x) { super.cloneTo(x); diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLUniqueConstraint.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLUniqueConstraint.java index 6c98e491e7..de7691fa90 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLUniqueConstraint.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLUniqueConstraint.java @@ -23,4 +23,5 @@ public interface SQLUniqueConstraint extends SQLConstraint { List getColumns(); + boolean containsColumn(String column); } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlCreateTableStatement.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlCreateTableStatement.java index b6d718b538..5971e69d9d 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlCreateTableStatement.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlCreateTableStatement.java @@ -15,11 +15,13 @@ */ package com.alibaba.druid.sql.dialect.mysql.ast.statement; +import java.io.IOException; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import com.alibaba.druid.sql.SQLUtils; import com.alibaba.druid.sql.ast.SQLCommentHint; import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLName; @@ -30,6 +32,7 @@ import com.alibaba.druid.sql.ast.statement.SQLExprTableSource; import com.alibaba.druid.sql.ast.statement.SQLSelect; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlObjectImpl; import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitor; +import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlShowColumnOutpuVisitor; import com.alibaba.druid.sql.visitor.SQLASTVisitor; import com.alibaba.druid.util.JdbcConstants; @@ -174,4 +177,26 @@ public class MySqlCreateTableStatement extends SQLCreateTableStatement implement tableOptions.clear(); super.simplify(); } + + public void showCoumns(Appendable out) throws IOException { + this.accept(new MySqlShowColumnOutpuVisitor(out)); + } + + public boolean apply(MySqlRenameTableStatement x) { + for (MySqlRenameTableStatement.Item item : x.getItems()) { + if (apply(item)) { + return true; + } + } + + return false; + } + + public boolean apply(MySqlRenameTableStatement.Item item) { + if (!SQLUtils.nameEquals((SQLName) item.getName(), this.getName())) { + return false; + } + this.setName((SQLName) item.getTo().clone()); + return true; + } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlSelectParser.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlSelectParser.java index e4ce665892..4bc84e0050 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlSelectParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlSelectParser.java @@ -186,7 +186,7 @@ public class MySqlSelectParser extends SQLSelectParser { queryBlock.setForUpdate(true); - if (identifierEquals("NO_WAIT")) { + if (identifierEquals("NO_WAIT") || identifierEquals("NOWAIT")) { lexer.nextToken(); queryBlock.setNoWait(true); } else if (identifierEquals("WAIT")) { diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java index 93ebd3b62d..a406f6774b 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java @@ -306,7 +306,7 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV println(); print0(ucase ? "FOR UPDATE" : "for update"); if (x.isNoWait()) { - print0(ucase ? " NO_WAIT" : " no_wait"); + print0(ucase ? " NOWAIT" : " nowait"); } else if (x.getWaitTime() != null) { print0(ucase ? " WAIT " : " wait "); x.getWaitTime().accept(this); diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlShowColumnOutpuVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlShowColumnOutpuVisitor.java new file mode 100644 index 0000000000..96fec7acbc --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlShowColumnOutpuVisitor.java @@ -0,0 +1,180 @@ +package com.alibaba.druid.sql.dialect.mysql.visitor; + +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLExpr; +import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition; +import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement; +import com.alibaba.druid.sql.ast.statement.SQLTableElement; +import com.alibaba.druid.sql.dialect.mysql.ast.MySqlUnique; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement; +import com.alibaba.druid.sql.visitor.SQLASTOutputVisitor; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by wenshao on 27/07/2017. + */ +public class MySqlShowColumnOutpuVisitor extends MySqlOutputVisitor { + public MySqlShowColumnOutpuVisitor(Appendable appender) { + super(appender); + } + + public boolean visit(MySqlCreateTableStatement x) { + List columns = new ArrayList(); + List dataTypes = new ArrayList(); + List defaultValues = new ArrayList(); + + int name_len = -1, dataType_len = -1, defaultVal_len = -1, extra_len = 5; + for (SQLTableElement element : x.getTableElementList()) { + if (element instanceof SQLColumnDefinition) { + SQLColumnDefinition column = (SQLColumnDefinition) element; + columns.add(column); + + String name = SQLUtils.normalize(column.getName().getSimpleName()); + if (name_len < name.length()) { + name_len = name.length(); + } + + String dataType = column.getDataType().getName(); + if (column.getDataType().getArguments().size() > 0) { + dataType += "("; + for (int i = 0; i < column.getDataType().getArguments().size(); i++) { + if (i != 0) { + dataType += ","; + } + SQLExpr arg = column.getDataType().getArguments().get(i); + dataType += arg.toString(); + } + dataType += ")"; + } + + if (dataType_len < dataType.length()) { + dataType_len = dataType.length(); + } + dataTypes.add(dataType); + + if (column.getDefaultExpr() == null) { + defaultValues.add(null); + } else { + String defaultVal = SQLUtils.toMySqlString(column.getDefaultExpr()); + if (defaultVal.length() > 2 && defaultVal.charAt(0) == '\'' && defaultVal.charAt(defaultVal.length() - 1) == '\'') { + defaultVal = defaultVal.substring(1, defaultVal.length() - 1); + } + defaultValues.add(defaultVal); + + if (defaultVal_len < defaultVal.length()) { + defaultVal_len = defaultVal.length(); + } + } + + if (column.isAutoIncrement()) { + extra_len = "auto_increment".length(); + } else if (column.getOnUpdate() != null) { + extra_len = "on update CURRENT_TIMESTAMP".length(); + } + } + } + + print("+-"); + print('-', name_len); + print("-+-"); + print('-', dataType_len); + print("-+------+-----+-"); + print('-', defaultVal_len); + print("-+-"); + print('-', extra_len); + print("-+\n"); + + print("| "); + print("Field", name_len, ' '); + print(" | "); + print("Type", dataType_len, ' '); + print(" | Null | Key | "); + print("Default", defaultVal_len, ' '); + print(" | "); + print("Extra", extra_len, ' '); + print(" |\n"); + + print("+-"); + print('-', name_len); + print("-+-"); + print('-', dataType_len); + print("-+------+-----+-"); + print('-', defaultVal_len); + print("-+-"); + print('-', extra_len); + print("-+\n"); + + for (int i = 0; i < columns.size(); i++) { + SQLColumnDefinition column = columns.get(i); + String name = SQLUtils.normalize(column.getName().getSimpleName()); + + print("| "); + print(name, name_len, ' '); + print(" | "); + + print(dataTypes.get(i), dataType_len, ' '); + print(" | "); + + if (column.containsNotNullConstaint()) { + print("YES"); + } else { + print("NO "); + } + print(" | "); + + MySqlUnique unique = null; + if (x.isPrimaryColumn(name)) { + print("PRI"); + } else if (x.isUNI(name)) { + print("UNI"); + } else if (x.isMUL(name)) { + print("MUL"); + } else { + print(" "); + } + print(" | "); + + String defaultVal = defaultValues.get(i); + if (defaultVal == null) { + print("NULL", defaultVal_len, ' '); + } else { + print(defaultVal, defaultVal_len, ' '); + } + print(" | "); + + if (column.isAutoIncrement()) { + print("auto_increment", extra_len, ' '); + } else if (column.getOnUpdate() != null) { + print("on update CURRENT_TIMESTAMP", extra_len, ' '); + } else { + print(' ', extra_len); + } + print(" |"); + print("\n"); + } + print("+-"); + print('-', name_len); + print("-+-"); + print('-', dataType_len); + print("-+------+-----+-"); + print('-', defaultVal_len); + print("-+-"); + print('-', extra_len); + print("-+\n"); + + return false; + } + + void print(char ch, int count) { + for (int i = 0; i < count; ++i) { + print(ch); + } + } + + void print(String text, int columnSize, char ch) { + print(text); + print(' ', columnSize - text.length()); + } +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/transform/NameResolveVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/transform/NameResolveVisitor.java new file mode 100644 index 0000000000..27f9775038 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/transform/NameResolveVisitor.java @@ -0,0 +1,72 @@ +/* + * Copyright 1999-2017 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.druid.sql.dialect.mysql.visitor.transform; + +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLName; +import com.alibaba.druid.sql.ast.SQLObject; +import com.alibaba.druid.sql.ast.expr.*; +import com.alibaba.druid.sql.ast.statement.*; +import com.alibaba.druid.sql.dialect.oracle.visitor.OracleASTVisitorAdapter; + +/** + * Created by wenshao on 26/07/2017. + */ +public class NameResolveVisitor extends OracleASTVisitorAdapter { + public boolean visit(SQLIdentifierExpr x) { + SQLObject parent = x.getParent(); + String name = x.getName(); + + if ("ROWNUM".equalsIgnoreCase(name)) { + return false; + } + + if (parent instanceof SQLPropertyExpr) { + return false; + } + + for (; parent != null; parent = parent.getParent()) { + if (parent instanceof SQLTableSource) { + return false; + } + + if (parent instanceof SQLSelectQueryBlock) { + SQLSelectQueryBlock queryBlock = (SQLSelectQueryBlock) parent; + + if (queryBlock.getInto() != null) { + return false; + } + + if (queryBlock.getParent() instanceof SQLSelect) { + SQLObject pp = queryBlock.getParent().getParent(); + if (pp instanceof SQLInSubQueryExpr || pp instanceof SQLExistsExpr) { + return false; + } + } + + SQLTableSource from = queryBlock.getFrom(); + if (from instanceof SQLExprTableSource || from instanceof SQLSubqueryTableSource) { + String alias = from.getAlias(); + if (alias != null) { + SQLUtils.replaceInParent(x, new SQLPropertyExpr(alias, name)); + } + } + return false; + } + } + return true; + } +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/transform/OrderByResolve.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/transform/OrderByResolve.java new file mode 100644 index 0000000000..e7f8c408c4 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/transform/OrderByResolve.java @@ -0,0 +1,69 @@ +/* + * Copyright 1999-2017 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.druid.sql.dialect.mysql.visitor.transform; + +import com.alibaba.druid.sql.ast.SQLExpr; +import com.alibaba.druid.sql.ast.SQLOrderBy; +import com.alibaba.druid.sql.ast.statement.SQLSelect; +import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem; +import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectQueryBlock; +import com.alibaba.druid.sql.dialect.oracle.visitor.OracleASTVisitorAdapter; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by wenshao on 27/07/2017. + */ +public class OrderByResolve extends OracleASTVisitorAdapter { + public boolean visit(SQLSelect x) { + SQLSelectQueryBlock queryBlock = x.getQueryBlock(); + if (queryBlock == null) { + return super.visit(x); + } + + if (x.getOrderBy() != null && queryBlock.isForUpdate() && queryBlock.getOrderBy() == null) { + queryBlock.setOrderBy(x.getOrderBy()); + x.setOrderBy(null); + } + + SQLOrderBy orderBy = queryBlock.getOrderBy(); + if (orderBy == null) { + return super.visit(x); + } + + List notContainsOrderBy = new ArrayList(); + for (SQLSelectOrderByItem orderByItem : orderBy.getItems()) { + SQLExpr orderByExpr = orderByItem.getExpr(); + if (queryBlock.selectIndexOf(orderByExpr) == -1) { + notContainsOrderBy.add(orderByItem); + } + } + + if (notContainsOrderBy.size() > 0) { + for (SQLSelectOrderByItem orderByItem : notContainsOrderBy) { + queryBlock.addSelectItem(orderByItem.getExpr()); + } + + OracleSelectQueryBlock queryBlock1 = new OracleSelectQueryBlock(); + queryBlock1.setFrom(queryBlock, "x"); + x.setQuery(queryBlock1); + } + + return super.visit(x); + } +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGExprParser.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGExprParser.java index f594722b38..f7c8bbde07 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGExprParser.java @@ -134,6 +134,10 @@ public class PGExprParser extends SQLExprParser { if (expr.getClass() == SQLIdentifierExpr.class) { String ident = ((SQLIdentifierExpr)expr).getName(); + + if (lexer.token() == Token.COMMA) { + return super.primaryRest(expr); + } if ("TIMESTAMP".equalsIgnoreCase(ident)) { if (lexer.token() != Token.LITERAL_ALIAS // diff --git a/src/test/java/com/alibaba/druid/bvt/sql/mysql/select/MySqlCreateTable_showColumns_repository_test.java b/src/test/java/com/alibaba/druid/bvt/sql/mysql/select/MySqlCreateTable_showColumns_repository_test.java new file mode 100644 index 0000000000..0a7d58aff1 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/mysql/select/MySqlCreateTable_showColumns_repository_test.java @@ -0,0 +1,155 @@ +/* + * Copyright 1999-2017 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.druid.bvt.sql.mysql.select; + +import com.alibaba.druid.sql.MysqlTest; +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.ast.statement.SQLAlterTableStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement; +import com.alibaba.druid.util.JdbcConstants; + +import java.util.List; + +public class MySqlCreateTable_showColumns_repository_test extends MysqlTest { + + public void test_0() throws Exception { + String sql = "CREATE TABLE `test1` (\n" + + " `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',\n" + + " `c_tinyint` tinyint(4) DEFAULT '1' COMMENT 'tinyint',\n" + + " `c_smallint` smallint(6) DEFAULT 0 COMMENT 'smallint',\n" + + " `c_mediumint` mediumint(9) DEFAULT NULL COMMENT 'mediumint',\n" + + " `c_int` int(11) DEFAULT NULL COMMENT 'int',\n" + + " `c_bigint` bigint(20) DEFAULT NULL COMMENT 'bigint',\n" + + " `c_decimal` decimal(10,3) DEFAULT NULL COMMENT 'decimal',\n" + + " `c_date` date DEFAULT '0000-00-00' COMMENT 'date',\n" + + " `c_datetime` datetime DEFAULT '0000-00-00 00:00:00' COMMENT 'datetime',\n" + + " `c_timestamp` timestamp NULL DEFAULT NULL COMMENT 'timestamp' ON UPDATE CURRENT_TIMESTAMP ,\n" + + " `c_time` time DEFAULT NULL COMMENT 'time',\n" + + " `c_char` char(10) DEFAULT NULL COMMENT 'char',\n" + + " `c_varchar` varchar(10) DEFAULT 'hello' COMMENT 'varchar',\n" + + " `c_blob` blob COMMENT 'blob',\n" + + " `c_text` text COMMENT 'text',\n" + + " `c_mediumtext` mediumtext COMMENT 'mediumtext',\n" + + " `c_longblob` longblob COMMENT 'longblob',\n" + + " PRIMARY KEY (`id`,`c_tinyint`),\n" + + " UNIQUE KEY `uk_a` (`c_varchar`,`c_mediumint`),\n" + + " KEY `k_c` (`c_tinyint`,`c_int`),\n" + + " KEY `k_d` (`c_char`,`c_bigint`)\n" + + ") ENGINE=InnoDB AUTO_INCREMENT=1769503 DEFAULT CHARSET=utf8mb4 COMMENT='10000000'"; + + + MySqlCreateTableStatement createTableStmt; + { + List statementList = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL, true); + assertEquals(1, statementList.size()); + createTableStmt = (MySqlCreateTableStatement) statementList.get(0); + } + assertEquals(21, createTableStmt.getTableElementList().size()); + + StringBuilder buf = new StringBuilder(); + createTableStmt.showCoumns(buf); + + assertEquals("+--------------+---------------+------+-----+---------------------+-----------------------------+\n" + + "| Field | Type | Null | Key | Default | Extra |\n" + + "+--------------+---------------+------+-----+---------------------+-----------------------------+\n" + + "| id | bigint(20) | YES | PRI | NULL | auto_increment |\n" + + "| c_tinyint | tinyint(4) | NO | PRI | 1 | |\n" + + "| c_smallint | smallint(6) | NO | | 0 | |\n" + + "| c_mediumint | mediumint(9) | NO | | NULL | |\n" + + "| c_int | int(11) | NO | | NULL | |\n" + + "| c_bigint | bigint(20) | NO | | NULL | |\n" + + "| c_decimal | decimal(10,3) | NO | | NULL | |\n" + + "| c_date | date | NO | | 0000-00-00 | |\n" + + "| c_datetime | datetime | NO | | 0000-00-00 00:00:00 | |\n" + + "| c_timestamp | timestamp | NO | | NULL | on update CURRENT_TIMESTAMP |\n" + + "| c_time | time | NO | | NULL | |\n" + + "| c_char | char(10) | NO | MUL | NULL | |\n" + + "| c_varchar | varchar(10) | NO | MUL | hello | |\n" + + "| c_blob | blob | NO | | NULL | |\n" + + "| c_text | text | NO | | NULL | |\n" + + "| c_mediumtext | mediumtext | NO | | NULL | |\n" + + "| c_longblob | longblob | NO | | NULL | |\n" + + "+--------------+---------------+------+-----+---------------------+-----------------------------+\n", buf.toString()); + + SQLAlterTableStatement stmtDropColumn; + { + List statementList = SQLUtils.parseStatements("alter table test1 drop column c_decimal;", JdbcConstants.MYSQL, true); + assertEquals(1, statementList.size()); + stmtDropColumn = (SQLAlterTableStatement) statementList.get(0); + } + createTableStmt.apply(stmtDropColumn); + assertEquals(20, createTableStmt.getTableElementList().size()); + + buf.delete(0, buf.length()); + createTableStmt.showCoumns(buf); + assertEquals("+--------------+--------------+------+-----+---------------------+-----------------------------+\n" + + "| Field | Type | Null | Key | Default | Extra |\n" + + "+--------------+--------------+------+-----+---------------------+-----------------------------+\n" + + "| id | bigint(20) | YES | PRI | NULL | auto_increment |\n" + + "| c_tinyint | tinyint(4) | NO | PRI | 1 | |\n" + + "| c_smallint | smallint(6) | NO | | 0 | |\n" + + "| c_mediumint | mediumint(9) | NO | | NULL | |\n" + + "| c_int | int(11) | NO | | NULL | |\n" + + "| c_bigint | bigint(20) | NO | | NULL | |\n" + + "| c_date | date | NO | | 0000-00-00 | |\n" + + "| c_datetime | datetime | NO | | 0000-00-00 00:00:00 | |\n" + + "| c_timestamp | timestamp | NO | | NULL | on update CURRENT_TIMESTAMP |\n" + + "| c_time | time | NO | | NULL | |\n" + + "| c_char | char(10) | NO | MUL | NULL | |\n" + + "| c_varchar | varchar(10) | NO | MUL | hello | |\n" + + "| c_blob | blob | NO | | NULL | |\n" + + "| c_text | text | NO | | NULL | |\n" + + "| c_mediumtext | mediumtext | NO | | NULL | |\n" + + "| c_longblob | longblob | NO | | NULL | |\n" + + "+--------------+--------------+------+-----+---------------------+-----------------------------+\n", buf.toString()); + + SQLAlterTableStatement stmtAddColumn; + { + List statementList = SQLUtils.parseStatements("alter table test1 add column c_decimal decimal(10,3) DEFAULT NULL COMMENT 'decimal';", JdbcConstants.MYSQL, true); + assertEquals(1, statementList.size()); + stmtAddColumn = (SQLAlterTableStatement) statementList.get(0); + } + createTableStmt.apply(stmtAddColumn); + assertEquals(21, createTableStmt.getTableElementList().size()); + + buf.delete(0, buf.length()); + createTableStmt.showCoumns(buf); + assertEquals("+--------------+---------------+------+-----+---------------------+-----------------------------+\n" + + "| Field | Type | Null | Key | Default | Extra |\n" + + "+--------------+---------------+------+-----+---------------------+-----------------------------+\n" + + "| id | bigint(20) | YES | PRI | NULL | auto_increment |\n" + + "| c_tinyint | tinyint(4) | NO | PRI | 1 | |\n" + + "| c_smallint | smallint(6) | NO | | 0 | |\n" + + "| c_mediumint | mediumint(9) | NO | | NULL | |\n" + + "| c_int | int(11) | NO | | NULL | |\n" + + "| c_bigint | bigint(20) | NO | | NULL | |\n" + + "| c_date | date | NO | | 0000-00-00 | |\n" + + "| c_datetime | datetime | NO | | 0000-00-00 00:00:00 | |\n" + + "| c_timestamp | timestamp | NO | | NULL | on update CURRENT_TIMESTAMP |\n" + + "| c_time | time | NO | | NULL | |\n" + + "| c_char | char(10) | NO | MUL | NULL | |\n" + + "| c_varchar | varchar(10) | NO | MUL | hello | |\n" + + "| c_blob | blob | NO | | NULL | |\n" + + "| c_text | text | NO | | NULL | |\n" + + "| c_mediumtext | mediumtext | NO | | NULL | |\n" + + "| c_longblob | longblob | NO | | NULL | |\n" + + "| c_decimal | decimal(10,3) | NO | | NULL | |\n" + + "+--------------+---------------+------+-----+---------------------+-----------------------------+\n", buf.toString()); + + //System.out.println(buf.toString()); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/mysql/select/MySqlCreateTable_showColumns_test.java b/src/test/java/com/alibaba/druid/bvt/sql/mysql/select/MySqlCreateTable_showColumns_test.java new file mode 100644 index 0000000000..c6adbf0019 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/mysql/select/MySqlCreateTable_showColumns_test.java @@ -0,0 +1,87 @@ +/* + * Copyright 1999-2017 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.druid.bvt.sql.mysql.select; + +import com.alibaba.druid.sql.MysqlTest; +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement; +import com.alibaba.druid.sql.visitor.SchemaStatVisitor; +import com.alibaba.druid.util.JdbcConstants; + +import java.util.List; + +public class MySqlCreateTable_showColumns_test extends MysqlTest { + + public void test_0() throws Exception { + String sql = "CREATE TABLE `test1` (\n" + + " `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',\n" + + " `c_tinyint` tinyint(4) DEFAULT '1' COMMENT 'tinyint',\n" + + " `c_smallint` smallint(6) DEFAULT 0 COMMENT 'smallint',\n" + + " `c_mediumint` mediumint(9) DEFAULT NULL COMMENT 'mediumint',\n" + + " `c_int` int(11) DEFAULT NULL COMMENT 'int',\n" + + " `c_bigint` bigint(20) DEFAULT NULL COMMENT 'bigint',\n" + + " `c_decimal` decimal(10,3) DEFAULT NULL COMMENT 'decimal',\n" + + " `c_date` date DEFAULT '0000-00-00' COMMENT 'date',\n" + + " `c_datetime` datetime DEFAULT '0000-00-00 00:00:00' COMMENT 'datetime',\n" + + " `c_timestamp` timestamp NULL DEFAULT NULL COMMENT 'timestamp' ON UPDATE CURRENT_TIMESTAMP ,\n" + + " `c_time` time DEFAULT NULL COMMENT 'time',\n" + + " `c_char` char(10) DEFAULT NULL COMMENT 'char',\n" + + " `c_varchar` varchar(10) DEFAULT 'hello' COMMENT 'varchar',\n" + + " `c_blob` blob COMMENT 'blob',\n" + + " `c_text` text COMMENT 'text',\n" + + " `c_mediumtext` mediumtext COMMENT 'mediumtext',\n" + + " `c_longblob` longblob COMMENT 'longblob',\n" + + " PRIMARY KEY (`id`,`c_tinyint`),\n" + + " UNIQUE KEY `uk_a` (`c_varchar`,`c_mediumint`),\n" + + " KEY `k_c` (`c_tinyint`,`c_int`),\n" + + " KEY `k_d` (`c_char`,`c_bigint`)\n" + + ") ENGINE=InnoDB AUTO_INCREMENT=1769503 DEFAULT CHARSET=utf8mb4 COMMENT='10000000'"; + + + List statementList = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL, true); + + assertEquals(1, statementList.size()); + + MySqlCreateTableStatement stmt = (MySqlCreateTableStatement) statementList.get(0); + + + StringBuilder buf = new StringBuilder(); + stmt.showCoumns(buf); + + assertEquals("+--------------+---------------+------+-----+---------------------+-----------------------------+\n" + + "| Field | Type | Null | Key | Default | Extra |\n" + + "+--------------+---------------+------+-----+---------------------+-----------------------------+\n" + + "| id | bigint(20) | YES | PRI | NULL | auto_increment |\n" + + "| c_tinyint | tinyint(4) | NO | PRI | 1 | |\n" + + "| c_smallint | smallint(6) | NO | | 0 | |\n" + + "| c_mediumint | mediumint(9) | NO | | NULL | |\n" + + "| c_int | int(11) | NO | | NULL | |\n" + + "| c_bigint | bigint(20) | NO | | NULL | |\n" + + "| c_decimal | decimal(10,3) | NO | | NULL | |\n" + + "| c_date | date | NO | | 0000-00-00 | |\n" + + "| c_datetime | datetime | NO | | 0000-00-00 00:00:00 | |\n" + + "| c_timestamp | timestamp | NO | | NULL | on update CURRENT_TIMESTAMP |\n" + + "| c_time | time | NO | | NULL | |\n" + + "| c_char | char(10) | NO | MUL | NULL | |\n" + + "| c_varchar | varchar(10) | NO | MUL | hello | |\n" + + "| c_blob | blob | NO | | NULL | |\n" + + "| c_text | text | NO | | NULL | |\n" + + "| c_mediumtext | mediumtext | NO | | NULL | |\n" + + "| c_longblob | longblob | NO | | NULL | |\n" + + "+--------------+---------------+------+-----+---------------------+-----------------------------+\n", buf.toString()); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/mysql/select/MySqlSelectTest_49_for_update_no_wait.java b/src/test/java/com/alibaba/druid/bvt/sql/mysql/select/MySqlSelectTest_49_for_update_no_wait.java new file mode 100644 index 0000000000..4c82b3f0d3 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/mysql/select/MySqlSelectTest_49_for_update_no_wait.java @@ -0,0 +1,82 @@ +/* + * Copyright 1999-2017 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.druid.bvt.sql.mysql.select; + +import com.alibaba.druid.sql.MysqlTest; +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.visitor.SchemaStatVisitor; +import com.alibaba.druid.util.JdbcConstants; + +import java.util.List; + +public class MySqlSelectTest_49_for_update_no_wait extends MysqlTest { + + public void test_0() throws Exception { + String sql = "select /*MS-ARCORE-AR-II-M-QUERY-IN-LOCK-BY-AR-NOS*/ /*+INDEX(AR_II_M_004 PRIMARY) */ tnt_inst_id, ar_no, ar_nm, ar_tp_code, ar_entity_type " + + "from tb_001 " + + "where tnt_inst_id = ?" + + " and ar_no in ( ? ) for update no_wait"; + + + List statementList = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL, true); + SQLStatement stmt = statementList.get(0); + + assertEquals(1, statementList.size()); + + SchemaStatVisitor visitor = SQLUtils.createSchemaStatVisitor(JdbcConstants.MYSQL); + stmt.accept(visitor); + +// System.out.println("Tables : " + visitor.getTables()); + System.out.println("fields : " + visitor.getColumns()); +// System.out.println("coditions : " + visitor.getConditions()); +// System.out.println("orderBy : " + visitor.getOrderByColumns()); + +// assertEquals(1, visitor.getTables().size()); +// assertEquals(1, visitor.getColumns().size()); +// assertEquals(0, visitor.getConditions().size()); +// assertEquals(0, visitor.getOrderByColumns().size()); + + { + String output = SQLUtils.toMySqlString(stmt); + assertEquals("SELECT /*+INDEX(AR_II_M_004 PRIMARY) */ tnt_inst_id, ar_no, ar_nm, ar_tp_code, ar_entity_type\n" + + "FROM tb_001\n" + + "WHERE tnt_inst_id = ?\n" + + "\tAND ar_no IN (?)\n" + + "FOR UPDATE NOWAIT", // + output); + } + { + String output = SQLUtils.toMySqlString(stmt, SQLUtils.DEFAULT_LCASE_FORMAT_OPTION); + assertEquals("select /*+INDEX(AR_II_M_004 PRIMARY) */ tnt_inst_id, ar_no, ar_nm, ar_tp_code, ar_entity_type\n" + + "from tb_001\n" + + "where tnt_inst_id = ?\n" + + "\tand ar_no in (?)\n" + + "for update nowait", // + output); + } + + { + String output = SQLUtils.toMySqlString(stmt, new SQLUtils.FormatOption(true, true, true)); + assertEquals("SELECT /*+INDEX(AR_II_M_004 PRIMARY) */ tnt_inst_id, ar_no, ar_nm, ar_tp_code, ar_entity_type\n" + + "FROM tb\n" + + "WHERE tnt_inst_id = ?\n" + + "\tAND ar_no IN (?)\n" + + "FOR UPDATE NOWAIT", // + output); + } + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/oracle/select/OracleSelectTest71.java b/src/test/java/com/alibaba/druid/bvt/sql/oracle/select/OracleSelectTest71.java new file mode 100644 index 0000000000..419e0e44dc --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/oracle/select/OracleSelectTest71.java @@ -0,0 +1,114 @@ +/* + * Copyright 1999-2017 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.druid.bvt.sql.oracle.select; + +import com.alibaba.druid.sql.OracleTest; +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.dialect.oracle.parser.OracleStatementParser; +import com.alibaba.druid.sql.dialect.oracle.visitor.OracleSchemaStatVisitor; +import org.junit.Assert; + +import java.util.List; + +public class OracleSelectTest71 extends OracleTest { + + public void test_0() throws Exception { + String sql = // + "/* SQL Analyze(130,1) *\n" + + "SELECT *\n" + + "FROM (\n" + + "\tSELECT pohjxx_czr0_.RYNBID AS RYNBID, pohjxx_czr0_.RYID AS RYID, pohjxx_czr0_.HHNBID AS HHNBID, pohjxx_czr0_.HHID AS HHID, pohjxx_czr0_.MLPNBID AS MLPNBID\n" + + "\t\t, pohjxx_czr0_.MLPID AS MLPID, pohjxx_czr0_.ZPID AS ZPID, pohjxx_czr0_.NBSFZID AS NBSFZID, pohjxx_czr0_.GMSFHM AS GMSFHM, pohjxx_czr0_.XM AS XM\n" + + "\t\t, pohjxx_czr0_.X AS X, pohjxx_czr0_.M AS M, pohjxx_czr0_.CYM AS CYM, pohjxx_czr0_.XMPY AS XMPY, pohjxx_czr0_.CYMPY AS CYMPY\n" + + "\t\t, pohjxx_czr0_.XB AS XB, pohjxx_czr0_.MZ AS MZ, pohjxx_czr0_.CSRQ AS CSRQ, pohjxx_czr0_.CSSJ AS CSSJ, pohjxx_czr0_.CSDGJDQ AS CSDGJDQ\n" + + "\t\t, pohjxx_czr0_.CSDSSXQ AS CSDSSXQ, pohjxx_czr0_.CSDXZ AS CSDXZ, pohjxx_czr0_.CSZMBH AS CSZMBH, pohjxx_czr0_.CSZQFRQ AS CSZQFRQ, pohjxx_czr0_.JGGJDQ AS JGGJDQ\n" + + "\t\t, pohjxx_czr0_.JGSSXQ AS JGSSXQ, pohjxx_czr0_.JGXZ AS JGXZ, pohjxx_czr0_.JHRYGMSFHM AS JHRYGMSFHM, pohjxx_czr0_.JHRYXM AS JHRYXM, pohjxx_czr0_.JHRYCYZJDM AS JHRYCYZJDM\n" + + "\t\t, pohjxx_czr0_.JHRYZJHM AS JHRYZJHM, pohjxx_czr0_.JHRYWWX AS JHRYWWX, pohjxx_czr0_.JHRYWWM AS JHRYWWM, pohjxx_czr0_.JHRYJHGX AS JHRYJHGX, pohjxx_czr0_.JHRYLXDH AS JHRYLXDH\n" + + "\t\t, pohjxx_czr0_.JHREGMSFHM AS JHREGMSFHM, pohjxx_czr0_.JHREXM AS JHREXM, pohjxx_czr0_.JHRECYZJDM AS JHRECYZJDM, pohjxx_czr0_.JHREZJHM AS JHREZJHM, pohjxx_czr0_.JHREWWX AS JHREWWX\n" + + "\t\t, pohjxx_czr0_.JHREWWM AS JHREWWM, pohjxx_czr0_.JHREJHGX AS JHREJHGX, pohjxx_czr0_.JHRELXDH AS JHRELXDH, pohjxx_czr0_.FQGMSFHM AS FQGMSFHM, pohjxx_czr0_.FQXM AS FQXM\n" + + "\t\t, pohjxx_czr0_.FQCYZJDM AS FQCYZJDM, pohjxx_czr0_.FQZJHM AS FQZJHM, pohjxx_czr0_.FQWWX AS FQWWX, pohjxx_czr0_.FQWWM AS FQWWM, pohjxx_czr0_.MQGMSFHM AS MQGMSFHM\n" + + "\t\t, pohjxx_czr0_.MQXM AS MQXM, pohjxx_czr0_.MQCYZJDM AS MQCYZJDM, pohjxx_czr0_.MQZJHM AS MQZJHM, pohjxx_czr0_.MQWWX AS MQWWX, pohjxx_czr0_.MQWWM AS MQWWM\n" + + "\t\t, pohjxx_czr0_.POGMSFHM AS POGMSFHM, pohjxx_czr0_.POXM AS POXM, pohjxx_czr0_.POCYZJDM AS POCYZJDM, pohjxx_czr0_.POZJHM AS POZJHM, pohjxx_czr0_.POWWX AS POWWX\n" + + "\t\t, pohjxx_czr0_.POWWM AS POWWM, pohjxx_czr0_.ZJXY AS ZJXY, pohjxx_czr0_.WHCD AS WHCD, pohjxx_czr0_.HYZK AS HYZK, pohjxx_czr0_.BYZK AS BYZK\n" + + "\t\t, pohjxx_czr0_.SG AS SG, pohjxx_czr0_.XX AS XX, pohjxx_czr0_.DHHM AS DHHM, pohjxx_czr0_.DHHM2 AS DHHM2, pohjxx_czr0_.CYZKDWBM AS CYZKDWBM\n" + + "\t\t, pohjxx_czr0_.CYZKDWMC AS CYZKDWMC, pohjxx_czr0_.ZY AS ZY, pohjxx_czr0_.ZYLB AS ZYLB, pohjxx_czr0_.FWCS AS FWCS, pohjxx_czr0_.XXJB AS XXJB\n" + + "\t\t, pohjxx_czr0_.HSQL AS HSQL, pohjxx_czr0_.HYQL AS HYQL, pohjxx_czr0_.HQYLDYY AS HQYLDYY, pohjxx_czr0_.HGJDQQL AS HGJDQQL, pohjxx_czr0_.HSSXQQL AS HSSXQQL\n" + + "\t\t, pohjxx_czr0_.HXZQL AS HXZQL, pohjxx_czr0_.HSLBZ AS HSLBZ, pohjxx_czr0_.HYLBZ AS HYLBZ, pohjxx_czr0_.HQYLDYYLBZ AS HQYLDYYLBZ, pohjxx_czr0_.HGJDQLBZ AS HGJDQLBZ\n" + + "\t\t, pohjxx_czr0_.HSSSQLBZ AS HSSSQLBZ, pohjxx_czr0_.HXZLBZ AS HXZLBZ, pohjxx_czr0_.SWRQ AS SWRQ, pohjxx_czr0_.SWZXLB AS SWZXLB, pohjxx_czr0_.SWYY AS SWYY\n" + + "\t\t, pohjxx_czr0_.SWZXRQ AS SWZXRQ, pohjxx_czr0_.QCRQ AS QCRQ, pohjxx_czr0_.QCZXLB AS QCZXLB, pohjxx_czr0_.QCQYLDYY AS QCQYLDYY, pohjxx_czr0_.QWDGJDQ AS QWDGJDQ\n" + + "\t\t, pohjxx_czr0_.QWDSSXQ AS QWDSSXQ, pohjxx_czr0_.QWDXZ AS QWDXZ, pohjxx_czr0_.BDFW AS BDFW, pohjxx_czr0_.RYLB AS RYLB, pohjxx_czr0_.RYZT AS RYZT\n" + + "\t\t, pohjxx_czr0_.RYSDZT AS RYSDZT, pohjxx_czr0_.LXDBID AS LXDBID, pohjxx_czr0_.JLBZ AS JLBZ, pohjxx_czr0_.YWNR AS YWNR, pohjxx_czr0_.CJHJYWID AS CJHJYWID\n" + + "\t\t, pohjxx_czr0_.CCHJYWID AS CCHJYWID, pohjxx_czr0_.QYSJ AS QYSJ, pohjxx_czr0_.JSSJ AS JSSJ, pohjxx_czr0_.CXBZ AS CXBZ, pohjxx_czr0_.XXQYSJ AS XXQYSJ\n" + + "\t\t, pohjxx_czr0_.ZXSJ AS ZXSJ, pohjxx_czr0_.GXSJ AS GXSJ, pohjxx_czr0_.SJGSDWDM AS SJGSDWDM, pohjxx_czr0_.SJGSDWMC AS SJGSDWMC, pohjxx_czr0_.HYLB AS HYLB\n" + + "\t\t, pohjxx_czr0_.BZ AS BZ, pohjxx_czr0_.SSXQ AS SSXQ, pohjxx_czr0_.JLX AS JLX, pohjxx_czr0_.MLPH AS MLPH, pohjxx_czr0_.MLXZ AS MLXZ\n" + + "\t\t, pohjxx_czr0_.PCS AS PCS, pohjxx_czr0_.ZRQ AS ZRQ, pohjxx_czr0_.XZJD AS XZJD, pohjxx_czr0_.JCWH AS JCWH, pohjxx_czr0_.PXH AS PXH\n" + + "\t\t, pohjxx_czr0_.HB AS HB, pohjxx_czr0_.HH AS HH, pohjxx_czr0_.HLX AS HLX, pohjxx_czr0_.YHZGX AS YHZGX, pohjxx_czr0_.QTSSXQ AS QTSSXQ\n" + + "\t\t, pohjxx_czr0_.QTZZ AS QTZZ, pohjxx_czr0_.XZDCJZT AS XZDCJZT, pohjxx_czr0_.HJDDZBM AS HJDDZBM, pohjxx_czr0_.HJDSSXQ AS HJDSSXQ, pohjxx_czr0_.HJDXXDZ AS HJDXXDZ\n" + + "\t\t, pohjxx_czr0_.HJDRHYZBS AS HJDRHYZBS, pohjxx_czr0_.JZDDZBM AS JZDDZBM, pohjxx_czr0_.JZDSSXQ AS JZDSSXQ, pohjxx_czr0_.JZDXXDZ AS JZDXXDZ, pohjxx_czr0_.QFJG AS QFJG\n" + + "\t\t, pohjxx_czr0_.YXQXQSRQ AS YXQXQSRQ, pohjxx_czr0_.YXQXJZRQ AS YXQXJZRQ, pohjxx_czr0_.ZJDZ AS ZJDZ, pohjxx_czr0_.ZJLB AS ZJLB, pohjxx_czr0_.ZWYZW AS ZWYZW\n" + + "\t\t, pohjxx_czr0_.ZWYZCJG AS ZWYZCJG, pohjxx_czr0_.ZWEZW AS ZWEZW, pohjxx_czr0_.ZWEZCJG AS ZWEZCJG, pohjxx_czr0_.ZWCJJGDM AS ZWCJJGDM, pohjxx_czr0_.SZYCZKDM AS SZYCZKDM\n" + + "\t\t, pohjxx_czr0_.DJZT AS DJZT, pohjxx_czr0_.DJSJ AS DJSJ, pohjxx_czr0_.DJYY AS DJYY, pohjxx_czr0_.JCDJSJ AS JCDJSJ, pohjxx_czr0_.HKDJID AS HKDJID\n" + + "\t\t, pohjxx_czr0_.TJYXZQH AS TJYXZQH, pohjxx_czr0_.CXSX AS CXSX\n" + + "\tFROM TB_001 pohjxx_czr0_\n" + + "\tWHERE 1 = 1\n" + + "\t\tAND (pohjxx_czr0_.CSRQ = ?\n" + + "\t\t\tAND pohjxx_czr0_.JLBZ = ?\n" + + "\t\t\tAND ryzt = ?\n" + + "\t\t\tAND pohjxx_czr0_.CXBZ = ?\n" + + "\t\t\tAND 1 = 1)\n" + + ")\n" + + "WHERE rownum <= :1"; // + + OracleStatementParser parser = new OracleStatementParser(sql); + List statementList = parser.parseStatementList(); + assertEquals(1, statementList.size()); + SQLStatement stmt = statementList.get(0); + print(statementList); + + Assert.assertEquals(1, statementList.size()); + + OracleSchemaStatVisitor visitor = new OracleSchemaStatVisitor(); + stmt.accept(visitor); + + System.out.println("Tables : " + visitor.getTables()); + System.out.println("fields : " + visitor.getColumns()); + System.out.println("coditions : " + visitor.getConditions()); + System.out.println("relationships : " + visitor.getRelationships()); + System.out.println("orderBy : " + visitor.getOrderByColumns()); + + assertEquals(3, visitor.getTables().size()); + + assertEquals(8, visitor.getColumns().size()); + + { + String text = SQLUtils.toOracleString(stmt); + + assertEquals("SELECT CAST(a.nsrdzdah AS char)\n" + + "FROM DJ_NSRXX_DZB a\n" + + "INNER JOIN DJ_NSRXX b ON a.nsrdzdah = b.nsrdzdah \n" + + "\tINNER JOIN DM_SWJG c ON b.nsr_swjg_dm = c.swjg_dm \n" + + "WHERE (a.nsrsbh_old = ?\n" + + "\t\tOR a.nsrsbh_new = ?)\n" + + "\tAND b.nsrzt_dm <= ?\n" + + "\tAND c.JBDM LIKE ?\n" + + "\tAND rownum = 1", text); + } + // Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("acduser.vw_acd_info", "xzqh"))); + + // Assert.assertTrue(visitor.getOrderByColumns().contains(new TableStat.Column("employees", "last_name"))); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/postgresql/select/PGSelectTest55.java b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/select/PGSelectTest55.java new file mode 100644 index 0000000000..8d36175368 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/postgresql/select/PGSelectTest55.java @@ -0,0 +1,85 @@ +/* + * Copyright 1999-2017 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.druid.bvt.sql.postgresql.select; + +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.visitor.SchemaStatVisitor; +import com.alibaba.druid.util.JdbcConstants; +import junit.framework.TestCase; + +import java.util.List; + +public class PGSelectTest55 extends TestCase { + private final String dbType = JdbcConstants.POSTGRESQL; + + public void test_0() throws Exception { + String sql = "select b.*,st_astext(p.pos) as pos,st_astext(p.polygon) as polygon " + + "from ts_biz as b join (" + + " select * from ts_polygon" + + " where type in (?) and st_intersects(st_transform(ST_GeomFromText(?, 4326),26986),st_transform(polygon,26986))" + + ") as p " + + " on b.objid=p.objid and b.type=p.type and (b.cp_code=p.cp_code or (b.cp_code is null and p.cp_code is null)) " + + "where b.cp_code=(?) or b.cp_code is null"; + + List stmtList = SQLUtils.parseStatements(sql, dbType); + SQLStatement stmt = stmtList.get(0); + + assertEquals("SELECT b.*, st_astext(p.pos) AS pos, st_astext(p.polygon) AS polygon\n" + + "FROM ts_biz b\n" + + "\tJOIN (\n" + + "\t\tSELECT *\n" + + "\t\tFROM ts_polygon\n" + + "\t\tWHERE type IN (?)\n" + + "\t\t\tAND st_intersects(st_transform(ST_GeomFromText(?, 4326), 26986), st_transform(polygon, 26986))\n" + + "\t) p\n" + + "\tON b.objid = p.objid\n" + + "\t\tAND b.type = p.type\n" + + "\t\tAND (b.cp_code = p.cp_code\n" + + "\t\t\tOR (b.cp_code IS NULL\n" + + "\t\t\t\tAND p.cp_code IS NULL))\n" + + "WHERE b.cp_code = ?\n" + + "\tOR b.cp_code IS NULL", SQLUtils.toPGString(stmt)); + + assertEquals("select b.*, st_astext(p.pos) as pos, st_astext(p.polygon) as polygon\n" + + "from ts_biz b\n" + + "\tjoin (\n" + + "\t\tselect *\n" + + "\t\tfrom ts_polygon\n" + + "\t\twhere type in (?)\n" + + "\t\t\tand st_intersects(st_transform(ST_GeomFromText(?, 4326), 26986), st_transform(polygon, 26986))\n" + + "\t) p\n" + + "\ton b.objid = p.objid\n" + + "\t\tand b.type = p.type\n" + + "\t\tand (b.cp_code = p.cp_code\n" + + "\t\t\tor (b.cp_code is null\n" + + "\t\t\t\tand p.cp_code is null))\n" + + "where b.cp_code = ?\n" + + "\tor b.cp_code is null", SQLUtils.toPGString(stmt, SQLUtils.DEFAULT_LCASE_FORMAT_OPTION)); + + assertEquals(1, stmtList.size()); + + SchemaStatVisitor visitor = SQLUtils.createSchemaStatVisitor(dbType); + stmt.accept(visitor); + +// System.out.println("Tables : " + visitor.getTables()); +// System.out.println("fields : " + visitor.getColumns()); +// System.out.println("coditions : " + visitor.getConditions()); + + assertEquals(7, visitor.getColumns().size()); + assertEquals(2, visitor.getTables().size()); + } +}