diff --git a/core/src/main/codegen/templates/Parser.jj b/core/src/main/codegen/templates/Parser.jj index 0aacdb9ff747..29607e6d43a2 100644 --- a/core/src/main/codegen/templates/Parser.jj +++ b/core/src/main/codegen/templates/Parser.jj @@ -1277,6 +1277,8 @@ void AddKeyValueOption(List list) : ) ( + value = NumericLiteral() + | value = StringLiteral() | value = SimpleIdentifier() diff --git a/core/src/main/java/org/apache/calcite/sql/SqlHint.java b/core/src/main/java/org/apache/calcite/sql/SqlHint.java index 38f54636ebe8..8c61828daec9 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlHint.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlHint.java @@ -197,18 +197,19 @@ public enum HintOptionFormat implements Symbolizable { * The hint options are list of key-value pairs. * For each pair, * the key is a simple identifier or string literal, - * the value is a string literal. + * the value is a string or numeric literal. */ KV_LIST } //~ Tools ------------------------------------------------------------------ - private static String getOptionAsString(SqlNode node) { + private String getOptionAsString(SqlNode node) { assert node instanceof SqlIdentifier || SqlUtil.isLiteral(node); if (node instanceof SqlIdentifier) { return ((SqlIdentifier) node).getSimple(); } - return ((SqlLiteral) node).getValueAs(String.class); + return requireNonNull(((SqlLiteral) node).toValue(), + () -> "null hint literal in " + options); } } diff --git a/core/src/test/java/org/apache/calcite/test/SqlHintsConverterTest.java b/core/src/test/java/org/apache/calcite/test/SqlHintsConverterTest.java index 9183134cd4e4..346e0c57e6b9 100644 --- a/core/src/test/java/org/apache/calcite/test/SqlHintsConverterTest.java +++ b/core/src/test/java/org/apache/calcite/test/SqlHintsConverterTest.java @@ -172,7 +172,7 @@ public final Fixture sql(String sql) { /** Test case for [CALCITE-7498] * The parser rejects the example hints from the documentation. */ @Test void testDocumentationExample() { - final String sql = "SELECT /*+ hint1, hint2(a='1', b='2') */ *\n" + final String sql = "SELECT /*+ hint1, hint2(a=1, b=2) */ *\n" + "FROM emp /*+ hint3(5, 'x') */\n" + "JOIN dept /*+ hint4(c=id), hint5 */\n" + "ON emp.deptno = dept.deptno"; @@ -201,6 +201,12 @@ public final Fixture sql(String sql) { sql(sql).ok(); } + @Test void testQueryHintWithKeyValueNumericLiteralOptions() { + final String sql = "select /*+ hint2(a=1, b=-1, c=1.1, d=-1.1, e=1e3, f=-1e-4) */ *\n" + + "from emp"; + sql(sql).ok(); + } + @Test void testNestedQueryHint() { final String sql = "select /*+ resource(parallelism='3'), repartition(10) */ empno\n" + "from (select /*+ resource(mem='20Mb')*/ empno, ename from emp)"; diff --git a/core/src/test/resources/org/apache/calcite/test/SqlHintsConverterTest.xml b/core/src/test/resources/org/apache/calcite/test/SqlHintsConverterTest.xml index e2cd95622d57..d06db165d0e2 100644 --- a/core/src/test/resources/org/apache/calcite/test/SqlHintsConverterTest.xml +++ b/core/src/test/resources/org/apache/calcite/test/SqlHintsConverterTest.xml @@ -60,7 +60,7 @@ Correlate:[[USE_HASH_JOIN inheritPath:[0] options:[ORDERS, PRODUCTS_TEMPORAL]]] - @@ -350,6 +350,17 @@ LogicalJoin:[[NO_HASH_JOIN inheritPath:[0, 0]]] TableScan:[[PROPERTIES inheritPath:[0, 0, 0] options:{K1=v1, K2=v2}], [INDEX inheritPath:[0, 0, 0] options:[ENAME]]] TableScan:[[PROPERTIES inheritPath:[0, 0, 1] options:{K1=v1, K2=v2}], [INDEX inheritPath:[0, 0, 1] options:[ENAME]]] TableScan:[[PROPERTIES inheritPath:[0, 1, 0] options:{K1=v1, K2=v2}], [INDEX inheritPath:[0, 1, 0] options:[ENAME]]] +]]> + + + + + + + + diff --git a/site/_docs/reference.md b/site/_docs/reference.md index e50acf936f1c..c8e132a1d669 100644 --- a/site/_docs/reference.md +++ b/site/_docs/reference.md @@ -3598,11 +3598,13 @@ optionKey: optionVal: simpleIdentifier + | numericLiteral | stringLiteral hintOption: simpleIdentifier - | stringLiteral + | numericLiteral + | stringLiteral {% endhighlight %} It is experimental in Calcite, and yet not fully implemented, what we have implemented are: 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 4ab6f776ba4a..a31f782784e6 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 @@ -9693,7 +9693,12 @@ private static Consumer> checkWarnings( final String sql1 = "select " + "/*+ properties(^k1^=123, k2='v2'), no_hash_join() */ " + "empno, ename, deptno from emps"; - sql(sql1).fails("(?s).*Encountered \"k1 = 123\" at .*"); + // Allow numeric literal k/v values. + final String expected1 = "SELECT\n" + + "/*+ `PROPERTIES`(`K1` = 123, `K2` = 'v2'), `NO_HASH_JOIN` */\n" + + "`EMPNO`, `ENAME`, `DEPTNO`\n" + + "FROM `EMPS`"; + sql(sql1).ok(expected1); final String sql2 = "select " + "/*+ properties(k1, k2^=^'v2'), no_hash_join */ " + "empno, ename, deptno from emps";