This is an automated email from the ASF dual-hosted git repository.

jackietien pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/master by this push:
     new 3e11b7bd7ab Fix status code of category or data type mismatch
3e11b7bd7ab is described below

commit 3e11b7bd7abc077cdcd003dc32db4772d7d22e64
Author: Jiang Tian <[email protected]>
AuthorDate: Thu Aug 22 16:32:42 2024 +0800

    Fix status code of category or data type mismatch
---
 .../relational/it/db/it/IoTDBInsertTableIT.java    | 63 +---------------
 .../iotdb/session/it/IoTDBSessionRelationalIT.java | 84 ++++++++++++++++++++++
 .../java/org/apache/iotdb/rpc/TSStatusCode.java    |  3 +-
 .../iotdb/db/exception/sql/SemanticException.java  |  8 +++
 .../db/queryengine/plan/analyze/AnalyzeUtils.java  |  9 ++-
 .../fetcher/TableHeaderSchemaValidator.java        | 17 ++++-
 .../relational/sql/ast/WrappedInsertStatement.java | 21 ++++--
 .../plan/statement/crud/InsertRowStatement.java    |  4 +-
 .../schema/table/column/TsTableColumnSchema.java   |  4 ++
 9 files changed, 139 insertions(+), 74 deletions(-)

diff --git 
a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBInsertTableIT.java
 
b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBInsertTableIT.java
index 44924251a36..53dfe7700fe 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBInsertTableIT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBInsertTableIT.java
@@ -173,66 +173,6 @@ public class IoTDBInsertTableIT {
     }
   }
 
