diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlConformance.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlConformance.java index fe902759db1..fcd3b46641f 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/SqlConformance.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlConformance.java @@ -375,6 +375,7 @@ default boolean isColonFieldAccessAllowed() { * fields of T if T is a STRUCT type. * *

Among the built-in conformance levels, true in + * {@link SqlConformanceEnum#BIG_QUERY}, * {@link SqlConformanceEnum#PRESTO}; * false otherwise. */ diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlConformanceEnum.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlConformanceEnum.java index 047f05981a1..f0f258171b3 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/SqlConformanceEnum.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlConformanceEnum.java @@ -435,6 +435,7 @@ public enum SqlConformanceEnum implements SqlConformance { @Override public boolean allowAliasUnnestItems() { switch (this) { + case BIG_QUERY: case PRESTO: return true; default: diff --git a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java index ebad0e9450a..1fe413761df 100644 --- a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java +++ b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java @@ -1939,6 +1939,32 @@ public static void checkActualAndReferenceFiles() { sql(sql).withConformance(SqlConformanceEnum.PRESTO).ok(); } + /** + * Test case for + * [CALCITE-7547] + * BIG_QUERY conformance should allow field access on + * UNNEST(array_of_struct) AS alias. + */ + @Test void testAliasUnnestArrayPlanWithSingleColumnBigQuery() { + final String sql = "select d.deptno, employee.empno\n" + + "from dept_nested_expanded as d,\n" + + " UNNEST(d.employees) as t(employee)"; + sql(sql).withConformance(SqlConformanceEnum.BIG_QUERY).ok(); + } + + /** + * Test case for + * [CALCITE-7547] + * BIG_QUERY conformance should allow field access on + * UNNEST(array_of_struct) AS alias. + */ + @Test void testAliasUnnestArrayPlanWithDoubleColumnBigQuery() { + final String sql = "select d.deptno, e, k.empno\n" + + "from dept_nested_expanded as d CROSS JOIN\n" + + " UNNEST(d.admins, d.employees) as t(e, k)"; + sql(sql).withConformance(SqlConformanceEnum.BIG_QUERY).ok(); + } + @Test void testArrayOfRecord() { sql("select employees[1].detail.skills[2+3].desc from dept_nested").ok(); } 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 5198762c106..9a080efbf86 100644 --- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java +++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java @@ -8816,6 +8816,37 @@ void testGroupExpressionEquivalenceParams() { + "\\('EMPNO', 'ENAME', 'DETAIL'\\), whereas alias list has 1 columns"); } + /** + * Test case for + * [CALCITE-7547] + * BIG_QUERY conformance should allow field access on + * UNNEST(array_of_struct) AS alias. + */ + @Test void testAliasUnnestMultipleArraysBigQuery() { + // for accessing a field in STRUCT type unnested from array + sql("select e.ENAME\n" + + "from dept_nested_expanded as d CROSS JOIN\n" + + " UNNEST(d.employees) as t(e)") + .withConformance(SqlConformanceEnum.BIG_QUERY).columnType("VARCHAR(10) NOT NULL"); + + // for unnesting multiple arrays at the same time + sql("select d.deptno, e, k.empno, l.\"unit\", l.\"X\" * l.\"Y\"\n" + + "from dept_nested_expanded as d CROSS JOIN\n" + + " UNNEST(d.admins, d.employees, d.offices) as t(e, k, l)") + .withConformance(SqlConformanceEnum.BIG_QUERY).ok(); + + // Make sure validation fails properly given illegal select items + sql("select d.deptno, ^e^.some_column, k.empno\n" + + "from dept_nested_expanded as d CROSS JOIN\n" + + " UNNEST(d.admins, d.employees) as t(e, k)") + .withConformance(SqlConformanceEnum.BIG_QUERY) + .fails("Table 'E' not found"); + sql("select d.deptno, e.detail, ^unknown^.detail\n" + + "from dept_nested_expanded as d CROSS JOIN\n" + + " UNNEST(d.employees) as t(e)") + .withConformance(SqlConformanceEnum.BIG_QUERY).fails("Incompatible types"); + } + @Test void testUnnestArray() { sql("select*from unnest(array[1])") .columnType("INTEGER NOT NULL"); diff --git a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml index 56f169629ae..5ee7180efa7 100644 --- a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml +++ b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml @@ -341,6 +341,23 @@ LogicalProject(DEPTNO=[$0], E=[$5], EMPNO=[$6.EMPNO]) + + + + + + + + @@ -358,6 +375,23 @@ LogicalProject(DEPTNO=[$0], EMPNO=[$5.EMPNO]) + + + + + + + +