diff --git a/src/main/java/com/alibaba/druid/sql/ast/SQLExpr.java b/src/main/java/com/alibaba/druid/sql/ast/SQLExpr.java index fa52741ea8..713221f5a7 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/SQLExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/SQLExpr.java @@ -17,4 +17,6 @@ package com.alibaba.druid.sql.ast; public interface SQLExpr extends SQLObject, Cloneable { SQLExpr clone(); + + SQLDataType computeDataType(); } diff --git a/src/main/java/com/alibaba/druid/sql/ast/SQLExprImpl.java b/src/main/java/com/alibaba/druid/sql/ast/SQLExprImpl.java index 69da273b24..2f567e91f6 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/SQLExprImpl.java +++ b/src/main/java/com/alibaba/druid/sql/ast/SQLExprImpl.java @@ -28,4 +28,8 @@ public abstract class SQLExprImpl extends SQLObjectImpl implements SQLExpr { public SQLExpr clone() { throw new UnsupportedOperationException(this.getClass().getName()); } + + public SQLDataType computeDataType() { + return null; + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/SQLObjectImpl.java b/src/main/java/com/alibaba/druid/sql/ast/SQLObjectImpl.java index 13d8152d95..c57c1f69ef 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/SQLObjectImpl.java +++ b/src/main/java/com/alibaba/druid/sql/ast/SQLObjectImpl.java @@ -211,4 +211,8 @@ public abstract class SQLObjectImpl implements SQLObject { public SQLObject clone() { throw new UnsupportedOperationException(this.getClass().getName()); } + + public SQLDataType computeDataType() { + return null; + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLAggregateExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLAggregateExpr.java index ea2a64f674..737d8d9293 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLAggregateExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLAggregateExpr.java @@ -20,11 +20,7 @@ import java.util.ArrayList; import java.util.List; import com.alibaba.druid.sql.SQLUtils; -import com.alibaba.druid.sql.ast.SQLExpr; -import com.alibaba.druid.sql.ast.SQLExprImpl; -import com.alibaba.druid.sql.ast.SQLKeep; -import com.alibaba.druid.sql.ast.SQLOrderBy; -import com.alibaba.druid.sql.ast.SQLOver; +import com.alibaba.druid.sql.ast.*; import com.alibaba.druid.sql.visitor.SQLASTVisitor; public class SQLAggregateExpr extends SQLExprImpl implements Serializable { @@ -206,4 +202,25 @@ public class SQLAggregateExpr extends SQLExprImpl implements Serializable { return x; } + + public SQLDataType computeDataType() { + if ("count".equals(methodName) + || "row_number".equals(methodName)) { + return SQLIntegerExpr.DEFAULT_DATA_TYPE; + } + + if (arguments.size() > 0) { + SQLDataType dataType = arguments.get(0).computeDataType(); + if (dataType != null) { + return dataType; + } + } + + if ("wm_conat".equals(methodName) + || "group_concat".equals(methodName)) { + return SQLCharExpr.DEFAULT_DATA_TYPE; + } + + return null; + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLAnyExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLAnyExpr.java index 64109fde05..a2d35719cb 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLAnyExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLAnyExpr.java @@ -15,10 +15,15 @@ */ package com.alibaba.druid.sql.ast.expr; +import com.alibaba.druid.sql.ast.SQLDataType; import com.alibaba.druid.sql.ast.SQLExprImpl; import com.alibaba.druid.sql.ast.statement.SQLSelect; +import com.alibaba.druid.sql.ast.statement.SQLSelectItem; +import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; import com.alibaba.druid.sql.visitor.SQLASTVisitor; +import java.util.List; + public class SQLAnyExpr extends SQLExprImpl { public SQLSelect subQuery; @@ -82,4 +87,22 @@ public class SQLAnyExpr extends SQLExprImpl { } return true; } + + public SQLDataType computeDataType() { + if (subQuery == null) { + return null; + } + + SQLSelectQueryBlock queryBlock = subQuery.getFirstQueryBlock(); + if (queryBlock == null) { + return null; + } + + List selectList = queryBlock.getSelectList(); + if (selectList.size() == 1) { + return selectList.get(0).computeDataType(); + } + + return null; + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBetweenExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBetweenExpr.java index 454ad0bd12..d7a6e1756f 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBetweenExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBetweenExpr.java @@ -17,6 +17,7 @@ package com.alibaba.druid.sql.ast.expr; import java.io.Serializable; +import com.alibaba.druid.sql.ast.SQLDataType; import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLExprImpl; import com.alibaba.druid.sql.visitor.SQLASTVisitor; @@ -143,4 +144,8 @@ public class SQLBetweenExpr extends SQLExprImpl implements Serializable { } return true; } + + public SQLDataType computeDataType() { + return SQLBooleanExpr.DEFAULT_DATA_TYPE; + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBinaryOpExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBinaryOpExpr.java index 72d61a3b06..39611a80d9 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBinaryOpExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBinaryOpExpr.java @@ -20,10 +20,7 @@ import java.util.ArrayList; import java.util.List; import com.alibaba.druid.sql.SQLUtils; -import com.alibaba.druid.sql.ast.SQLExpr; -import com.alibaba.druid.sql.ast.SQLExprImpl; -import com.alibaba.druid.sql.ast.SQLObject; -import com.alibaba.druid.sql.ast.SQLReplaceable; +import com.alibaba.druid.sql.ast.*; import com.alibaba.druid.sql.visitor.SQLASTVisitor; import com.alibaba.druid.util.Utils; @@ -429,4 +426,30 @@ public class SQLBinaryOpExpr extends SQLExprImpl implements SQLReplaceable, Seri return false; } + + public SQLDataType computeDataType() { + if (operator != null && operator.isRelational()) { + return SQLBooleanExpr.DEFAULT_DATA_TYPE; + } + + SQLDataType leftDataType = null, rightDataType = null; + if (left != null) { + leftDataType = left.computeDataType(); + } + if (right != null) { + rightDataType = right.computeDataType(); + } + + if (operator == SQLBinaryOperator.Concat) { + if (leftDataType != null) { + return leftDataType; + } + if (rightDataType != null) { + return rightDataType; + } + return SQLCharExpr.DEFAULT_DATA_TYPE; + } + + return null; + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBinaryOperator.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBinaryOperator.java index 247354b58e..952b4beac6 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBinaryOperator.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBinaryOperator.java @@ -138,6 +138,8 @@ public enum SQLBinaryOperator { case NotRLike: case RegExp: case NotRegExp: + case Is: + case IsNot: return true; default: return false; diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBooleanExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBooleanExpr.java index e29740d82a..69043fd9a0 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBooleanExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBooleanExpr.java @@ -15,11 +15,14 @@ */ package com.alibaba.druid.sql.ast.expr; +import com.alibaba.druid.sql.ast.SQLDataType; import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLExprImpl; +import com.alibaba.druid.sql.ast.statement.SQLCharacterDataType; import com.alibaba.druid.sql.visitor.SQLASTVisitor; public class SQLBooleanExpr extends SQLExprImpl implements SQLExpr, SQLLiteralExpr { + public static final SQLDataType DEFAULT_DATA_TYPE = new SQLCharacterDataType("boolean"); private boolean value; @@ -77,4 +80,7 @@ public class SQLBooleanExpr extends SQLExprImpl implements SQLExpr, SQLLiteralEx return true; } + public SQLDataType computeDataType() { + return DEFAULT_DATA_TYPE; + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLCaseExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLCaseExpr.java index 24d5434c59..774ba6cb68 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLCaseExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLCaseExpr.java @@ -19,10 +19,7 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.List; -import com.alibaba.druid.sql.ast.SQLExpr; -import com.alibaba.druid.sql.ast.SQLExprImpl; -import com.alibaba.druid.sql.ast.SQLObjectImpl; -import com.alibaba.druid.sql.ast.SQLReplaceable; +import com.alibaba.druid.sql.ast.*; import com.alibaba.druid.sql.visitor.SQLASTVisitor; public class SQLCaseExpr extends SQLExprImpl implements SQLReplaceable, Serializable { @@ -255,4 +252,22 @@ public class SQLCaseExpr extends SQLExprImpl implements SQLReplaceable, Serializ return x; } + + public SQLDataType computeDataType() { + for (Item item : items) { + SQLExpr expr = item.getValueExpr(); + if (expr != null) { + SQLDataType dataType = expr.computeDataType(); + if (dataType != null) { + return dataType; + } + } + } + + if(elseExpr != null) { + return elseExpr.computeDataType(); + } + + return null; + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLCastExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLCastExpr.java index dc5e9e5061..4ad6ca99b6 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLCastExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLCastExpr.java @@ -94,4 +94,7 @@ public class SQLCastExpr extends SQLExprImpl { return true; } + public SQLDataType computeDataType() { + return dataType; + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLCharExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLCharExpr.java index 908ebd52c1..905caa147a 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLCharExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLCharExpr.java @@ -16,10 +16,13 @@ package com.alibaba.druid.sql.ast.expr; import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLDataType; +import com.alibaba.druid.sql.ast.statement.SQLCharacterDataType; import com.alibaba.druid.sql.visitor.SQLASTOutputVisitor; import com.alibaba.druid.sql.visitor.SQLASTVisitor; public class SQLCharExpr extends SQLTextLiteralExpr implements SQLValuableExpr{ + public static final SQLDataType DEFAULT_DATA_TYPE = new SQLCharacterDataType("varchar"); public SQLCharExpr(){ @@ -55,4 +58,8 @@ public class SQLCharExpr extends SQLTextLiteralExpr implements SQLValuableExpr{ public SQLCharExpr clone() { return new SQLCharExpr(this.text); } + + public SQLDataType computeDataType() { + return DEFAULT_DATA_TYPE; + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLDateExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLDateExpr.java index 0691825543..ca58cf2332 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLDateExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLDateExpr.java @@ -15,12 +15,15 @@ */ package com.alibaba.druid.sql.ast.expr; +import com.alibaba.druid.sql.ast.SQLDataType; import com.alibaba.druid.sql.ast.SQLExprImpl; +import com.alibaba.druid.sql.ast.statement.SQLCharacterDataType; import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleExpr; import com.alibaba.druid.sql.dialect.oracle.visitor.OracleASTVisitor; import com.alibaba.druid.sql.visitor.SQLASTVisitor; public class SQLDateExpr extends SQLExprImpl implements SQLLiteralExpr { + public static final SQLDataType DEFAULT_DATA_TYPE = new SQLCharacterDataType("date"); private String literal; diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLIdentifierExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLIdentifierExpr.java index 1b1a70b798..4aa7fee2ba 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLIdentifierExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLIdentifierExpr.java @@ -16,6 +16,7 @@ package com.alibaba.druid.sql.ast.expr; import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLDataType; import com.alibaba.druid.sql.ast.SQLExprImpl; import com.alibaba.druid.sql.ast.SQLName; import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition; @@ -147,4 +148,12 @@ public class SQLIdentifierExpr extends SQLExprImpl implements SQLName { public void setResolvedColumn(SQLColumnDefinition resolvedColumn) { this.resolvedColumn = resolvedColumn; } + + public SQLDataType computeDataType() { + if (resolvedColumn != null) { + return resolvedColumn.getDataType(); + } + + return null; + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLInListExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLInListExpr.java index f5134cfd16..9ae3b4cad2 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLInListExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLInListExpr.java @@ -19,6 +19,7 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.List; +import com.alibaba.druid.sql.ast.SQLDataType; import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLExprImpl; import com.alibaba.druid.sql.visitor.SQLASTVisitor; @@ -121,4 +122,8 @@ public class SQLInListExpr extends SQLExprImpl implements Serializable { } return true; } + + public SQLDataType computeDataType() { + return SQLBooleanExpr.DEFAULT_DATA_TYPE; + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLInSubQueryExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLInSubQueryExpr.java index 8662b4ec35..f4c3f00b78 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLInSubQueryExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLInSubQueryExpr.java @@ -17,6 +17,7 @@ package com.alibaba.druid.sql.ast.expr; import java.io.Serializable; +import com.alibaba.druid.sql.ast.SQLDataType; import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLExprImpl; import com.alibaba.druid.sql.ast.statement.SQLSelect; @@ -125,4 +126,7 @@ public class SQLInSubQueryExpr extends SQLExprImpl implements Serializable { return true; } + public SQLDataType computeDataType() { + return SQLBooleanExpr.DEFAULT_DATA_TYPE; + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLIntegerExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLIntegerExpr.java index e78fc793dc..0f0ce69d77 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLIntegerExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLIntegerExpr.java @@ -15,9 +15,12 @@ */ package com.alibaba.druid.sql.ast.expr; +import com.alibaba.druid.sql.ast.SQLDataType; +import com.alibaba.druid.sql.ast.SQLDataTypeImpl; import com.alibaba.druid.sql.visitor.SQLASTVisitor; public class SQLIntegerExpr extends SQLNumericLiteralExpr implements SQLValuableExpr{ + public static final SQLDataType DEFAULT_DATA_TYPE = new SQLDataTypeImpl("bigint"); private Number number; @@ -86,4 +89,8 @@ public class SQLIntegerExpr extends SQLNumericLiteralExpr implements SQLValuable public SQLIntegerExpr clone() { return new SQLIntegerExpr(this.number); } + + public SQLDataType computeDataType() { + return DEFAULT_DATA_TYPE; + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLNCharExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLNCharExpr.java index af245da2b0..d7cf7a2fb3 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLNCharExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLNCharExpr.java @@ -15,9 +15,12 @@ */ package com.alibaba.druid.sql.ast.expr; +import com.alibaba.druid.sql.ast.SQLDataType; +import com.alibaba.druid.sql.ast.statement.SQLCharacterDataType; import com.alibaba.druid.sql.visitor.SQLASTVisitor; public class SQLNCharExpr extends SQLTextLiteralExpr { + private static SQLDataType defaultDataType = new SQLCharacterDataType("nvarchar"); public SQLNCharExpr(){ @@ -46,4 +49,8 @@ public class SQLNCharExpr extends SQLTextLiteralExpr { public SQLNCharExpr clone() { return new SQLNCharExpr(text); } + + public SQLDataType computeDataType() { + return defaultDataType; + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLNotExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLNotExpr.java index 804f48f2a5..11020796cc 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLNotExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLNotExpr.java @@ -17,6 +17,7 @@ package com.alibaba.druid.sql.ast.expr; import java.io.Serializable; +import com.alibaba.druid.sql.ast.SQLDataType; import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLExprImpl; import com.alibaba.druid.sql.visitor.SQLASTVisitor; @@ -94,4 +95,8 @@ public class SQLNotExpr extends SQLExprImpl implements Serializable { } return x; } + + public SQLDataType computeDataType() { + return SQLBooleanExpr.DEFAULT_DATA_TYPE; + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLNumberExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLNumberExpr.java index 5da4ec4b0a..5ea6bd6c77 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLNumberExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLNumberExpr.java @@ -15,9 +15,12 @@ */ package com.alibaba.druid.sql.ast.expr; +import com.alibaba.druid.sql.ast.SQLDataType; +import com.alibaba.druid.sql.ast.SQLDataTypeImpl; import com.alibaba.druid.sql.visitor.SQLASTVisitor; public class SQLNumberExpr extends SQLNumericLiteralExpr { + private static SQLDataType defaultDataType = new SQLDataTypeImpl("number"); private Number number; @@ -80,4 +83,8 @@ public class SQLNumberExpr extends SQLNumericLiteralExpr { public SQLNumberExpr clone() { return new SQLNumberExpr(number); } + + public SQLDataType computeDataType() { + return defaultDataType; + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLPropertyExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLPropertyExpr.java index a39017b207..2539118106 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLPropertyExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLPropertyExpr.java @@ -16,6 +16,7 @@ package com.alibaba.druid.sql.ast.expr; import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLDataType; import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLExprImpl; import com.alibaba.druid.sql.ast.SQLName; @@ -164,4 +165,12 @@ public class SQLPropertyExpr extends SQLExprImpl implements SQLName { public void setResolvedColumn(SQLColumnDefinition resolvedColumn) { this.resolvedColumn = resolvedColumn; } + + public SQLDataType computeDataType() { + if (resolvedColumn != null) { + return resolvedColumn.getDataType(); + } + + return null; + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLQueryExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLQueryExpr.java index 688ddfcd0c..fed31ad1ff 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLQueryExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLQueryExpr.java @@ -16,9 +16,13 @@ package com.alibaba.druid.sql.ast.expr; import java.io.Serializable; +import java.util.List; +import com.alibaba.druid.sql.ast.SQLDataType; import com.alibaba.druid.sql.ast.SQLExprImpl; import com.alibaba.druid.sql.ast.statement.SQLSelect; +import com.alibaba.druid.sql.ast.statement.SQLSelectItem; +import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; import com.alibaba.druid.sql.visitor.SQLASTVisitor; public class SQLQueryExpr extends SQLExprImpl implements Serializable { @@ -97,4 +101,22 @@ public class SQLQueryExpr extends SQLExprImpl implements Serializable { return x; } + + public SQLDataType computeDataType() { + if (subQuery == null) { + return null; + } + + SQLSelectQueryBlock queryBlock = subQuery.getFirstQueryBlock(); + if (queryBlock == null) { + return null; + } + + List selectList = queryBlock.getSelectList(); + if (selectList.size() == 1) { + return selectList.get(0).computeDataType(); + } + + return null; + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLSomeExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLSomeExpr.java index f53ca454c0..baf0704905 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLSomeExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLSomeExpr.java @@ -15,10 +15,15 @@ */ package com.alibaba.druid.sql.ast.expr; +import com.alibaba.druid.sql.ast.SQLDataType; import com.alibaba.druid.sql.ast.SQLExprImpl; import com.alibaba.druid.sql.ast.statement.SQLSelect; +import com.alibaba.druid.sql.ast.statement.SQLSelectItem; +import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; import com.alibaba.druid.sql.visitor.SQLASTVisitor; +import java.util.List; + public class SQLSomeExpr extends SQLExprImpl { public SQLSelect subQuery; @@ -82,4 +87,22 @@ public class SQLSomeExpr extends SQLExprImpl { } return true; } + + public SQLDataType computeDataType() { + if (subQuery == null) { + return null; + } + + SQLSelectQueryBlock queryBlock = subQuery.getFirstQueryBlock(); + if (queryBlock == null) { + return null; + } + + List selectList = queryBlock.getSelectList(); + if (selectList.size() == 1) { + return selectList.get(0).computeDataType(); + } + + return null; + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLTimestampExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLTimestampExpr.java index f985be92c7..6eac940894 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLTimestampExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLTimestampExpr.java @@ -1,7 +1,9 @@ package com.alibaba.druid.sql.ast.expr; import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLDataType; import com.alibaba.druid.sql.ast.SQLExprImpl; +import com.alibaba.druid.sql.ast.statement.SQLCharacterDataType; import com.alibaba.druid.sql.visitor.SQLASTVisitor; /* @@ -20,6 +22,7 @@ import com.alibaba.druid.sql.visitor.SQLASTVisitor; * limitations under the License. */ public class SQLTimestampExpr extends SQLExprImpl { + public static final SQLDataType DEFAULT_DATA_TYPE = new SQLCharacterDataType("datetime"); protected String literal; protected String timeZone; @@ -105,4 +108,8 @@ public class SQLTimestampExpr extends SQLExprImpl { public String toString() { return SQLUtils.toSQLString(this, null); } + + public SQLDataType computeDataType() { + return DEFAULT_DATA_TYPE; + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLExprTableSource.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLExprTableSource.java index cc476ac0de..8b75eee12b 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLExprTableSource.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLExprTableSource.java @@ -21,6 +21,7 @@ import java.util.List; import com.alibaba.druid.sql.SQLUtils; 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.SQLIdentifierExpr; import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr; import com.alibaba.druid.sql.repository.SchemaObject; @@ -171,4 +172,17 @@ public class SQLExprTableSource extends SQLTableSourceImpl { return false; } + + public SQLColumnDefinition findColumn(String columnName) { + if (schemaObject == null) { + return null; + } + + SQLStatement stmt = schemaObject.getStatement(); + if (stmt instanceof SQLCreateTableStatement) { + SQLCreateTableStatement createTableStmt = (SQLCreateTableStatement) stmt; + return createTableStmt.findColumn(columnName); + } + return null; + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLJoinTableSource.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLJoinTableSource.java index 2f3df40074..f322011060 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLJoinTableSource.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLJoinTableSource.java @@ -21,6 +21,7 @@ import java.util.List; import com.alibaba.druid.sql.SQLUtils; import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLReplaceable; +import com.alibaba.druid.sql.ast.SQLStatement; import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr; import com.alibaba.druid.sql.ast.expr.SQLBinaryOperator; import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; @@ -368,4 +369,19 @@ public class SQLJoinTableSource extends SQLTableSourceImpl implements SQLReplace return false; } + public SQLColumnDefinition findColumn(String columnName) { + if (left != null) { + SQLColumnDefinition column = left.findColumn(columnName); + if (column != null) { + return column; + } + } + + if (right != null) { + return right.findColumn(columnName); + } + + return null; + } + } diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelect.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelect.java index d6e3518a6d..57961a06d7 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelect.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelect.java @@ -272,4 +272,15 @@ public class SQLSelect extends SQLObjectImpl { this.xmlPath = xmlPath; } + public SQLSelectQueryBlock getFirstQueryBlock() { + if (query instanceof SQLSelectQueryBlock) { + return (SQLSelectQueryBlock) query; + } + + if (query instanceof SQLUnionQuery) { + return ((SQLUnionQuery) query).getFirstQueryBlock(); + } + + return null; + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectItem.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectItem.java index 615818697f..98852e98f7 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectItem.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectItem.java @@ -82,23 +82,11 @@ public class SQLSelectItem extends SQLObjectImpl implements SQLReplaceable { } public SQLDataType computeDataType() { - if (expr instanceof SQLIdentifierExpr) { - SQLIdentifierExpr identExpr = (SQLIdentifierExpr) expr; - if (identExpr.getResolvedColumn() != null) { - return identExpr.getResolvedColumn().getDataType(); - } + if (expr == null) { return null; } - if (expr instanceof SQLPropertyExpr) { - SQLPropertyExpr propertyExpr = (SQLPropertyExpr) expr; - if (propertyExpr.getResolvedColumn() != null) { - return propertyExpr.getResolvedColumn().getDataType(); - } - return null; - } - - return null; + return expr.computeDataType(); } public String getAlias() { diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectQueryBlock.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectQueryBlock.java index fa63725bc1..09ef7849b9 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectQueryBlock.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelectQueryBlock.java @@ -23,6 +23,7 @@ import com.alibaba.druid.sql.ast.*; import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr; import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr; +import com.alibaba.druid.sql.repository.SchemaObject; import com.alibaba.druid.sql.visitor.SQLASTVisitor; public class SQLSelectQueryBlock extends SQLObjectImpl implements SQLSelectQuery, SQLReplaceable { @@ -533,4 +534,18 @@ public class SQLSelectQueryBlock extends SQLObjectImpl implements SQLSelectQuery return -1; } + + public SQLColumnDefinition computeColumn(SQLIdentifierExpr identExpr) { + SQLColumnDefinition column = identExpr.getResolvedColumn(); + if (column != null) { + return column; + } + + column = from.findColumn(identExpr.getName()); + if (column != null) { + identExpr.setResolvedColumn(column); + } + + return column; + } } diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLTableSource.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLTableSource.java index 8fe61bc508..47a37f4aa7 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLTableSource.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLTableSource.java @@ -36,4 +36,6 @@ public interface SQLTableSource extends SQLObject { SQLExpr getFlashback(); void setFlashback(SQLExpr flashback); + + SQLColumnDefinition findColumn(String columnName); } diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLTableSourceImpl.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLTableSourceImpl.java index 2d9cd90263..bb3cc9aa71 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLTableSourceImpl.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLTableSourceImpl.java @@ -94,4 +94,8 @@ public abstract class SQLTableSourceImpl extends SQLObjectImpl implements SQLTab return false; } + + public SQLColumnDefinition findColumn(String columnName) { + return null; + } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/OracleSQLObjectImpl.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/OracleSQLObjectImpl.java index def8d0cdbd..b1aa9e9d9c 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/OracleSQLObjectImpl.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/OracleSQLObjectImpl.java @@ -15,6 +15,7 @@ */ package com.alibaba.druid.sql.dialect.oracle.ast; +import com.alibaba.druid.sql.ast.SQLDataType; import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLObjectImpl; import com.alibaba.druid.sql.dialect.oracle.visitor.OracleASTVisitor; @@ -36,4 +37,8 @@ public abstract class OracleSQLObjectImpl extends SQLObjectImpl implements Oracl public OracleSQLObject clone() { throw new UnsupportedOperationException(); } + + public SQLDataType computeDataType() { + return null; + } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/expr/OracleAnalytic.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/expr/OracleAnalytic.java index 0fbd586ba6..bfba082260 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/expr/OracleAnalytic.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/expr/OracleAnalytic.java @@ -15,6 +15,7 @@ */ package com.alibaba.druid.sql.dialect.oracle.ast.expr; +import com.alibaba.druid.sql.ast.SQLDataType; import com.alibaba.druid.sql.ast.SQLOver; import com.alibaba.druid.sql.dialect.oracle.visitor.OracleASTVisitor; import com.alibaba.druid.sql.visitor.SQLASTVisitor; @@ -60,4 +61,8 @@ public class OracleAnalytic extends SQLOver implements OracleExpr { public void setWindowing(OracleAnalyticWindowing windowing) { this.windowing = windowing; } + + public SQLDataType computeDataType() { + return null; + } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/expr/OracleTreatExpr.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/expr/OracleTreatExpr.java index adb0486ed3..6c318d9ecb 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/expr/OracleTreatExpr.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/ast/expr/OracleTreatExpr.java @@ -15,6 +15,7 @@ */ package com.alibaba.druid.sql.dialect.oracle.ast.expr; +import com.alibaba.druid.sql.ast.SQLDataType; import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.dialect.oracle.ast.OracleSQLObjectImpl; import com.alibaba.druid.sql.dialect.oracle.visitor.OracleASTVisitor; diff --git a/src/main/java/com/alibaba/druid/sql/repository/Schema.java b/src/main/java/com/alibaba/druid/sql/repository/Schema.java index 858431f55d..9468d8e366 100644 --- a/src/main/java/com/alibaba/druid/sql/repository/Schema.java +++ b/src/main/java/com/alibaba/druid/sql/repository/Schema.java @@ -196,14 +196,7 @@ public class Schema { select.accept( repository.createResolveVisitor()); - SQLSelectQuery query = select.getQuery(); - SQLSelectQueryBlock queryBlock = null; - if (query instanceof SQLSelectQueryBlock) { - queryBlock = (SQLSelectQueryBlock) query; - } else if (query instanceof SQLUnionQuery) { - queryBlock = ((SQLUnionQuery) query).getFirstQueryBlock(); - } - + SQLSelectQueryBlock queryBlock = select.getFirstQueryBlock(); if (queryBlock != null) { List selectList = queryBlock.getSelectList(); for (SQLSelectItem selectItem : selectList) { diff --git a/src/main/java/com/alibaba/druid/sql/repository/SchemaRepository.java b/src/main/java/com/alibaba/druid/sql/repository/SchemaRepository.java index a11d36151e..1922ae99ff 100644 --- a/src/main/java/com/alibaba/druid/sql/repository/SchemaRepository.java +++ b/src/main/java/com/alibaba/druid/sql/repository/SchemaRepository.java @@ -266,32 +266,69 @@ public class SchemaRepository { public class MySqlResolveVisitor extends MySqlASTVisitorAdapter { + public boolean visit(SQLExprTableSource x) { + if (x.getSchemaObject() != null) { + return false; + } + + SQLExpr expr = x.getExpr(); + if (expr instanceof SQLName) { + SchemaObject table = findTable((SQLName) expr); + if (table != null) { + x.setSchemaObject(table); + } + } + return false; + } + public boolean visit(MySqlSelectQueryBlock x) { + SQLTableSource from = x.getFrom(); + from.accept(this); + List selectList = x.getSelectList(); + + List columns = new ArrayList(); for (int i = selectList.size() - 1; i >= 0; i--) { SQLSelectItem selectItem = selectList.get(i); SQLExpr expr = selectItem.getExpr(); if (expr instanceof SQLAllColumnExpr) { - SQLTableSource from = x.getFrom(); - List columns = new ArrayList(); - if (from instanceof SQLExprTableSource) { - SchemaObject table = findTable((SQLExprTableSource) from); - if (table != null) { - SQLCreateTableStatement createTableStmt = (SQLCreateTableStatement) table.getStatement(); - for (SQLTableElement e : createTableStmt.getTableElementList()) { - if (e instanceof SQLColumnDefinition) { - SQLColumnDefinition column = (SQLColumnDefinition) e; - SQLIdentifierExpr name = (SQLIdentifierExpr) column.getName().clone(); - name.setResolvedColumn(column); - columns.add(new SQLSelectItem(name)); - } - } - } + extractColumns(from, columns); + } else if (expr instanceof SQLPropertyExpr) { + SQLPropertyExpr propertyExpr = (SQLPropertyExpr) expr; + String ownerName = propertyExpr.getOwnernName(); + if (propertyExpr.getName().equals("*")) { + SQLTableSource tableSource = x.findTableSource(ownerName); + extractColumns(tableSource, columns); } + SQLColumnDefinition column = propertyExpr.getResolvedColumn(); + if (column != null) { + continue; + } + SQLTableSource tableSource = x.findTableSource(propertyExpr.getOwnernName()); + if (tableSource != null) { + column = tableSource.findColumn(propertyExpr.getName()); + if (column != null) { + propertyExpr.setResolvedColumn(column); + } + } + } else if (expr instanceof SQLIdentifierExpr) { + SQLIdentifierExpr identExpr = (SQLIdentifierExpr) expr; + SQLColumnDefinition column = identExpr.getResolvedColumn(); + if (column != null) { + continue; + } + column = from.findColumn(identExpr.getName()); + if (column != null) { + identExpr.setResolvedColumn(column); + } + } + + if (columns.size() > 0) { for (SQLSelectItem column : columns) { column.setParent(x); } + selectList.remove(i); selectList.addAll(i, columns); } @@ -301,6 +338,23 @@ public class SchemaRepository { } } + private void extractColumns(SQLTableSource from, List columns) { + if (from instanceof SQLExprTableSource) { + SchemaObject table = findTable((SQLExprTableSource) from); + if (table != null) { + SQLCreateTableStatement createTableStmt = (SQLCreateTableStatement) table.getStatement(); + for (SQLTableElement e : createTableStmt.getTableElementList()) { + if (e instanceof SQLColumnDefinition) { + SQLColumnDefinition column = (SQLColumnDefinition) e; + SQLIdentifierExpr name = (SQLIdentifierExpr) column.getName().clone(); + name.setResolvedColumn(column); + columns.add(new SQLSelectItem(name)); + } + } + } + } + } + public SchemaObject findTable(SQLExprTableSource x) { if (x == null) { return null; diff --git a/src/test/java/com/alibaba/druid/bvt/sql/mysql/select/MySqlCreateTable_showColumns_repository_test.java b/src/test/java/com/alibaba/druid/bvt/sql/mysql/select/MySqlCreateTable_showColumns_repository_test.java index 7058f86600..f19f962eb7 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/mysql/select/MySqlCreateTable_showColumns_repository_test.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/mysql/select/MySqlCreateTable_showColumns_repository_test.java @@ -413,5 +413,55 @@ public class MySqlCreateTable_showColumns_repository_test extends MysqlTest { "| c_mediumtext | mediumtext | NO | | NULL | |\n" + "| c_longblob | longblob | NO | | NULL | |\n" + "+--------------+--------------+------+-----+---------+-------+\n", repository.console("show columns from test3")); + + repository.console("CREATE TABLE test4 as select a.* from test2 a"); + assertEquals("CREATE TABLE test4 (\n" + + "\tc_decimal_1 INT(11),\n" + + "\tid bigint(20),\n" + + "\tc_tinyint tinyint(4),\n" + + "\tc_smallint smallint(6),\n" + + "\tc_mediumint mediumint(9),\n" + + "\tc_int int(11),\n" + + "\tc_bigint bigint(20),\n" + + "\tc_date date,\n" + + "\tc_datetime datetime,\n" + + "\tc_timestamp timestamp,\n" + + "\tc_time time,\n" + + "\tc_char char(10),\n" + + "\tc_varchar varchar(10),\n" + + "\tc_blob blob,\n" + + "\tc_text text,\n" + + "\tc_mediumtext mediumtext,\n" + + "\tc_longblob longblob\n" + + ")", repository.console("show create table test4")); + + repository.console("CREATE TABLE test5 as select a.* from test2 a union all select * from test3"); + assertEquals("CREATE TABLE test5 (\n" + + "\tc_decimal_1 INT(11),\n" + + "\tid bigint(20),\n" + + "\tc_tinyint tinyint(4),\n" + + "\tc_smallint smallint(6),\n" + + "\tc_mediumint mediumint(9),\n" + + "\tc_int int(11),\n" + + "\tc_bigint bigint(20),\n" + + "\tc_date date,\n" + + "\tc_datetime datetime,\n" + + "\tc_timestamp timestamp,\n" + + "\tc_time time,\n" + + "\tc_char char(10),\n" + + "\tc_varchar varchar(10),\n" + + "\tc_blob blob,\n" + + "\tc_text text,\n" + + "\tc_mediumtext mediumtext,\n" + + "\tc_longblob longblob\n" + + ")", repository.console("show create table test5")); + + repository.console("CREATE TABLE test6 as select a.id, c_tinyint, 'a' f3, 3 f4 from test2 a"); + assertEquals("CREATE TABLE test6 (\n" + + "\tid bigint(20),\n" + + "\tc_tinyint tinyint(4),\n" + + "\tf3 varchar,\n" + + "\tf4 bigint\n" + + ")", repository.console("show create table test6")); } }