This is an automated email from the ASF dual-hosted git repository. jiajunxie pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/calcite.git
The following commit(s) were added to refs/heads/main by this push: new f901d7d44a [CALCITE-5870] Allow literals like DECIMAL '12.3' (consistent with Postgres) f901d7d44a is described below commit f901d7d44a41e3a1db010c42dd4a422dcb31996c Author: shenlang <shenl...@zbyte-inc.com> AuthorDate: Tue Jul 25 20:14:07 2023 +0800 [CALCITE-5870] Allow literals like DECIMAL '12.3' (consistent with Postgres) --- core/src/main/codegen/templates/Parser.jj | 6 +++ .../apache/calcite/sql/parser/SqlParserUtil.java | 12 ++++++ .../apache/calcite/sql/test/SqlAdvisorTest.java | 1 + .../org/apache/calcite/test/SqlValidatorTest.java | 2 + core/src/test/resources/sql/misc.iq | 23 ++++++++++++ site/_docs/reference.md | 2 +- .../apache/calcite/sql/parser/SqlParserTest.java | 43 ++++++++++++++++++++++ 7 files changed, 88 insertions(+), 1 deletion(-) diff --git a/core/src/main/codegen/templates/Parser.jj b/core/src/main/codegen/templates/Parser.jj index ee9a9c02a7..6780339003 100644 --- a/core/src/main/codegen/templates/Parser.jj +++ b/core/src/main/codegen/templates/Parser.jj @@ -4447,6 +4447,7 @@ SqlNode LiteralOrIntervalExpression() : /** Parses a unsigned numeric literal */ SqlNumericLiteral UnsignedNumericLiteral() : { +final String p; } { <UNSIGNED_INTEGER_LITERAL> { @@ -4456,6 +4457,11 @@ SqlNumericLiteral UnsignedNumericLiteral() : <DECIMAL_NUMERIC_LITERAL> { return SqlLiteral.createExactNumeric(token.image, getPos()); } +| + <DECIMAL> + p = SimpleStringLiteral() { + return SqlParserUtil.parseDecimalLiteral(SqlParserUtil.trim(p, " "), getPos()); + } | <APPROX_NUMERIC_LITERAL> { return SqlLiteral.createApproxNumeric(token.image, getPos()); diff --git a/core/src/main/java/org/apache/calcite/sql/parser/SqlParserUtil.java b/core/src/main/java/org/apache/calcite/sql/parser/SqlParserUtil.java index 5f36342e81..e4b8ef2b41 100644 --- a/core/src/main/java/org/apache/calcite/sql/parser/SqlParserUtil.java +++ b/core/src/main/java/org/apache/calcite/sql/parser/SqlParserUtil.java @@ -325,6 +325,18 @@ public final class SqlParserUtil { return SqlLiteral.createDate(d, pos); } + public static SqlNumericLiteral parseDecimalLiteral(String s, SqlParserPos pos) { + try { + // The s maybe scientific notation string,e.g. 1.2E-3, + // we need to convert it to 0.0012 + s = new BigDecimal(s).toPlainString(); + } catch (NumberFormatException e) { + throw SqlUtil.newContextException(pos, + RESOURCE.invalidLiteral(s, "DECIMAL")); + } + return SqlLiteral.createExactNumeric(s, pos); + } + public static SqlTimeLiteral parseTimeLiteral(String s, SqlParserPos pos) { final DateTimeUtils.PrecisionTime pt = DateTimeUtils.parsePrecisionDateTimeLiteral(s, diff --git a/core/src/test/java/org/apache/calcite/sql/test/SqlAdvisorTest.java b/core/src/test/java/org/apache/calcite/sql/test/SqlAdvisorTest.java index eba04ac157..f3195b3f92 100644 --- a/core/src/test/java/org/apache/calcite/sql/test/SqlAdvisorTest.java +++ b/core/src/test/java/org/apache/calcite/sql/test/SqlAdvisorTest.java @@ -165,6 +165,7 @@ class SqlAdvisorTest extends SqlValidatorTestCase { "KEYWORD(CURSOR)", "KEYWORD(DATE)", "KEYWORD(DATETIME)", + "KEYWORD(DECIMAL)", "KEYWORD(DENSE_RANK)", "KEYWORD(ELEMENT)", "KEYWORD(EVERY)", diff --git a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java index cb6184d65d..d068702d59 100644 --- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java +++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java @@ -243,6 +243,8 @@ public class SqlValidatorTest extends SqlValidatorTestCase { .columnType("BOOLEAN NOT NULL"); expr("unknown") .columnType("BOOLEAN"); + expr("DECIMAL '123456.7890'") + .columnType("DECIMAL(10, 4) NOT NULL"); } /** Tests that date-time literals with invalid strings are considered invalid. diff --git a/core/src/test/resources/sql/misc.iq b/core/src/test/resources/sql/misc.iq index b868a090f1..321843c183 100644 --- a/core/src/test/resources/sql/misc.iq +++ b/core/src/test/resources/sql/misc.iq @@ -2520,4 +2520,27 @@ EnumerableCalc(expr#0..7=[{inputs}], expr#8=[CAST($t6):INTEGER], expr#9=[IS NOT EnumerableTableScan(table=[[scott, EMP]]) !plan +# [CALCITE-5870] Allow literals like DECIMAL '12.3' (consistent with Postgres) +# Test a decimal value between decimal logic for range checking. +select 12.3 between decimal '5.6' and decimal '17.8'; ++--------+ +| EXPR$0 | ++--------+ +| true | ++--------+ +(1 row) + +!ok + +# Test the decimal 'xx' + a decimal constant value case +select decimal'12.3' + 5.6; ++--------+ +| EXPR$0 | ++--------+ +| 17.9 | ++--------+ +(1 row) + +!ok + # End misc.iq diff --git a/site/_docs/reference.md b/site/_docs/reference.md index 791fce5b4f..e31ee67fd1 100644 --- a/site/_docs/reference.md +++ b/site/_docs/reference.md @@ -1154,7 +1154,7 @@ name will have been converted to upper case also. | SMALLINT | 2 byte signed integer | Range is -32768 to 32767 | INTEGER, INT | 4 byte signed integer | Range is -2147483648 to 2147483647 | BIGINT | 8 byte signed integer | Range is -9223372036854775808 to 9223372036854775807 -| DECIMAL(p, s) | Fixed point | Example: 123.45 is a DECIMAL(5, 2) value. +| DECIMAL(p, s) | Fixed point | Example: 123.45 or DECIMAL '123.45' is a DECIMAL(5, 2) value. | NUMERIC | Fixed point | | REAL, FLOAT | 4 byte floating point | 6 decimal digits precision | DOUBLE | 8 byte floating point | 15 decimal digits precision diff --git a/testkit/src/main/java/org/apache/calcite/sql/parser/SqlParserTest.java b/testkit/src/main/java/org/apache/calcite/sql/parser/SqlParserTest.java index 7cadf913bb..b1c9762649 100644 --- a/testkit/src/main/java/org/apache/calcite/sql/parser/SqlParserTest.java +++ b/testkit/src/main/java/org/apache/calcite/sql/parser/SqlParserTest.java @@ -907,6 +907,49 @@ public class SqlParserTest { .ok(expectedBigQuery); } + @Test void testDecimalLiteral() { + sql("select DECIMAL '99.999'") + .ok("SELECT 99.999"); + sql("select DECIMAL ' 99.999'") + .ok("SELECT 99.999"); + sql("select DECIMAL ' 99.999 '") + .ok("SELECT 99.999"); + sql("select DECIMAL '+99.999'") + .ok("SELECT 99.999"); + sql("select DECIMAL '-99.999'") + .ok("SELECT -99.999"); + sql("select DECIMAL'-99.999'") + .ok("SELECT -99.999"); + sql("select DECIMAL'99.999'") + .ok("SELECT 99.999"); + sql("select DECIMAL'.999'") + .ok("SELECT 0.999"); + sql("select DECIMAL'999.'") + .ok("SELECT 999"); + sql("select DECIMAL'999'") + .ok("SELECT 999"); + sql("select DECIMAL '2.11E-2'") + .ok("SELECT 0.0211"); + sql("select DECIMAL '2.11E2'") + .ok("SELECT 211"); + sql("select DECIMAL '.11E-2'") + .ok("SELECT 0.0011"); + sql("select DECIMAL ^''^") + .fails("(?s)Literal '' can not be parsed to type 'DECIMAL'.*"); + sql("select DECIMAL ^'-'^") + .fails("(?s)Literal '-' can not be parsed to type 'DECIMAL'.*"); + sql("select DECIMAL ^'foo'^") + .fails("(?s)Literal 'foo' can not be parsed to type 'DECIMAL'.*"); + + // Test with bigquery + sql("select DECIMAL \"2.11E-2\"") + .withDialect(BIG_QUERY) + .ok("SELECT 0.0211"); + sql("select DECIMAL \"999\"") + .withDialect(BIG_QUERY) + .ok("SELECT 999"); + } + @Test void testDerivedColumnList() { sql("select * from emp as e (empno, gender) where true") .ok("SELECT *\n"