-  @Test
-  public void testPartialInsertionRestart() throws SQLException {
-    try (Connection connection = 
EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
-        Statement statement = connection.createStatement()) {
-      statement.execute("USE \"test\"");
-      statement.execute("SET CONFIGURATION enable_auto_create_schema='false'");
-      statement.execute(
-          "create table sg5 (id1 string id, s1 text measurement, s2 double 
measurement)");
-
-      try {
-        statement.execute("INSERT INTO sg5(id1,time,s1,s2) VALUES('d1', 
100,'test','test')");
-      } catch (SQLException e) {
-        // ignore
-      }
-    } finally {
-      try (Connection connection = 
EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
-          Statement statement = connection.createStatement()) {
-        statement.execute("SET CONFIGURATION 
enable_auto_create_schema='true'");
-      }
-    }
-
-    // TODO: replace restartDaemon() with new methods in Env.
-    /*
-    long time = 0;
-    try {
-      EnvironmentUtils.restartDaemon();
-      StorageEngine.getInstance().recover();
-      // wait for recover
-      while (!StorageEngine.getInstance().isAllSgReady()) {
-        Thread.sleep(500);
-        time += 500;
-        if (time > 10000) {
-          logger.warn("wait too long in restart, wait for: " + time / 1000 + 
"s");
-        }
-      }
-    } catch (Exception e) {
-      fail(e.getMessage());
-    }
-     */
-
-    try (Connection connection = 
EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
-        Statement statement = connection.createStatement()) {
-      statement.execute("use \"test\"");
-
-      try (ResultSet resultSet = statement.executeQuery("SELECT s1 FROM sg5")) 
{
-        assertNotNull(resultSet);
-        int cnt = 0;
-        while (resultSet.next()) {
-          cnt++;
-          assertEquals("test", resultSet.getString("s1"));
-        }
-        assertEquals(1, cnt);
-      }
-      try (ResultSet resultSet = statement.executeQuery("SELECT s2 FROM sg5")) 
{
-        assertNotNull(resultSet);
-        assertFalse(resultSet.next());
-      }
-    }
-  }
-
   @Test
   public void testPartialInsertTablet() {
     try (ISession session = 
EnvFactory.getEnv().getSessionConnection(BaseEnv.TABLE_SQL_DIALECT)) {
@@ -522,8 +462,7 @@ public class IoTDBInsertTableIT {
       st1.execute("insert into wt14(time, s1, s2) values(100, null, 1), (101, 
null, 2)");
       fail();
     } catch (SQLException e) {
-      assertTrue(
-          
e.getMessage().contains(Integer.toString(TSStatusCode.METADATA_ERROR.getStatusCode())));
+      assertEquals("507: Table wt14 does not exist", e.getMessage());
     }
     try (Connection connection = 
EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT)) {
       try (Statement st2 = connection.createStatement()) {
diff --git 
a/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionRelationalIT.java
 
b/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionRelationalIT.java
index 8d01cdb15ab..fc7c96daeff 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionRelationalIT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionRelationalIT.java
@@ -344,6 +344,90 @@ public class IoTDBSessionRelationalIT {
     }
   }
 
+  @Test
+  @Category({LocalStandaloneIT.class, ClusterIT.class})
+  public void partialInsertSQLTest() throws IoTDBConnectionException, 
StatementExecutionException {
+    try (ISession session = 
EnvFactory.getEnv().getSessionConnection(TREE_SQL_DIALECT)) {
+      // disable auto-creation only for this test
+      session.executeNonQueryStatement("SET CONFIGURATION 
\"enable_auto_create_schema\"=\"false\"");
+    }
+    try (ISession session = 
EnvFactory.getEnv().getSessionConnection(TABLE_SQL_DIALECT)) {
+      session.executeNonQueryStatement("USE \"db1\"");
+      // the table is missing column "m2"
+      session.executeNonQueryStatement(
+          "CREATE TABLE table2_2 (id1 string id, attr1 string attribute, "
+              + "m1 double "
+              + "measurement)");
+      try {
+        session.executeNonQueryStatement(
+            "INSERT INTO table2_2 (time, id1, attr1, m1, m2) values (1, '1', 
'1', 1.0, 2.0)");
+        fail("Exception expected");
+      } catch (StatementExecutionException e) {
+        assertEquals(
+            "616: Unknown column category for m2. Cannot auto create column.", 
e.getMessage());
+      }
+
+    } finally {
+      try (ISession session = 
EnvFactory.getEnv().getSessionConnection(TREE_SQL_DIALECT)) {
+        session.executeNonQueryStatement(
+            "SET CONFIGURATION \"enable_auto_create_schema\"=\"true\"");
+      }
+    }
+  }
+
+  @Test
+  @Category({LocalStandaloneIT.class, ClusterIT.class})
+  public void partialInsertRelationalRowFailTest()
+      throws IoTDBConnectionException, StatementExecutionException {
+    try (ISession session = 
EnvFactory.getEnv().getSessionConnection(TREE_SQL_DIALECT)) {
+      // disable auto-creation only for this test
+      session.executeNonQueryStatement("SET CONFIGURATION 
\"enable_auto_create_schema\"=\"false\"");
+      session.executeNonQueryStatement("SET CONFIGURATION 
\"enable_partial_insert\"=\"false\"");
+    }
+    try (ISession session = 
EnvFactory.getEnv().getSessionConnection(TABLE_SQL_DIALECT)) {
+      session.executeNonQueryStatement("USE \"db1\"");
+      // the table is missing column "m2"
+      session.executeNonQueryStatement(
+          "CREATE TABLE table2_3 (id1 string id, attr1 string attribute, "
+              + "m1 double "
+              + "measurement)");
+
+      // the insertion contains "m2"
+      List<IMeasurementSchema> schemaList = new ArrayList<>();
+      schemaList.add(new MeasurementSchema("id1", TSDataType.STRING));
+      schemaList.add(new MeasurementSchema("attr1", TSDataType.STRING));
+      schemaList.add(new MeasurementSchema("m1", TSDataType.DOUBLE));
+      schemaList.add(new MeasurementSchema("m2", TSDataType.DOUBLE));
+      final List<ColumnType> columnTypes =
+          Arrays.asList(
+              ColumnType.ID, ColumnType.ATTRIBUTE, ColumnType.MEASUREMENT, 
ColumnType.MEASUREMENT);
+      List<String> measurementIds =
+          schemaList.stream()
+              .map(IMeasurementSchema::getMeasurementId)
+              .collect(Collectors.toList());
+      List<TSDataType> dataTypes =
+          
schemaList.stream().map(IMeasurementSchema::getType).collect(Collectors.toList());
+
+      Object[] values = new Object[] {"id:" + 1, "attr:" + 1, 1 * 1.0, 1 * 
1.0};
+      try {
+        session.insertRelationalRecord(
+            "table2_3", 1, measurementIds, dataTypes, columnTypes, values);
+        fail("Exception expected");
+      } catch (StatementExecutionException e) {
+        assertEquals(
+            "507: Fail to insert measurements [m2] caused by [Column m2 does 
not exists or fails to be created]",
+            e.getMessage());
+      }
+
+    } finally {
+      try (ISession session = 
EnvFactory.getEnv().getSessionConnection(TREE_SQL_DIALECT)) {
+        session.executeNonQueryStatement(
+            "SET CONFIGURATION \"enable_auto_create_schema\"=\"true\"");
+        session.executeNonQueryStatement("SET CONFIGURATION 
\"enable_partial_insert\"=\"true\"");
+      }
+    }
+  }
+
   @Test
   @Category({LocalStandaloneIT.class, ClusterIT.class})
   public void insertRelationalRowTest()
diff --git 
a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java 
b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java
index cb2e8220e90..53aa7125775 100644
--- 
a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java
+++ 
b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java
@@ -107,8 +107,9 @@ public enum TSStatusCode {
   DISK_SPACE_INSUFFICIENT(611),
   OVERSIZE_TTL(612),
   TTL_CONFIG_ERROR(613),
-  COLUMN_TYPE_MISMATCH(614),
+  DATA_TYPE_MISMATCH(614),
   COLUMN_CATEGORY_MISMATCH(615),
+  COLUMN_NOT_EXISTS(616),
 
   // Query Engine
   SQL_PARSE_ERROR(700),
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/exception/sql/SemanticException.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/exception/sql/SemanticException.java
index 66f3af08e91..630929318c2 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/exception/sql/SemanticException.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/exception/sql/SemanticException.java
@@ -24,6 +24,14 @@ import org.apache.iotdb.rpc.TSStatusCode;
 
 public class SemanticException extends IoTDBRuntimeException {
 
+  public SemanticException(String message, int statusCode) {
+    super(message, statusCode);
+  }
+
+  public SemanticException(Throwable cause, int statusCode) {
+    super(cause, statusCode);
+  }
+
   public SemanticException(String message) {
     super(message, TSStatusCode.SEMANTIC_ERROR.getStatusCode());
   }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeUtils.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeUtils.java
index 8c7d245f113..9d6556b501f 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeUtils.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeUtils.java
@@ -210,7 +210,14 @@ public class AnalyzeUtils {
         analysis.setFailStatus(
             RpcUtils.getStatus(exception.getErrorCode(), 
exception.getMessage()));
       } else {
-        analysis.setFailStatus(RpcUtils.getStatus(TSStatusCode.METADATA_ERROR, 
e.getMessage()));
+        if (e.getErrorCode() != TSStatusCode.SEMANTIC_ERROR.getStatusCode()) {
+          // a specific code has been set, use it
+          analysis.setFailStatus(RpcUtils.getStatus(e.getErrorCode(), 
e.getMessage()));
+        } else {
+          // use METADATA_ERROR by default
+          analysis.setFailStatus(
+              RpcUtils.getStatus(TSStatusCode.METADATA_ERROR.getStatusCode(), 
e.getMessage()));
+        }
       }
     } finally {
       
PERFORMANCE_OVERVIEW_METRICS.recordScheduleSchemaValidateCost(System.nanoTime() 
- startTime);
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/TableHeaderSchemaValidator.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/TableHeaderSchemaValidator.java
index 3bd069e2a0a..48c95f8c469 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/TableHeaderSchemaValidator.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/TableHeaderSchemaValidator.java
@@ -54,6 +54,7 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Optional;
 import java.util.concurrent.ExecutionException;
+import java.util.stream.Collectors;
 
 import static 
org.apache.iotdb.db.queryengine.plan.relational.type.InternalTypeManager.getTSDataType;
 import static 
org.apache.iotdb.db.utils.EncodingInferenceUtils.getDefaultEncoding;
@@ -119,13 +120,15 @@ public class TableHeaderSchemaValidator {
           throw new SemanticException(
               String.format(
                   "Unknown column category for %s. Cannot auto create column.",
-                  columnSchema.getName()));
+                  columnSchema.getName()),
+              TSStatusCode.COLUMN_NOT_EXISTS.getStatusCode());
         }
         if (columnSchema.getType() == null) {
           throw new SemanticException(
               String.format(
                   "Unknown column data type for %s. Cannot auto create 
column.",
-                  columnSchema.getName()));
+                  columnSchema.getName()),
+              TSStatusCode.COLUMN_NOT_EXISTS.getStatusCode());
         }
         missingColumnList.add(columnSchema);
       } else {
@@ -136,7 +139,8 @@ public class TableHeaderSchemaValidator {
         if (columnSchema.getColumnCategory() != null
             && 
!existingColumn.getColumnCategory().equals(columnSchema.getColumnCategory())) {
           throw new SemanticException(
-              String.format("Wrong category at column %s.", 
columnSchema.getName()));
+              String.format("Wrong category at column %s.", 
columnSchema.getName()),
+              TSStatusCode.COLUMN_CATEGORY_MISMATCH.getStatusCode());
         }
       }
     }
