From 087094ed63e651093612d6407c6fc14a239f03e7 Mon Sep 17 00:00:00 2001 From: LiZongbo Date: Sat, 23 Mar 2024 00:45:35 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E5=A2=9E=E5=BC=BApostgresql=20create=20ind?= =?UTF-8?q?ex=20=E7=9A=84=E8=A7=A3=E6=9E=90=E8=83=BD=E5=8A=9B=20#5780?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 增强postgresql create index 的解析能力 #5780 --- .../ast/statement/SQLSelectOrderByItem.java | 10 ++++ .../druid/sql/parser/SQLExprParser.java | 11 +++- .../sql/visitor/SQLASTOutputVisitor.java | 16 ++--- .../bvt/sql/postgresql/issues/Issue5780.java | 59 +++++++++++++++++++ 4 files changed, 88 insertions(+), 8 deletions(-) create mode 100644 core/src/test/java/com/alibaba/druid/bvt/sql/postgresql/issues/Issue5780.java diff --git a/core/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectOrderByItem.java b/core/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectOrderByItem.java index 79a0d00126..042b13eb86 100644 --- a/core/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectOrderByItem.java +++ b/core/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectOrderByItem.java @@ -24,6 +24,8 @@ public final class SQLSelectOrderByItem extends SQLObjectImpl implements SQLReplaceable { protected SQLExpr expr; protected String collate; + protected SQLExpr opclass; + protected SQLOrderingSpecification type; protected NullsOrderType nullsOrderType; @@ -60,6 +62,14 @@ public void setCollate(String collate) { this.collate = collate; } + public SQLExpr getOpclass() { + return opclass; + } + + public void setOpclass(SQLExpr opclass) { + this.opclass = opclass; + } + public SQLOrderingSpecification getType() { return this.type; } diff --git a/core/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java b/core/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java index fa3db1d13b..7b6a005c6f 100644 --- a/core/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java +++ b/core/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java @@ -2987,8 +2987,17 @@ public SQLSelectOrderByItem parseSelectOrderByItem() { String collate = lexer.stringVal(); item.setCollate(collate); lexer.nextToken(); + if (lexer.token == Token.DOT) { + lexer.nextToken(); + String collateOther = lexer.stringVal(); + item.setCollate(collate + "." + collateOther); + lexer.nextToken(); + } + } + if (lexer.token == Token.LITERAL_ALIAS) { + SQLExpr name = this.expr(); + item.setOpclass(name); } - if (lexer.token == Token.ASC) { lexer.nextToken(); item.setType(SQLOrderingSpecification.ASC); diff --git a/core/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java b/core/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java index b722372d10..4fdbd8e274 100644 --- a/core/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java +++ b/core/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java @@ -2804,18 +2804,20 @@ public boolean visit(SQLSelectOrderByItem x) { printExpr(expr, parameterized); } - SQLOrderingSpecification type = x.getType(); - if (type != null) { - print(' '); - print0(ucase ? type.name : type.nameLCase); - } - String collate = x.getCollate(); if (collate != null) { print0(ucase ? " COLLATE " : " collate "); print0(collate); } - + if (x.getOpclass() != null) { + print(' '); + x.getOpclass().accept(this); + } + SQLOrderingSpecification type = x.getType(); + if (type != null) { + print(' '); + print0(ucase ? type.name : type.nameLCase); + } SQLSelectOrderByItem.NullsOrderType nullsOrderType = x.getNullsOrderType(); if (nullsOrderType != null) { print(' '); diff --git a/core/src/test/java/com/alibaba/druid/bvt/sql/postgresql/issues/Issue5780.java b/core/src/test/java/com/alibaba/druid/bvt/sql/postgresql/issues/Issue5780.java new file mode 100644 index 0000000000..582982df83 --- /dev/null +++ b/core/src/test/java/com/alibaba/druid/bvt/sql/postgresql/issues/Issue5780.java @@ -0,0 +1,59 @@ +package com.alibaba.druid.bvt.sql.postgresql.issues; + +import java.util.List; + +import com.alibaba.druid.DbType; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.parser.SQLParserUtils; +import com.alibaba.druid.sql.parser.SQLStatementParser; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * @author lizongbo + * @see Issue来源 + * @see ALTER TABLE + * @see CREATE INDEX + */ +public class Issue5780 { + + @Test + public void test_parse_alter_table_sql() { + for (DbType dbType : new DbType[]{DbType.postgresql, DbType.greenplum, DbType.edb}) { + + for (String sql : new String[]{ + "CREATE INDEX \"index_log\" ON \"public\".\"check_log\" USING btree (\n" + + " \"t_no\" COLLATE \"pg_catalog\".\"default\" \"pg_catalog\".\"text_ops\" ASC NULLS LAST\n" + + ");", + //"CREATE UNIQUE INDEX title_idx ON films (title);", + //"CREATE UNIQUE INDEX title_idx ON films (title) INCLUDE (director, rating);", +// "CREATE INDEX title_idx ON films (title) WITH (deduplicate_items = off);", +// "CREATE INDEX ON films ((lower(title)));", +// "CREATE INDEX title_idx_german ON films (title COLLATE \"de_DE\");", +// "CREATE INDEX title_idx_nulls_low ON films (title NULLS FIRST);", +// "CREATE UNIQUE INDEX title_idx ON films (title) WITH (fillfactor = 70);", +// "CREATE INDEX gin_idx ON documents_table USING GIN (locations) WITH (fastupdate = off);", +// "CREATE INDEX code_idx ON films (code) TABLESPACE indexspace;", +// "CREATE INDEX pointloc\n" +// + " ON points USING gist (box(location,location));", +// "CREATE INDEX CONCURRENTLY sales_quantity_index ON sales_table (quantity);", + }) { + System.out.println("原始的sql===" + sql); + SQLStatementParser parser = SQLParserUtils.createSQLStatementParser(sql, dbType); + List statementList = parser.parseStatementList(); + System.out.println("生成的sql===" + statementList); + StringBuilder sb = new StringBuilder(); + for (SQLStatement statement : statementList) { + sb.append(statement.toString()).append(";"); + } + sb.deleteCharAt(sb.length() - 1); + parser = SQLParserUtils.createSQLStatementParser(sb.toString(), dbType); + List statementListNew = parser.parseStatementList(); + System.out.println("重新解析再生成的sql===" + statementListNew); + assertEquals(statementList.toString(), statementListNew.toString()); + } + } + } +} From c2203d451457ba9b2a9d47bf747cabfd184133d8 Mon Sep 17 00:00:00 2001 From: LiZongbo Date: Sat, 23 Mar 2024 00:50:07 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E5=A2=9E=E5=8A=A0Issue=E7=9A=84=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E6=A8=A1=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 增加Issue的默认模板,方便分析跟进 --- .github/ISSUE_TEMPLATE.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000000..df7e1190ff --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,27 @@ + +**dbtype:** +**dbversion:** +**druid verion:** +**error sql:** +**testcase code:** +**stacktrace info:** +**error info:** +--- +