Native CREATE TABLE / DROP TABLE for DataLakeCatalog; optionally prune on DROP#1896
Native CREATE TABLE / DROP TABLE for DataLakeCatalog; optionally prune on DROP#1896zvonand wants to merge 15 commits into
CREATE TABLE / DROP TABLE for DataLakeCatalog; optionally prune on DROP#1896Conversation
- Port \`IcebergPathResolver::reverseResolve\` from upstream (predates the PR upstream but was missing on this branch). - Handle the Altinity-only \`S3_TABLES\` catalog type in \`getLocationSchemeForTableCreation\` (it is always S3-backed). - Drop the \`unique_key\` check in \`DatabaseDataLake::createTable\`: \`ASTStorage\` has no \`UNIQUE KEY\` clause on this branch. - \`getInMemoryMetadataPtr\` does not take a context argument on this branch. ClickHouse#98670 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3983fab to
3ac9ae4
Compare
|
AI audit note: This review comment was generated by AI (claude-4.6-opus). Audit update for PR #1896 (Native CREATE TABLE / DROP TABLE for DataLakeCatalog)Confirmed defectsMedium: GlueCatalog orphans metadata file on CreateTable API failure
Medium:
|
| Category | Status |
|---|---|
| Scope reviewed | InterpreterCreateQuery engine-less path, InterpreterDropQuery ON CLUSTER check, InterpreterAlterQuery ON CLUSTER check, DatabaseDataLake::createTable, DatabaseDataLake::dropTable, GlueCatalog::createTable/dropTable, RestCatalog::createTable/dropTable/namespaceToJSONArray/encodeNamespaceForURI, S3TablesCatalog::dropTable, ICatalog::storageTypeToScheme, constructTableLocation, IcebergMetadata::createInitial metadata filename, MetadataGenerator::generateNextMetadata parent_snapshot/metadata-log changes, IcebergWrites previous_metadata_file_path tracking, Mutations.cpp reverseResolve + writeMetadataFiles, Utils.cpp cleanup-on-failure, IcebergPath::reverseResolve, StorageObjectStorage::alter/checkAlterIsPossible/drop |
| Categories failed | Partial-update rollback (GlueCatalog metadata write), path resolution edge case (reverseResolve) |
| Categories passed | Concurrency/thread-safety, memory lifetime, exception safety (DDL guard RAII), integer overflow (N/A), ON CLUSTER rejection, namespace encoding, setting rename/alias, DROP purge semantics, metadata-log correctness, metadata filename UUID, test coverage |
| Assumptions/limits | Static analysis only; GlueCatalog AWS interactions not runtime-tested; Mutations.cpp retry logic assumed correct based on pre-existing patterns |
There's an export partition regression fail that looks like it's caused by this PR.Under ice catalog, exporting multiple partitions in one ALTER does some concurrent writes. Exports are marked as COMPLETED but DataLakeCatalog read-back is short on rows. The same scenarios pass on baseline Antalya and under no_catalog (direct S3). The regression lines up with the PR’s Iceberg commit changes in IcebergWrites.cpp / MetadataGenerator.cpp: when one ALTER fires several parallel exports to the same REST-catalog table, later commits can land without chaining onto earlier snapshots’ manifests, so only the latest partition’s data is visible even though every export succeeded. |
|
@DimensionWieldr how it could've happened? this PR is not yet merged, and the latest run has not yet finished build jobs (there are no regression results yet) |
Sorry I should've specified. This is a fail from CI on this PR, from the previous commit. I was asked to take a look at export partition fails earlier today. Maybe the new CI run for the most recent commit will look better. |
|
AI audit note: This review comment was generated by AI (claude-4.6-opus). Audit update for PR #1896 — commit 7a5ddbf (Native CREATE TABLE / DROP TABLE for DataLakeCatalog)Confirmed defectsMedium: Missing null-safety for
|
| Category | Status |
|---|---|
| Scope reviewed | All 36 changed files; focused re-analysis on IcebergWrites.cpp retry/concurrency path, MetadataGenerator.cpp parent-snapshot logic, generateManifestList chaining, GlueCatalog cleanup, IcebergMetadata::createInitial cleanup, reverseResolve fix |
| Categories failed | Null-safety (IcebergWrites.cpp current-snapshot-id), UX (S3Tables CREATE TABLE error message) |
| Categories passed | Partial-update rollback (fixed), path resolution (fixed), concurrency/manifest-chaining (correct), memory lifetime, exception safety, ON CLUSTER rejection, namespace encoding, setting rename/alias, DROP purge semantics, metadata-log correctness, test coverage |
| Assumptions/limits | Static analysis only; export partition regression analyzed by code tracing only, not runtime-reproduced; Poco JSON isNull vs has semantics assumed standard |
Hmm, are we sure? Regression test Fix directions
|
#1896 (comment) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CREATE TABLE / DROP TABLE for DataLakeCatalog; optionally prune on DROPCREATE TABLE / DROP TABLE for DataLakeCatalog; optionally prune on DROP
|
Two issues left:
|
|
SHOW TABLES is not working #1988 (using build from the latest commit) |
Audit update for PR #1896 — commit
|
| Finding | Fix |
|---|---|
GlueCatalog orphans metadata file on createTable failure |
SCOPE_EXIT + registered flag cleans up the written S3 metadata file if the Glue API call fails |
reverseResolve produces malformed path |
table_location prefix check added before the concatenation fallback in IcebergPath.h |
IcebergMetadata::createInitial partial-update rollback |
SCOPE_EXIT removes both metadata file and version-hint on catalog registration failure |
| Concurrent export-partition data loss (REST catalog) | assert-ref-snapshot-id always included in updateMetadata, covering initial (ref-absent) and subsequent (parent-snapshot-id) commits; parent-snapshot-id omitted from snapshot when -1 so generateManifestList skips manifest-chaining for first snapshot |
| Transactional catalog writes duplicate metadata files | Metadata JSON write skipped for transactional catalogs in IcebergWrites, Mutations, truncate, and expireSnapshots; metadata submitted exclusively via catalog->updateMetadata |
IcebergMetadata::drop doubled path |
purgeTableDataFiles uses listFiles(object_storage, table_path, "", "") (empty prefix); IcebergMetadata::drop now delegates to it |
iceberg_delete_data_on_drop setting rename |
Renamed to data_lake_delete_data_on_drop with iceberg_delete_data_on_drop kept as alias via DECLARE_WITH_ALIAS |
Glue metadata_location empty-string populating iceberg_metadata_file_location |
!table_params.at("metadata_location").empty() guard added |
Coverage summary
- Scope reviewed: All 44 changed files at
498d41e; deep analysis onIcebergWrites.cpp(transactional metadata fetch, null-safety, metadata-log path),Mutations.cpp(null check,previous_metadata_file_path),MetadataGenerator.cpp(parent-snapshot-id omission, metadata-log guard),IcebergMetadata.cpp(transactionalcreateInitialearly-return, drop → purge),GlueCatalog.cpp(S3-write + SCOPE_EXIT, purge),RestCatalog.cpp(CAS requirement, sort-order, namespace encoding),DatabaseDataLake.cpp(engine-less CREATE, context-aware DROP),Common.cpp(constructTableLocation,getMetadataLocationFromCatalog),InterpreterCreateQuery.cpp(engine-less gate,isDatalakeCatalogchecks),executeDDLQueryOnCluster.cpp(checkDatabaseSupportsOnClusterDDL),StorageObjectStorage.cpp(drop passespurge=false,checkAlterIsPossibleupdate call) - Categories failed: Null-safety (
IcebergWrites.cppcurrent-snapshot-id), URI parsing (constructTableLocationS3 bucket), path format mismatch (getMetadataLocationFromCatalog), UX (S3TablesCREATE TABLE) - Categories passed: Partial-update rollback, concurrent commit safety, manifest chaining, duplicate metadata-file write prevention, ON CLUSTER rejection, namespace encoding, setting rename/alias, DROP purge semantics (Glue + REST + S3Tables), metadata-log correctness, purge path correctness, IF NOT EXISTS, memory lifetime/RAII, exception-safety
- Assumptions/limits: Static analysis only;
getMetadataLocationFromCatalogpath-format mismatch not runtime-reproduced (REST catalog confirmed working, suggestingtable_pathmay be absolute for catalog tables in practice — defect may be configuration-dependent);constructTableLocationS3 URI bug not covered by the new unit tests ingtest_construct_table_location.cpp.
| { | ||
| String table_location = metadata_content->getValue<String>("location"); | ||
| while (table_location.ends_with('/')) | ||
| table_location = table_location.substr(0, table_location.size() - 1); |
| auto fields = sort_order->getArray("fields"); | ||
| if (fields && fields->size() > 0) | ||
| { | ||
| if (sort_order->getValue<int>("order-id") == 0) |
There was a problem hiding this comment.
I would probably add some comment here explaining the change. I had to dig through the spec with Claude to understand why this change was made :)
| /* force_fetch_latest_metadata */ true, | ||
| /* ignore_explicit_metadata_file_path */ true); | ||
| Iceberg::MetadataFileWithInfo latest_metadata_file_info; | ||
| if (catalog && catalog->isTransactional()) |
There was a problem hiding this comment.
Just a style nitpick: the checks for transactional catalog are a bit inconsistent. You added const bool at some parts, but not here. I'd personally say that maybe introducing that bool is not really necessary, but I'll leave this for you to decide.

Changelog category (leave one):
Changelog entry (a user-readable short description of the changes that goes into CHANGELOG.md):
Supports
CREATE TABLE,CREATE TABLE … AS source, andDROP TABLEfor DataLakeCatalog; optional catalog-side data purge can be triggered ( newdatabase_iceberg_purge_on_dropsetting).Documentation entry for user-facing changes
CI/CD Options
Exclude tests:
Regression jobs to run: