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 1990ed7022..283bf3271f 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 @@ -28,23 +28,7 @@ import com.alibaba.druid.sql.ast.expr.SQLAggregateExpr; import com.alibaba.druid.sql.ast.expr.SQLCharExpr; import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr; import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr; -import com.alibaba.druid.sql.ast.statement.SQLAlterTableAddColumn; -import com.alibaba.druid.sql.ast.statement.SQLAlterTableItem; -import com.alibaba.druid.sql.ast.statement.SQLAlterTableStatement; -import com.alibaba.druid.sql.ast.statement.SQLAssignItem; -import com.alibaba.druid.sql.ast.statement.SQLBlockStatement; -import com.alibaba.druid.sql.ast.statement.SQLCharacterDataType; -import com.alibaba.druid.sql.ast.statement.SQLColumnConstraint; -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.SQLExprTableSource; -import com.alibaba.druid.sql.ast.statement.SQLIfStatement; -import com.alibaba.druid.sql.ast.statement.SQLInsertStatement; -import com.alibaba.druid.sql.ast.statement.SQLLoopStatement; -import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; -import com.alibaba.druid.sql.ast.statement.SQLShowTablesStatement; -import com.alibaba.druid.sql.ast.statement.SQLStartTransactionStatement; +import com.alibaba.druid.sql.ast.statement.*; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlForceIndexHint; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlIgnoreIndexHint; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlKey; @@ -2661,43 +2645,22 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV @Override public boolean visit(MySqlUnionQuery x) { - { - boolean needParen = false; - if (x.getLeft() instanceof MySqlSelectQueryBlock) { - MySqlSelectQueryBlock right = (MySqlSelectQueryBlock) x.getLeft(); - if (right.getOrderBy() != null || right.getLimit() != null) { - needParen = true; - } - } - if (needParen) { - print('('); - x.getLeft().accept(this); - print(')'); - } else { - x.getLeft().accept(this); - } - } + print('('); + x.getLeft().accept(this); + print(')'); println(); print0(ucase ? x.getOperator().name : x.getOperator().name_lcase); println(); - boolean needParen = false; - - if (x.getOrderBy() != null || x.getLimit() != null) { - needParen = true; - } else if (x.getRight() instanceof MySqlSelectQueryBlock) { - MySqlSelectQueryBlock right = (MySqlSelectQueryBlock) x.getRight(); - if (right.getOrderBy() != null || right.getLimit() != null) { - needParen = true; - } - } + SQLSelectQuery right = x.getRight(); + boolean needParen = ! (right instanceof SQLUnionQuery); if (needParen) { print('('); - x.getRight().accept(this); + right.accept(this); print(')'); } else { - x.getRight().accept(this); + right.accept(this); } if (x.getOrderBy() != null) { diff --git a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java index 222a4c3817..7f8c86b3f8 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java @@ -1712,16 +1712,23 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Paramet @Override public boolean visit(SQLUnionQuery x) { - x.getLeft().accept(this); - println(); - print0(ucase ? x.getOperator().name : x.getOperator().name_lcase); - println(); + SQLUnionOperator operator = x.getOperator(); - boolean needParen = false; + boolean mysqlUnion = (JdbcConstants.MYSQL.equals(dbType) // + && (operator == SQLUnionOperator.UNION || operator == SQLUnionOperator.UNION_ALL)); - if (x.getOrderBy() != null) { - needParen = true; + if (mysqlUnion) { + print('('); } + x.getLeft().accept(this); + if (mysqlUnion) { + print(')'); + } + println(); + print0(ucase ? operator.name : operator.name_lcase); + println(); + + boolean needParen = x.getOrderBy() != null || mysqlUnion; if (needParen) { print('('); diff --git a/src/test/java/com/alibaba/druid/bvt/filter/wall/TenantInsertTest.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/TenantInsertTest.java index 13fbaf0d3c..839f6393a0 100644 --- a/src/test/java/com/alibaba/druid/bvt/filter/wall/TenantInsertTest.java +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/TenantInsertTest.java @@ -126,15 +126,15 @@ public class TenantInsertTest extends TestCase { public void testMySql6() throws Exception { String insert_sql = "INSERT INTO orders (ID, NAME) SELECT ID, NAME FROM temp1 WHERE age = 18 UNION SELECT ID, NAME FROM temp2 UNION ALL SELECT ID, NAME FROM temp3"; String expect_sql = "INSERT INTO orders (ID, NAME, tenant)" + // - "\nSELECT ID, NAME, 123" + // + "\n(SELECT ID, NAME, 123" + // "\nFROM temp1" + // - "\nWHERE age = 18" + // + "\nWHERE age = 18)" + // "\nUNION" + // - "\nSELECT ID, NAME, 123" + // - "\nFROM temp2" + // + "\n(SELECT ID, NAME, 123" + // + "\nFROM temp2)" + // "\nUNION ALL" + // - "\nSELECT ID, NAME, 123" + // - "\nFROM temp3"; + "\n(SELECT ID, NAME, 123" + // + "\nFROM temp3)"; { MySqlWallProvider provider = new MySqlWallProvider(config_callback); diff --git a/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest_Count_MySql_0.java b/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest_Count_MySql_0.java index 754f3cb9e8..63944d9bc8 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest_Count_MySql_0.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest_Count_MySql_0.java @@ -51,11 +51,11 @@ public class PagerUtilsTest_Count_MySql_0 extends TestCase { String sql = "select id, name from t1 union select id, name from t2 order by id"; String result = PagerUtils.count(sql, JdbcConstants.MYSQL); Assert.assertEquals("SELECT COUNT(*)\n" + // - "FROM (SELECT id, name" + // - "\n\tFROM t1" + // + "FROM ((SELECT id, name" + // + "\n\tFROM t1)" + // "\n\tUNION" + // - "\n\tSELECT id, name" + // - "\n\tFROM t2" + // + "\n\t(SELECT id, name" + // + "\n\tFROM t2)" + // "\n\t) ALIAS_COUNT", result); } } diff --git a/src/test/java/com/alibaba/druid/bvt/sql/cobar/DMLSelectParserTest.java b/src/test/java/com/alibaba/druid/bvt/sql/cobar/DMLSelectParserTest.java index 63e36ed8f2..d9e5330624 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/cobar/DMLSelectParserTest.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/cobar/DMLSelectParserTest.java @@ -31,11 +31,11 @@ public class DMLSelectParserTest extends TestCase { SQLStatement stmt = parser.parseStatementList().get(0); parser.match(Token.EOF); String output = SQLUtils.toMySqlString(stmt); - Assert.assertEquals("SELECT id\n" + // - "FROM t1\n" + // + Assert.assertEquals("(SELECT id\n" + // + "FROM t1)\n" + // "UNION ALL\n" + // - "SELECT id\n" + // - "FROM t2\n" + // + "(SELECT id\n" + // + "FROM t2)\n" + // "UNION ALL\n" + // "(SELECT id\n" + // "FROM t3)\n" + // @@ -49,8 +49,8 @@ public class DMLSelectParserTest extends TestCase { SQLStatement stmt = parser.parseStatementList().get(0); parser.match(Token.EOF); String output = SQLUtils.toMySqlString(stmt); - Assert.assertEquals("SELECT id\n" + // - "FROM t1\n" + // + Assert.assertEquals("(SELECT id\n" + // + "FROM t1)\n" + // "UNION\n" + // "(SELECT id\n" + // "FROM t2\n" + // @@ -67,7 +67,7 @@ public class DMLSelectParserTest extends TestCase { SQLStatement stmt = parser.parseStatementList().get(0); parser.match(Token.EOF); String output = SQLUtils.toMySqlString(stmt); - Assert.assertEquals("SELECT id\nFROM t1\nUNION DISTINCT\nSELECT id\nFROM t2\nUNION\nSELECT id\nFROM t3", output); + Assert.assertEquals("(SELECT id\nFROM t1)\nUNION DISTINCT\n(SELECT id\nFROM t2)\nUNION\n(SELECT id\nFROM t3)", output); } public void test_select_0() throws Exception { diff --git a/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlDeleteTest_3.java b/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlDeleteTest_3.java index 49119327f6..6c6d871815 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlDeleteTest_3.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlDeleteTest_3.java @@ -49,13 +49,13 @@ public class MySqlDeleteTest_3 extends MysqlTest { + "\n\t\t\tSELECT *" + "\n\t\t\tFROM t3" + "\n\t\t\tWHERE ROW(5 * t2.s1, 77) = (" - + "\n\t\t\t\tSELECT 50, 11 * s1" - + "\n\t\t\t\tFROM t4" + + "\n\t\t\t\t(SELECT 50, 11 * s1" + + "\n\t\t\t\tFROM t4)" + "\n\t\t\t\tUNION" - + "\n\t\t\t\tSELECT 50, 77" + + "\n\t\t\t\t(SELECT 50, 77" + "\n\t\t\t\tFROM (SELECT *" + "\n\t\t\t\t\tFROM t5" - + "\n\t\t\t\t\t) t5" + + "\n\t\t\t\t\t) t5)" + "\n\t\t\t\t)" + "\n\t\t\t))", SQLUtils.toMySqlString(stmt)); Assert.assertEquals("delete from t1" @@ -65,13 +65,13 @@ public class MySqlDeleteTest_3 extends MysqlTest { + "\n\t\t\tselect *" + "\n\t\t\tfrom t3" + "\n\t\t\twhere ROW(5 * t2.s1, 77) = (" - + "\n\t\t\t\tselect 50, 11 * s1" - + "\n\t\t\t\tfrom t4" + + "\n\t\t\t\t(select 50, 11 * s1" + + "\n\t\t\t\tfrom t4)" + "\n\t\t\t\tunion" - + "\n\t\t\t\tselect 50, 77" + + "\n\t\t\t\t(select 50, 77" + "\n\t\t\t\tfrom (select *" + "\n\t\t\t\t\tfrom t5" - + "\n\t\t\t\t\t) t5" + + "\n\t\t\t\t\t) t5)" + "\n\t\t\t\t)" + "\n\t\t\t))", SQLUtils.toMySqlString(stmt, SQLUtils.DEFAULT_LCASE_FORMAT_OPTION)); diff --git a/src/test/java/com/alibaba/druid/bvt/sql/mysql/SQLUtilsTest.java b/src/test/java/com/alibaba/druid/bvt/sql/mysql/SQLUtilsTest.java index d87a2087e8..2112073d53 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/mysql/SQLUtilsTest.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/mysql/SQLUtilsTest.java @@ -40,11 +40,13 @@ public class SQLUtilsTest extends TestCase { public void test_format_3() throws Exception { String sql = "select lottery_notice_issue,lottery_notice_date,lottery_notice_result from tb_lottery_notice where lottery_type_id=8 and lottery_notice_issue<=2014066 UNION ALL SELECT NULL, NULL, NULL, NULL, NULL, NULL# and lottery_notice_issue>=2014062 order by lottery_notice_issue desc"; String formattedSql = SQLUtils.formatMySql(sql); - String expected = "SELECT lottery_notice_issue, lottery_notice_date, lottery_notice_result" - + "\nFROM tb_lottery_notice" + "\nWHERE lottery_type_id = 8" - + "\n\tAND lottery_notice_issue <= 2014066" + "\nUNION ALL" - + "\nSELECT NULL, NULL, NULL, NULL, NULL" // - + "\n\t, NULL# and lottery_notice_issue>=2014062 order by lottery_notice_issue desc"; + String expected = "(SELECT lottery_notice_issue, lottery_notice_date, lottery_notice_result" + + "\nFROM tb_lottery_notice" + + "\nWHERE lottery_type_id = 8" + + "\n\tAND lottery_notice_issue <= 2014066)" + + "\nUNION ALL" + + "\n(SELECT NULL, NULL, NULL, NULL, NULL" // + + "\n\t, NULL)# and lottery_notice_issue>=2014062 order by lottery_notice_issue desc"; Assert.assertEquals(expected, formattedSql); } } diff --git a/src/test/resources/bvt/parser/mysql-6.txt b/src/test/resources/bvt/parser/mysql-6.txt index bf4d3016e2..7d03d274c6 100644 --- a/src/test/resources/bvt/parser/mysql-6.txt +++ b/src/test/resources/bvt/parser/mysql-6.txt @@ -39,19 +39,19 @@ from ( --------------------------- SELECT COUNT(*) FROM ( - SELECT a.activity_offer_id AS adResourceId, a.title AS adResourceName, a.b2boffer_url AS adResourceURL, a.custid, b.memberid + (SELECT a.activity_offer_id AS adResourceId, a.title AS adResourceName, a.b2boffer_url AS adResourceURL, a.custid, b.memberid , c.position_name AS positionName, c.charge_setting AS feeRegulation, a.priority_weight AS priorityWeight, a.audit_state AS adResourceState, 0 AS adResourceType , a.gmt_create, a.refuse_remark FROM q_activity_offer_enroll a, q_custinfo b, q_activity_position c WHERE a.custid = b.custid AND a.activity_position_id = c.activity_position_id - AND c.activity_id = ? + AND c.activity_id = ?) UNION ALL - SELECT a.reg_position_id AS adResourceId, b.custname AS adResourceName, NULL AS adResourceURL, a.custid, b.memberid + (SELECT a.reg_position_id AS adResourceId, b.custname AS adResourceName, NULL AS adResourceURL, a.custid, b.memberid , c.position_name AS positionName, c.charge_setting AS feeRegulation, NULL AS priorityWeight, a.audit_state AS adResourceState, 1 AS adResourceType , a.gmt_create, a.refuse_remark FROM q_activity_custom_enroll a, q_custinfo b, q_activity_position c WHERE a.custid = b.custid AND a.activity_position_id = c.activity_position_id - AND c.activity_id = ? + AND c.activity_id = ?) ) a