@@ -469,6 +469,10 @@ class LanceSchemaEntry final : public DuckSchemaEntry {
469469 : DuckSchemaEntry(catalog, info), directory_ns(std::move(directory_ns)),
470470 rest_ns (std::move(rest_ns)) {}
471471
472+ void SetTableDefaultGenerator (DefaultGenerator *generator) {
473+ table_default_generator = generator;
474+ }
475+
472476 void Alter (CatalogTransaction transaction, AlterInfo &info) override {
473477 auto &set = GetCatalogSet (info.GetCatalogType ());
474478 auto entry = set.GetEntry (transaction, info.name );
@@ -654,6 +658,16 @@ class LanceSchemaEntry final : public DuckSchemaEntry {
654658 throw InternalException (
655659 " Could not drop element because of an internal error" );
656660 }
661+
662+ // DropEntry with a system (committed) CatalogTransaction leaves a committed
663+ // tombstone behind. This blocks subsequent lazy discovery of a recreated
664+ // dataset with the same name, because CatalogSet::GetEntryDetailed will
665+ // find the tombstone and never consult the default generator. Since ATTACH
666+ // TYPE LANCE catalogs are ephemeral, we can eagerly clean up the entry
667+ // chain (old entry + tombstone).
668+ set.CleanupEntry (*existing_entry);
669+
670+ InvalidateTableDefaults ();
657671 }
658672
659673 optional_ptr<CatalogEntry> CreateTable (CatalogTransaction transaction,
@@ -723,6 +737,7 @@ class LanceSchemaEntry final : public DuckSchemaEntry {
723737 exists ? existing_id : (prefixed_id.empty () ? leaf_id : prefixed_id);
724738 if (create_info.on_conflict == OnCreateConflict::IGNORE_ON_CONFLICT &&
725739 exists) {
740+ InvalidateTableDefaults ();
726741 return nullptr ;
727742 }
728743 if (create_info.on_conflict == OnCreateConflict::ERROR_ON_CONFLICT &&
@@ -790,6 +805,7 @@ class LanceSchemaEntry final : public DuckSchemaEntry {
790805 DirectoryNamespaceTableExists (*directory_ns, create_info.table );
791806 if (create_info.on_conflict == OnCreateConflict::IGNORE_ON_CONFLICT &&
792807 exists) {
808+ InvalidateTableDefaults ();
793809 return nullptr ;
794810 }
795811 if (create_info.on_conflict == OnCreateConflict::ERROR_ON_CONFLICT &&
@@ -866,12 +882,21 @@ class LanceSchemaEntry final : public DuckSchemaEntry {
866882 }
867883 }
868884
885+ InvalidateTableDefaults ();
869886 return nullptr ;
870887 }
871888
872889private:
890+ void InvalidateTableDefaults () {
891+ if (!table_default_generator) {
892+ return ;
893+ }
894+ table_default_generator->created_all_entries = false ;
895+ }
896+
873897 shared_ptr<LanceDirectoryNamespaceConfig> directory_ns;
874898 shared_ptr<LanceRestNamespaceConfig> rest_ns;
899+ DefaultGenerator *table_default_generator = nullptr ;
875900};
876901
877902class LanceDuckCatalog final : public DuckCatalog {
@@ -1529,6 +1554,7 @@ LanceStorageAttach(optional_ptr<StorageExtensionInfo>, ClientContext &context,
15291554 catalog->ReplaceDefaultSchemaWithLanceSchema (system_transaction);
15301555 auto &schema = catalog->GetSchema (system_transaction, DEFAULT_SCHEMA);
15311556
1557+ auto &lance_schema = schema.Cast <LanceSchemaEntry>();
15321558 auto &duck_schema = schema.Cast <DuckSchemaEntry>();
15331559 auto &catalog_set = duck_schema.GetCatalogSet (CatalogType::TABLE_ENTRY);
15341560
@@ -1541,7 +1567,9 @@ LanceStorageAttach(optional_ptr<StorageExtensionInfo>, ClientContext &context,
15411567 std::move (api_key), delimiter, bearer_token_override, api_key_override,
15421568 headers_tsv);
15431569 }
1570+ auto *generator_ptr = generator.get ();
15441571 catalog_set.SetDefaultGenerator (std::move (generator));
1572+ lance_schema.SetTableDefaultGenerator (generator_ptr);
15451573
15461574 (void )name;
15471575 return std::move (catalog);
0 commit comments