diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/metadata/IgniteMdCollation.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/metadata/IgniteMdCollation.java index 3dd9e38d3eeba..d369b0222789a 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/metadata/IgniteMdCollation.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/metadata/IgniteMdCollation.java @@ -164,7 +164,9 @@ public ImmutableList collations(TableModify rel, /** */ public ImmutableList collations(TableScan scan, RelMetadataQuery mq) { - return ImmutableList.copyOf(table(scan.getTable())); + List collations = table(scan.getTable()); + + return collations == null ? ImmutableList.of() : ImmutableList.copyOf(collations); } /** */ diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/metadata/IgniteMdDistribution.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/metadata/IgniteMdDistribution.java index c832235fdef3c..a1f1ad33b92eb 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/metadata/IgniteMdDistribution.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/metadata/IgniteMdDistribution.java @@ -73,7 +73,9 @@ public IgniteDistribution distribution(IgniteRel rel, RelMetadataQuery mq) { * See {@link IgniteMdDistribution#distribution(RelNode, RelMetadataQuery)} */ public IgniteDistribution distribution(TableScan rel, RelMetadataQuery mq) { - return rel.getTable().unwrap(IgniteTable.class).distribution(); + IgniteTable tbl = rel.getTable().unwrap(IgniteTable.class); + + return tbl == null ? TraitUtils.distribution(rel.getTraitSet()) : tbl.distribution(); } /** diff --git a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/RecursiveCteIntegrationTest.java b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/RecursiveCteIntegrationTest.java new file mode 100644 index 0000000000000..ff77e4f1e0f10 --- /dev/null +++ b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/integration/RecursiveCteIntegrationTest.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.internal.processors.query.calcite.integration; + +import org.apache.calcite.plan.RelOptPlanner; +import org.apache.ignite.internal.processors.query.IgniteSQLException; +import org.apache.ignite.testframework.GridTestUtils; +import org.junit.Test; + +/** + * Integration tests for recursive common table expressions. + */ +public class RecursiveCteIntegrationTest extends AbstractBasicIntegrationTest { + /** */ + @Test + public void testHierarchicalQueryIsNotSupported() { + sql("CREATE TABLE employee (id INT PRIMARY KEY, manager_id INT, name VARCHAR)"); + sql("INSERT INTO employee VALUES " + + "(1, NULL, 'CEO'), " + + "(2, 1, 'Manager'), " + + "(3, 2, 'Developer'), " + + "(4, 1, 'Accountant')"); + + String qry = "WITH RECURSIVE employee_hierarchy (id, manager_id, name, depth) AS (" + + "SELECT id, manager_id, name, 0 FROM employee WHERE manager_id IS NULL " + + "UNION ALL " + + "SELECT e.id, e.manager_id, e.name, h.depth + 1 " + + "FROM employee e " + + "JOIN employee_hierarchy h ON e.manager_id = h.id" + + ") " + + "SELECT id, manager_id, name, depth FROM employee_hierarchy ORDER BY depth, id"; + + Throwable err = GridTestUtils.assertThrows( + log, + () -> sql(qry), + IgniteSQLException.class, + "Failed to plan query" + ); + + assertEquals(1, err.getSuppressed().length); + assertTrue(err.getSuppressed()[0] instanceof RelOptPlanner.CannotPlanException); + assertTrue(err.getSuppressed()[0].getMessage().contains( + "There are not enough rules to produce a node with desired properties")); + } +} diff --git a/modules/calcite/src/test/java/org/apache/ignite/testsuites/IntegrationTestSuite.java b/modules/calcite/src/test/java/org/apache/ignite/testsuites/IntegrationTestSuite.java index 7c32feb318621..14090f03f871d 100644 --- a/modules/calcite/src/test/java/org/apache/ignite/testsuites/IntegrationTestSuite.java +++ b/modules/calcite/src/test/java/org/apache/ignite/testsuites/IntegrationTestSuite.java @@ -66,6 +66,7 @@ import org.apache.ignite.internal.processors.query.calcite.integration.QueryEngineConfigurationIntegrationTest; import org.apache.ignite.internal.processors.query.calcite.integration.QueryMetadataIntegrationTest; import org.apache.ignite.internal.processors.query.calcite.integration.QueryWithPartitionsIntegrationTest; +import org.apache.ignite.internal.processors.query.calcite.integration.RecursiveCteIntegrationTest; import org.apache.ignite.internal.processors.query.calcite.integration.RunningQueriesIntegrationTest; import org.apache.ignite.internal.processors.query.calcite.integration.ScalarInIntegrationTest; import org.apache.ignite.internal.processors.query.calcite.integration.SelectByKeyFieldTest; @@ -120,6 +121,7 @@ AggregatesIntegrationTest.class, MetadataIntegrationTest.class, RunningQueriesIntegrationTest.class, + RecursiveCteIntegrationTest.class, SqlDiagnosticIntegrationTest.class, SortAggregateIntegrationTest.class, TableDdlIntegrationTest.class,