From c27bd340758bc9f6ae90abce6f2d57277dc274f7 Mon Sep 17 00:00:00 2001 From: Nong Li Date: Wed, 26 Mar 2014 14:56:17 -0700 Subject: [PATCH] Revert "Disable decimal in analysis." This reverts commit 695017410adf6d4f8426c4117798c93f823a4b4b. Change-Id: I919d965e8e711d588e6c56dcdbd3c8e0d9ec7a05 Reviewed-on: http://gerrit.ent.cloudera.com:8080/2104 Reviewed-by: Nong Li Tested-by: jenkins --- .../cloudera/impala/catalog/ColumnType.java | 4 +- .../impala/analysis/AnalyzeDDLTest.java | 15 +- .../impala/analysis/AnalyzeExprsTest.java | 439 +++++++++--------- .../impala/analysis/AnalyzeStmtsTest.java | 11 +- .../cloudera/impala/analysis/ToSqlTest.java | 2 +- .../functional/functional_schema_template.sql | 10 + .../functional/schema_constraints.csv | 2 +- 7 files changed, 237 insertions(+), 246 deletions(-) diff --git a/fe/src/main/java/com/cloudera/impala/catalog/ColumnType.java b/fe/src/main/java/com/cloudera/impala/catalog/ColumnType.java index ad4fab60c..f1566c288 100644 --- a/fe/src/main/java/com/cloudera/impala/catalog/ColumnType.java +++ b/fe/src/main/java/com/cloudera/impala/catalog/ColumnType.java @@ -412,8 +412,9 @@ public class ColumnType { } public void analyze() throws AnalysisException { - if (isAnalyzed_) return; Preconditions.checkState(type_ != PrimitiveType.INVALID_TYPE); + + if (isAnalyzed_) return; if (type_ == PrimitiveType.CHAR) { if (len_ <= 0) { throw new AnalysisException("Char size must be > 0. Size was set to: " + @@ -431,7 +432,6 @@ public class ColumnType { throw new AnalysisException("Decimal scale (" + scale_+ ") must be <= " + "precision (" + precision_ + ")."); } - throw new AnalysisException("Decimal is not yet implemented."); } isAnalyzed_ = true; } diff --git a/fe/src/test/java/com/cloudera/impala/analysis/AnalyzeDDLTest.java b/fe/src/test/java/com/cloudera/impala/analysis/AnalyzeDDLTest.java index dad162ca8..35dd50b9d 100644 --- a/fe/src/test/java/com/cloudera/impala/analysis/AnalyzeDDLTest.java +++ b/fe/src/test/java/com/cloudera/impala/analysis/AnalyzeDDLTest.java @@ -635,11 +635,9 @@ public class AnalyzeDDLTest extends AnalyzerTest { AnalyzesOk("create table functional.new_table (i int) row format delimited fields " + "terminated by '|'"); - // TODO: add more tests: Reenable decimal and update tests. - //AnalyzesOk("create table new_table (i int) PARTITIONED BY (d decimal)"); - //AnalyzesOk("create table new_table(d1 decimal, d2 decimal(10), d3 decimal(5, 2))"); - AnalysisError("create table new_table (i int) PARTITIONED BY (d decimal)", - "Decimal is not yet implemented."); + // TODO: add more tests + AnalyzesOk("create table new_table (i int) PARTITIONED BY (d decimal)"); + AnalyzesOk("create table new_table(d1 decimal, d2 decimal(10), d3 decimal(5, 2))"); AnalysisError("create table new_table(d1 decimal(1,10))", "Decimal scale (10) must be <= precision (1)."); AnalysisError("create table new_table(d1 decimal(0,0))", @@ -858,8 +856,6 @@ public class AnalyzeDDLTest extends AnalyzerTest { "SYMBOL='_Z8IdentityPN10impala_udf15FunctionContextERKNS_10BooleanValE'"); AnalyzesOk("create function foo() RETURNS int LOCATION '/binary.JAR' SYMBOL='a'"); - /* - TODO Reenable tests. AnalyzesOk("create function foo() RETURNS decimal" + udfSuffix); AnalyzesOk("create function foo() RETURNS decimal(38,10)" + udfSuffix); AnalyzesOk("create function foo(Decimal, decimal(10, 2)) RETURNS int" + udfSuffix); @@ -867,9 +863,6 @@ public class AnalyzeDDLTest extends AnalyzerTest { "Decimal precision must be <= 38."); AnalysisError("create function foo(Decimal(2, 3)) RETURNS int" + udfSuffix, "Decimal scale (3) must be <= precision (2)."); - */ - AnalysisError("create function foo() RETURNS decimal" + udfSuffix, - "Decimal is not yet implemented."); // Varargs AnalyzesOk("create function foo(INT...) RETURNS int" + udfSuffix); @@ -1098,7 +1091,6 @@ public class AnalyzeDDLTest extends AnalyzerTest { "INTERMEDIATE char(10)" + loc + "UPDATE_FN='AggUpdate'", "UDAs with an intermediate type, CHAR(10), that is different from the " + "return type, INT, are currently not supported."); - /* AnalysisError("create aggregate function foo(int) RETURNS int " + "INTERMEDIATE decimal(10)" + loc + "UPDATE_FN='AggUpdate'", "UDAs with an intermediate type, DECIMAL(10,0), that is different from the " + @@ -1106,7 +1098,6 @@ public class AnalyzeDDLTest extends AnalyzerTest { AnalysisError("create aggregate function foo(int) RETURNS int " + "INTERMEDIATE decimal(40)" + loc + "UPDATE_FN='AggUpdate'", "Decimal precision must be <= 38."); - */ //AnalyzesOk("create aggregate function foo(int) RETURNS int " + // "INTERMEDIATE CHAR(10)" + loc + "UPDATE_FN='AggUpdate'"); //AnalysisError("create aggregate function foo(int) RETURNS int " + diff --git a/fe/src/test/java/com/cloudera/impala/analysis/AnalyzeExprsTest.java b/fe/src/test/java/com/cloudera/impala/analysis/AnalyzeExprsTest.java index 8ddb89723..2b615669b 100644 --- a/fe/src/test/java/com/cloudera/impala/analysis/AnalyzeExprsTest.java +++ b/fe/src/test/java/com/cloudera/impala/analysis/AnalyzeExprsTest.java @@ -165,41 +165,40 @@ public class AnalyzeExprsTest extends AnalyzerTest { } - // TODO: reneable -// @Test -// public void TestDecimalCasts() throws AnalysisException { -// String decimal = "cast('1.1' as decimal)"; -// AnalysisError("select cast(" + decimal + " as boolean)", -// "Invalid type cast of CAST('1.1' AS DECIMAL(9,0)) " + -// "from DECIMAL(9,0) to BOOLEAN"); -// AnalysisError("select cast(true as decimal)", -// "Invalid type cast of TRUE from BOOLEAN to DECIMAL(9,0)"); -// AnalysisError("select cast(" + decimal + " as timestamp)", -// "Invalid type cast of CAST('1.1' AS DECIMAL(9,0)) " + -// "from DECIMAL(9,0) to TIMESTAMP"); -// AnalysisError("select cast(cast(1 as timestamp) as decimal)", -// "Invalid type cast of CAST(1 AS TIMESTAMP) from TIMESTAMP to DECIMAL(9,0)"); -// -// for (ColumnType type: ColumnType.getSupportedTypes()) { -// if (type.isNull() || type.isDecimal() || type.isBoolean() || type.isDateType()) { -// continue; -// } -// AnalyzesOk("select cast(" + decimal + " as " + type + ")"); -// AnalyzesOk("select cast(cast(1 as " + type + ") as decimal)"); -// } -// -// // Casts to all other decimals are supported. -// for (int precision = 1; precision <= ColumnType.MAX_PRECISION; ++precision) { -// for (int scale = 0; scale < precision; ++scale) { -// ColumnType t = ColumnType.createDecimalType(precision, scale); -// AnalyzesOk("select cast(" + decimal + " as " + t + ")"); -// AnalyzesOk("select cast(cast(1 as " + t + ") as decimal)"); -// } -// } -// -// AnalysisError("select cast(1 as decimal(0, 1))", -// "Decimal precision must be greater than 0."); -// } + @Test + public void TestDecimalCasts() throws AnalysisException { + String decimal = "cast('1.1' as decimal)"; + AnalysisError("select cast(" + decimal + " as boolean)", + "Invalid type cast of CAST('1.1' AS DECIMAL(9,0)) " + + "from DECIMAL(9,0) to BOOLEAN"); + AnalysisError("select cast(true as decimal)", + "Invalid type cast of TRUE from BOOLEAN to DECIMAL(9,0)"); + AnalysisError("select cast(" + decimal + " as timestamp)", + "Invalid type cast of CAST('1.1' AS DECIMAL(9,0)) " + + "from DECIMAL(9,0) to TIMESTAMP"); + AnalysisError("select cast(cast(1 as timestamp) as decimal)", + "Invalid type cast of CAST(1 AS TIMESTAMP) from TIMESTAMP to DECIMAL(9,0)"); + + for (ColumnType type: ColumnType.getSupportedTypes()) { + if (type.isNull() || type.isDecimal() || type.isBoolean() || type.isDateType()) { + continue; + } + AnalyzesOk("select cast(" + decimal + " as " + type + ")"); + AnalyzesOk("select cast(cast(1 as " + type + ") as decimal)"); + } + + // Casts to all other decimals are supported. + for (int precision = 1; precision <= ColumnType.MAX_PRECISION; ++precision) { + for (int scale = 0; scale < precision; ++scale) { + ColumnType t = ColumnType.createDecimalType(precision, scale); + AnalyzesOk("select cast(" + decimal + " as " + t + ")"); + AnalyzesOk("select cast(cast(1 as " + t + ") as decimal)"); + } + } + + AnalysisError("select cast(1 as decimal(0, 1))", + "Decimal precision must be greater than 0."); + } @Test public void TestStringCasts() throws AnalysisException { @@ -268,8 +267,7 @@ public class AnalyzeExprsTest extends AnalyzerTest { AnalyzesOk("select cast('abc' as string)"); // Cast decimal to string - // TODO: reenable. -// AnalyzesOk("select cast(cast('1.234' as decimal) as string)"); + AnalyzesOk("select cast(cast('1.234' as decimal) as string)"); } /** @@ -282,9 +280,7 @@ public class AnalyzeExprsTest extends AnalyzerTest { if (type.getPrimitiveType() == PrimitiveType.CHAR) continue; // Cannot cast to NULL_TYPE if (type.isNull()) continue; - // TODO: reenable. - if (type.isDecimal()) continue; -// if (type.isDecimal()) type = ColumnType.DEFAULT_DECIMAL; + if (type.isDecimal()) type = ColumnType.DEFAULT_DECIMAL; checkExprType("select cast(null as " + type + ")", type); } } @@ -826,16 +822,15 @@ public class AnalyzeExprsTest extends AnalyzerTest { AnalysisError("select * from functional.alltypes where pi(*) = 5", "Cannot pass '*' to scalar function."); - // Call function that only accepts decimal: - // TODO: reenable. -// AnalyzesOk("select precision(cast('1.1' as decimal))"); -// AnalyzesOk("select scale(1.1)"); -// AnalysisError("select scale('1.1')", -// "No matching function with signature: scale(STRING)."); -// -// AnalyzesOk("select round(cast('1.1' as decimal), cast(1 as int))"); -// // 1 is a tinyint, so the function is not a perfect match -// AnalyzesOk("select round(cast('1.1' as decimal), 1)"); + // Call function that only accepts decimal + AnalyzesOk("select precision(cast('1.1' as decimal))"); + AnalyzesOk("select scale(1.1)"); + AnalysisError("select scale('1.1')", + "No matching function with signature: scale(STRING)."); + + AnalyzesOk("select round(cast('1.1' as decimal), cast(1 as int))"); + // 1 is a tinyint, so the function is not a perfect match + AnalyzesOk("select round(cast('1.1' as decimal), 1)"); } @Test @@ -1119,178 +1114,178 @@ public class AnalyzeExprsTest extends AnalyzerTest { expectedType.equals(actualType)); } -// TODO: reenable. -// @Test -// public void TestDecimalArithmetic() { -// String decimal_10_0 = "cast(1 as decimal(10,0))"; -// String decimal_5_5 = "cast(1 as decimal(5, 5))"; -// String decimal_38_34 = "cast(1 as decimal(38, 34))"; -// -// testDecimalExpr(decimal_10_0, ColumnType.createDecimalType(10, 0)); -// testDecimalExpr(decimal_5_5, ColumnType.createDecimalType(5, 5)); -// testDecimalExpr(decimal_38_34, ColumnType.createDecimalType(38, 34)); -// -// // Test arithmetic operations. -// testDecimalExpr(decimal_10_0 + " + " + decimal_10_0, -// ColumnType.createDecimalType(11, 0)); -// testDecimalExpr(decimal_10_0 + " - " + decimal_10_0, -// ColumnType.createDecimalType(11, 0)); -// testDecimalExpr(decimal_10_0 + " * " + decimal_10_0, -// ColumnType.createDecimalType(21, 0)); -// testDecimalExpr(decimal_10_0 + " / " + decimal_10_0, -// ColumnType.createDecimalType(21, 11)); -// testDecimalExpr(decimal_10_0 + " % " + decimal_10_0, -// ColumnType.createDecimalType(10, 0)); -// -// testDecimalExpr(decimal_10_0 + " + " + decimal_5_5, -// ColumnType.createDecimalType(16, 5)); -// testDecimalExpr(decimal_10_0 + " - " + decimal_5_5, -// ColumnType.createDecimalType(16, 5)); -// testDecimalExpr(decimal_10_0 + " * " + decimal_5_5, -// ColumnType.createDecimalType(16, 5)); -// testDecimalExpr(decimal_10_0 + " / " + decimal_5_5, -// ColumnType.createDecimalType(21, 6)); -// testDecimalExpr(decimal_10_0 + " % " + decimal_5_5, -// ColumnType.createDecimalType(5, 5)); -// -// testDecimalExpr(decimal_5_5 + " + " + decimal_10_0, -// ColumnType.createDecimalType(16, 5)); -// testDecimalExpr(decimal_5_5 + " - " + decimal_10_0, -// ColumnType.createDecimalType(16, 5)); -// testDecimalExpr(decimal_5_5 + " * " + decimal_10_0, -// ColumnType.createDecimalType(16, 5)); -// testDecimalExpr(decimal_5_5 + " / " + decimal_10_0, -// ColumnType.createDecimalType(16, 16)); -// testDecimalExpr(decimal_5_5 + " % " + decimal_10_0, -// ColumnType.createDecimalType(5, 5)); -// -// // Test some overflow cases. -// testDecimalExpr(decimal_10_0 + " + " + decimal_38_34, -// ColumnType.createDecimalType(38, 34)); -// testDecimalExpr(decimal_10_0 + " - " + decimal_38_34, -// ColumnType.createDecimalType(38, 34)); -// testDecimalExpr(decimal_10_0 + " * " + decimal_38_34, -// ColumnType.createDecimalType(38, 34)); -// testDecimalExpr(decimal_10_0 + " / " + decimal_38_34, -// ColumnType.createDecimalType(38, 38)); -// testDecimalExpr(decimal_10_0 + " % " + decimal_38_34, -// ColumnType.createDecimalType(38, 34)); -// -// testDecimalExpr(decimal_38_34 + " + " + decimal_5_5, -// ColumnType.createDecimalType(38, 34)); -// testDecimalExpr(decimal_38_34 + " - " + decimal_5_5, -// ColumnType.createDecimalType(38, 34)); -// testDecimalExpr(decimal_38_34 + " * " + decimal_5_5, -// ColumnType.createDecimalType(38, 38)); -// testDecimalExpr(decimal_38_34 + " / " + decimal_5_5, -// ColumnType.createDecimalType(38, 38)); -// testDecimalExpr(decimal_38_34 + " % " + decimal_5_5, -// ColumnType.createDecimalType(34, 34)); -// -// testDecimalExpr(decimal_10_0 + " + " + decimal_10_0 + " + " + decimal_10_0, -// ColumnType.createDecimalType(12, 0)); -// testDecimalExpr(decimal_10_0 + " - " + decimal_10_0 + " * " + decimal_10_0, -// ColumnType.createDecimalType(22, 0)); -// testDecimalExpr(decimal_10_0 + " / " + decimal_10_0 + " / " + decimal_10_0, -// ColumnType.createDecimalType(32, 22)); -// testDecimalExpr(decimal_10_0 + " % " + decimal_10_0 + " + " + decimal_10_0, -// ColumnType.createDecimalType(11, 0)); -// -// // Operators between decimal and numeric types should be supported. The int -// // should be cast to the appropriate decimal (e.g. tinyint -> decimal(3,0)). -// testDecimalExpr(decimal_10_0 + " + cast(1 as tinyint)", -// ColumnType.createDecimalType(11, 0)); -// testDecimalExpr(decimal_10_0 + " + cast(1 as smallint)", -// ColumnType.createDecimalType(11, 0)); -// testDecimalExpr(decimal_10_0 + " + cast(1 as int)", -// ColumnType.createDecimalType(11, 0)); -// testDecimalExpr(decimal_10_0 + " + cast(1 as bigint)", -// ColumnType.createDecimalType(21, 0)); -// testDecimalExpr(decimal_10_0 + " + cast(1 as float)", -// ColumnType.createDecimalType(38, 9)); -// testDecimalExpr(decimal_10_0 + " + cast(1 as double)", -// ColumnType.createDecimalType(38, 17)); -// -// testDecimalExpr(decimal_5_5 + " + cast(1 as tinyint)", -// ColumnType.createDecimalType(9, 5)); -// testDecimalExpr(decimal_5_5 + " - cast(1 as smallint)", -// ColumnType.createDecimalType(11, 5)); -// testDecimalExpr(decimal_5_5 + " * cast(1 as int)", -// ColumnType.createDecimalType(16, 5)); -// testDecimalExpr(decimal_5_5 + " % cast(1 as bigint)", -// ColumnType.createDecimalType(5, 5)); -// testDecimalExpr(decimal_5_5 + " / cast(1 as float)", -// ColumnType.createDecimalType(38, 38)); -// testDecimalExpr(decimal_5_5 + " + cast(1 as double)", -// ColumnType.createDecimalType(38, 17)); -// -// AnalyzesOk("select " + decimal_5_5 + " = cast(1 as tinyint)"); -// AnalyzesOk("select " + decimal_5_5 + " != cast(1 as smallint)"); -// AnalyzesOk("select " + decimal_5_5 + " > cast(1 as int)"); -// AnalyzesOk("select " + decimal_5_5 + " < cast(1 as bigint)"); -// AnalyzesOk("select " + decimal_5_5 + " >= cast(1 as float)"); -// AnalyzesOk("select " + decimal_5_5 + " <= cast(1 as double)"); -// -// AnalysisError("select " + decimal_5_5 + " + 'abcd'", -// "Arithmetic operation requires numeric operands: " -// + "CAST(1 AS DECIMAL(5,5)) + 'abcd'"); -// AnalysisError("select " + decimal_5_5 + " + 'cast(1 as timestamp)'", -// "Arithmetic operation requires numeric operands: " -// + "CAST(1 AS DECIMAL(5,5)) + 'cast(1 as timestamp)'"); -// -// AnalysisError("select " + decimal_5_5 + " = 'abcd'", -// "operands are not comparable: CAST(1 AS DECIMAL(5,5)) = 'abcd'"); -// AnalysisError("select " + decimal_5_5 + " > 'cast(1 as timestamp)'", -// "operands are not comparable: " -// + "CAST(1 AS DECIMAL(5,5)) > 'cast(1 as timestamp)'"); -// } -// -// @Test -// public void TestDecimalOperators() throws AnalysisException { -// AnalyzesOk("select d2 % d5 from functional.decimal_tbl"); -// -// AnalyzesOk("select d1 from functional.decimal_tbl"); -// AnalyzesOk("select cast(d2 as decimal(1)) from functional.decimal_tbl"); -// AnalyzesOk("select d3 + d4 from functional.decimal_tbl"); -// AnalyzesOk("select d5 - d1 from functional.decimal_tbl"); -// AnalyzesOk("select d2 * d2 from functional.decimal_tbl"); -// AnalyzesOk("select d4 / d1 from functional.decimal_tbl"); -// AnalyzesOk("select d2 % d5 from functional.decimal_tbl"); -// -// AnalysisError("select d1 & d1 from functional.decimal_tbl", -// "Invalid non-integer argument to operation '&': d1 & d1"); -// AnalysisError("select d1 | d1 from functional.decimal_tbl", -// "Invalid non-integer argument to operation '|': d1 | d1"); -// AnalysisError("select d1 ^ d1 from functional.decimal_tbl", -// "Invalid non-integer argument to operation '^': d1 ^ d1"); -// AnalysisError("select ~d1 from functional.decimal_tbl", -// "Bitwise operations only allowed on fixed-point types: ~d1"); -// -// AnalyzesOk("select d3 = d4 from functional.decimal_tbl"); -// AnalyzesOk("select d5 != d1 from functional.decimal_tbl"); -// AnalyzesOk("select d2 > d2 from functional.decimal_tbl"); -// AnalyzesOk("select d4 >= d1 from functional.decimal_tbl"); -// AnalyzesOk("select d2 < d5 from functional.decimal_tbl"); -// AnalyzesOk("select d2 <= d5 from functional.decimal_tbl"); -// } -// -// @Test -// public void TestDecimalType() throws AnalysisException { -// AnalyzesOk("select cast(1 as decimal)"); -// AnalyzesOk("select cast(1 as decimal(1))"); -// AnalyzesOk("select cast(1 as decimal(38))"); -// AnalyzesOk("select cast(1 as decimal(1, 0))"); -// AnalyzesOk("select cast(1 as decimal(10, 5))"); -// AnalyzesOk("select cast(1 as decimal(38, 0))"); -// AnalyzesOk("select cast(1 as decimal(38, 38))"); -// -// AnalysisError("select cast(1 as decimal(0))", -// "Decimal precision must be greater than 0."); -// AnalysisError("select cast(1 as decimal(39))", -// "Decimal precision must be <= 38."); -// AnalysisError("select cast(1 as decimal(1, 2))", -// "Decimal scale (2) must be <= precision (1)."); -// } + @Test + public void TestDecimalArithmetic() { + String decimal_10_0 = "cast(1 as decimal(10,0))"; + String decimal_5_5 = "cast(1 as decimal(5, 5))"; + String decimal_38_34 = "cast(1 as decimal(38, 34))"; + + testDecimalExpr(decimal_10_0, ColumnType.createDecimalType(10, 0)); + testDecimalExpr(decimal_5_5, ColumnType.createDecimalType(5, 5)); + testDecimalExpr(decimal_38_34, ColumnType.createDecimalType(38, 34)); + + // Test arithmetic operations. + testDecimalExpr(decimal_10_0 + " + " + decimal_10_0, + ColumnType.createDecimalType(11, 0)); + testDecimalExpr(decimal_10_0 + " - " + decimal_10_0, + ColumnType.createDecimalType(11, 0)); + testDecimalExpr(decimal_10_0 + " * " + decimal_10_0, + ColumnType.createDecimalType(21, 0)); + testDecimalExpr(decimal_10_0 + " / " + decimal_10_0, + ColumnType.createDecimalType(21, 11)); + testDecimalExpr(decimal_10_0 + " % " + decimal_10_0, + ColumnType.createDecimalType(10, 0)); + + testDecimalExpr(decimal_10_0 + " + " + decimal_5_5, + ColumnType.createDecimalType(16, 5)); + testDecimalExpr(decimal_10_0 + " - " + decimal_5_5, + ColumnType.createDecimalType(16, 5)); + testDecimalExpr(decimal_10_0 + " * " + decimal_5_5, + ColumnType.createDecimalType(16, 5)); + testDecimalExpr(decimal_10_0 + " / " + decimal_5_5, + ColumnType.createDecimalType(21, 6)); + testDecimalExpr(decimal_10_0 + " % " + decimal_5_5, + ColumnType.createDecimalType(5, 5)); + + testDecimalExpr(decimal_5_5 + " + " + decimal_10_0, + ColumnType.createDecimalType(16, 5)); + testDecimalExpr(decimal_5_5 + " - " + decimal_10_0, + ColumnType.createDecimalType(16, 5)); + testDecimalExpr(decimal_5_5 + " * " + decimal_10_0, + ColumnType.createDecimalType(16, 5)); + testDecimalExpr(decimal_5_5 + " / " + decimal_10_0, + ColumnType.createDecimalType(16, 16)); + testDecimalExpr(decimal_5_5 + " % " + decimal_10_0, + ColumnType.createDecimalType(5, 5)); + + // Test some overflow cases. + testDecimalExpr(decimal_10_0 + " + " + decimal_38_34, + ColumnType.createDecimalType(38, 34)); + testDecimalExpr(decimal_10_0 + " - " + decimal_38_34, + ColumnType.createDecimalType(38, 34)); + testDecimalExpr(decimal_10_0 + " * " + decimal_38_34, + ColumnType.createDecimalType(38, 34)); + testDecimalExpr(decimal_10_0 + " / " + decimal_38_34, + ColumnType.createDecimalType(38, 38)); + testDecimalExpr(decimal_10_0 + " % " + decimal_38_34, + ColumnType.createDecimalType(38, 34)); + + testDecimalExpr(decimal_38_34 + " + " + decimal_5_5, + ColumnType.createDecimalType(38, 34)); + testDecimalExpr(decimal_38_34 + " - " + decimal_5_5, + ColumnType.createDecimalType(38, 34)); + testDecimalExpr(decimal_38_34 + " * " + decimal_5_5, + ColumnType.createDecimalType(38, 38)); + testDecimalExpr(decimal_38_34 + " / " + decimal_5_5, + ColumnType.createDecimalType(38, 38)); + testDecimalExpr(decimal_38_34 + " % " + decimal_5_5, + ColumnType.createDecimalType(34, 34)); + + testDecimalExpr(decimal_10_0 + " + " + decimal_10_0 + " + " + decimal_10_0, + ColumnType.createDecimalType(12, 0)); + testDecimalExpr(decimal_10_0 + " - " + decimal_10_0 + " * " + decimal_10_0, + ColumnType.createDecimalType(22, 0)); + testDecimalExpr(decimal_10_0 + " / " + decimal_10_0 + " / " + decimal_10_0, + ColumnType.createDecimalType(32, 22)); + testDecimalExpr(decimal_10_0 + " % " + decimal_10_0 + " + " + decimal_10_0, + ColumnType.createDecimalType(11, 0)); + + // Operators between decimal and numeric types should be supported. The int + // should be cast to the appropriate decimal (e.g. tinyint -> decimal(3,0)). + testDecimalExpr(decimal_10_0 + " + cast(1 as tinyint)", + ColumnType.createDecimalType(11, 0)); + testDecimalExpr(decimal_10_0 + " + cast(1 as smallint)", + ColumnType.createDecimalType(11, 0)); + testDecimalExpr(decimal_10_0 + " + cast(1 as int)", + ColumnType.createDecimalType(11, 0)); + testDecimalExpr(decimal_10_0 + " + cast(1 as bigint)", + ColumnType.createDecimalType(21, 0)); + testDecimalExpr(decimal_10_0 + " + cast(1 as float)", + ColumnType.createDecimalType(38, 9)); + testDecimalExpr(decimal_10_0 + " + cast(1 as double)", + ColumnType.createDecimalType(38, 17)); + + testDecimalExpr(decimal_5_5 + " + cast(1 as tinyint)", + ColumnType.createDecimalType(9, 5)); + testDecimalExpr(decimal_5_5 + " - cast(1 as smallint)", + ColumnType.createDecimalType(11, 5)); + testDecimalExpr(decimal_5_5 + " * cast(1 as int)", + ColumnType.createDecimalType(16, 5)); + testDecimalExpr(decimal_5_5 + " % cast(1 as bigint)", + ColumnType.createDecimalType(5, 5)); + testDecimalExpr(decimal_5_5 + " / cast(1 as float)", + ColumnType.createDecimalType(38, 38)); + testDecimalExpr(decimal_5_5 + " + cast(1 as double)", + ColumnType.createDecimalType(38, 17)); + + AnalyzesOk("select " + decimal_5_5 + " = cast(1 as tinyint)"); + AnalyzesOk("select " + decimal_5_5 + " != cast(1 as smallint)"); + AnalyzesOk("select " + decimal_5_5 + " > cast(1 as int)"); + AnalyzesOk("select " + decimal_5_5 + " < cast(1 as bigint)"); + AnalyzesOk("select " + decimal_5_5 + " >= cast(1 as float)"); + AnalyzesOk("select " + decimal_5_5 + " <= cast(1 as double)"); + + AnalysisError("select " + decimal_5_5 + " + 'abcd'", + "Arithmetic operation requires numeric operands: " + + "CAST(1 AS DECIMAL(5,5)) + 'abcd'"); + AnalysisError("select " + decimal_5_5 + " + 'cast(1 as timestamp)'", + "Arithmetic operation requires numeric operands: " + + "CAST(1 AS DECIMAL(5,5)) + 'cast(1 as timestamp)'"); + + AnalysisError("select " + decimal_5_5 + " = 'abcd'", + "operands of type DECIMAL(5,5) and STRING are not comparable: " + + "CAST(1 AS DECIMAL(5,5)) = 'abcd'"); + AnalysisError("select " + decimal_5_5 + " > 'cast(1 as timestamp)'", + "operands of type DECIMAL(5,5) and STRING are not comparable: " + + "CAST(1 AS DECIMAL(5,5)) > 'cast(1 as timestamp)'"); + } + + @Test + public void TestDecimalOperators() throws AnalysisException { + AnalyzesOk("select d2 % d5 from functional.decimal_tbl"); + + AnalyzesOk("select d1 from functional.decimal_tbl"); + AnalyzesOk("select cast(d2 as decimal(1)) from functional.decimal_tbl"); + AnalyzesOk("select d3 + d4 from functional.decimal_tbl"); + AnalyzesOk("select d5 - d1 from functional.decimal_tbl"); + AnalyzesOk("select d2 * d2 from functional.decimal_tbl"); + AnalyzesOk("select d4 / d1 from functional.decimal_tbl"); + AnalyzesOk("select d2 % d5 from functional.decimal_tbl"); + + AnalysisError("select d1 & d1 from functional.decimal_tbl", + "Invalid non-integer argument to operation '&': d1 & d1"); + AnalysisError("select d1 | d1 from functional.decimal_tbl", + "Invalid non-integer argument to operation '|': d1 | d1"); + AnalysisError("select d1 ^ d1 from functional.decimal_tbl", + "Invalid non-integer argument to operation '^': d1 ^ d1"); + AnalysisError("select ~d1 from functional.decimal_tbl", + "Bitwise operations only allowed on fixed-point types: ~d1"); + + AnalyzesOk("select d3 = d4 from functional.decimal_tbl"); + AnalyzesOk("select d5 != d1 from functional.decimal_tbl"); + AnalyzesOk("select d2 > d2 from functional.decimal_tbl"); + AnalyzesOk("select d4 >= d1 from functional.decimal_tbl"); + AnalyzesOk("select d2 < d5 from functional.decimal_tbl"); + AnalyzesOk("select d2 <= d5 from functional.decimal_tbl"); + } + + @Test + public void TestDecimalType() throws AnalysisException { + AnalyzesOk("select cast(1 as decimal)"); + AnalyzesOk("select cast(1 as decimal(1))"); + AnalyzesOk("select cast(1 as decimal(38))"); + AnalyzesOk("select cast(1 as decimal(1, 0))"); + AnalyzesOk("select cast(1 as decimal(10, 5))"); + AnalyzesOk("select cast(1 as decimal(38, 0))"); + AnalyzesOk("select cast(1 as decimal(38, 38))"); + + AnalysisError("select cast(1 as decimal(0))", + "Decimal precision must be greater than 0."); + AnalysisError("select cast(1 as decimal(39))", + "Decimal precision must be <= 38."); + AnalysisError("select cast(1 as decimal(1, 2))", + "Decimal scale (2) must be <= precision (1)."); + } /** * Test expr depth limit of operators in infix notation, e.g., 1 + 1. diff --git a/fe/src/test/java/com/cloudera/impala/analysis/AnalyzeStmtsTest.java b/fe/src/test/java/com/cloudera/impala/analysis/AnalyzeStmtsTest.java index bec969fae..b84ff03b9 100644 --- a/fe/src/test/java/com/cloudera/impala/analysis/AnalyzeStmtsTest.java +++ b/fe/src/test/java/com/cloudera/impala/analysis/AnalyzeStmtsTest.java @@ -582,7 +582,6 @@ public class AnalyzeStmtsTest extends AnalyzerTest { } // Decimal - /* AnalyzesOk("select min(d1), max(d2), count(d3), sum(d4) " + "from functional.decimal_tbl"); AnalyzesOk("select ndv(d1), distinctpc(d2), distinctpcsa(d3), count(distinct d4) " @@ -590,7 +589,6 @@ public class AnalyzeStmtsTest extends AnalyzerTest { AnalyzesOk("select avg(d5) from functional.decimal_tbl"); AnalysisError("select group_concat(d5) from functional.decimal_tbl", "No matching function with signature: group_concat(DECIMAL(10,5))"); - */ } @Test @@ -704,10 +702,8 @@ public class AnalyzeStmtsTest extends AnalyzerTest { // ok for constants in select list not to be in group by list AnalyzesOk("select true, NULL, 1*2+5 as a, zip, count(*) from functional.testtbl " + "group by zip"); - - // TODO: reneable -// AnalyzesOk("select d1, d2, count(*) from functional.decimal_tbl " + -// "group by 1, 2"); + AnalyzesOk("select d1, d2, count(*) from functional.decimal_tbl " + + "group by 1, 2"); // doesn't group by all non-agg select list items AnalysisError("select zip, count(*) from functional.testtbl", @@ -791,8 +787,7 @@ public class AnalyzeStmtsTest extends AnalyzerTest { AnalyzesOk("select zip, id from functional.testtbl order by zip desc"); AnalyzesOk("select zip, id from functional.testtbl " + "order by true asc, false desc, NULL asc"); - - //AnalyzesOk("select d1, d2 from functional.decimal_tbl order by d1"); + AnalyzesOk("select d1, d2 from functional.decimal_tbl order by d1"); // resolves ordinals AnalyzesOk("select zip, id from functional.testtbl order by 1"); diff --git a/fe/src/test/java/com/cloudera/impala/analysis/ToSqlTest.java b/fe/src/test/java/com/cloudera/impala/analysis/ToSqlTest.java index 775d50910..461e26e01 100644 --- a/fe/src/test/java/com/cloudera/impala/analysis/ToSqlTest.java +++ b/fe/src/test/java/com/cloudera/impala/analysis/ToSqlTest.java @@ -618,6 +618,6 @@ public class ToSqlTest extends AnalyzerTest { */ @Test public void testDecimal() { - //testToSql("select cast(1 as decimal)", "SELECT CAST(1 AS DECIMAL(9,0))"); + testToSql("select cast(1 as decimal)", "SELECT CAST(1 AS DECIMAL(9,0))"); } } diff --git a/testdata/datasets/functional/functional_schema_template.sql b/testdata/datasets/functional/functional_schema_template.sql index b66759ce6..bab170d11 100644 --- a/testdata/datasets/functional/functional_schema_template.sql +++ b/testdata/datasets/functional/functional_schema_template.sql @@ -1215,3 +1215,13 @@ STORED AS INPUTFORMAT OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.RCFileOutputFormat'; ==== +---- DATASET +functional +---- BASE_TABLE_NAME +decimal_tbl +---- COLUMNS +d1 DECIMAL +d2 DECIMAL(10, 0) +d3 DECIMAL(20, 10) +d4 DECIMAL(38, 38) +d5 DECIMAL(10, 5) diff --git a/testdata/datasets/functional/schema_constraints.csv b/testdata/datasets/functional/schema_constraints.csv index ace18ed76..eae0bd207 100644 --- a/testdata/datasets/functional/schema_constraints.csv +++ b/testdata/datasets/functional/schema_constraints.csv @@ -92,4 +92,4 @@ table_name:nullformat_custom, constraint:exclude, table_format:hbase/none/none table_name:unsupported_types, constraint:exclude, table_format:hbase/none/none # Decimal is only supported for text for now. -#table_name:decimal_tbl, constraint:restrict_to, table_format:text/none/none +table_name:decimal_tbl, constraint:restrict_to, table_format:text/none/none