@@ -148,6 +152,13 @@ public class TableHeaderSchemaValidator {
       // check id or attribute column data type in this method
       autoCreateColumn(database, tableSchema.getTableName(), 
missingColumnList, context);
       table = DataNodeTableCache.getInstance().getTable(database, 
tableSchema.getTableName());
+    } else if (!missingColumnList.isEmpty()
+        && !IoTDBDescriptor.getInstance().getConfig().isEnablePartialInsert()) 
{
+      throw new SemanticException(
+          String.format(
+              "Missing columns %s.",
+              
missingColumnList.stream().map(ColumnSchema::getName).collect(Collectors.toList())),
+          TSStatusCode.COLUMN_NOT_EXISTS.getStatusCode());
     }
 
     table
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/WrappedInsertStatement.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/WrappedInsertStatement.java
index 801ec407b90..b951c02cc49 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/WrappedInsertStatement.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/WrappedInsertStatement.java
@@ -30,6 +30,8 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.metadata.Metadata;
 import org.apache.iotdb.db.queryengine.plan.relational.metadata.TableSchema;
 import 
org.apache.iotdb.db.queryengine.plan.relational.type.InternalTypeManager;
 import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertBaseStatement;
+import org.apache.iotdb.db.utils.TypeInferenceUtils;
+import org.apache.iotdb.rpc.TSStatusCode;
 
 import org.apache.tsfile.common.conf.TSFileDescriptor;
 import org.apache.tsfile.enums.TSDataType;
