From 512b8dbabdde38097110f58234cd6aa6fb7b86d7 Mon Sep 17 00:00:00 2001 From: wenshao Date: Tue, 1 Aug 2017 17:15:04 +0800 Subject: [PATCH] improved sql parser. --- .../druid/sql/ast/expr/SQLCharExpr.java | 13 +- .../ast/statement/SQLAlterTableRename.java | 15 ++ .../ast/statement/SQLColumnDefinition.java | 8 + .../statement/SQLCreateTableStatement.java | 187 +++++++++++++-- .../sql/dialect/mysql/ast/MySqlUnique.java | 2 +- .../MySqlAlterTableChangeColumn.java | 12 +- .../MySqlAlterTableModifyColumn.java | 13 +- .../ast/statement/MySqlAlterTableOption.java | 16 +- .../statement/MySqlCreateTableStatement.java | 149 +++++++++++- .../MySqlShowCreateTableStatement.java | 7 +- .../mysql/ast/statement/MySqlTableIndex.java | 7 +- .../mysql/parser/MySqlCreateTableParser.java | 2 +- .../mysql/parser/MySqlStatementParser.java | 2 +- .../alibaba/druid/sql/repository/Schema.java | 81 ++++++- .../sql/repository/SchemaRepository.java | 68 ++++++ .../com/alibaba/druid/util/JdbcUtils.java | 12 + ...eateTable_showColumns_repository_test.java | 220 ++++++++++++++++-- 17 files changed, 734 insertions(+), 80 deletions(-) diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLCharExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLCharExpr.java index 55e2a7ef39..908ebd52c1 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLCharExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLCharExpr.java @@ -16,6 +16,7 @@ package com.alibaba.druid.sql.ast.expr; import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.visitor.SQLASTOutputVisitor; import com.alibaba.druid.sql.visitor.SQLASTVisitor; public class SQLCharExpr extends SQLTextLiteralExpr implements SQLValuableExpr{ @@ -30,13 +31,11 @@ public class SQLCharExpr extends SQLTextLiteralExpr implements SQLValuableExpr{ @Override public void output(StringBuffer buf) { - if ((this.text == null) || (this.text.length() == 0)) { - buf.append("NULL"); - } else { - buf.append("'"); - buf.append(this.text.replaceAll("'", "''")); - buf.append("'"); - } + output((Appendable) buf); + } + + public void output(Appendable buf) { + this.accept(new SQLASTOutputVisitor(buf)); } protected void accept0(SQLASTVisitor visitor) { diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLAlterTableRename.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLAlterTableRename.java index 80aa7ae0b8..3adc382391 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLAlterTableRename.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLAlterTableRename.java @@ -16,6 +16,7 @@ package com.alibaba.druid.sql.ast.statement; import com.alibaba.druid.sql.ast.SQLExpr; +import com.alibaba.druid.sql.ast.SQLName; import com.alibaba.druid.sql.ast.SQLObjectImpl; import com.alibaba.druid.sql.visitor.SQLASTVisitor; @@ -35,6 +36,20 @@ public class SQLAlterTableRename extends SQLObjectImpl implements SQLAlterTableI return to; } + public SQLName getToName() { + if (to == null) { + return null; + } + + SQLExpr expr = to.expr; + + if (expr instanceof SQLName) { + return (SQLName) expr; + } + + return null; + } + public void setTo(SQLExprTableSource to) { if (to != null) { to.setParent(this); 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 58f8cc076b..9c9188899f 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 @@ -96,6 +96,14 @@ public class SQLColumnDefinition extends SQLObjectImpl implements SQLTableElemen return name; } + public String getNameAsString() { + if (name == null) { + return null; + } + + return name.toString(); + } + public void setName(SQLName name) { this.name = name; } 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 d9b617d30c..6ea42fb5a5 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 @@ -26,7 +26,6 @@ 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.sql.dialect.mysql.visitor.MySqlShowColumnOutpuVisitor; import com.alibaba.druid.util.ListDG; import com.alibaba.druid.util.lang.Consumer; @@ -263,27 +262,32 @@ public class SQLCreateTableStatement extends SQLStatementImpl implements SQLDDLS public SQLTableElement findIndex(String columnName) { for (SQLTableElement element : tableElementList) { - List keyColumns = null; if (element instanceof SQLUniqueConstraint) { SQLUniqueConstraint unique = (SQLUniqueConstraint) element; - keyColumns = unique.getColumns(); + for (SQLExpr columnExpr : unique.getColumns()) { + if (columnExpr instanceof SQLIdentifierExpr) { + String keyColumName = ((SQLIdentifierExpr) columnExpr).getName(); + keyColumName = SQLUtils.normalize(keyColumName); + if (keyColumName.equalsIgnoreCase(columnName)) { + return element; + } + } + } + } else if (element instanceof MySqlTableIndex) { - keyColumns = ((MySqlTableIndex) element).getColumns(); - } - - if (keyColumns == null) { - continue; - } - - for (SQLExpr columnExpr : keyColumns) { - if (columnExpr instanceof SQLIdentifierExpr) { - String keyColumName = ((SQLIdentifierExpr) columnExpr).getName(); - keyColumName = SQLUtils.normalize(keyColumName); - if (keyColumName.equalsIgnoreCase(columnName)) { - return element; + List indexColumns = ((MySqlTableIndex) element).getColumns(); + for (SQLSelectOrderByItem orderByItem : indexColumns) { + SQLExpr columnExpr = orderByItem.getExpr(); + if (columnExpr instanceof SQLIdentifierExpr) { + String keyColumName = ((SQLIdentifierExpr) columnExpr).getName(); + keyColumName = SQLUtils.normalize(keyColumName); + if (keyColumName.equalsIgnoreCase(columnName)) { + return element; + } } } } + } return null; @@ -529,20 +533,153 @@ public class SQLCreateTableStatement extends SQLStatementImpl implements SQLDDLS 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++; - } + if (alterApply(item)) { + applyCount++; } } return applyCount > 0; } + protected boolean alterApply(SQLAlterTableItem item) { + if (item instanceof SQLAlterTableDropColumnItem) { + return apply((SQLAlterTableDropColumnItem) item); + + } else if (item instanceof SQLAlterTableAddColumn) { + return apply((SQLAlterTableAddColumn) item); + + } else if (item instanceof SQLAlterTableAddConstraint) { + return apply((SQLAlterTableAddConstraint) item); + + } else if (item instanceof SQLAlterTableDropPrimaryKey) { + return apply((SQLAlterTableDropPrimaryKey) item); + + } else if (item instanceof SQLAlterTableDropIndex) { + return apply((SQLAlterTableDropIndex) item); + + } else if (item instanceof SQLAlterTableDropConstraint) { + return apply((SQLAlterTableDropConstraint) item); + + } else if (item instanceof SQLAlterTableDropKey) { + return apply((SQLAlterTableDropKey) item); + + } else if (item instanceof SQLAlterTableDropForeignKey) { + return apply((SQLAlterTableDropForeignKey) item); + + } else if (item instanceof SQLAlterTableRename) { + return apply((SQLAlterTableRename) item); + + } else if (item instanceof SQLAlterTableRenameColumn) { + return apply((SQLAlterTableRenameColumn) item); + } + + return false; + } + + // SQLAlterTableRenameColumn + + private boolean apply(SQLAlterTableRenameColumn item) { + int columnIndex = columnIndexOf(item.getColumn()); + if (columnIndex == -1) { + return false; + } + + SQLColumnDefinition column = (SQLColumnDefinition) tableElementList.get(columnIndex); + column.setName(item.getTo().clone()); + + return true; + } + + private boolean apply(SQLAlterTableRename item) { + SQLName name = item.getToName(); + if (name == null) { + return false; + } + + this.setName(name.clone()); + + return true; + } + + private boolean apply(SQLAlterTableDropForeignKey item) { + for (int i = tableElementList.size() - 1; i >= 0; i--) { + SQLTableElement e = tableElementList.get(i); + if (e instanceof SQLUniqueConstraint) { + SQLForeignKeyConstraint fk = (SQLForeignKeyConstraint) e; + if (SQLUtils.nameEquals(fk.getName(), item.getIndexName())) { + tableElementList.remove(i); + return true; + } + } + } + return false; + } + + private boolean apply(SQLAlterTableDropKey item) { + for (int i = tableElementList.size() - 1; i >= 0; i--) { + SQLTableElement e = tableElementList.get(i); + if (e instanceof SQLUniqueConstraint) { + SQLUniqueConstraint unique = (SQLUniqueConstraint) e; + if (SQLUtils.nameEquals(unique.getName(), item.getKeyName())) { + tableElementList.remove(i); + return true; + } + } + } + return false; + } + + private boolean apply(SQLAlterTableDropConstraint item) { + for (int i = tableElementList.size() - 1; i >= 0; i--) { + SQLTableElement e = tableElementList.get(i); + if (e instanceof SQLConstraint) { + SQLConstraint constraint = (SQLConstraint) e; + if (SQLUtils.nameEquals(constraint.getName(), item.getConstraintName())) { + tableElementList.remove(i); + return true; + } + } + } + return false; + } + + private boolean apply(SQLAlterTableDropIndex item) { + for (int i = tableElementList.size() - 1; i >= 0; i--) { + SQLTableElement e = tableElementList.get(i); + if (e instanceof SQLUniqueConstraint) { + SQLUniqueConstraint unique = (SQLUniqueConstraint) e; + if (SQLUtils.nameEquals(unique.getName(), item.getIndexName())) { + tableElementList.remove(i); + return true; + } + + } else if (e instanceof MySqlTableIndex) { + MySqlTableIndex tableIndex = (MySqlTableIndex) e; + if (SQLUtils.nameEquals(tableIndex.getName(), item.getIndexName())) { + tableElementList.remove(i); + return true; + } + } + } + return false; + } + + private boolean apply(SQLAlterTableDropPrimaryKey item) { + for (int i = tableElementList.size() - 1; i >= 0; i--) { + SQLTableElement e = tableElementList.get(i); + if (e instanceof SQLPrimaryKey) { + tableElementList.remove(i); + return true; + } + } + return false; + } + + private boolean apply(SQLAlterTableAddConstraint item) { + tableElementList.add((SQLTableElement) item.getConstraint()); + return true; + } + private boolean apply(SQLAlterTableDropColumnItem item) { for (SQLName column : item.getColumns()) { String columnName = column.getSimpleName(); @@ -583,7 +720,7 @@ public class SQLCreateTableStatement extends SQLStatementImpl implements SQLDDLS return true; } - private int columnIndexOf(SQLName column) { + protected int columnIndexOf(SQLName column) { if (column == null) { return -1; } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/MySqlUnique.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/MySqlUnique.java index 2a6cfe3035..5bf3de6633 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/MySqlUnique.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/MySqlUnique.java @@ -18,7 +18,7 @@ package com.alibaba.druid.sql.dialect.mysql.ast; import com.alibaba.druid.sql.ast.statement.SQLPrimaryKey; import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitor; -public class MySqlUnique extends MySqlKey implements SQLPrimaryKey { +public class MySqlUnique extends MySqlKey { public MySqlUnique(){ diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlAlterTableChangeColumn.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlAlterTableChangeColumn.java index 333683d3d0..745a57505b 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlAlterTableChangeColumn.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlAlterTableChangeColumn.java @@ -30,8 +30,8 @@ public class MySqlAlterTableChangeColumn extends MySqlObjectImpl implements SQLA private boolean first; - private SQLExpr firstColumn; - private SQLExpr afterColumn; + private SQLName firstColumn; + private SQLName afterColumn; @Override public void accept0(MySqlASTVisitor visitor) { @@ -44,19 +44,19 @@ public class MySqlAlterTableChangeColumn extends MySqlObjectImpl implements SQLA } } - public SQLExpr getFirstColumn() { + public SQLName getFirstColumn() { return firstColumn; } - public void setFirstColumn(SQLExpr firstColumn) { + public void setFirstColumn(SQLName firstColumn) { this.firstColumn = firstColumn; } - public SQLExpr getAfterColumn() { + public SQLName getAfterColumn() { return afterColumn; } - public void setAfterColumn(SQLExpr afterColumn) { + public void setAfterColumn(SQLName afterColumn) { this.afterColumn = afterColumn; } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlAlterTableModifyColumn.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlAlterTableModifyColumn.java index a6e4254f25..50a5643dcb 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlAlterTableModifyColumn.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlAlterTableModifyColumn.java @@ -16,6 +16,7 @@ package com.alibaba.druid.sql.dialect.mysql.ast.statement; import com.alibaba.druid.sql.ast.SQLExpr; +import com.alibaba.druid.sql.ast.SQLName; import com.alibaba.druid.sql.ast.statement.SQLAlterTableItem; import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlObjectImpl; @@ -27,8 +28,8 @@ public class MySqlAlterTableModifyColumn extends MySqlObjectImpl implements SQLA private boolean first; - private SQLExpr firstColumn; - private SQLExpr afterColumn; + private SQLName firstColumn; + private SQLName afterColumn; @Override public void accept0(MySqlASTVisitor visitor) { @@ -40,19 +41,19 @@ public class MySqlAlterTableModifyColumn extends MySqlObjectImpl implements SQLA } } - public SQLExpr getFirstColumn() { + public SQLName getFirstColumn() { return firstColumn; } - public void setFirstColumn(SQLExpr firstColumn) { + public void setFirstColumn(SQLName firstColumn) { this.firstColumn = firstColumn; } - public SQLExpr getAfterColumn() { + public SQLName getAfterColumn() { return afterColumn; } - public void setAfterColumn(SQLExpr afterColumn) { + public void setAfterColumn(SQLName afterColumn) { this.afterColumn = afterColumn; } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlAlterTableOption.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlAlterTableOption.java index 98f923d961..89814db256 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlAlterTableOption.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlAlterTableOption.java @@ -15,6 +15,8 @@ */ package com.alibaba.druid.sql.dialect.mysql.ast.statement; +import com.alibaba.druid.sql.ast.SQLObject; +import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; import com.alibaba.druid.sql.ast.statement.SQLAlterTableItem; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlObjectImpl; import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitor; @@ -22,11 +24,15 @@ import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitor; public class MySqlAlterTableOption extends MySqlObjectImpl implements SQLAlterTableItem { private String name; - private Object value; + private SQLObject value; - public MySqlAlterTableOption(String name, Object value){ + public MySqlAlterTableOption(String name, String value){ + this(name, new SQLIdentifierExpr(value)); + } + + public MySqlAlterTableOption(String name, SQLObject value){ this.name = name; - this.value = value; + this.setValue(value); } public MySqlAlterTableOption(){ @@ -46,11 +52,11 @@ public class MySqlAlterTableOption extends MySqlObjectImpl implements SQLAlterTa this.name = name; } - public Object getValue() { + public SQLObject getValue() { return value; } - public void setValue(Object value) { + public void setValue(SQLObject value) { this.value = value; } 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 5971e69d9d..d0a5356697 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 @@ -27,11 +27,10 @@ import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLName; import com.alibaba.druid.sql.ast.SQLObject; import com.alibaba.druid.sql.ast.SQLPartitionBy; -import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement; -import com.alibaba.druid.sql.ast.statement.SQLExprTableSource; -import com.alibaba.druid.sql.ast.statement.SQLSelect; +import com.alibaba.druid.sql.ast.statement.*; 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.MySqlOutputVisitor; import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlShowColumnOutpuVisitor; import com.alibaba.druid.sql.visitor.SQLASTVisitor; import com.alibaba.druid.util.JdbcConstants; @@ -192,6 +191,57 @@ public class MySqlCreateTableStatement extends SQLCreateTableStatement implement return false; } + protected boolean alterApply(SQLAlterTableItem item) { + if (item instanceof MySqlAlterTableAlterColumn) { + return apply((MySqlAlterTableAlterColumn) item); + + } else if (item instanceof MySqlAlterTableChangeColumn) { + return apply((MySqlAlterTableChangeColumn) item); + + } else if (item instanceof MySqlAlterTableCharacter) { + return apply((MySqlAlterTableCharacter) item); + + } else if (item instanceof MySqlAlterTableModifyColumn) { + return apply((MySqlAlterTableModifyColumn) item); + + } else if (item instanceof MySqlAlterTableOption) { + return apply((MySqlAlterTableOption) item); + } + + return super.alterApply(item); + } + + public boolean apply(SQLAlterTableAddIndex x) { + MySqlTableIndex index = new MySqlTableIndex(); + + index.setName(x.getName()); + for (SQLSelectOrderByItem orderByItem : x.getItems()) { + index.addColumn(orderByItem.clone()); + } + index.setParent(this); + this.tableElementList.add(index); + + return true; + } + + public boolean apply(MySqlAlterTableOption item) { + this.tableOptions.put(item.getName(), item.getValue()); + return true; + } + + public boolean apply(MySqlAlterTableCharacter item) { + SQLExpr charset = item.getCharacterSet(); + if (charset != null) { + this.tableOptions.put("CHARACTER SET", charset); + } + + SQLExpr collate = item.getCollate(); + if (collate != null) { + this.tableOptions.put("COLLATE", collate); + } + return true; + } + public boolean apply(MySqlRenameTableStatement.Item item) { if (!SQLUtils.nameEquals((SQLName) item.getName(), this.getName())) { return false; @@ -199,4 +249,97 @@ public class MySqlCreateTableStatement extends SQLCreateTableStatement implement this.setName((SQLName) item.getTo().clone()); return true; } + + public boolean apply(MySqlAlterTableAlterColumn x) { + int columnIndex = columnIndexOf(x.getColumn()); + if (columnIndex == -1) { + return false; + } + + SQLExpr defaultExpr = x.getDefaultExpr(); + SQLColumnDefinition column = (SQLColumnDefinition) tableElementList.get(columnIndex); + + if (x.isDropDefault()) { + column.setDefaultExpr(null); + } else if (defaultExpr != null) { + column.setDefaultExpr(defaultExpr); + } + + return true; + } + + public boolean apply(MySqlAlterTableChangeColumn item) { + SQLName columnName = item.getColumnName(); + int columnIndex = columnIndexOf(columnName); + if (columnIndex == -1) { + return false; + } + + int afterIndex = columnIndexOf(item.getAfterColumn()); + int beforeIndex = columnIndexOf(item.getFirstColumn()); + + int insertIndex = -1; + if (beforeIndex != -1) { + insertIndex = beforeIndex; + } else if (afterIndex != -1) { + insertIndex = afterIndex + 1; + } + + SQLColumnDefinition column = item.getNewColumnDefinition().clone(); + column.setParent(this); + if (insertIndex == -1 || insertIndex == columnIndex) { + tableElementList.set(columnIndex, column); + return true; + } else { + if (insertIndex > columnIndex) { + tableElementList.add(insertIndex, column); + tableElementList.remove(columnIndex); + } else { + tableElementList.remove(columnIndex); + tableElementList.add(insertIndex, column); + } + } + + return true; + } + + public boolean apply(MySqlAlterTableModifyColumn item) { + SQLColumnDefinition column = item.getNewColumnDefinition().clone(); + SQLName columnName = column.getName(); + + int columnIndex = columnIndexOf(columnName); + if (columnIndex == -1) { + return false; + } + + int afterIndex = columnIndexOf(item.getAfterColumn()); + int beforeIndex = columnIndexOf(item.getFirstColumn()); + + int insertIndex = -1; + if (beforeIndex != -1) { + insertIndex = beforeIndex; + } else if (afterIndex != -1) { + insertIndex = afterIndex + 1; + } + + column.setParent(this); + if (insertIndex == -1 || insertIndex == columnIndex) { + tableElementList.set(columnIndex, column); + return true; + } else { + if (insertIndex > columnIndex) { + tableElementList.add(insertIndex, column); + tableElementList.remove(columnIndex); + } else { + tableElementList.remove(columnIndex); + tableElementList.add(insertIndex, column); + } + } + + return true; + } + + public void output(StringBuffer buf) { + this.accept(new MySqlOutputVisitor(buf)); + } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlShowCreateTableStatement.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlShowCreateTableStatement.java index db8a35b056..d4808305f8 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlShowCreateTableStatement.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlShowCreateTableStatement.java @@ -16,11 +16,12 @@ package com.alibaba.druid.sql.dialect.mysql.ast.statement; import com.alibaba.druid.sql.ast.SQLExpr; +import com.alibaba.druid.sql.ast.SQLName; import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitor; public class MySqlShowCreateTableStatement extends MySqlStatementImpl implements MySqlShowStatement { - private SQLExpr name; + private SQLName name; public void accept0(MySqlASTVisitor visitor) { if (visitor.visit(this)) { @@ -29,11 +30,11 @@ public class MySqlShowCreateTableStatement extends MySqlStatementImpl implements visitor.endVisit(this); } - public SQLExpr getName() { + public SQLName getName() { return name; } - public void setName(SQLExpr name) { + public void setName(SQLName name) { if (name != null) { name.setParent(this); } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlTableIndex.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlTableIndex.java index 4b1dd48a1f..ef576083a3 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlTableIndex.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlTableIndex.java @@ -20,6 +20,7 @@ import java.util.List; import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLName; +import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem; import com.alibaba.druid.sql.ast.statement.SQLTableElement; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlObjectImpl; import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitor; @@ -28,7 +29,7 @@ public class MySqlTableIndex extends MySqlObjectImpl implements SQLTableElement private SQLName name; private String indexType; - private List columns = new ArrayList(); + private List columns = new ArrayList(); public MySqlTableIndex(){ @@ -50,11 +51,11 @@ public class MySqlTableIndex extends MySqlObjectImpl implements SQLTableElement this.name = name; } - public List getColumns() { + public List getColumns() { return columns; } - public void addColumn(SQLExpr column) { + public void addColumn(SQLSelectOrderByItem column) { if (column != null) { column.setParent(this); } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlCreateTableParser.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlCreateTableParser.java index d911d989d5..f1e15ab832 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlCreateTableParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlCreateTableParser.java @@ -140,7 +140,7 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { accept(Token.LPAREN); for (;;) { - idx.addColumn(this.exprParser.expr()); + idx.addColumn(this.exprParser.parseSelectOrderByItem()); if (!(lexer.token() == (Token.COMMA))) { break; } else { 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 1ab8d8a611..09df6d9aca 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 @@ -2843,7 +2843,7 @@ public class MySqlStatementParser extends SQLStatementParser { } else if (identifierEquals(AUTO_INCREMENT)) { lexer.nextToken(); accept(Token.EQ); - stmt.addItem(new MySqlAlterTableOption(AUTO_INCREMENT, lexer.integerValue())); + stmt.addItem(new MySqlAlterTableOption(AUTO_INCREMENT, new SQLIntegerExpr(lexer.integerValue()))); lexer.nextToken(); } else if (identifierEquals(COLLATE2)) { lexer.nextToken(); diff --git a/src/main/java/com/alibaba/druid/sql/repository/Schema.java b/src/main/java/com/alibaba/druid/sql/repository/Schema.java index f1e8819bab..976e69ac73 100644 --- a/src/main/java/com/alibaba/druid/sql/repository/Schema.java +++ b/src/main/java/com/alibaba/druid/sql/repository/Schema.java @@ -24,8 +24,12 @@ import com.alibaba.druid.sql.ast.expr.SQLAllColumnExpr; import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr; import com.alibaba.druid.sql.ast.statement.*; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement; +import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitorAdapter; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleCreateTableStatement; import com.alibaba.druid.sql.dialect.oracle.visitor.OracleASTVisitorAdapter; +import com.alibaba.druid.sql.visitor.SQLASTVisitor; +import com.alibaba.druid.util.JdbcConstants; import java.util.LinkedHashMap; import java.util.List; @@ -42,12 +46,18 @@ public class Schema { private final Map functions = new ConcurrentSkipListMap(); - private final Schema.SchemaVisitor visitor = new Schema.SchemaVisitor(); + private final SQLASTVisitor visitor; private SchemaRepository repository; public Schema(SchemaRepository repository) { this.repository = repository; + + if (JdbcConstants.MYSQL.equals(repository.dbType)) { + visitor = new MySqlSchemaVisitor(); + } else { + visitor = new OracleSchemaVisitor(); + } } public String getName() { @@ -59,7 +69,6 @@ public class Schema { } - public SchemaObject findTable(String tableName) { String lowerName = tableName.toLowerCase(); SchemaObject object = objects.get(lowerName); @@ -109,7 +118,7 @@ public class Schema { && object.getType() == SchemaObjectType.Sequence; } - public class SchemaVisitor extends OracleASTVisitorAdapter { + public class OracleSchemaVisitor extends OracleASTVisitorAdapter { public boolean visit(SQLDropSequenceStatement x) { String name = x.getName().getSimpleName(); @@ -175,6 +184,72 @@ public class Schema { } } + private class MySqlSchemaVisitor extends MySqlASTVisitorAdapter { + + public boolean visit(SQLDropSequenceStatement x) { + String name = x.getName().getSimpleName(); + objects.remove(name); + return false; + } + + public boolean visit(SQLCreateSequenceStatement x) { + String name = x.getName().getSimpleName(); + SchemaObject object = new SchemaObjectImpl(name, SchemaObjectType.Sequence); + + objects.put(name.toLowerCase(), object); + return false; + } + + public boolean visit(MySqlCreateTableStatement x) { + visit((SQLCreateTableStatement) x); + return false; + } + + public boolean visit(SQLCreateTableStatement x) { + String name = x.computeName(); + SchemaObject object = new SchemaObjectImpl(name, SchemaObjectType.Table, x); + + String name_lower = name.toLowerCase(); + if (objects.containsKey(name_lower)) { + return false; + } + objects.put(name_lower, object); + + return false; + } + + public boolean visit(SQLCreateViewStatement x) { + String name = x.computeName(); + SchemaObject object = new SchemaObjectImpl(name, SchemaObjectType.View, x); + + String name_lower = name.toLowerCase(); + if (objects.containsKey(name_lower)) { + return false; + } + objects.put(name_lower, object); + + return false; + } + + public boolean visit(SQLCreateIndexStatement x) { + String name = x.getName().getSimpleName(); + SchemaObject object = new SchemaObjectImpl(name, SchemaObjectType.Index); + + objects.put(name.toLowerCase(), object); + + return false; + } + + public boolean visit(SQLCreateFunctionStatement x) { + String name = x.getName().getSimpleName(); + SchemaObject object = new SchemaObjectImpl(name, SchemaObjectType.Function, x); + + functions.put(name.toLowerCase(), object); + + return false; + } + } + public SchemaObject findTable(SQLTableSource tableSource, String alias) { if (tableSource instanceof SQLExprTableSource) { if (alias.equalsIgnoreCase(tableSource.computeAlias())) { diff --git a/src/main/java/com/alibaba/druid/sql/repository/SchemaRepository.java b/src/main/java/com/alibaba/druid/sql/repository/SchemaRepository.java index 71d7bec974..0fe92dd7e1 100644 --- a/src/main/java/com/alibaba/druid/sql/repository/SchemaRepository.java +++ b/src/main/java/com/alibaba/druid/sql/repository/SchemaRepository.java @@ -15,6 +15,7 @@ */ package com.alibaba.druid.sql.repository; +import com.alibaba.druid.DruidRuntimeException; import com.alibaba.druid.sql.SQLUtils; import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLName; @@ -24,9 +25,14 @@ import com.alibaba.druid.sql.ast.expr.SQLAllColumnExpr; import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr; import com.alibaba.druid.sql.ast.statement.*; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowColumnsStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowCreateTableStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleCreateTableStatement; import com.alibaba.druid.sql.dialect.oracle.visitor.OracleASTVisitorAdapter; +import com.alibaba.druid.util.JdbcUtils; +import java.io.IOException; import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; @@ -38,6 +44,15 @@ import java.util.concurrent.ConcurrentSkipListMap; */ public class SchemaRepository { private Schema defaultSchema; + protected String dbType; + + public SchemaRepository() { + + } + + public SchemaRepository(String dbType) { + this.dbType = dbType; + } private Map schemas = new LinkedHashMap(); @@ -136,6 +151,10 @@ public class SchemaRepository { return getDefaultSchema().findFunction(functionName); } + public void acceptDDL(String ddl) { + acceptDDL(ddl, dbType); + } + public void acceptDDL(String ddl, String dbType) { getDefaultSchema().acceptDDL(ddl, dbType); } @@ -183,4 +202,53 @@ public class SchemaRepository { public int getViewCount() { return getDefaultSchema().getViewCount(); } + + public String console(String input) { + try { + StringBuffer buf = new StringBuffer(); + + List stmtList = SQLUtils.parseStatements(input, dbType); + + for (SQLStatement stmt : stmtList) { + if (stmt instanceof MySqlShowColumnsStatement) { + MySqlShowColumnsStatement showColumns = ((MySqlShowColumnsStatement) stmt); + SQLName table = showColumns.getTable(); + SchemaObject schemaObject = findSchemaObject(table); + MySqlCreateTableStatement createTableStmt = (MySqlCreateTableStatement) schemaObject.getStatement(); + createTableStmt.showCoumns(buf); + } else if (stmt instanceof MySqlShowCreateTableStatement) { + MySqlShowCreateTableStatement showCreateTableStmt = (MySqlShowCreateTableStatement) stmt; + SQLName table = showCreateTableStmt.getName(); + SchemaObject schemaObject = findSchemaObject(table); + MySqlCreateTableStatement createTableStmt = (MySqlCreateTableStatement) schemaObject.getStatement(); + createTableStmt.output(buf); + } + } + + return buf.toString(); + } catch (IOException ex) { + throw new DruidRuntimeException("exeucte command error.", ex); + } + } + + private SchemaObject findSchemaObject(SQLName name) { + if (name instanceof SQLIdentifierExpr) { + return findTable(((SQLIdentifierExpr) name).getName()); + } + + if (name instanceof SQLPropertyExpr) { + SQLPropertyExpr propertyExpr = (SQLPropertyExpr) name; + String schema = propertyExpr.getOwnernName(); + String table = propertyExpr.getName(); + + Schema schemaObj = findSchema(schema); + if (schemaObj == null) { + return null; + } + + return schemaObj.findTable(table); + } + + return null; + } } diff --git a/src/main/java/com/alibaba/druid/util/JdbcUtils.java b/src/main/java/com/alibaba/druid/util/JdbcUtils.java index f42030ef33..ea1999264f 100644 --- a/src/main/java/com/alibaba/druid/util/JdbcUtils.java +++ b/src/main/java/com/alibaba/druid/util/JdbcUtils.java @@ -767,6 +767,18 @@ public final class JdbcUtils implements JdbcConstants { } } + public static List showTables(Connection conn, String dbType) throws SQLException { + if (JdbcConstants.MYSQL.equals(dbType)) { + return MySqlUtils.showTables(conn); + } + + if (JdbcConstants.ORACLE.equals(dbType)) { + return OracleUtils.showTables(conn); + } + + throw new SQLException("show tables dbType not support for " + dbType); + } + public static String getCreateTableScript(Connection conn, String dbType) throws SQLException { return getCreateTableScript(conn, dbType, true, true); } 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 index 0a7d58aff1..cc1f4f5a1d 100644 --- 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 @@ -20,11 +20,14 @@ 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.sql.repository.SchemaRepository; import com.alibaba.druid.util.JdbcConstants; import java.util.List; public class MySqlCreateTable_showColumns_repository_test extends MysqlTest { + private SchemaRepository repository = new SchemaRepository(JdbcConstants.MYSQL); + public void test_0() throws Exception { String sql = "CREATE TABLE `test1` (\n" + @@ -52,16 +55,13 @@ public class MySqlCreateTable_showColumns_repository_test extends MysqlTest { ") 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); - } + repository.acceptDDL(sql); + + MySqlCreateTableStatement createTableStmt = (MySqlCreateTableStatement) repository.findTable("test1").getStatement(); assertEquals(21, createTableStmt.getTableElementList().size()); - StringBuilder buf = new StringBuilder(); - createTableStmt.showCoumns(buf); + //StringBuilder buf = new StringBuilder(); + //createTableStmt.showCoumns(buf); assertEquals("+--------------+---------------+------+-----+---------------------+-----------------------------+\n" + "| Field | Type | Null | Key | Default | Extra |\n" + @@ -83,7 +83,7 @@ public class MySqlCreateTable_showColumns_repository_test extends MysqlTest { "| c_text | text | NO | | NULL | |\n" + "| c_mediumtext | mediumtext | NO | | NULL | |\n" + "| c_longblob | longblob | NO | | NULL | |\n" + - "+--------------+---------------+------+-----+---------------------+-----------------------------+\n", buf.toString()); + "+--------------+---------------+------+-----+---------------------+-----------------------------+\n", repository.console("show columns from test1")); SQLAlterTableStatement stmtDropColumn; { @@ -94,8 +94,6 @@ public class MySqlCreateTable_showColumns_repository_test extends MysqlTest { 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" + @@ -115,7 +113,7 @@ public class MySqlCreateTable_showColumns_repository_test extends MysqlTest { "| c_text | text | NO | | NULL | |\n" + "| c_mediumtext | mediumtext | NO | | NULL | |\n" + "| c_longblob | longblob | NO | | NULL | |\n" + - "+--------------+--------------+------+-----+---------------------+-----------------------------+\n", buf.toString()); + "+--------------+--------------+------+-----+---------------------+-----------------------------+\n", repository.console("show columns from test1")); SQLAlterTableStatement stmtAddColumn; { @@ -126,8 +124,6 @@ public class MySqlCreateTable_showColumns_repository_test extends MysqlTest { 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" + @@ -148,8 +144,200 @@ public class MySqlCreateTable_showColumns_repository_test extends MysqlTest { "| c_mediumtext | mediumtext | NO | | NULL | |\n" + "| c_longblob | longblob | NO | | NULL | |\n" + "| c_decimal | decimal(10,3) | NO | | NULL | |\n" + - "+--------------+---------------+------+-----+---------------------+-----------------------------+\n", buf.toString()); + "+--------------+---------------+------+-----+---------------------+-----------------------------+\n", repository.console("show columns from test1")); - //System.out.println(buf.toString()); + SQLAlterTableStatement stmtChangeColumn; + { + List statementList = SQLUtils.parseStatements("ALTER TABLE test1 CHANGE COLUMN c_decimal c_decimal_1 INT(11) NOT NULL DEFAULT NULL FIRST id;", JdbcConstants.MYSQL, true); + assertEquals(1, statementList.size()); + stmtChangeColumn = (SQLAlterTableStatement) statementList.get(0); + } + createTableStmt.apply(stmtChangeColumn); + assertEquals(21, createTableStmt.getTableElementList().size()); + //String sql = "ALTER TABLE `test`.`tb1` CHANGE COLUMN `fid` `fid` INT(11) NOT NULL DEFAULT NULL, ADD PRIMARY KEY (`fid`) ;"; + + assertEquals("+--------------+--------------+------+-----+---------------------+-----------------------------+\n" + + "| Field | Type | Null | Key | Default | Extra |\n" + + "+--------------+--------------+------+-----+---------------------+-----------------------------+\n" + + "| c_decimal_1 | INT(11) | YES | | NULL | |\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", repository.console("show columns from test1")); + + + SQLAlterTableStatement stmtDropPk; + { + List statementList = SQLUtils.parseStatements("ALTER TABLE test1 DROP PRIMARY KEY;", JdbcConstants.MYSQL, true); + assertEquals(1, statementList.size()); + stmtDropPk = (SQLAlterTableStatement) statementList.get(0); + } + createTableStmt.apply(stmtDropPk); + assertEquals(20, createTableStmt.getTableElementList().size()); + + assertEquals("CREATE TABLE `test1` (\n" + + "\tc_decimal_1 INT(11) NOT NULL DEFAULT NULL,\n" + + "\t`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',\n" + + "\t`c_tinyint` tinyint(4) DEFAULT '1' COMMENT 'tinyint',\n" + + "\t`c_smallint` smallint(6) DEFAULT 0 COMMENT 'smallint',\n" + + "\t`c_mediumint` mediumint(9) DEFAULT NULL COMMENT 'mediumint',\n" + + "\t`c_int` int(11) DEFAULT NULL COMMENT 'int',\n" + + "\t`c_bigint` bigint(20) DEFAULT NULL COMMENT 'bigint',\n" + + "\t`c_date` date DEFAULT '0000-00-00' COMMENT 'date',\n" + + "\t`c_datetime` datetime DEFAULT '0000-00-00 00:00:00' COMMENT 'datetime',\n" + + "\t`c_timestamp` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT 'timestamp',\n" + + "\t`c_time` time DEFAULT NULL COMMENT 'time',\n" + + "\t`c_char` char(10) DEFAULT NULL COMMENT 'char',\n" + + "\t`c_varchar` varchar(10) DEFAULT 'hello' COMMENT 'varchar',\n" + + "\t`c_blob` blob COMMENT 'blob',\n" + + "\t`c_text` text COMMENT 'text',\n" + + "\t`c_mediumtext` mediumtext COMMENT 'mediumtext',\n" + + "\t`c_longblob` longblob COMMENT 'longblob',\n" + + "\tUNIQUE `uk_a` (`c_varchar`, `c_mediumint`),\n" + + "\tKEY `k_c` (`c_tinyint`, `c_int`),\n" + + "\tKEY `k_d` (`c_char`, `c_bigint`)\n" + + ") ENGINE = InnoDB AUTO_INCREMENT = 1769503 CHARSET = utf8mb4 COMMENT = '10000000'", repository.console("show create table test1")); + + + assertEquals("+--------------+--------------+------+-----+---------------------+-----------------------------+\n" + + "| Field | Type | Null | Key | Default | Extra |\n" + + "+--------------+--------------+------+-----+---------------------+-----------------------------+\n" + + "| c_decimal_1 | INT(11) | YES | | NULL | |\n" + + "| id | bigint(20) | YES | | NULL | auto_increment |\n" + + "| c_tinyint | tinyint(4) | NO | MUL | 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", repository.console("show columns from test1")); + + SQLAlterTableStatement stmtDropIdx; + { + List statementList = SQLUtils.parseStatements("ALTER TABLE test1 DROP INDEX k_d;", JdbcConstants.MYSQL, true); + assertEquals(1, statementList.size()); + stmtDropIdx = (SQLAlterTableStatement) statementList.get(0); + } + createTableStmt.apply(stmtDropIdx); + assertEquals(19, createTableStmt.getTableElementList().size()); + + assertEquals("CREATE TABLE `test1` (\n" + + "\tc_decimal_1 INT(11) NOT NULL DEFAULT NULL,\n" + + "\t`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',\n" + + "\t`c_tinyint` tinyint(4) DEFAULT '1' COMMENT 'tinyint',\n" + + "\t`c_smallint` smallint(6) DEFAULT 0 COMMENT 'smallint',\n" + + "\t`c_mediumint` mediumint(9) DEFAULT NULL COMMENT 'mediumint',\n" + + "\t`c_int` int(11) DEFAULT NULL COMMENT 'int',\n" + + "\t`c_bigint` bigint(20) DEFAULT NULL COMMENT 'bigint',\n" + + "\t`c_date` date DEFAULT '0000-00-00' COMMENT 'date',\n" + + "\t`c_datetime` datetime DEFAULT '0000-00-00 00:00:00' COMMENT 'datetime',\n" + + "\t`c_timestamp` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT 'timestamp',\n" + + "\t`c_time` time DEFAULT NULL COMMENT 'time',\n" + + "\t`c_char` char(10) DEFAULT NULL COMMENT 'char',\n" + + "\t`c_varchar` varchar(10) DEFAULT 'hello' COMMENT 'varchar',\n" + + "\t`c_blob` blob COMMENT 'blob',\n" + + "\t`c_text` text COMMENT 'text',\n" + + "\t`c_mediumtext` mediumtext COMMENT 'mediumtext',\n" + + "\t`c_longblob` longblob COMMENT 'longblob',\n" + + "\tUNIQUE `uk_a` (`c_varchar`, `c_mediumint`),\n" + + "\tKEY `k_c` (`c_tinyint`, `c_int`)\n" + + ") ENGINE = InnoDB AUTO_INCREMENT = 1769503 CHARSET = utf8mb4 COMMENT = '10000000'", repository.console("show create table test1")); + + assertEquals("+--------------+--------------+------+-----+---------------------+-----------------------------+\n" + + "| Field | Type | Null | Key | Default | Extra |\n" + + "+--------------+--------------+------+-----+---------------------+-----------------------------+\n" + + "| c_decimal_1 | INT(11) | YES | | NULL | |\n" + + "| id | bigint(20) | YES | | NULL | auto_increment |\n" + + "| c_tinyint | tinyint(4) | NO | MUL | 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 | | 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", repository.console("show columns from test1")); + + + SQLAlterTableStatement stmtDropUk; + { + List statementList = SQLUtils.parseStatements("ALTER TABLE test1 DROP INDEX uk_a;", JdbcConstants.MYSQL, true); + assertEquals(1, statementList.size()); + stmtDropUk = (SQLAlterTableStatement) statementList.get(0); + } + createTableStmt.apply(stmtDropUk); + assertEquals(18, createTableStmt.getTableElementList().size()); + + assertEquals("CREATE TABLE `test1` (\n" + + "\tc_decimal_1 INT(11) NOT NULL DEFAULT NULL,\n" + + "\t`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',\n" + + "\t`c_tinyint` tinyint(4) DEFAULT '1' COMMENT 'tinyint',\n" + + "\t`c_smallint` smallint(6) DEFAULT 0 COMMENT 'smallint',\n" + + "\t`c_mediumint` mediumint(9) DEFAULT NULL COMMENT 'mediumint',\n" + + "\t`c_int` int(11) DEFAULT NULL COMMENT 'int',\n" + + "\t`c_bigint` bigint(20) DEFAULT NULL COMMENT 'bigint',\n" + + "\t`c_date` date DEFAULT '0000-00-00' COMMENT 'date',\n" + + "\t`c_datetime` datetime DEFAULT '0000-00-00 00:00:00' COMMENT 'datetime',\n" + + "\t`c_timestamp` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT 'timestamp',\n" + + "\t`c_time` time DEFAULT NULL COMMENT 'time',\n" + + "\t`c_char` char(10) DEFAULT NULL COMMENT 'char',\n" + + "\t`c_varchar` varchar(10) DEFAULT 'hello' COMMENT 'varchar',\n" + + "\t`c_blob` blob COMMENT 'blob',\n" + + "\t`c_text` text COMMENT 'text',\n" + + "\t`c_mediumtext` mediumtext COMMENT 'mediumtext',\n" + + "\t`c_longblob` longblob COMMENT 'longblob',\n" + + "\tKEY `k_c` (`c_tinyint`, `c_int`)\n" + + ") ENGINE = InnoDB AUTO_INCREMENT = 1769503 CHARSET = utf8mb4 COMMENT = '10000000'", createTableStmt.toString()); + + assertEquals("+--------------+--------------+------+-----+---------------------+-----------------------------+\n" + + "| Field | Type | Null | Key | Default | Extra |\n" + + "+--------------+--------------+------+-----+---------------------+-----------------------------+\n" + + "| c_decimal_1 | INT(11) | YES | | NULL | |\n" + + "| id | bigint(20) | YES | | NULL | auto_increment |\n" + + "| c_tinyint | tinyint(4) | NO | MUL | 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 | | NULL | |\n" + + "| c_varchar | varchar(10) | NO | | 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", repository.console("show columns from test1")); } }