Copilot commented on code in PR #10757:
URL: https://github.com/apache/gravitino/pull/10757#discussion_r3114625433


##########
trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/GravitinoMetadata.java:
##########
@@ -220,6 +221,46 @@ public void createTable(
     catalogConnectorMetadata.createTable(table, saveMode == SaveMode.IGNORE);
   }
 
+  @Override
+  public ConnectorOutputTableHandle beginCreateTable(
+      ConnectorSession session,
+      ConnectorTableMetadata tableMetadata,
+      Optional<ConnectorTableLayout> layout,
+      RetryMode retryMode,
+      boolean noExistingData) {
+    // First, create the table in the Gravitino catalog
+    GravitinoTable table = metadataAdapter.createTable(tableMetadata);
+    catalogConnectorMetadata.createTable(table, false);
+
+    // Get the table handle from the internal connector for the newly created 
table
+    SchemaTableName tableName = tableMetadata.getTable();
+    ConnectorTableHandle internalTableHandle =
+        internalMetadata.getTableHandle(session, tableName, Optional.empty(), 
Optional.empty());
+
+    // Delegate to the internal connector's insert path to write data,
+    // avoiding double table creation in the original connector
+    List<ColumnHandle> columns =
+        new ArrayList<>(internalMetadata.getColumnHandles(session, 
internalTableHandle).values());
+    ConnectorInsertTableHandle insertTableHandle =
+        internalMetadata.beginInsert(session, internalTableHandle, columns, 
retryMode);
+    return new GravitinoOutputTableHandle(insertTableHandle, tableName);

Review Comment:
   `beginCreateTable()` creates the table in Gravitino before obtaining an 
internal table handle / starting the insert. If 
`internalMetadata.getTableHandle(...)` returns null or `beginInsert(...)` 
throws, the method will fail after the table is already registered, leaving an 
orphaned table (the failure mode this PR is trying to eliminate). Consider 
wrapping the internal-handle lookup + `beginInsert` in a try/catch and dropping 
the newly created table on failure; also handle the `internalTableHandle == 
null` case explicitly with a TrinoException.
   ```suggestion
       SchemaTableName tableName = tableMetadata.getTable();
       try {
         // Get the table handle from the internal connector for the newly 
created table
         ConnectorTableHandle internalTableHandle =
             internalMetadata.getTableHandle(session, tableName, 
Optional.empty(), Optional.empty());
         if (internalTableHandle == null) {
           throw new TrinoException(
               GRAVITINO_TABLE_NOT_EXISTS,
               String.format("Table '%s' was created but is not available for 
insert", tableName));
         }
   
         // Delegate to the internal connector's insert path to write data,
         // avoiding double table creation in the original connector
         List<ColumnHandle> columns =
             new ArrayList<>(internalMetadata.getColumnHandles(session, 
internalTableHandle).values());
         ConnectorInsertTableHandle insertTableHandle =
             internalMetadata.beginInsert(session, internalTableHandle, 
columns, retryMode);
         return new GravitinoOutputTableHandle(insertTableHandle, tableName);
       } catch (RuntimeException e) {
         try {
           catalogConnectorMetadata.dropTable(table);
         } catch (RuntimeException cleanupException) {
           e.addSuppressed(cleanupException);
         }
         throw e;
       }
   ```



##########
trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/GravitinoOutputTableHandle.java:
##########
@@ -0,0 +1,103 @@
+/*
+ * 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.gravitino.trino.connector;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.trino.spi.connector.ConnectorInsertTableHandle;
+import io.trino.spi.connector.ConnectorOutputTableHandle;
+import io.trino.spi.connector.SchemaTableName;
+
+/**
+ * The GravitinoOutputTableHandle is used for handling CTAS (CREATE TABLE AS 
SELECT) operations.
+ *
+ * <p>Internally wraps a {@link ConnectorInsertTableHandle} because the 
Gravitino connector creates
+ * the table first via catalogConnectorMetadata, then delegates data writing 
to the internal
+ * connector's insert path, avoiding double table creation.
+ *
+ * <p>Also stores the {@link SchemaTableName} so that {@code 
rollbackCreateTable} can drop the table
+ * from the Gravitino catalog if the CTAS operation fails.
+ */

Review Comment:
   This JavaDoc states the handle is used by `rollbackCreateTable` to drop the 
table on CTAS failure, but there is no `rollbackCreateTable` implementation in 
the connector metadata shown in this PR. Either implement 
`ConnectorMetadata.rollbackCreateTable(...)` to use `toSchemaTableName()` (and 
ensure it’s invoked across supported SPI versions), or update/remove this 
JavaDoc to avoid implying rollback semantics that aren’t actually provided.



##########
trino-connector/trino-connector/src/main/java/org/apache/gravitino/trino/connector/GravitinoMetadata.java:
##########
@@ -220,6 +221,46 @@ public void createTable(
     catalogConnectorMetadata.createTable(table, saveMode == SaveMode.IGNORE);
   }
 
+  @Override
+  public ConnectorOutputTableHandle beginCreateTable(
+      ConnectorSession session,
+      ConnectorTableMetadata tableMetadata,
+      Optional<ConnectorTableLayout> layout,
+      RetryMode retryMode,
+      boolean noExistingData) {
+    // First, create the table in the Gravitino catalog
+    GravitinoTable table = metadataAdapter.createTable(tableMetadata);
+    catalogConnectorMetadata.createTable(table, false);
+
+    // Get the table handle from the internal connector for the newly created 
table
+    SchemaTableName tableName = tableMetadata.getTable();
+    ConnectorTableHandle internalTableHandle =
+        internalMetadata.getTableHandle(session, tableName, Optional.empty(), 
Optional.empty());
+
+    // Delegate to the internal connector's insert path to write data,
+    // avoiding double table creation in the original connector
+    List<ColumnHandle> columns =
+        new ArrayList<>(internalMetadata.getColumnHandles(session, 
internalTableHandle).values());

Review Comment:
   The `columns` list passed to `internalMetadata.beginInsert(...)` is built 
from `getColumnHandles(...).values()`. Map value iteration order is not 
guaranteed, and `beginInsert` expects the column handles to correspond to the 
table columns in a deterministic order. Build the list in the same order as 
`tableMetadata.getColumns()` (resolve each name to a handle) to avoid incorrect 
column-to-value mapping during CTAS writes.
   ```suggestion
       Map<String, ColumnHandle> internalColumnHandles =
           internalMetadata.getColumnHandles(session, internalTableHandle);
       List<ColumnHandle> columns = new 
ArrayList<>(tableMetadata.getColumns().size());
       for (ColumnMetadata columnMetadata : tableMetadata.getColumns()) {
         ColumnHandle columnHandle = 
internalColumnHandles.get(columnMetadata.getName());
         if (columnHandle == null) {
           throw new TrinoException(
               GRAVITINO_COLUMN_NOT_EXISTS,
               "Column does not exist: " + columnMetadata.getName());
         }
         columns.add(columnHandle);
       }
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to