From 8d82757aed6577b0c77ad5727c649d7aa608dd0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=95=8A=E8=A5=BF?= Date: Thu, 24 Oct 2024 11:38:04 +0800 Subject: [PATCH] Gaussdb parser support insert overwrite. --- .../ast/stmt/GaussDbInsertStatement.java | 24 +++ .../dialect/gaussdb/parser/GaussDbLexer.java | 1 + .../parser/GaussDbStatementParser.java | 157 ++++++++++++++++++ .../gaussdb/visitor/GaussDbASTVisitor.java | 8 + .../gaussdb/visitor/GaussDbOutputVisitor.java | 69 ++++++++ ...eateTest.java => GaussDbResourceTest.java} | 4 +- .../test/resources/bvt/parser/gaussdb/1.txt | 16 ++ 7 files changed, 277 insertions(+), 2 deletions(-) create mode 100644 core/src/main/java/com/alibaba/druid/sql/dialect/gaussdb/ast/stmt/GaussDbInsertStatement.java rename core/src/test/java/com/alibaba/druid/bvt/sql/gaussdb/{GaussDbCreateTest.java => GaussDbResourceTest.java} (77%) create mode 100644 core/src/test/resources/bvt/parser/gaussdb/1.txt diff --git a/core/src/main/java/com/alibaba/druid/sql/dialect/gaussdb/ast/stmt/GaussDbInsertStatement.java b/core/src/main/java/com/alibaba/druid/sql/dialect/gaussdb/ast/stmt/GaussDbInsertStatement.java new file mode 100644 index 0000000000..077155b5e8 --- /dev/null +++ b/core/src/main/java/com/alibaba/druid/sql/dialect/gaussdb/ast/stmt/GaussDbInsertStatement.java @@ -0,0 +1,24 @@ +package com.alibaba.druid.sql.dialect.gaussdb.ast.stmt; + +import com.alibaba.druid.sql.ast.SQLExpr; +import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGInsertStatement; + +import java.util.ArrayList; +import java.util.List; + +public class GaussDbInsertStatement extends PGInsertStatement { + private final List partition = new ArrayList(4); + private boolean hasTableIdentifier; + + public List getPartition() { + return partition; + } + + public void setHasTableIdentifier(boolean hasTableIdentifier) { + this.hasTableIdentifier = hasTableIdentifier; + } + + public boolean isHasTableIdentifier() { + return hasTableIdentifier; + } +} diff --git a/core/src/main/java/com/alibaba/druid/sql/dialect/gaussdb/parser/GaussDbLexer.java b/core/src/main/java/com/alibaba/druid/sql/dialect/gaussdb/parser/GaussDbLexer.java index 217e303aca..51f9a7dddf 100644 --- a/core/src/main/java/com/alibaba/druid/sql/dialect/gaussdb/parser/GaussDbLexer.java +++ b/core/src/main/java/com/alibaba/druid/sql/dialect/gaussdb/parser/GaussDbLexer.java @@ -19,6 +19,7 @@ protected Keywords loadKeywords() { map.put("START", Token.START); map.put("PARTIAL", Token.PARTIAL); map.put("KEY", Token.KEY); + map.put("OVERWRITE", Token.OVERWRITE); map.putAll(super.loadKeywords().getKeywords()); return new Keywords(map); } diff --git a/core/src/main/java/com/alibaba/druid/sql/dialect/gaussdb/parser/GaussDbStatementParser.java b/core/src/main/java/com/alibaba/druid/sql/dialect/gaussdb/parser/GaussDbStatementParser.java index de4472cac4..936e16e91e 100644 --- a/core/src/main/java/com/alibaba/druid/sql/dialect/gaussdb/parser/GaussDbStatementParser.java +++ b/core/src/main/java/com/alibaba/druid/sql/dialect/gaussdb/parser/GaussDbStatementParser.java @@ -1,8 +1,21 @@ package com.alibaba.druid.sql.dialect.gaussdb.parser; +import com.alibaba.druid.sql.ast.SQLExpr; +import com.alibaba.druid.sql.ast.SQLName; +import com.alibaba.druid.sql.ast.expr.SQLListExpr; +import com.alibaba.druid.sql.ast.expr.SQLQueryExpr; import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement; +import com.alibaba.druid.sql.ast.statement.SQLInsertStatement; +import com.alibaba.druid.sql.ast.statement.SQLUpdateSetItem; +import com.alibaba.druid.sql.dialect.gaussdb.ast.stmt.GaussDbInsertStatement; +import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGInsertStatement; import com.alibaba.druid.sql.dialect.postgresql.parser.PGSQLStatementParser; import com.alibaba.druid.sql.parser.SQLParserFeature; +import com.alibaba.druid.sql.parser.Token; +import com.alibaba.druid.util.FnvHash; + +import java.util.ArrayList; +import java.util.List; public class GaussDbStatementParser extends PGSQLStatementParser { public GaussDbStatementParser(String sql) { @@ -21,4 +34,148 @@ public GaussDbCreateTableParser getSQLCreateTableParser() { public SQLCreateTableStatement parseCreateTable() { return getSQLCreateTableParser().parseCreateTable(); } + + @Override + public PGInsertStatement parseInsert() { + GaussDbInsertStatement stmt = new GaussDbInsertStatement(); + + if (lexer.token() == Token.INSERT) { + lexer.nextToken(); + if (lexer.token() == Token.INTO) { + lexer.nextToken(); + } else { + accept(Token.OVERWRITE); + stmt.setOverwrite(true); + } + + if (lexer.token() == Token.TABLE) { + lexer.nextToken(); + stmt.setHasTableIdentifier(true); + } + stmt.setTableSource(this.exprParser.name()); + if (lexer.token() == Token.AS) { + lexer.nextToken(); + stmt.setAlias(lexer.stringVal()); + lexer.nextToken(); + } else if (lexer.token() == Token.IDENTIFIER) { + stmt.setAlias(lexer.stringVal()); + lexer.nextToken(); + } + + } + + if (lexer.token() == Token.PARTITION) { + lexer.nextToken(); + accept(Token.LPAREN); + this.exprParser.exprList(stmt.getPartition(), stmt); + accept(Token.RPAREN); + } + + if (lexer.token() == Token.DEFAULT) { + lexer.nextToken(); + accept(Token.VALUES); + stmt.setDefaultValues(true); + } + + if (lexer.token() == (Token.LPAREN)) { + lexer.nextToken(); + this.exprParser.exprList(stmt.getColumns(), stmt); + accept(Token.RPAREN); + } + + if (lexer.token() == (Token.VALUES)) { + lexer.nextToken(); + + for (; ; ) { + accept(Token.LPAREN); + SQLInsertStatement.ValuesClause valuesCaluse = new SQLInsertStatement.ValuesClause(); + this.exprParser.exprList(valuesCaluse.getValues(), valuesCaluse); + stmt.addValueCause(valuesCaluse); + + accept(Token.RPAREN); + if (lexer.token() == Token.COMMA) { + lexer.nextToken(); + continue; + } + break; + } + } else if (lexer.token() == (Token.SELECT)) { + SQLQueryExpr queryExpr = (SQLQueryExpr) this.exprParser.expr(); + stmt.setQuery(queryExpr.getSubQuery()); + } + + if (lexer.token() == Token.ON) { + lexer.nextToken(); + if (lexer.identifierEquals(FnvHash.Constants.CONFLICT)) { + lexer.nextToken(); + + if (lexer.token() == Token.LPAREN) { + lexer.nextToken(); + List onConflictTarget = new ArrayList(); + this.exprParser.exprList(onConflictTarget, stmt); + stmt.setOnConflictTarget(onConflictTarget); + accept(Token.RPAREN); + } + + if (lexer.token() == Token.ON) { + lexer.nextToken(); + accept(Token.CONSTRAINT); + SQLName constraintName = this.exprParser.name(); + stmt.setOnConflictConstraint(constraintName); + } + + if (lexer.token() == Token.WHERE) { + lexer.nextToken(); + SQLExpr where = this.exprParser.expr(); + stmt.setOnConflictWhere(where); + } + + if (lexer.token() == Token.DO) { + lexer.nextToken(); + + if (lexer.identifierEquals(FnvHash.Constants.NOTHING)) { + lexer.nextToken(); + stmt.setOnConflictDoNothing(true); + } else { + accept(Token.UPDATE); + accept(Token.SET); + + for (; ; ) { + SQLUpdateSetItem item = this.exprParser.parseUpdateSetItem(); + stmt.addConflicUpdateItem(item); + + if (lexer.token() != Token.COMMA) { + break; + } + + lexer.nextToken(); + } + if (lexer.token() == Token.WHERE) { + lexer.nextToken(); + SQLExpr where = this.exprParser.expr(); + stmt.setOnConflictUpdateWhere(where); + } + } + } + } + } + + if (lexer.token() == Token.RETURNING) { + lexer.nextToken(); + SQLExpr returning = this.exprParser.expr(); + + if (lexer.token() == Token.COMMA) { + lexer.nextToken(); + SQLListExpr list = new SQLListExpr(); + list.addItem(returning); + + this.exprParser.exprList(list.getItems(), list); + + returning = list; + } + + stmt.setReturning(returning); + } + return stmt; + } } diff --git a/core/src/main/java/com/alibaba/druid/sql/dialect/gaussdb/visitor/GaussDbASTVisitor.java b/core/src/main/java/com/alibaba/druid/sql/dialect/gaussdb/visitor/GaussDbASTVisitor.java index 49d25129c1..93f6bfd56c 100644 --- a/core/src/main/java/com/alibaba/druid/sql/dialect/gaussdb/visitor/GaussDbASTVisitor.java +++ b/core/src/main/java/com/alibaba/druid/sql/dialect/gaussdb/visitor/GaussDbASTVisitor.java @@ -2,6 +2,7 @@ import com.alibaba.druid.sql.dialect.gaussdb.ast.GaussDbCreateTableStatement; import com.alibaba.druid.sql.dialect.gaussdb.ast.GaussDbDistributeBy; +import com.alibaba.druid.sql.dialect.gaussdb.ast.stmt.GaussDbInsertStatement; import com.alibaba.druid.sql.visitor.SQLASTVisitor; public interface GaussDbASTVisitor extends SQLASTVisitor { @@ -15,4 +16,11 @@ default boolean visit(GaussDbDistributeBy x) { } default void endVisit(GaussDbDistributeBy x) { } + + default boolean visit(GaussDbInsertStatement x) { + return true; + } + + default void endVisit(GaussDbInsertStatement x) { + } } diff --git a/core/src/main/java/com/alibaba/druid/sql/dialect/gaussdb/visitor/GaussDbOutputVisitor.java b/core/src/main/java/com/alibaba/druid/sql/dialect/gaussdb/visitor/GaussDbOutputVisitor.java index 2a79507ec8..289583b245 100644 --- a/core/src/main/java/com/alibaba/druid/sql/dialect/gaussdb/visitor/GaussDbOutputVisitor.java +++ b/core/src/main/java/com/alibaba/druid/sql/dialect/gaussdb/visitor/GaussDbOutputVisitor.java @@ -4,9 +4,12 @@ import com.alibaba.druid.sql.ast.*; import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition; import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement; +import com.alibaba.druid.sql.ast.statement.SQLInsertStatement; +import com.alibaba.druid.sql.ast.statement.SQLWithSubqueryClause; import com.alibaba.druid.sql.dialect.gaussdb.ast.GaussDbCreateTableStatement; import com.alibaba.druid.sql.dialect.gaussdb.ast.GaussDbDistributeBy; import com.alibaba.druid.sql.dialect.gaussdb.ast.GaussDbPartitionValue; +import com.alibaba.druid.sql.dialect.gaussdb.ast.stmt.GaussDbInsertStatement; import com.alibaba.druid.sql.visitor.SQLASTOutputVisitor; import java.util.List; @@ -309,4 +312,70 @@ public boolean visit(GaussDbDistributeBy x) { } return false; } + + @Override + public boolean visit(SQLInsertStatement x) { + if (x instanceof GaussDbInsertStatement) { + return visit((GaussDbInsertStatement) x); + } + return super.visit(x); + } + + @Override + public boolean visit(GaussDbInsertStatement x) { + List headHints = x.getHeadHintsDirect(); + if (headHints != null) { + for (SQLCommentHint hint : headHints) { + hint.accept(this); + println(); + } + } + + if (x.getInsertBeforeCommentsDirect() != null) { + printlnComments(x.getInsertBeforeCommentsDirect()); + } + + SQLWithSubqueryClause with = x.getWith(); + if (with != null) { + visit(with); + println(); + } + + if (x.isOverwrite()) { + print0(ucase ? "INSERT OVERWRITE " : "insert overwrite "); + } else { + print0(ucase ? "INSERT INTO " : "insert into "); + } + + if (x.isHasTableIdentifier()) { + print0(ucase ? "TABLE " : "table "); + } + x.getTableSource().accept(this); + + if (!x.getPartition().isEmpty()) { + print(" PARTITION ("); + printAndAccept(x.getPartition(), ","); + print(")"); + } + + String columnsString = x.getColumnsString(); + if (columnsString != null) { + print0(columnsString); + } else { + printInsertColumns(x.getColumns()); + } + + if (!x.getValuesList().isEmpty()) { + println(); + print0(ucase ? "VALUES " : "values "); + printAndAccept(x.getValuesList(), ", "); + } else { + if (x.getQuery() != null) { + println(); + x.getQuery().accept(this); + } + } + + return false; + } } diff --git a/core/src/test/java/com/alibaba/druid/bvt/sql/gaussdb/GaussDbCreateTest.java b/core/src/test/java/com/alibaba/druid/bvt/sql/gaussdb/GaussDbResourceTest.java similarity index 77% rename from core/src/test/java/com/alibaba/druid/bvt/sql/gaussdb/GaussDbCreateTest.java rename to core/src/test/java/com/alibaba/druid/bvt/sql/gaussdb/GaussDbResourceTest.java index 1d6957dd97..1487d96bfa 100644 --- a/core/src/test/java/com/alibaba/druid/bvt/sql/gaussdb/GaussDbCreateTest.java +++ b/core/src/test/java/com/alibaba/druid/bvt/sql/gaussdb/GaussDbResourceTest.java @@ -2,8 +2,8 @@ import com.alibaba.druid.DbType; import com.alibaba.druid.bvt.sql.SQLResourceTest; import org.junit.Test; -public class GaussDbCreateTest extends SQLResourceTest { - public GaussDbCreateTest() { +public class GaussDbResourceTest extends SQLResourceTest { + public GaussDbResourceTest() { super(DbType.gaussdb); } @Test diff --git a/core/src/test/resources/bvt/parser/gaussdb/1.txt b/core/src/test/resources/bvt/parser/gaussdb/1.txt new file mode 100644 index 0000000000..ad5aae6fdd --- /dev/null +++ b/core/src/test/resources/bvt/parser/gaussdb/1.txt @@ -0,0 +1,16 @@ +insert overwrite table edw_dwi.dwi_pub_eps_itsm_work_order_history_da partition (dt = '${deal_date}') +select + historyid as history_id , + workorderid as work_order_id , + operationownerid as operation_owner_id , + operationtime as operation_time , + description as description , + operation as operation +from smart_sdi.sdi_itsm_public_workorderhistory_da +where dt = '${deal_date}' +-------------------- +INSERT OVERWRITE TABLE edw_dwi.dwi_pub_eps_itsm_work_order_history_da PARTITION (dt = '${deal_date}') +SELECT historyid AS history_id, workorderid AS work_order_id, operationownerid AS operation_owner_id, operationtime AS operation_time, description AS description + , operation AS operation +FROM smart_sdi.sdi_itsm_public_workorderhistory_da +WHERE dt = '${deal_date}' \ No newline at end of file