You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by ca...@apache.org on 2024/07/30 03:08:23 UTC

(iotdb) branch ty/TableModelGrammar updated: Fixed the bug that duplicate table creation may delete the original table

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

caogaofei 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 b9c9603470c Fixed the bug that duplicate table creation may delete the original table
b9c9603470c is described below

commit b9c9603470c1cbb91b54099a228aaef317263d29
Author: Caideyipi <87...@users.noreply.github.com>
AuthorDate: Tue Jul 30 11:08:18 2024 +0800

    Fixed the bug that duplicate table creation may delete the original table
---
 .../iotdb/relational/it/schema/IoTDBTableIT.java   | 97 ++++++++++++----------
 .../manager/schema/ClusterSchemaManager.java       |  3 +-
 .../persistence/schema/ClusterSchemaInfo.java      |  3 +-
 .../confignode/persistence/schema/ConfigMTree.java | 13 +--
 .../impl/schema/table/CreateTableProcedure.java    | 24 +++++-
 .../procedure/state/schema/CreateTableState.java   |  1 +
 .../table/TableAlreadyExistsException.java         |  2 +-
 7 files changed, 90 insertions(+), 53 deletions(-)

diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBTableIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBTableIT.java
index 76bda1ee3a0..f34f051f397 100644
--- a/integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBTableIT.java
+++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBTableIT.java
@@ -69,12 +69,12 @@ public class IoTDBTableIT {
       // should specify database before create table
       try {
         statement.execute(
-            "create table table1(region_id STRING ID, plant_id STRING ID, device_id STRING ID, model STRING ATTRIBUTE, temperature FLOAT MEASUREMENT, humidity DOUBLE MEASUREMENT) with (TTL=3600000)");
+            "create table table1(region_id STRING ID, plant_id STRING ID, device_id STRING ID, model STRING ATTRIBUTE, temperature FLOAT MEASUREMENT, humidity DOUBLE MEASUREMENT)");
       } catch (final SQLException e) {
         assertEquals("701: database is not specified", e.getMessage());
       }
 
