markhoerth opened a new issue, #10803:
URL: https://github.com/apache/gravitino/issues/10803

   ### Version
   
   main branch
   
   ### Describe what's wrong
   
   When `gravitino.authorization.enable = true`, Trino `CREATE TABLE` against 
the IRC fails with `NoSuchTableException`. The root cause is in 
`IcebergTableHookDispatcher.createTable()`, which unconditionally calls 
`importTable()` after the table is created in the backing catalog. When the 
Iceberg client sends `stageCreate=true` (which Trino does by default for all 
CREATE TABLE operations), the table is staged but not committed — it does not 
exist in the backing catalog yet. The `importTable()` call then attempts to 
`loadTable()` through the full catalog dispatcher chain, which fails because 
the staged table cannot be found.
   
   Without authorization enabled, the `IcebergTableHookDispatcher` is not in 
the execution path and staged creates succeed.
   
   
   ### Error message and/or stacktrace
   
   ```
   org.apache.gravitino.exceptions.NoSuchTableException: Iceberg table does not 
exist: staged_repro
     at 
org.apache.gravitino.catalog.lakehouse.iceberg.IcebergCatalogOperations.loadTable(IcebergCatalogOperations.java:393)
     at 
org.apache.gravitino.catalog.TableOperationDispatcher.lambda$internalLoadTable$20(TableOperationDispatcher.java:502)
     at 
org.apache.gravitino.catalog.CatalogManager$CatalogWrapper.lambda$doWithTableOps$1(CatalogManager.java:153)
     at 
org.apache.gravitino.utils.IsolatedClassLoader.withClassLoader(IsolatedClassLoader.java:86)
     ...
     at 
org.apache.gravitino.catalog.TableOperationDispatcher.loadTable(TableOperationDispatcher.java:117)
     at 
org.apache.gravitino.hook.TableHookDispatcher.loadTable(TableHookDispatcher.java:63)
     at 
org.apache.gravitino.catalog.TableNormalizeDispatcher.loadTable(TableNormalizeDispatcher.java:63)
     at 
org.apache.gravitino.listener.TableEventDispatcher.loadTable(TableEventDispatcher.java:99)
     at 
org.apache.gravitino.iceberg.service.dispatcher.IcebergTableHookDispatcher.importTable(IcebergTableHookDispatcher.java:185)
     at 
org.apache.gravitino.iceberg.service.dispatcher.IcebergTableHookDispatcher.createTable(IcebergTableHookDispatcher.java:60)
   ```
   
   ### How to reproduce
   
   1. Deploy Gravitino 1.2.0 full server with IRC as auxiliary service using 
`dynamic-config-provider`
   2. Enable authorization: `gravitino.authorization.enable = true`
   3. Create a metalake and lakehouse-iceberg catalog
   4. Connect Trino to the IRC endpoint as a REST catalog
   5. Run: `CREATE TABLE irc_catalog.test_ns.my_table (id BIGINT, data 
VARCHAR);`
   
   Result: `Query failed: Server error: NoSuchTableException: Iceberg table 
does not exist: my_table`
   
   ### Additional context
   
   **Root Cause**
   
   In `IcebergTableHookDispatcher.java`, the `createTable` method (line 60) 
unconditionally calls `importTable()` after creating the table:
   
   ```java
   LoadTableResponse response = dispatcher.createTable(context, namespace, 
createTableRequest);
   importTable(context.catalogName(), namespace, createTableRequest.name());
   ```
   
   For staged creates, the table is not yet committed in the backing catalog. 
The `importTable` → `loadTable` call fails with `NoSuchTableException`.
   
   **Proposed Fix**
   
   In `createTable()`, check `createTableRequest.stageCreate()` and skip the 
import. Defer the import to `updateTable()` when the commit arrives with an 
`AssertTableDoesNotExist` requirement:
   
   ```java
   @Override
   public LoadTableResponse createTable(
       IcebergRequestContext context, Namespace namespace, CreateTableRequest 
createTableRequest) {
     LoadTableResponse response = dispatcher.createTable(context, namespace, 
createTableRequest);
     if (!createTableRequest.stageCreate()) {
       importTable(context.catalogName(), namespace, createTableRequest.name());
       IcebergOwnershipUtils.setTableOwner(...);
     }
     return response;
   }
   
   @Override
   public LoadTableResponse updateTable(
       IcebergRequestContext context, TableIdentifier tableIdentifier,
       UpdateTableRequest updateTableRequest) {
     LoadTableResponse response = dispatcher.updateTable(context, 
tableIdentifier, updateTableRequest);
     if (updateTableRequest.requirements().stream()
         .anyMatch(r -> r instanceof 
UpdateRequirement.AssertTableDoesNotExist)) {
       importTable(context.catalogName(), tableIdentifier.namespace(), 
tableIdentifier.name());
       IcebergOwnershipUtils.setTableOwner(...);
     }
     return response;
   }
   ```
   
   **Environment**
   
   - Gravitino: 1.2.0
   - Trino: 469 (also reproduced by customer on Trino 479)
   - IRC config: dynamic-config-provider, JDBC catalog backend, S3 storage
   - Authorization: enabled (simple auth with serviceAdmins)
   
   **Notes**
   
   - This bug does NOT reproduce with `gravitino.authorization.enable = false` 
because the `IcebergTableHookDispatcher` is not wired into the execution path
   - This bug does NOT reproduce with the standalone IRC server 
(`apache/gravitino-iceberg-rest`) because it lacks the dispatcher layer
   - Trino sends `stageCreate=true` for ALL `CREATE TABLE` statements, making 
this a complete blocker for Trino + IRC + authorization
   - CTAS operations (issue #10750) are likely affected by the same root cause


-- 
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