diff --git a/src/main/java/com/alibaba/druid/sql/SQLUtils.java b/src/main/java/com/alibaba/druid/sql/SQLUtils.java index 54316c274c..53bad0bf76 100644 --- a/src/main/java/com/alibaba/druid/sql/SQLUtils.java +++ b/src/main/java/com/alibaba/druid/sql/SQLUtils.java @@ -172,6 +172,14 @@ public class SQLUtils { public static String toSQLServerString(SQLObject sqlObject, FormatOption option) { return toSQLString(sqlObject, JdbcConstants.SQL_SERVER, option); } + + public static String toTeradataString(SQLObject sqlObject) { + return toTeradataString(sqlObject, null); + } + + public static String toTeradataString(SQLObject sqlObject, FormatOption option) { + return toSQLString(sqlObject, JdbcConstants.TERADATA, option); + } public static String formatPGSql(String sql, FormatOption option) { return format(sql, JdbcConstants.POSTGRESQL, option); diff --git a/src/main/java/com/alibaba/druid/sql/dialect/teradata/ast/stmt/TeradataSelectQueryBlock.java b/src/main/java/com/alibaba/druid/sql/dialect/teradata/ast/stmt/TeradataSelectQueryBlock.java index 706db3dc67..cefebc2ea8 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/teradata/ast/stmt/TeradataSelectQueryBlock.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/teradata/ast/stmt/TeradataSelectQueryBlock.java @@ -1,5 +1,6 @@ package com.alibaba.druid.sql.dialect.teradata.ast.stmt; +import com.alibaba.druid.sql.SQLUtils; import com.alibaba.druid.sql.ast.SQLOrderBy; import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; import com.alibaba.druid.sql.dialect.teradata.visitor.TeradataASTVisitor; @@ -41,4 +42,8 @@ public class TeradataSelectQueryBlock extends SQLSelectQueryBlock { public void setOrderBy(SQLOrderBy orderBy) { this.orderBy = orderBy; } + + public String toString() { + return SQLUtils.toTeradataString(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 e111143145..3976fba0ec 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 @@ -23,6 +23,7 @@ import com.alibaba.druid.sql.ast.expr.SQLAggregateExpr; import com.alibaba.druid.sql.ast.expr.SQLAggregateOption; import com.alibaba.druid.sql.ast.expr.SQLCastExpr; import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; +import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr; import com.alibaba.druid.sql.ast.expr.SQLQueryExpr; import com.alibaba.druid.sql.dialect.teradata.ast.expr.TeradataAnalytic; import com.alibaba.druid.sql.dialect.teradata.ast.expr.TeradataAnalyticWindowing; @@ -81,6 +82,44 @@ public class TeradataExprParser extends SQLExprParser { } } + protected SQLExpr methodRest(SQLExpr expr, boolean acceptLPAREN) { + if (acceptLPAREN) { + accept(Token.LPAREN); + } + + if (expr instanceof SQLIdentifierExpr) { + String methodName = ((SQLIdentifierExpr) expr).getName(); + SQLMethodInvokeExpr methodExpr = new SQLMethodInvokeExpr(methodName); + if ("trim".equalsIgnoreCase(methodName)) { + if (identifierEquals("LEADING") + || identifierEquals("TRAILING") + || identifierEquals("BOTH")) { + methodExpr.putAttribute("trim_option", lexer.stringVal()); + lexer.nextToken(); + if (lexer.token() == Token.LITERAL_CHARS) { + SQLExpr trim_character = this.primary(); + trim_character.setParent(methodExpr); + methodExpr.putAttribute("trim_character", trim_character); + } + } else { + SQLExpr trim_character = this.primary(); + trim_character.setParent(methodExpr); + methodExpr.putAttribute("trim_character", trim_character); + } + + if (lexer.token() == Token.FROM) { + lexer.nextToken(); + SQLExpr trim_source = this.expr(); + methodExpr.addParameter(trim_source); + } + + accept(Token.RPAREN); + return primaryRest(methodExpr); + } + } + return super.methodRest(expr, false); + } + protected SQLAggregateExpr parseAggregateExpr(String methodName) { methodName = methodName.toUpperCase(); diff --git a/src/main/java/com/alibaba/druid/sql/dialect/teradata/visitor/TeradataOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/teradata/visitor/TeradataOutputVisitor.java index f0bc9ab3dc..e09580fde5 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/teradata/visitor/TeradataOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/teradata/visitor/TeradataOutputVisitor.java @@ -15,10 +15,12 @@ */ package com.alibaba.druid.sql.dialect.teradata.visitor; +import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLObject; import com.alibaba.druid.sql.ast.SQLOrderBy; import com.alibaba.druid.sql.ast.SQLSetQuantifier; import com.alibaba.druid.sql.ast.expr.SQLAggregateExpr; +import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr; import com.alibaba.druid.sql.ast.statement.SQLSelect; import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; import com.alibaba.druid.sql.dialect.teradata.ast.expr.TeradataAnalytic; @@ -173,4 +175,32 @@ public class TeradataOutputVisitor extends SQLASTOutputVisitor implements Terada public void endVisit(TeradataIntervalExpr x) { } + + public void endVisit(SQLMethodInvokeExpr x) { + + } + + public boolean visit(SQLMethodInvokeExpr x) { + if ("trim".equalsIgnoreCase(x.getMethodName())) { + SQLExpr trim_character = (SQLExpr) x.getAttribute("trim_character"); + + print0(x.getMethodName()); + print('('); + String trim_option = (String) x.getAttribute("trim_option"); + if (trim_option != null && trim_option.length() != 0) { + print0(trim_option); + print(' '); + } + if (trim_character != null) { + trim_character.accept(this); + } + if (x.getParameters().size() > 0) { + print0(ucase ? " FROM " : " from "); + x.getParameters().get(0).accept(this); + } + print(')'); + return false; + } + return super.visit(x); + } } diff --git a/src/test/java/com/alibaba/druid/bvt/sql/teradata/TeradataSelectTest_3.java b/src/test/java/com/alibaba/druid/bvt/sql/teradata/TeradataSelectTest_3.java new file mode 100644 index 0000000000..a962062a17 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/teradata/TeradataSelectTest_3.java @@ -0,0 +1,45 @@ +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.SQLSelectStatement; +import com.alibaba.druid.sql.dialect.oracle.parser.OracleStatementParser; +import com.alibaba.druid.sql.dialect.teradata.parser.TeradataStatementParser; +import com.alibaba.druid.sql.dialect.teradata.visitor.TeradataSchemaStatVisitor; +import com.alibaba.druid.stat.TableStat; +import com.alibaba.druid.stat.TableStat.Column; + +public class TeradataSelectTest_3 extends TeradataTest { + public void test_trim() throws Exception { + String sql = "select trim(trailing from columnname) from dbc.columnsv;"; + + TeradataStatementParser parser = new TeradataStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + + Assert.assertTrue(stmt instanceof SQLSelectStatement); + print(statementList); + + 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()); + + Assert.assertEquals(1, visitor.getTables().size()); + Assert.assertEquals(1, visitor.getColumns().size()); + Assert.assertEquals(0, visitor.getConditions().size()); + + Assert.assertTrue(visitor.getTables().containsKey(new TableStat.Name("dbc.columnsv"))); + + Assert.assertTrue(visitor.getColumns().contains(new Column("dbc.columnsv", "columnname"))); + System.out.println("------ end of " + new Object(){}.getClass().getEnclosingMethod().getName() + " ------"); + + } +}