diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLDeleteStatement.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLDeleteStatement.java index d4b8ab7a53..8241b3abbc 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLDeleteStatement.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLDeleteStatement.java @@ -54,7 +54,23 @@ public class SQLDeleteStatement extends SQLStatementImpl { } public SQLName getTableName() { - return (SQLName) getExprTableSource().getExpr(); + if (this.tableSource instanceof SQLExprTableSource) { + SQLExprTableSource exprTableSource = (SQLExprTableSource) this.tableSource; + return (SQLName) exprTableSource.getExpr(); + } + + if (tableSource instanceof SQLSubqueryTableSource) { + SQLSelectQuery selectQuery = ((SQLSubqueryTableSource) tableSource).getSelect().getQuery(); + if (selectQuery instanceof SQLSelectQueryBlock) { + SQLTableSource subQueryTableSource = ((SQLSelectQueryBlock) selectQuery).getFrom(); + if (subQueryTableSource instanceof SQLExprTableSource) { + SQLExpr subQueryTableSourceExpr = ((SQLExprTableSource) subQueryTableSource).getExpr(); + return (SQLName) subQueryTableSourceExpr; + } + } + } + + return null; } public void setTableName(SQLName tableName) { diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleStatementParser.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleStatementParser.java index 14218e6135..75a16a94f2 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleStatementParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleStatementParser.java @@ -29,30 +29,7 @@ import com.alibaba.druid.sql.ast.expr.SQLBinaryOperator; import com.alibaba.druid.sql.ast.expr.SQLCharExpr; import com.alibaba.druid.sql.ast.expr.SQLNullExpr; import com.alibaba.druid.sql.ast.expr.SQLQueryExpr; -import com.alibaba.druid.sql.ast.statement.SQLAlterTableAddColumn; -import com.alibaba.druid.sql.ast.statement.SQLAlterTableAddConstraint; -import com.alibaba.druid.sql.ast.statement.SQLAlterTableDisableConstraint; -import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropColumnItem; -import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropConstraint; -import com.alibaba.druid.sql.ast.statement.SQLAlterTableEnableConstraint; -import com.alibaba.druid.sql.ast.statement.SQLAlterTableStatement; -import com.alibaba.druid.sql.ast.statement.SQLBlockStatement; -import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition; -import com.alibaba.druid.sql.ast.statement.SQLCreateProcedureStatement; -import com.alibaba.druid.sql.ast.statement.SQLDropProcedureStatement; -import com.alibaba.druid.sql.ast.statement.SQLDropSequenceStatement; -import com.alibaba.druid.sql.ast.statement.SQLDropTableStatement; -import com.alibaba.druid.sql.ast.statement.SQLDropTriggerStatement; -import com.alibaba.druid.sql.ast.statement.SQLDropUserStatement; -import com.alibaba.druid.sql.ast.statement.SQLIfStatement; -import com.alibaba.druid.sql.ast.statement.SQLInsertInto; -import com.alibaba.druid.sql.ast.statement.SQLLoopStatement; -import com.alibaba.druid.sql.ast.statement.SQLRollbackStatement; -import com.alibaba.druid.sql.ast.statement.SQLSelect; -import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem; -import com.alibaba.druid.sql.ast.statement.SQLSelectStatement; -import com.alibaba.druid.sql.ast.statement.SQLSetStatement; -import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement; +import com.alibaba.druid.sql.ast.statement.*; import com.alibaba.druid.sql.dialect.oracle.ast.clause.OracleReturningClause; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleAlterIndexStatement; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleAlterProcedureStatement; @@ -1283,6 +1260,9 @@ public class OracleStatementParser extends SQLStatementParser { deleteStatement.setTableName(tableName); accept(Token.RPAREN); + } else if (lexer.token() == Token.LPAREN) { + SQLTableSource tableSource = this.createSQLSelectParser().parseTableSource(); + deleteStatement.setTableSource(tableSource); } else { SQLName tableName = exprParser.name(); deleteStatement.setTableName(tableName); diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleOutputVisitor.java index 00225b21de..05217b0823 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleOutputVisitor.java @@ -28,24 +28,8 @@ import com.alibaba.druid.sql.ast.expr.SQLCharExpr; import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; import com.alibaba.druid.sql.ast.expr.SQLLiteralExpr; import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr; -import com.alibaba.druid.sql.ast.statement.SQLAlterTableItem; -import com.alibaba.druid.sql.ast.statement.SQLAlterTableStatement; -import com.alibaba.druid.sql.ast.statement.SQLBlockStatement; -import com.alibaba.druid.sql.ast.statement.SQLCharacterDataType; -import com.alibaba.druid.sql.ast.statement.SQLCheck; -import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition; -import com.alibaba.druid.sql.ast.statement.SQLCreateProcedureStatement; -import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement; -import com.alibaba.druid.sql.ast.statement.SQLForeignKeyImpl; -import com.alibaba.druid.sql.ast.statement.SQLIfStatement; -import com.alibaba.druid.sql.ast.statement.SQLInsertStatement; +import com.alibaba.druid.sql.ast.statement.*; import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource.JoinType; -import com.alibaba.druid.sql.ast.statement.SQLRollbackStatement; -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.ast.statement.SQLTruncateStatement; -import com.alibaba.druid.sql.ast.statement.SQLUnique; import com.alibaba.druid.sql.dialect.oracle.ast.OracleDataTypeIntervalDay; import com.alibaba.druid.sql.dialect.oracle.ast.OracleDataTypeIntervalYear; import com.alibaba.druid.sql.dialect.oracle.ast.OracleDataTypeTimestamp; @@ -264,26 +248,27 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS } public boolean visit(OracleDeleteStatement x) { - if (x.getTableName() != null) { - print0(ucase ? "DELETE " : "delete "); - - if (x.getHints().size() > 0) { - printAndAccept(x.getHints(), ", "); - print(' '); - } + print0(ucase ? "DELETE " : "delete "); - print0(ucase ? "FROM " : "from "); - if (x.isOnly()) { - print0(ucase ? "ONLY (" : "only ("); - x.getTableName().accept(this); - print(')'); - } else { - x.getTableName().accept(this); - } + SQLTableSource tableSource = x.getTableSource(); - printAlias(x.getAlias()); + if (x.getHints().size() > 0) { + printAndAccept(x.getHints(), ", "); + print(' '); } + print0(ucase ? "FROM " : "from "); + if (x.isOnly()) { + print0(ucase ? "ONLY (" : "only ("); + x.getTableName().accept(this); + print(')'); + } else { + x.getTableSource().accept(this); + } + + printAlias(x.getAlias()); + + if (x.getWhere() != null) { println(); incrementIndent(); diff --git a/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java b/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java index fefba543b9..af0e3c30bd 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java @@ -1232,6 +1232,14 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter { putAliasMap(this.aliasMap, x.getAlias(), tableName); } + if (x.getTableSource() instanceof SQLSubqueryTableSource) { + SQLSelectQuery selectQuery = ((SQLSubqueryTableSource) x.getTableSource()).getSelect().getQuery(); + if (selectQuery instanceof SQLSelectQueryBlock) { + SQLSelectQueryBlock subQueryBlock = ((SQLSelectQueryBlock) selectQuery); + subQueryBlock.getWhere().accept(this); + } + } + TableStat stat = getTableStat(tableName); stat.incrementDeleteCount(); diff --git a/src/test/java/com/alibaba/druid/bvt/sql/oracle/OracleDeleteTest_2.java b/src/test/java/com/alibaba/druid/bvt/sql/oracle/OracleDeleteTest_2.java new file mode 100644 index 0000000000..47709137c5 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/oracle/OracleDeleteTest_2.java @@ -0,0 +1,76 @@ +/* + * Copyright 1999-2101 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; + +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 com.alibaba.druid.stat.TableStat; +import org.junit.Assert; + +import java.util.List; + +public class OracleDeleteTest_2 extends OracleTest { + + public void test_0() throws Exception { + String sql = "DELETE FROM (SELECT * FROM ABC WHERE ID=6000)"; + + OracleStatementParser parser = new OracleStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + + 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()); + + Assert.assertEquals(1, visitor.getTables().size()); + Assert.assertEquals(1, visitor.getColumns().size()); + + Assert.assertTrue(visitor.getTables().containsKey(new TableStat.Name("ABC"))); + // + Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("ABC", "ID"))); + // Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("employees", "salary"))); + // Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("employees", "commission_pct"))); + + { + String output = SQLUtils.toOracleString(stmt); + Assert.assertEquals("DELETE FROM (\n" + + "\tSELECT *\n" + + "\tFROM ABC\n" + + "\tWHERE ID = 6000\n" + + ")", // + output); + } + { + String output = SQLUtils.toOracleString(stmt, SQLUtils.DEFAULT_LCASE_FORMAT_OPTION); + Assert.assertEquals("delete from (\n" + + "\tselect *\n" + + "\tfrom ABC\n" + + "\twhere ID = 6000\n" + + ")", // + output); + } + } + +}