@@ -77,12 +79,16 @@ public abstract class WrappedInsertStatement extends 
WrappedStatement
         new ArrayList<>(insertBaseStatement.getMeasurements().length);
     for (int i = 0; i < insertBaseStatement.getMeasurements().length; i++) {
       if (insertBaseStatement.getMeasurements()[i] != null) {
+        TSDataType dataType = insertBaseStatement.getDataType(i);
+        if (dataType == null) {
+          dataType =
+              TypeInferenceUtils.getPredictedDataType(
+                  insertBaseStatement.getFirstValueOfIndex(i), true);
+        }
         columnSchemas.add(
             new ColumnSchema(
                 insertBaseStatement.getMeasurements()[i],
-                insertBaseStatement.getDataType(i) != null
-                    ? TypeFactory.getType(insertBaseStatement.getDataType(i))
-                    : null,
+                dataType != null ? TypeFactory.getType(dataType) : null,
                 false,
                 insertBaseStatement.getColumnCategory(i)));
       } else {
@@ -159,7 +165,8 @@ public abstract class WrappedInsertStatement extends 
WrappedStatement
       // the column does not exist and auto-creation is disabled
       SemanticException semanticException =
           new SemanticException(
-              "Column " + incoming.getName() + " does not exists or fails to 
be " + "created");
+              "Column " + incoming.getName() + " does not exists or fails to 
be " + "created",
+              TSStatusCode.COLUMN_NOT_EXISTS.getStatusCode());
       if (incoming.getColumnCategory() != TsTableColumnCategory.MEASUREMENT) {
         // non-measurement columns cannot be partially inserted
         throw semanticException;
@@ -179,7 +186,8 @@ public abstract class WrappedInsertStatement extends 
WrappedStatement
           new SemanticException(
               String.format(
                   "Inconsistent data type of column %s: %s/%s",
-                  incoming.getName(), incoming.getType(), real.getType()));
+                  incoming.getName(), incoming.getType(), real.getType()),
+              TSStatusCode.DATA_TYPE_MISMATCH.getStatusCode());
       if (incoming.getColumnCategory() != TsTableColumnCategory.MEASUREMENT) {
         // non-measurement columns cannot be partially inserted
         throw semanticException;
@@ -195,7 +203,8 @@ public abstract class WrappedInsertStatement extends 
WrappedStatement
       throw new SemanticException(
           String.format(
               "Inconsistent column category of column %s: %s/%s",
-              incoming.getName(), incoming.getColumnCategory(), 
real.getColumnCategory()));
+              incoming.getName(), incoming.getColumnCategory(), 
real.getColumnCategory()),
+          TSStatusCode.COLUMN_CATEGORY_MISMATCH.getStatusCode());
     }
     TSDataType tsDataType = InternalTypeManager.getTSDataType(real.getType());
     MeasurementSchema measurementSchema =
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/crud/InsertRowStatement.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/crud/InsertRowStatement.java
index f2fa614fc58..a0b67ba997d 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/crud/InsertRowStatement.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/crud/InsertRowStatement.java
@@ -40,6 +40,7 @@ import 
org.apache.iotdb.db.queryengine.plan.statement.StatementVisitor;
 import org.apache.iotdb.db.utils.CommonUtils;
 import org.apache.iotdb.db.utils.TypeInferenceUtils;
 import org.apache.iotdb.db.utils.annotations.TableModel;
+import org.apache.iotdb.rpc.TSStatusCode;
 
 import org.apache.tsfile.enums.TSDataType;
 import org.apache.tsfile.file.metadata.IDeviceID;
@@ -247,7 +248,8 @@ public class InsertRowStatement extends InsertBaseStatement 
implements ISchemaVa
         if 
(!IoTDBDescriptor.getInstance().getConfig().isEnablePartialInsert()) {
           throw e;
         } else {
-          markFailedMeasurement(i, e);
+          markFailedMeasurement(
+              i, new SemanticException(e, 
TSStatusCode.DATA_TYPE_MISMATCH.getStatusCode()));
         }
       }
     }
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/column/TsTableColumnSchema.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/column/TsTableColumnSchema.java
index f1bf80b5a52..af6baf7c043 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/column/TsTableColumnSchema.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/table/column/TsTableColumnSchema.java
@@ -71,4 +71,8 @@ public abstract class TsTableColumnSchema {
   public int hashCode() {
     return Objects.hash(columnName);
   }
+
+  public void setDataType(TSDataType dataType) {
+    this.dataType = dataType;
+  }
 }

Reply via email to