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

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


The following commit(s) were added to refs/heads/ty/TableModelGrammar by this 
push:
     new 661f436a47a Support auto create table (#12841)
661f436a47a is described below

commit 661f436a47a26bf4f734534b1831d2d946e3f5c4
Author: Jackie Tien <[email protected]>
AuthorDate: Wed Jul 3 15:02:27 2024 +0800

    Support auto create table (#12841)
---
 .../execution/config/TableConfigTaskVisitor.java   | 35 +---------
 .../metadata/fetcher/TableDeviceSchemaFetcher.java | 15 +++--
 .../fetcher/TableHeaderSchemaValidator.java        | 78 +++++++++++++++++++++-
 3 files changed, 89 insertions(+), 39 deletions(-)

diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/TableConfigTaskVisitor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/TableConfigTaskVisitor.java
index f1dc7ba7403..39cebe3007f 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/TableConfigTaskVisitor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/TableConfigTaskVisitor.java
@@ -20,9 +20,6 @@
 package org.apache.iotdb.db.queryengine.plan.execution.config;
 
 import org.apache.iotdb.commons.schema.table.TsTable;
-import org.apache.iotdb.commons.schema.table.column.AttributeColumnSchema;
-import org.apache.iotdb.commons.schema.table.column.IdColumnSchema;
-import org.apache.iotdb.commons.schema.table.column.MeasurementColumnSchema;
 import org.apache.iotdb.commons.schema.table.column.TsTableColumnCategory;
 import org.apache.iotdb.db.exception.sql.SemanticException;
 import org.apache.iotdb.db.protocol.session.IClientSession;
@@ -36,6 +33,7 @@ import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.relational
 import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.relational.ShowTablesTask;
 import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.relational.UseDBTask;
 import org.apache.iotdb.db.queryengine.plan.relational.metadata.Metadata;
+import 
org.apache.iotdb.db.queryengine.plan.relational.metadata.fetcher.TableHeaderSchemaValidator;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.AstVisitor;
 import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ColumnDefinition;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.CreateDB;
@@ -54,7 +52,6 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ShowTables;
 import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Use;
 import 
org.apache.iotdb.db.queryengine.plan.relational.type.TypeNotFoundException;
 
-import org.apache.tsfile.common.conf.TSFileDescriptor;
 import org.apache.tsfile.enums.TSDataType;
 
 import java.util.HashMap;
@@ -66,7 +63,6 @@ import java.util.Set;
 import static 
org.apache.iotdb.db.queryengine.common.header.ColumnHeaderConstant.COLUMN_TTL;
 import static 
org.apache.iotdb.db.queryengine.plan.relational.type.InternalTypeManager.getTSDataType;
 import static 
org.apache.iotdb.db.queryengine.plan.relational.type.TypeSignatureTranslator.toTypeSignature;
-import static 
org.apache.iotdb.db.utils.EncodingInferenceUtils.getDefaultEncoding;
 
 public class TableConfigTaskVisitor extends AstVisitor<IConfigTask, 
MPPQueryContext> {
 
@@ -150,34 +146,7 @@ public class TableConfigTaskVisitor extends 
AstVisitor<IConfigTask, MPPQueryCont
             String.format("Columns in table shall not share the same name 
%s.", columnName));
       }
       TSDataType dataType = getDataType(columnDefinition.getType());
-      switch (category) {
-        case ID:
-          if (!TSDataType.STRING.equals(dataType)) {
-            throw new SemanticException(
-                "DataType of ID Column should only be STRING, current is " + 
dataType);
-          }
-          table.addColumnSchema(new IdColumnSchema(columnName, dataType));
-          break;
-        case ATTRIBUTE:
-          if (!TSDataType.STRING.equals(dataType)) {
-            throw new SemanticException(
-                "DataType of ATTRIBUTE Column should only be STRING, current 
is " + dataType);
-          }
-          table.addColumnSchema(new AttributeColumnSchema(columnName, 
dataType));
-          break;
-        case TIME:
-          break;
-        case MEASUREMENT:
-          table.addColumnSchema(
-              new MeasurementColumnSchema(
-                  columnName,
-                  dataType,
-                  getDefaultEncoding(dataType),
-                  TSFileDescriptor.getInstance().getConfig().getCompressor()));
-          break;
-        default:
-          throw new IllegalArgumentException();
-      }
+      TableHeaderSchemaValidator.generateColumnSchema(table, category, 
columnName, dataType);
     }
     return new CreateTableTask(table, database, node.isIfNotExists());
   }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/TableDeviceSchemaFetcher.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/TableDeviceSchemaFetcher.java
index 46e59cd2e1e..33c94832498 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/TableDeviceSchemaFetcher.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/fetcher/TableDeviceSchemaFetcher.java
@@ -184,8 +184,11 @@ public class TableDeviceSchemaFetcher {
     // expressions inner each element are and-concat representing conditions 
of different column
     List<List<Expression>> idPredicateList =
         
SchemaPredicateUtil.convertDeviceIdPredicateToOrConcatList(idDeterminedPredicateList);
+    // List<Expression> in idPredicateList contains all id columns comparison 
which can use
+    // SchemaCache
     List<Integer> idSingleMatchIndexList =
         
SchemaPredicateUtil.extractIdSingleMatchExpressionCases(idPredicateList, 
tableInstance);
+    // store missing cache index in idSingleMatchIndexList
     List<Integer> idSingleMatchPredicateNotInCache = new ArrayList<>();
 
     if (!idSingleMatchIndexList.isEmpty()) {
@@ -214,18 +217,22 @@ public class TableDeviceSchemaFetcher {
     }
 
     if (idSingleMatchIndexList.size() < idPredicateList.size()
-        || idSingleMatchPredicateNotInCache.size() > 0) {
+        || !idSingleMatchPredicateNotInCache.isEmpty()) {
       List<List<Expression>> idPredicateForFetch =
           new ArrayList<>(
               idPredicateList.size()
                   - idSingleMatchIndexList.size()
                   + idSingleMatchPredicateNotInCache.size());
-      for (int i = 0, idx1 = 0, idx2 = 0; i < idPredicateList.size(); i++) {
-        if (i != idSingleMatchIndexList.get(idx1)) {
+      int idx1 = 0;
+      int idx2 = 0;
+      for (int i = 0; i < idPredicateList.size(); i++) {
+        //
+        if (idx1 >= idSingleMatchIndexList.size() || i != 
idSingleMatchIndexList.get(idx1)) {
           idPredicateForFetch.add(idPredicateList.get(i));
         } else {
           idx1++;
-          if (i == idSingleMatchPredicateNotInCache.get(idx2)) {
+          if (idx2 >= idSingleMatchPredicateNotInCache.size()
+              || i == idSingleMatchPredicateNotInCache.get(idx2)) {
             idPredicateForFetch.add(idPredicateList.get(i));
             idx2++;
           }
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 4a2e93384a6..3588d670298 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
@@ -21,6 +21,10 @@ package 
org.apache.iotdb.db.queryengine.plan.relational.metadata.fetcher;
 
 import org.apache.iotdb.commons.exception.IoTDBException;
 import org.apache.iotdb.commons.schema.table.TsTable;
+import org.apache.iotdb.commons.schema.table.column.AttributeColumnSchema;
+import org.apache.iotdb.commons.schema.table.column.IdColumnSchema;
+import org.apache.iotdb.commons.schema.table.column.MeasurementColumnSchema;
+import org.apache.iotdb.commons.schema.table.column.TsTableColumnCategory;
 import org.apache.iotdb.commons.schema.table.column.TsTableColumnSchema;
 import org.apache.iotdb.db.exception.metadata.table.TableNotExistsException;
 import org.apache.iotdb.db.exception.sql.SemanticException;
@@ -28,12 +32,15 @@ import 
org.apache.iotdb.db.queryengine.common.MPPQueryContext;
 import org.apache.iotdb.db.queryengine.plan.execution.config.ConfigTaskResult;
 import 
org.apache.iotdb.db.queryengine.plan.execution.config.executor.ClusterConfigTaskExecutor;
 import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.relational.AlterTableAddColumnTask;
+import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.relational.CreateTableTask;
 import org.apache.iotdb.db.queryengine.plan.relational.metadata.ColumnSchema;
 import org.apache.iotdb.db.queryengine.plan.relational.metadata.TableSchema;
 import org.apache.iotdb.db.schemaengine.table.DataNodeTableCache;
 import org.apache.iotdb.rpc.TSStatusCode;
 
 import com.google.common.util.concurrent.ListenableFuture;
+import org.apache.tsfile.common.conf.TSFileDescriptor;
+import org.apache.tsfile.enums.TSDataType;
 import org.apache.tsfile.read.common.type.TypeFactory;
 import org.apache.tsfile.read.common.type.UnknownType;
 import org.slf4j.Logger;
@@ -43,6 +50,9 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.ExecutionException;
 
+import static 
org.apache.iotdb.db.queryengine.plan.relational.type.InternalTypeManager.getTSDataType;
+import static 
org.apache.iotdb.db.utils.EncodingInferenceUtils.getDefaultEncoding;
+
 public class TableHeaderSchemaValidator {
 
   private static final Logger LOGGER = 
LoggerFactory.getLogger(TableHeaderSchemaValidator.class);
@@ -125,8 +135,12 @@ public class TableHeaderSchemaValidator {
 
     // auto create missing table or columns
     if (table == null) {
-      autoCreateTable(database, tableSchema, context);
+      autoCreateTable(database, tableSchema);
       table = DataNodeTableCache.getInstance().getTable(database, 
tableSchema.getTableName());
+      if (table == null) {
+        throw new IllegalStateException(
+            "auto create table succeed, but cannot get table schema in current 
node's DataNodeTableCache, may be caused by concurrently auto creating table");
+      }
     } else if (inputColumnList == null) {
       // do nothing
     } else {
@@ -147,10 +161,70 @@ public class TableHeaderSchemaValidator {
     return new TableSchema(tableSchema.getTableName(), resultColumnList);
   }
 
-  private void autoCreateTable(String database, TableSchema tableSchema, 
MPPQueryContext context) {
+  private void autoCreateTable(String database, TableSchema tableSchema) {
+    TsTable tsTable = new TsTable(tableSchema.getTableName());
+    addColumnSchema(tableSchema.getColumns(), tsTable);
+    CreateTableTask createTableTask = new CreateTableTask(tsTable, database, 
true);
+    try {
+      ListenableFuture<ConfigTaskResult> future = 
createTableTask.execute(configTaskExecutor);
+      ConfigTaskResult result = future.get();
+      if (result.getStatusCode().getStatusCode() != 
TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+        throw new RuntimeException(
+            new IoTDBException(
+                "Auto create table column failed.", 
result.getStatusCode().getStatusCode()));
+      }
+    } catch (ExecutionException | InterruptedException e) {
+      LOGGER.warn("Auto create table column failed.", e);
+      throw new RuntimeException(e);
+    }
     throw new SemanticException(new TableNotExistsException(database, 
tableSchema.getTableName()));
   }
 
+  private void addColumnSchema(List<ColumnSchema> columnSchemas, TsTable 
tsTable) {
+    for (ColumnSchema columnSchema : columnSchemas) {
+      TsTableColumnCategory category = columnSchema.getColumnCategory();
+      String columnName = columnSchema.getName();
+      if (tsTable.getColumnSchema(columnName) != null) {
+        throw new SemanticException(
+            String.format("Columns in table shall not share the same name 
%s.", columnName));
+      }
+      TSDataType dataType = getTSDataType(columnSchema.getType());
+      generateColumnSchema(tsTable, category, columnName, dataType);
+    }
+  }
+
+  public static void generateColumnSchema(
+      TsTable tsTable, TsTableColumnCategory category, String columnName, 
TSDataType dataType) {
+    switch (category) {
+      case ID:
+        if (!TSDataType.STRING.equals(dataType)) {
+          throw new SemanticException(
+              "DataType of ID Column should only be STRING, current is " + 
dataType);
+        }
+        tsTable.addColumnSchema(new IdColumnSchema(columnName, dataType));
+        break;
+      case ATTRIBUTE:
+        if (!TSDataType.STRING.equals(dataType)) {
+          throw new SemanticException(
+              "DataType of ATTRIBUTE Column should only be STRING, current is 
" + dataType);
+        }
+        tsTable.addColumnSchema(new AttributeColumnSchema(columnName, 
dataType));
+        break;
+      case TIME:
+        break;
+      case MEASUREMENT:
+        tsTable.addColumnSchema(
+            new MeasurementColumnSchema(
+                columnName,
+                dataType,
+                getDefaultEncoding(dataType),
+                TSFileDescriptor.getInstance().getConfig().getCompressor()));
+        break;
+      default:
+        throw new IllegalArgumentException();
+    }
+  }
+
   private void autoCreateColumn(
       String database,
       String tableName,

Reply via email to