This is an automated email from the ASF dual-hosted git repository. ppa pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push: new d7a6037705 IGNITE-19116 Sql. Fixed NPE when a DML statement fails on a non-existing table (#1917) d7a6037705 is described below commit d7a6037705f85a66cf086d70316d4d2855da7360 Author: Pavel Pereslegin <xxt...@gmail.com> AuthorDate: Wed Apr 12 22:50:43 2023 +0300 IGNITE-19116 Sql. Fixed NPE when a DML statement fails on a non-existing table (#1917) --- .../sql/engine/prepare/IgniteSqlValidator.java | 13 ++++++++- .../sql/engine/planner/DmlPlannerTest.java | 31 ++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/IgniteSqlValidator.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/IgniteSqlValidator.java index e084e73113..311a13181f 100644 --- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/IgniteSqlValidator.java +++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/IgniteSqlValidator.java @@ -169,6 +169,11 @@ public class IgniteSqlValidator extends SqlValidatorImpl { final SqlIdentifier targetTable = (SqlIdentifier) call.getTargetTable(); final SqlValidatorTable table = getCatalogReader().getTable(targetTable.names); + if (table == null) { + // TODO IGNITE-14865 Calcite exception should be converted/wrapped into a public ignite exception. + throw newValidationError(call.getTargetTable(), RESOURCE.objectNotFound(targetTable.toString())); + } + SqlIdentifier alias = call.getAlias() != null ? call.getAlias() : new SqlIdentifier(deriveAlias(targetTable, 0), SqlParserPos.ZERO); @@ -208,7 +213,13 @@ public class IgniteSqlValidator extends SqlValidatorImpl { @Override protected SqlSelect createSourceSelectForDelete(SqlDelete call) { final SqlNodeList selectList = new SqlNodeList(SqlParserPos.ZERO); - final SqlValidatorTable table = getCatalogReader().getTable(((SqlIdentifier) call.getTargetTable()).names); + final SqlIdentifier targetTable = (SqlIdentifier) call.getTargetTable(); + final SqlValidatorTable table = getCatalogReader().getTable(targetTable.names); + + if (table == null) { + // TODO IGNITE-14865 Calcite exception should be converted/wrapped into a public ignite exception. + throw newValidationError(targetTable, RESOURCE.objectNotFound(targetTable.toString())); + } table.unwrap(IgniteTable.class).descriptor().deleteRowType((IgniteTypeFactory) typeFactory) .getFieldNames().stream() diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/DmlPlannerTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/DmlPlannerTest.java index 8613120468..6200ffa7cb 100644 --- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/DmlPlannerTest.java +++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/planner/DmlPlannerTest.java @@ -20,6 +20,7 @@ package org.apache.ignite.internal.sql.engine.planner; import java.util.List; import java.util.UUID; import java.util.stream.Stream; +import org.apache.calcite.sql.validate.SqlValidatorException; import org.apache.ignite.internal.schema.NativeTypes; import org.apache.ignite.internal.sql.engine.framework.TestBuilders; import org.apache.ignite.internal.sql.engine.rel.IgniteExchange; @@ -30,6 +31,7 @@ import org.apache.ignite.internal.sql.engine.schema.IgniteSchema; import org.apache.ignite.internal.sql.engine.schema.IgniteTable; import org.apache.ignite.internal.sql.engine.trait.IgniteDistribution; import org.apache.ignite.internal.sql.engine.trait.IgniteDistributions; +import org.apache.ignite.internal.testframework.IgniteTestUtils; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -152,6 +154,35 @@ public class DmlPlannerTest extends AbstractPlannerTest { ); } + /** + * Test for check basic dml operators when table doesn't exist. + */ + @ParameterizedTest + @MethodSource("basicStatements") + public void testDmlQueriesOnNonExistingTable(String query) { + //noinspection ThrowableNotThrown + IgniteTestUtils.assertThrowsWithCause( + () -> physicalPlan(query, createSchema(newTestTable("TEST", IgniteDistributions.single()))), + SqlValidatorException.class, + "Object 'UNKNOWN' not found" + ); + } + + private static Stream<String> basicStatements() { + return Stream.of( + "SELECT * FROM unknown", + "INSERT INTO unknown VALUES(1)", + "UPDATE unknown SET ID=1", + "DELETE FROM unknown", + "MERGE INTO unknown DST USING test SRC ON DST.C1 = SRC.C1" + + " WHEN MATCHED THEN UPDATE SET C2 = SRC.C2" + + " WHEN NOT MATCHED THEN INSERT (C1, C2) VALUES (SRC.C1, SRC.C2)", + "MERGE INTO test DST USING unknown SRC ON DST.C1 = SRC.C1" + + " WHEN MATCHED THEN UPDATE SET C2 = SRC.C2" + + " WHEN NOT MATCHED THEN INSERT (C1, C2) VALUES (SRC.C1, SRC.C2)" + ); + } + // Class name is fully-qualified because AbstractPlannerTest defines a class with the same name. private static org.apache.ignite.internal.sql.engine.framework.TestTable newTestTable( String tableName, IgniteDistribution distribution) {