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:**
+---
+
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());
+ }
+ }
+ }
+}