diff --git a/src/main/java/com/alibaba/druid/sql/dialect/teradata/ast/stmt/TeradataInsertStatement.java b/src/main/java/com/alibaba/druid/sql/dialect/teradata/ast/stmt/TeradataInsertStatement.java new file mode 100644 index 0000000000..1b51738075 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/teradata/ast/stmt/TeradataInsertStatement.java @@ -0,0 +1,56 @@ +package com.alibaba.druid.sql.dialect.teradata.ast.stmt; + +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.druid.sql.ast.statement.SQLInsertStatement; +import com.alibaba.druid.sql.dialect.teradata.visitor.TeradataASTVisitor; +import com.alibaba.druid.sql.visitor.SQLASTVisitor; + +public class TeradataInsertStatement extends SQLInsertStatement { + private List valuesList = new ArrayList(); + + public ValuesClause getValues() { + if (valuesList.size() == 0) { + return null; + } + return valuesList.get(0); + } + + public void setValues(ValuesClause values) { + if (valuesList.size() == 0) { + valuesList.add(values); + } else { + valuesList.set(0, values); + } + } + + public List getValuesList() { + return valuesList; + } + + public void addValueCause(ValuesClause valueClause) { + valueClause.setParent(this); + valuesList.add(valueClause); + } + + @Override + protected void accept0(SQLASTVisitor visitor) { + if (visitor instanceof TeradataASTVisitor) { + accept0((TeradataASTVisitor) visitor); + } else { + throw new IllegalArgumentException("not support visitor type : " + visitor.getClass().getName()); + } + } + + protected void accept0(TeradataASTVisitor visitor) { + if (visitor.visit(this)) { + this.acceptChild(visitor, getTableSource()); + this.acceptChild(visitor, getColumns()); + this.acceptChild(visitor, getValuesList()); + this.acceptChild(visitor, getQuery()); + } + + visitor.endVisit(this); + } +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/teradata/parser/TeradataExprParser.java b/src/main/java/com/alibaba/druid/sql/dialect/teradata/parser/TeradataExprParser.java index 3976fba0ec..93ca424523 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/teradata/parser/TeradataExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/teradata/parser/TeradataExprParser.java @@ -32,6 +32,7 @@ import com.alibaba.druid.sql.dialect.teradata.ast.expr.TeradataIntervalUnit; import com.alibaba.druid.sql.parser.Lexer; import com.alibaba.druid.sql.parser.ParserException; import com.alibaba.druid.sql.parser.SQLExprParser; +import com.alibaba.druid.sql.parser.SQLSelectParser; import com.alibaba.druid.sql.parser.Token; import com.alibaba.druid.util.JdbcConstants; @@ -82,6 +83,10 @@ public class TeradataExprParser extends SQLExprParser { } } + public SQLSelectParser createSelectParser() { + return new TeradataSelectParser(this); + } + protected SQLExpr methodRest(SQLExpr expr, boolean acceptLPAREN) { if (acceptLPAREN) { accept(Token.LPAREN); diff --git a/src/main/java/com/alibaba/druid/sql/dialect/teradata/parser/TeradataStatementParser.java b/src/main/java/com/alibaba/druid/sql/dialect/teradata/parser/TeradataStatementParser.java index 1506862e0f..5ca482bcfd 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/teradata/parser/TeradataStatementParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/teradata/parser/TeradataStatementParser.java @@ -15,12 +15,22 @@ */ package com.alibaba.druid.sql.dialect.teradata.parser; +import java.util.ArrayList; import java.util.List; +import com.alibaba.druid.sql.ast.SQLExpr; +import com.alibaba.druid.sql.ast.SQLName; import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.ast.expr.SQLCharExpr; +import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr; +import com.alibaba.druid.sql.ast.expr.SQLNCharExpr; +import com.alibaba.druid.sql.ast.statement.SQLInsertStatement; +import com.alibaba.druid.sql.ast.statement.SQLSelect; import com.alibaba.druid.sql.ast.statement.SQLSelectStatement; -import com.alibaba.druid.sql.dialect.oracle.parser.OracleSelectParser; +import com.alibaba.druid.sql.ast.statement.SQLInsertStatement.ValuesClause; +import com.alibaba.druid.sql.dialect.teradata.ast.stmt.TeradataInsertStatement; import com.alibaba.druid.sql.parser.Lexer; +import com.alibaba.druid.sql.parser.ParserException; import com.alibaba.druid.sql.parser.SQLStatementParser; import com.alibaba.druid.sql.parser.Token; import com.alibaba.druid.util.JdbcConstants; @@ -48,6 +58,160 @@ public class TeradataStatementParser extends SQLStatementParser { return new SQLSelectStatement(selectParser.select(), JdbcConstants.TERADATA); } + public SQLInsertStatement parseInsert() { + TeradataInsertStatement insertStatement = new TeradataInsertStatement(); + + if (lexer.token() == Token.INSERT) { + lexer.nextToken(); + + if (lexer.token() == Token.INTO) { + lexer.nextToken(); + } + + SQLName tableName = this.exprParser.name(); + insertStatement.setTableName(tableName); + + if (lexer.token() == Token.IDENTIFIER && !identifierEquals("VALUE")) { + insertStatement.setAlias(lexer.stringVal()); + lexer.nextToken(); + } + } + + int columnSize = 0; + if (lexer.token() == (Token.LPAREN)) { + lexer.nextToken(); + if (lexer.token() == (Token.SELECT)) { + SQLSelect select = this.exprParser.createSelectParser().select(); + select.setParent(insertStatement); + insertStatement.setQuery(select); + } else { + this.exprParser.exprList(insertStatement.getColumns(), insertStatement); + columnSize = insertStatement.getColumns().size(); + } + accept(Token.RPAREN); + } + + if (lexer.token() == Token.VALUES || identifierEquals("VALUE")) { + lexer.nextTokenLParen(); + parseValueClause(insertStatement.getValuesList(), columnSize); + } else if (lexer.token() == Token.SET) { + lexer.nextToken(); + + SQLInsertStatement.ValuesClause values = new SQLInsertStatement.ValuesClause(); + insertStatement.getValuesList().add(values); + + for (;;) { + SQLName name = this.exprParser.name(); + insertStatement.addColumn(name); + if (lexer.token() == Token.EQ) { + lexer.nextToken(); + } else { + accept(Token.COLONEQ); + } + values.addValue(this.exprParser.expr()); + + if (lexer.token() == Token.COMMA) { + lexer.nextToken(); + continue; + } + + break; + } + + } else if (lexer.token() == (Token.SELECT)) { + SQLSelect select = this.exprParser.createSelectParser().select(); + select.setParent(insertStatement); + insertStatement.setQuery(select); + } else if (lexer.token() == (Token.LPAREN)) { + lexer.nextToken(); + SQLSelect select = this.exprParser.createSelectParser().select(); + select.setParent(insertStatement); + insertStatement.setQuery(select); + accept(Token.RPAREN); + } + + return insertStatement; + } + + private void parseValueClause(List valueClauseList, int columnSize) { + for (;;) { + if (lexer.token() != Token.LPAREN) { + throw new ParserException("syntax error, expect ')'"); + } + lexer.nextTokenValue(); + + if (lexer.token() != Token.RPAREN) { + List valueExprList; + if (columnSize > 0) { + valueExprList = new ArrayList(columnSize); + } else { + valueExprList = new ArrayList(); + } + + for (;;) { + SQLExpr expr; + if (lexer.token() == Token.LITERAL_INT) { + expr = new SQLIntegerExpr(lexer.integerValue()); + lexer.nextTokenComma(); + } else if (lexer.token() == Token.LITERAL_CHARS) { + expr = new SQLCharExpr(lexer.stringVal()); + lexer.nextTokenComma(); + } else if (lexer.token() == Token.LITERAL_NCHARS) { + expr = new SQLNCharExpr(lexer.stringVal()); + lexer.nextTokenComma(); + } else { + expr = exprParser.expr(); + } + + if (lexer.token() == Token.COMMA) { + valueExprList.add(expr); + lexer.nextTokenValue(); + continue; + } else if (lexer.token() == Token.RPAREN) { + valueExprList.add(expr); + break; + } else { + expr = this.exprParser.primaryRest(expr); + if (lexer.token() != Token.COMMA && lexer.token() != Token.RPAREN) { + expr = this.exprParser.exprRest(expr); + } + + valueExprList.add(expr); + if (lexer.token() == Token.COMMA) { + lexer.nextToken(); + continue; + } else { + break; + } + } + } + + SQLInsertStatement.ValuesClause values = new SQLInsertStatement.ValuesClause(valueExprList); + valueClauseList.add(values); + } else { + SQLInsertStatement.ValuesClause values = new SQLInsertStatement.ValuesClause(new ArrayList(0)); + valueClauseList.add(values); + } + + if (lexer.token() != Token.RPAREN) { + throw new ParserException("syntax error"); + } + + if (!parseCompleteValues && valueClauseList.size() >= parseValuesSize) { + lexer.skipToEOF(); + break; + } + + lexer.nextTokenComma(); + if (lexer.token() == Token.COMMA) { + lexer.nextTokenLParen(); + continue; + } else { + break; + } + } + } + public void parseStatementList(List statementList, int max) { for (;;) { if (max != -1) { diff --git a/src/test/java/com/alibaba/druid/bvt/sql/teradata/TeradataInsertTest_1.java b/src/test/java/com/alibaba/druid/bvt/sql/teradata/TeradataInsertTest_1.java new file mode 100644 index 0000000000..5d36ef00be --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/teradata/TeradataInsertTest_1.java @@ -0,0 +1,95 @@ +package com.alibaba.druid.bvt.sql.teradata; + +import java.util.List; + +import org.junit.Assert; + +import com.alibaba.druid.sql.TeradataTest; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.ast.statement.SQLInsertStatement; +import com.alibaba.druid.sql.ast.statement.SQLSelect; +import com.alibaba.druid.sql.dialect.teradata.ast.stmt.TeradataInsertStatement; +import com.alibaba.druid.sql.dialect.teradata.ast.stmt.TeradataSelectQueryBlock; +import com.alibaba.druid.sql.dialect.teradata.parser.TeradataStatementParser; +import com.alibaba.druid.sql.dialect.teradata.visitor.TeradataSchemaStatVisitor; +import com.alibaba.druid.stat.TableStat.Column; + + +public class TeradataInsertTest_1 extends TeradataTest { + public void test_values() throws Exception { + String ins_sql = "INSERT INTO t1(c1, c2) VALUES " + + "('a', 'b')," + + "('c', 'd')," + + "('e', 'f')"; + + TeradataStatementParser parser = new TeradataStatementParser(ins_sql); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + + Assert.assertTrue(stmt instanceof SQLInsertStatement); + + TeradataInsertStatement insertStmt = (TeradataInsertStatement) stmt; + Assert.assertEquals("t1", insertStmt.getTableSource().toString()); + Assert.assertEquals("c1", insertStmt.getColumns().get(0).toString()); + Assert.assertEquals("c2", insertStmt.getColumns().get(1).toString()); + Assert.assertEquals(3, insertStmt.getValuesList().size()); + Assert.assertEquals(2, insertStmt.getValuesList().get(0).getValues().size()); + + SQLSelect insertQuery = insertStmt.getQuery(); + Assert.assertNull(insertQuery); + + TeradataSchemaStatVisitor visitor = new TeradataSchemaStatVisitor(); + insertStmt.accept(visitor); + System.out.println(visitor.getColumns()); + System.out.println(visitor.getTables()); + System.out.println("------ end of " + new Object(){}.getClass().getEnclosingMethod().getName() + " ------"); + } + + public void test_select() throws Exception { + String ins_sql = "INSERT INTO d1.t1(col1, col2) " + + "SELECT c1, c2 " + + "FROM d2.t2 " + + "WHERE c1=0;"; + TeradataStatementParser parser = new TeradataStatementParser(ins_sql); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + + Assert.assertTrue(stmt instanceof SQLInsertStatement); + + TeradataInsertStatement insertStmt = (TeradataInsertStatement) stmt; + SQLSelect insertQuery = insertStmt.getQuery(); + Assert.assertNotNull(insertQuery); + + // retrieve SELECT sub-clause from INSERT query + TeradataSelectQueryBlock insertBlock = (TeradataSelectQueryBlock) insertQuery.getQuery(); + Assert.assertNotNull(insertBlock); + + // target table + Assert.assertEquals("d1.t1", insertStmt.getTableSource().toString()); + Assert.assertEquals(2, insertStmt.getColumns().size()); + Assert.assertEquals("col1", insertStmt.getColumns().get(0).toString()); + Assert.assertEquals("col2", insertStmt.getColumns().get(1).toString()); + // source table + Assert.assertEquals("d2.t2", insertBlock.getFrom().toString()); + Assert.assertEquals(2, insertBlock.getSelectList().size()); + Assert.assertEquals("c1", insertBlock.getSelectList().get(0).toString()); + Assert.assertEquals("c2", insertBlock.getSelectList().get(1).toString()); + + System.out.println("***********below is useful info **********"); + System.out.println("target table: " + insertStmt.getTableSource()); + System.out.println("target columns: " + insertStmt.getColumns()); + System.out.println("source from: " + insertBlock.getFrom()); + System.out.println("source columns : " + insertBlock.getSelectList()); + System.out.println("source condition: " + insertBlock.getWhere()); + System.out.println("********"); + + TeradataSchemaStatVisitor visitor = new TeradataSchemaStatVisitor(); + stmt.accept(visitor); + System.out.println("Tables : " + visitor.getTables()); + System.out.println("fields : " + visitor.getColumns()); + System.out.println("coditions : " + visitor.getConditions()); + System.out.println("orderBy : " + visitor.getOrderByColumns()); + + System.out.println("------ end of " + new Object(){}.getClass().getEnclosingMethod().getName() + " ------"); + } +}