From 23099a6a54431f67241137b52814ded2ef3c80fa Mon Sep 17 00:00:00 2001 From: Ran Tao Date: Wed, 24 Jan 2024 16:39:59 +0800 Subject: [PATCH] [CALCITE-6063] ARRAY subquery with OrderBy loses Sort --- .../calcite/sql2rel/SqlToRelConverter.java | 2 +- core/src/test/resources/sql/sub-query.iq | 48 +++++++++++++++++++ site/_docs/reference.md | 8 ++++ .../apache/calcite/test/SqlOperatorTest.java | 33 ++++++++++--- 4 files changed, 84 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java index e5afc62468f0..f6bb6df8c512 100644 --- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java +++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java @@ -5538,7 +5538,7 @@ ImmutableList retrieveCursors() { case ARRAY_QUERY_CONSTRUCTOR: call = (SqlCall) expr; query = Iterables.getOnlyElement(call.getOperandList()); - root = convertQueryRecursive(query, false, null); + root = convertQueryRecursive(query, true, null); return RexSubQuery.array(root.rel); case MAP_QUERY_CONSTRUCTOR: diff --git a/core/src/test/resources/sql/sub-query.iq b/core/src/test/resources/sql/sub-query.iq index 48508dfab721..4d76b3fb6b9e 100644 --- a/core/src/test/resources/sql/sub-query.iq +++ b/core/src/test/resources/sql/sub-query.iq @@ -3726,4 +3726,52 @@ SELECT map(SELECT empno, deptno from emp where false); !ok +# [CALCITE-6063] ARRAY subquery with OrderBy loses Sort +# normal behavior +SELECT array(SELECT empno FROM emp); ++--------------------------------------------------------------------------------------+ +| EXPR$0 | ++--------------------------------------------------------------------------------------+ +| [7369, 7499, 7521, 7566, 7654, 7698, 7782, 7788, 7839, 7844, 7876, 7900, 7902, 7934] | ++--------------------------------------------------------------------------------------+ +(1 row) + +!ok + +# [CALCITE-6063] ARRAY subquery with OrderBy loses Sort +# with filter +SELECT array(SELECT empno FROM emp WHERE empno > 7800); ++--------------------------------------+ +| EXPR$0 | ++--------------------------------------+ +| [7839, 7844, 7876, 7900, 7902, 7934] | ++--------------------------------------+ +(1 row) + +!ok + +# [CALCITE-6063] ARRAY subquery with OrderBy loses Sort +# with filter and order by +SELECT array(SELECT empno FROM emp WHERE empno > 7800 ORDER BY empno DESC); ++--------------------------------------+ +| EXPR$0 | ++--------------------------------------+ +| [7934, 7902, 7900, 7876, 7844, 7839] | ++--------------------------------------+ +(1 row) + +!ok + +# [CALCITE-6063] ARRAY subquery with OrderBy loses Sort +# with filter and order by and limit +SELECT array(SELECT empno FROM emp WHERE empno > 7800 ORDER BY empno DESC LIMIT 2); ++--------------+ +| EXPR$0 | ++--------------+ +| [7934, 7902] | ++--------------+ +(1 row) + +!ok + # End sub-query.iq diff --git a/site/_docs/reference.md b/site/_docs/reference.md index 1ba228d312c9..fd2f0b2c8a00 100644 --- a/site/_docs/reference.md +++ b/site/_docs/reference.md @@ -1643,6 +1643,14 @@ Implicit type coercion of following cases are ignored: | ARRAY '[' value [, value ]* ']' | Creates an array from a list of values. | MAP '[' key, value [, key, value ]* ']' | Creates a map from a list of key-value pairs. +### Value constructors by query + +| Operator syntax | Description | +|:-----------------------------------|:------------| +| ARRAY (sub-query) | Creates an array from the result of a sub-query. Example: `ARRAY(SELECT empno FROM emp)` | +| MAP (sub-query) | Creates a map from the result of a key-value pair sub-query. Example: `MAP(SELECT empno, deptno FROM emp)` | +| MULTISET (sub-query) | Creates a multiset from the result of a sub-query. Example: `MULTISET(SELECT empno FROM emp)` | + ### Collection functions | Operator syntax | Description diff --git a/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java b/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java index 24bf9945919f..30b276beff86 100644 --- a/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java +++ b/testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java @@ -10697,20 +10697,41 @@ private static void checkArrayConcatAggFuncFails(SqlOperatorFixture t) { "[1 , 2 , Hi , null]", "CHAR(10) ARRAY NOT NULL"); } - /** - * Test case for - * [CALCITE-4999] - * ARRAY, MULTISET functions should return an collection of scalars - * if a sub-query returns 1 column. - */ @Test void testArrayQueryConstructor() { final SqlOperatorFixture f = fixture(); f.setFor(SqlStdOperatorTable.ARRAY_QUERY, SqlOperatorFixture.VmName.EXPAND); + + // Test case for [CALCITE-4999] ARRAY, MULTISET functions should + // return a collection of scalars if a sub-query returns 1 column f.checkScalar("array(select 1)", "[1]", "INTEGER NOT NULL ARRAY NOT NULL"); f.check("select array(select ROW(1,2))", "RecordType(INTEGER NOT NULL EXPR$0, INTEGER NOT NULL EXPR$1) NOT NULL ARRAY NOT NULL", "[{1, 2}]"); + + // single sub-clause test + f.check("select array(select x from unnest(array[1,2,3,4]) as t(x))", + "INTEGER NOT NULL ARRAY NOT NULL", "[1, 2, 3, 4]"); + f.check("select array(select x from unnest(array[1,2,3,4]) as t(x) where x > 1)", + "INTEGER NOT NULL ARRAY NOT NULL", "[2, 3, 4]"); + f.check("select array(select x from unnest(array[1,2,3,4]) as t(x) limit 2)", + "INTEGER NOT NULL ARRAY NOT NULL", "[1, 2]"); + f.check("select array(select x from unnest(array[1,2,3,4]) as t(x) where x > 1 limit 2)", + "INTEGER NOT NULL ARRAY NOT NULL", "[2, 3]"); + + // combined tests + f.check("select array(select x from unnest(array[1,2,3,4]) as t(x) " + + "order by x asc)", "INTEGER NOT NULL ARRAY NOT NULL", "[1, 2, 3, 4]"); + f.check("select array(select x from unnest(array[1,2,3,4]) as t(x) " + + "where x > 1 order by x asc)", "INTEGER NOT NULL ARRAY NOT NULL", "[2, 3, 4]"); + f.check("select array(select x from unnest(array[1,2,3,4]) as t(x) " + + "where x > 1 order by x asc limit 2)", "INTEGER NOT NULL ARRAY NOT NULL", "[2, 3]"); + f.check("select array(select x from unnest(array[1,2,3,4]) as t(x) " + + "order by x desc)", "INTEGER NOT NULL ARRAY NOT NULL", "[4, 3, 2, 1]"); + f.check("select array(select x from unnest(array[1,2,3,4]) as t(x) " + + "where x > 1 order by x desc)", "INTEGER NOT NULL ARRAY NOT NULL", "[4, 3, 2]"); + f.check("select array(select x from unnest(array[1,2,3,4]) as t(x) " + + "where x > 1 order by x desc limit 2)", "INTEGER NOT NULL ARRAY NOT NULL", "[4, 3]"); } /**