-      // Show tables shall succeed in a newly created database
+      // Show tables shall succeed in a newly created database with no tables
       try (final ResultSet resultSet = statement.executeQuery("SHOW tables from test1")) {
         ResultSetMetaData metaData = resultSet.getMetaData();
         assertEquals(showTablesColumnHeaders.size(), metaData.getColumnCount());
@@ -87,10 +87,59 @@ public class IoTDBTableIT {
 
       // or use full qualified table name
       statement.execute(
-          "create table test1.table1(region_id STRING ID, plant_id STRING ID, device_id STRING ID, model STRING ATTRIBUTE, temperature FLOAT MEASUREMENT, humidity DOUBLE MEASUREMENT) with (TTL=3600000)");
+          "create table test1.table1(region_id STRING ID, plant_id STRING ID, device_id STRING ID, model STRING ATTRIBUTE, temperature FLOAT MEASUREMENT, humidity DOUBLE MEASUREMENT)");
+
+      try {
+        statement.execute(
+            "create table test1.table1(region_id STRING ID, plant_id STRING ID, device_id STRING ID, model STRING ATTRIBUTE, temperature FLOAT MEASUREMENT, humidity DOUBLE MEASUREMENT)");
+      } catch (final SQLException e) {
+        assertEquals("551: Table 'test1.table1' already exists.", e.getMessage());
+      }
+
+      String[] tableNames = new String[] {"table1"};
+      String[] ttls = new String[] {"INF"};
 
       statement.execute("use test2");
 
+      // show tables by specifying another database
+      // Check duplicate create table won't affect table state
+      // using SHOW tables in
+      try (final ResultSet resultSet = statement.executeQuery("SHOW tables in test1")) {
+        int cnt = 0;
+        ResultSetMetaData metaData = resultSet.getMetaData();
+        assertEquals(showTablesColumnHeaders.size(), metaData.getColumnCount());
+        for (int i = 0; i < showTablesColumnHeaders.size(); i++) {
+          assertEquals(
+              showTablesColumnHeaders.get(i).getColumnName(), metaData.getColumnName(i + 1));
+        }
+        while (resultSet.next()) {
+          assertEquals(tableNames[cnt], resultSet.getString(1));
+          assertEquals(ttls[cnt], resultSet.getString(2));
+          cnt++;
+        }
+        assertEquals(tableNames.length, cnt);
+      }
+
+      // using SHOW tables from
+      try (final ResultSet resultSet = statement.executeQuery("SHOW tables from test1")) {
+        int cnt = 0;
+        final ResultSetMetaData metaData = resultSet.getMetaData();
+        assertEquals(showTablesColumnHeaders.size(), metaData.getColumnCount());
+        for (int i = 0; i < showTablesColumnHeaders.size(); i++) {
+          assertEquals(
+              showTablesColumnHeaders.get(i).getColumnName(), metaData.getColumnName(i + 1));
+        }
+        while (resultSet.next()) {
+          assertEquals(tableNames[cnt], resultSet.getString(1));
+          assertEquals(ttls[cnt], resultSet.getString(2));
+          cnt++;
+        }
+        assertEquals(tableNames.length, cnt);
+      }
+
+      statement.execute(
+          "create table if not exists test1.table1(region_id STRING ID, plant_id STRING ID, device_id STRING ID, model STRING ATTRIBUTE, temperature FLOAT MEASUREMENT, humidity DOUBLE MEASUREMENT)");
+
       try {
         statement.execute(
             "create table table2(region_id STRING ID, plant_id STRING ID, device_id STRING ID, model STRING ATTRIBUTE, temperature FLOAT MEASUREMENT, humidity DOUBLE MEASUREMENT, time2 INT64 TIME) with (TTL=3600000)");
@@ -143,8 +192,8 @@ public class IoTDBTableIT {
       statement.execute(
           "create table table2(region_id STRING ID, plant_id STRING ID, color STRING ATTRIBUTE, temperature FLOAT MEASUREMENT, speed DOUBLE MEASUREMENT) with (TTL=6600000)");
 
-      String[] tableNames = new String[] {"table2"};
-      String[] ttls = new String[] {"6600000"};
+      tableNames = new String[] {"table2"};
+      ttls = new String[] {"6600000"};
 
       // show tables from current database
       try (final ResultSet resultSet = statement.executeQuery("SHOW tables")) {
@@ -163,44 +212,6 @@ public class IoTDBTableIT {
         assertEquals(tableNames.length, cnt);
       }
 
-      // show tables by specifying another database
-      tableNames = new String[] {"table1"};
-      ttls = new String[] {"3600000"};
-
-      // using SHOW tables in
-      try (final ResultSet resultSet = statement.executeQuery("SHOW tables in test1")) {
-        int cnt = 0;
-        ResultSetMetaData metaData = resultSet.getMetaData();
-        assertEquals(showTablesColumnHeaders.size(), metaData.getColumnCount());
-        for (int i = 0; i < showTablesColumnHeaders.size(); i++) {
-          assertEquals(
-              showTablesColumnHeaders.get(i).getColumnName(), metaData.getColumnName(i + 1));
-        }
-        while (resultSet.next()) {
-          assertEquals(tableNames[cnt], resultSet.getString(1));
-          assertEquals(ttls[cnt], resultSet.getString(2));
-          cnt++;
-        }
-        assertEquals(tableNames.length, cnt);
-      }
-
-      // using SHOW tables from
-      try (final ResultSet resultSet = statement.executeQuery("SHOW tables from test1")) {
-        int cnt = 0;
-        ResultSetMetaData metaData = resultSet.getMetaData();
-        assertEquals(showTablesColumnHeaders.size(), metaData.getColumnCount());
-        for (int i = 0; i < showTablesColumnHeaders.size(); i++) {
-          assertEquals(
-              showTablesColumnHeaders.get(i).getColumnName(), metaData.getColumnName(i + 1));
-        }
-        while (resultSet.next()) {
-          assertEquals(tableNames[cnt], resultSet.getString(1));
-          assertEquals(ttls[cnt], resultSet.getString(2));
-          cnt++;
-        }
-        assertEquals(tableNames.length, cnt);
-      }
-
       // show tables from a non-exist database
       try {
         statement.executeQuery("SHOW tables from test3");
diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/schema/ClusterSchemaManager.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/schema/ClusterSchemaManager.java
index 924ffbc763c..c1f028a1049 100644
--- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/schema/ClusterSchemaManager.java
+++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/schema/ClusterSchemaManager.java
@@ -99,6 +99,7 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.locks.ReentrantLock;
@@ -1106,7 +1107,7 @@ public class ClusterSchemaManager {
     schemaQuotaStatistics.setSeriesThreshold(seriesThreshold);
   }
 
-  public TsTable getTable(String database, String tableName) {
+  public Optional<TsTable> getTable(final String database, final String tableName) {
     return clusterSchemaInfo.getTsTable(database, tableName);
   }
 
diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ClusterSchemaInfo.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ClusterSchemaInfo.java
index 02c97416698..e565ac48f35 100644
--- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ClusterSchemaInfo.java
+++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ClusterSchemaInfo.java
@@ -92,6 +92,7 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -1118,7 +1119,7 @@ public class ClusterSchemaInfo implements SnapshotProcessor {
     }
   }
 
-  public TsTable getTsTable(String database, String tableName) {
+  public Optional<TsTable> getTsTable(String database, String tableName) {
     databaseReadWriteLock.readLock().lock();
     try {
       return mTree.getTable(new PartialPath(database), tableName);
diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ConfigMTree.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ConfigMTree.java
index bfa0adb60fd..ca617748e01 100644
--- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ConfigMTree.java
+++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ConfigMTree.java
@@ -64,6 +64,7 @@ import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
 import java.util.Stack;
 import java.util.TreeSet;
@@ -718,14 +719,14 @@ public class ConfigMTree {
     return result;
   }
 
-  public TsTable getTable(PartialPath database, String tableName) throws MetadataException {
-    IConfigMNode databaseNode = getDatabaseNodeByDatabasePath(database).getAsMNode();
+  public Optional<TsTable> getTable(final PartialPath database, final String tableName)
+      throws MetadataException {
+    final IConfigMNode databaseNode = getDatabaseNodeByDatabasePath(database).getAsMNode();
     if (!databaseNode.hasChild(tableName)) {
-      throw new TableNotExistsException(
-          database.getFullPath().substring(ROOT.length() + 1), tableName);
+      return Optional.empty();
     }
-    ConfigTableNode tableNode = (ConfigTableNode) databaseNode.getChild(tableName);
-    return tableNode.getTable();
+    final ConfigTableNode tableNode = (ConfigTableNode) databaseNode.getChild(tableName);
+    return Optional.of(tableNode.getTable());
   }
 
   public void addTableColumn(
diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/CreateTableProcedure.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/CreateTableProcedure.java
index ab002e20f8e..3d5546b476b 100644
--- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/CreateTableProcedure.java
+++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/CreateTableProcedure.java
@@ -66,6 +66,7 @@ import java.util.Set;
 
 import static org.apache.iotdb.commons.conf.IoTDBConstant.MULTI_LEVEL_PATH_WILDCARD;
 import static org.apache.iotdb.commons.schema.SchemaConstant.ROOT;
+import static org.apache.iotdb.rpc.TSStatusCode.TABLE_ALREADY_EXISTS;
 
 public class CreateTableProcedure
     extends StateMachineProcedure<ConfigNodeProcedureEnv, CreateTableState> {
@@ -91,6 +92,10 @@ public class CreateTableProcedure
     final long startTime = System.currentTimeMillis();
     try {
       switch (state) {
+        case CHECK_TABLE_EXISTENCE:
+          LOGGER.info("Check the existence of table {}.{}", database, table.getTableName());
+          checkTableExistence(env);
+          break;
         case PRE_CREATE:
           LOGGER.info("Pre create table {}.{}", database, table.getTableName());
           preCreateTable(env);
@@ -127,6 +132,23 @@ public class CreateTableProcedure
     }
   }
 
+  private void checkTableExistence(final ConfigNodeProcedureEnv env) {
+    if (env.getConfigManager()
+        .getClusterSchemaManager()
+        .getTable(database, table.getTableName())
+        .isPresent()) {
+      setFailure(
+          new ProcedureException(
+              new IoTDBException(
+                  String.format(
+                      "Table '%s.%s' already exists.",
+                      database.substring(ROOT.length() + 1), table.getTableName()),
+                  TABLE_ALREADY_EXISTS.getStatusCode())));
+    } else {
+      setNextState(CreateTableState.PRE_CREATE);
+    }
+  }
+
   private void preCreateTable(final ConfigNodeProcedureEnv env) {
     final PreCreateTablePlan plan = new PreCreateTablePlan(database, table);
     TSStatus status;
@@ -390,7 +412,7 @@ public class CreateTableProcedure
 
   @Override
   protected CreateTableState getInitialState() {
-    return CreateTableState.PRE_CREATE;
+    return CreateTableState.CHECK_TABLE_EXISTENCE;
   }
 
   public String getDatabase() {
diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/state/schema/CreateTableState.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/state/schema/CreateTableState.java
index ba22c4a892d..9d09a09cfb8 100644
--- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/state/schema/CreateTableState.java
+++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/state/schema/CreateTableState.java
@@ -20,6 +20,7 @@
 package org.apache.iotdb.confignode.procedure.state.schema;
 
 public enum CreateTableState {
+  CHECK_TABLE_EXISTENCE,
   PRE_CREATE,
   PRE_RELEASE,
   VALIDATE_TIMESERIES_EXISTENCE,
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/exception/metadata/table/TableAlreadyExistsException.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/exception/metadata/table/TableAlreadyExistsException.java
index d745b6eb0a3..31f91d98cf0 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/exception/metadata/table/TableAlreadyExistsException.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/exception/metadata/table/TableAlreadyExistsException.java
@@ -26,7 +26,7 @@ public class TableAlreadyExistsException extends MetadataException {
 
   public TableAlreadyExistsException(String database, String tableName) {
     super(
-        String.format("Table %s.%s already exists.", database, tableName),
+        String.format("Table '%s.%s' already exists.", database, tableName),
         TSStatusCode.TABLE_ALREADY_EXISTS.getStatusCode());
   }
 }