From fa8e4ec2f0547f35b2636d52070169f818b49d66 Mon Sep 17 00:00:00 2001 From: HappenLee Date: Fri, 8 Apr 2022 09:13:56 +0800 Subject: [PATCH] [fix] Disable cast operation of object type (#8882) Disable cast between string and object type(bitmap, hll, quantile_state) --- .../org/apache/doris/analysis/CastExpr.java | 28 ++++++++++------- .../doris/analysis/FunctionCallExpr.java | 4 +-- .../apache/doris/catalog/PrimitiveType.java | 12 ------- .../org/apache/doris/catalog/ScalarType.java | 12 +++++-- .../apache/doris/planner/QueryPlanTest.java | 31 ++++++++++++------- .../doris/planner/TableFunctionPlanTest.java | 4 +-- 6 files changed, 48 insertions(+), 43 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/CastExpr.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/CastExpr.java index c39b2b7cfc..ed7bd624ee 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/CastExpr.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/CastExpr.java @@ -134,23 +134,29 @@ public class CastExpr extends Expr { return targetTypeDef; } + private static boolean disableRegisterCastingFunction(Type fromType, Type toType) { + // Disable casting from boolean to decimal or datetime or date + if (fromType.isBoolean() && + (toType.equals(Type.DECIMALV2) || + toType.equals(Type.DATETIME) || toType.equals(Type.DATE))) { + return true; + } + + // Disable casting operation of hll/bitmap/quantile_state + if (fromType.isObjectStored() || toType.isObjectStored()) { + return true; + } + // Disable no-op casting + return fromType.equals(toType); + } + public static void initBuiltins(FunctionSet functionSet) { for (Type fromType : Type.getSupportedTypes()) { if (fromType.isNull()) { continue; } for (Type toType : Type.getSupportedTypes()) { - if (toType.isNull()) { - continue; - } - // Disable casting from boolean to decimal or datetime or date - if (fromType.isBoolean() && - (toType.equals(Type.DECIMALV2) || - toType.equals(Type.DATETIME) || toType.equals(Type.DATE))) { - continue; - } - // Disable no-op casts - if (fromType.equals(toType)) { + if (toType.isNull() || disableRegisterCastingFunction(fromType, toType)) { continue; } String beClass = toType.isDecimalV2() || fromType.isDecimalV2() ? "DecimalV2Operators" : "CastFunctions"; diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/FunctionCallExpr.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/FunctionCallExpr.java index 261fa40725..79c13fe03b 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/FunctionCallExpr.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/FunctionCallExpr.java @@ -89,8 +89,6 @@ public class FunctionCallExpr extends Expr { private boolean isRewrote = false; - public static final String UNKNOWN_TABLE_FUNCTION_MSG = "This table function not supported now"; - public void setIsAnalyticFnCall(boolean v) { isAnalyticFnCall = v; } @@ -827,7 +825,7 @@ public class FunctionCallExpr extends Expr { fn = getTableFunction(fnName.getFunction(), childTypes, Function.CompareMode.IS_NONSTRICT_SUPERTYPE_OF); if (fn == null) { - throw new AnalysisException(UNKNOWN_TABLE_FUNCTION_MSG); + throw new AnalysisException(getFunctionNotFoundError(argTypes)); } } else { // now first find function in built-in functions diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/PrimitiveType.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/PrimitiveType.java index 5521966d58..2b29dbabe3 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/PrimitiveType.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/PrimitiveType.java @@ -248,9 +248,6 @@ public enum PrimitiveType { builder.put(VARCHAR, DECIMALV2); builder.put(VARCHAR, VARCHAR); builder.put(VARCHAR, STRING); - builder.put(VARCHAR, HLL); - builder.put(VARCHAR, BITMAP); - builder.put(VARCHAR, QUANTILE_STATE); // Varchar builder.put(STRING, BOOLEAN); @@ -266,9 +263,6 @@ public enum PrimitiveType { builder.put(STRING, DECIMALV2); builder.put(STRING, VARCHAR); builder.put(STRING, STRING); - builder.put(STRING, HLL); - builder.put(STRING, BITMAP); - builder.put(STRING, QUANTILE_STATE); // DecimalV2 builder.put(DECIMALV2, BOOLEAN); @@ -285,18 +279,12 @@ public enum PrimitiveType { // HLL builder.put(HLL, HLL); - builder.put(HLL, VARCHAR); - builder.put(HLL, STRING); // BITMAP builder.put(BITMAP, BITMAP); - builder.put(BITMAP, VARCHAR); - builder.put(BITMAP, STRING); // QUANTILE_STATE builder.put(QUANTILE_STATE, QUANTILE_STATE); - builder.put(QUANTILE_STATE, VARCHAR); - builder.put(QUANTILE_STATE, STRING); //TIME builder.put(TIME, TIME); diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/ScalarType.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/ScalarType.java index 71f0882739..fda252309a 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/ScalarType.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/ScalarType.java @@ -546,9 +546,6 @@ public class ScalarType extends Type { if (type == PrimitiveType.VARCHAR && scalarType.isStringType()) { return true; } - if (type == PrimitiveType.HLL && scalarType.isStringType()) { - return true; - } if (isDecimalV2() && scalarType.isWildcardDecimal()) { Preconditions.checkState(!isWildcardDecimal()); return true; @@ -682,6 +679,15 @@ public class ScalarType extends Type { return INVALID; } + boolean t1IsBitMap = t1.type == PrimitiveType.BITMAP; + boolean t2IsBitMap = t2.type == PrimitiveType.BITMAP; + if (t1IsBitMap || t2IsBitMap) { + if (t1IsBitMap && t2IsBitMap) { + return BITMAP; + } + return INVALID; + } + // for cast all type if (t1.type == PrimitiveType.ALL || t2.type == PrimitiveType.ALL) { return Type.ALL; diff --git a/fe/fe-core/src/test/java/org/apache/doris/planner/QueryPlanTest.java b/fe/fe-core/src/test/java/org/apache/doris/planner/QueryPlanTest.java index bfaec003ad..20a5c7c704 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/planner/QueryPlanTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/planner/QueryPlanTest.java @@ -476,18 +476,6 @@ public class QueryPlanTest { Assert.assertTrue(explainString.contains("OUTPUT EXPRS:`id` | `id2`")); Assert.assertTrue(explainString.contains("0:OlapScanNode")); - queryStr = "explain insert into test.bitmap_table select id, to_bitmap(id2) from test.bitmap_table_2;"; - explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr); - Assert.assertTrue(explainString.contains("OLAP TABLE SINK")); - Assert.assertTrue(explainString.contains("OUTPUT EXPRS:`id` | to_bitmap(CAST(`id2` AS CHARACTER))")); - Assert.assertTrue(explainString.contains("0:OlapScanNode")); - - queryStr = "explain insert into test.bitmap_table select id, bitmap_hash(id2) from test.bitmap_table_2;"; - explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr); - Assert.assertTrue(explainString.contains("OLAP TABLE SINK")); - Assert.assertTrue(explainString.contains("OUTPUT EXPRS:`id` | bitmap_hash(CAST(`id2` AS CHARACTER))")); - Assert.assertTrue(explainString.contains("0:OlapScanNode")); - queryStr = "explain insert into test.bitmap_table select id, id from test.bitmap_table_2;"; String errorMsg = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, queryStr); Assert.assertTrue(errorMsg.contains("bitmap column require the function return type is BITMAP")); @@ -615,6 +603,25 @@ public class QueryPlanTest { sql = "SHOW VARIABLES LIKE 'lower_case_%'; SHOW VARIABLES LIKE 'sql_mode'"; List stmts = UtFrameUtils.parseAndAnalyzeStmts(sql, connectContext); Assert.assertEquals(2, stmts.size()); + + // disable cast hll/bitmap to string + testHLLQueryPlan( + "select cast(id2 as varchar) from test.hll_table;", + "Invalid type cast of `id2` from HLL to VARCHAR(*)" + ); + testBitmapQueryPlan( + "select cast(id2 as varchar) from test.bitmap_table;", + "Invalid type cast of `id2` from BITMAP to VARCHAR(*)" + ); + // disable implicit cast hll/bitmap to string + testHLLQueryPlan( + "select length(id2) from test.hll_table;", + "No matching function with signature: length(hll)" + ); + testBitmapQueryPlan( + "select length(id2) from test.bitmap_table;", + "No matching function with signature: length(bitmap)" + ); } @Test diff --git a/fe/fe-core/src/test/java/org/apache/doris/planner/TableFunctionPlanTest.java b/fe/fe-core/src/test/java/org/apache/doris/planner/TableFunctionPlanTest.java index 58e4c9de86..15d84f7f39 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/planner/TableFunctionPlanTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/planner/TableFunctionPlanTest.java @@ -184,11 +184,11 @@ public class TableFunctionPlanTest { public void errorParam() throws Exception { String sql = "explain select k1, e1 from db1.tbl1 lateral view explode_split(k2) tmp as e1;"; String explainString = UtFrameUtils.getSQLPlanOrErrorMsg(ctx, sql); - Assert.assertTrue(explainString.contains(FunctionCallExpr.UNKNOWN_TABLE_FUNCTION_MSG)); + Assert.assertTrue(explainString.contains("No matching function with signature: explode_split(varchar(1))")); sql = "explain select k1, e1 from db1.tbl1 lateral view explode_split(k1) tmp as e1;"; explainString = UtFrameUtils.getSQLPlanOrErrorMsg(ctx, sql); - Assert.assertTrue(explainString.contains(FunctionCallExpr.UNKNOWN_TABLE_FUNCTION_MSG)); + Assert.assertTrue(explainString.contains("No matching function with signature: explode_split(int(11))")); } /* Case2 table function in where stmt