LuciferYang opened a new issue, #977:
URL: https://github.com/apache/iceberg-cpp/issues/977

   ## Summary
   
   `InMemoryCatalog` fails to validate that a table's namespace exists before 
acting, in two methods.
   
   `CreateTable` writes the table metadata file through `FileIO` before it 
checks the namespace. Creating a table under a namespace that does not exist 
returns `kNoSuchNamespace`, but on an object-store `FileIO` the call first 
writes an orphaned `00000-<uuid>.metadata.json` that nothing ever removes 
(`DropTable`'s purge only touches registered tables). On the default local 
`FileIO` the stray write fails first, so the caller gets a misleading 
`kIOError` instead of `kNoSuchNamespace`.
   
   `RegisterTable` guards with `if 
(!root_namespace_->NamespaceExists(identifier.ns))`. `NamespaceExists` returns 
`Result<bool>` (`std::expected<bool, Error>`); `!result` tests `has_value()`, 
not the contained bool, and a missing namespace is reported as a value `false`, 
never an error. The guard therefore never fires, so registering under a missing 
namespace falls through and surfaces as `kUnknownError` ("The registry 
failed.") instead of `kNoSuchNamespace`.
   
   ## Root Cause
   
   `CreateTable` (`src/iceberg/catalog/memory/in_memory_catalog.cc`): the 
namespace is only enforced inside `UpdateTableMetadataLocation`, which runs 
after `TableMetadataUtil::Write` has already persisted the file. 
`TableExists(identifier).value_or(false)` ahead of the write swallows the 
`kNoSuchNamespace` from the namespace lookup and reports "table absent", so 
control falls through to the write.
   
   `RegisterTable`: `if (!root_namespace_->NamespaceExists(identifier.ns))` 
reads as `if (!result.has_value())`. `NamespaceExists` maps a missing namespace 
to `Ok(false)`, so the branch is dead code; the error later comes out of the 
inner `RegisterTable` and is rewritten to `kUnknownError`.
   
   ## Impact
   
   `CreateTable` leaks an orphan metadata file on object-store `FileIO` and 
returns the wrong error kind (`kIOError`) on local `FileIO`. `InMemoryCatalog` 
is documented as not for production use (unit tests, prototyping, 
demonstration), so this is a correctness and robustness issue, not a security 
one.
   
   `RegisterTable` returns `kUnknownError` for a missing namespace instead of 
`kNoSuchNamespace`. `SqlCatalog::RegisterTable` and the REST error handler both 
return `kNoSuchNamespace`, so `InMemoryCatalog` is the outlier here.
   
   ## Proposed Fix
   
   Unwrap `NamespaceExists` and return `kNoSuchNamespace` before any metadata 
write, in both methods, mirroring `SqlCatalog::CreateTable`.
   
   ## Out of scope
   
   - `RegisterTable` still masks `kAlreadyExists` as `kUnknownError` on the 
duplicate-registration path (`if (!root_namespace_->RegisterTable(...))`); the 
clean fix is `ICEBERG_RETURN_UNEXPECTED(...)`, as `RenameTable` already does. 
Follow-up.
   - `StageCreateTable` and `UpdateTable`'s create branch share the same 
write-before-validate pattern. Follow-up.
   


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


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to