@@ -46,6 +46,7 @@ extern "C" {
4646#include < icm/json.hpp>
4747#include < icm/string_map.hpp>
4848#include < nd/none.hpp>
49+ #include < unordered_set>
4950
5051#include < algorithm>
5152#include < vector>
@@ -287,34 +288,84 @@ void table_storage::load_table_metadata()
287288 continue ;
288289 }
289290
291+ // Snapshot tables_ keys so we can roll back C++ state on failure
292+ std::vector<Oid> tables_before;
293+ tables_before.reserve (tables_.size ());
294+ for (const auto & [oid, _] : tables_) {
295+ tables_before.push_back (oid);
296+ }
297+
290298 MemoryContext saved_context = CurrentMemoryContext;
291299 ResourceOwner saved_owner = CurrentResourceOwner;
292300 BeginInternalSubTransaction (nullptr );
293301 PG_TRY ();
294302 {
295303 set_catalog_only_create (true );
296- pg::utils::spi_connector connector ;
304+ SPI_connect () ;
297305 bool pushed_snapshot = false ;
298306 if (!ActiveSnapshotSet ()) {
299307 PushActiveSnapshot (GetTransactionSnapshot ());
300308 pushed_snapshot = true ;
301309 }
310+ // Restore the original search_path so unqualified names resolve correctly
311+ std::string saved_search_path;
312+ if (!entry.search_path .empty ()) {
313+ const char * current_sp = GetConfigOption (" search_path" , true , false );
314+ if (current_sp != nullptr ) {
315+ saved_search_path = current_sp;
316+ }
317+ StringInfoData sp_sql;
318+ initStringInfo (&sp_sql);
319+ appendStringInfo (&sp_sql,
320+ " SELECT pg_catalog.set_config('search_path', %s, true)" ,
321+ quote_literal_cstr (entry.search_path .c_str ()));
322+ SPI_execute (sp_sql.data , true , 0 );
323+ pfree (sp_sql.data );
324+ }
302325 SPI_execute (entry.ddl_sql .c_str (), false , 0 );
326+ // Restore the session's original search_path
327+ if (!entry.search_path .empty ()) {
328+ StringInfoData restore_sql;
329+ initStringInfo (&restore_sql);
330+ appendStringInfo (&restore_sql,
331+ " SELECT pg_catalog.set_config('search_path', %s, true)" ,
332+ quote_literal_cstr (saved_search_path.c_str ()));
333+ SPI_execute (restore_sql.data , true , 0 );
334+ pfree (restore_sql.data );
335+ }
303336 if (pushed_snapshot) {
304337 PopActiveSnapshot ();
305338 }
339+ SPI_finish ();
306340 set_catalog_only_create (false );
307341 ReleaseCurrentSubTransaction ();
308342 }
309343 PG_CATCH ();
310344 {
311345 set_catalog_only_create (false );
312346 MemoryContextSwitchTo (saved_context);
347+ ErrorData* edata = CopyErrorData ();
313348 CurrentResourceOwner = saved_owner;
314349 RollbackAndReleaseCurrentSubTransaction ();
315350 FlushErrorState ();
316- elog (WARNING , " pg_deeplake: DDL WAL replay failed (seq=%ld, tag=%s): %.200s" ,
317- entry.seq , entry.command_tag .c_str (), entry.ddl_sql .c_str ());
351+
352+ // Remove any tables_ entries added during the failed replay,
353+ // since the subtransaction rollback undid the catalog changes
354+ // but the C++ map entries persist.
355+ std::unordered_set<Oid> before_set (tables_before.begin (), tables_before.end ());
356+ for (auto it = tables_.begin (); it != tables_.end (); ) {
357+ if (!before_set.contains (it->first )) {
358+ it = tables_.erase (it);
359+ } else {
360+ ++it;
361+ }
362+ }
363+
364+ elog (WARNING , " pg_deeplake: DDL WAL replay failed (seq=%ld, tag=%s): %s (SQL: %.200s)" ,
365+ entry.seq , entry.command_tag .c_str (),
366+ edata->message ? edata->message : " unknown error" ,
367+ entry.ddl_sql .c_str ());
368+ FreeErrorData (edata);
318369 }
319370 PG_END_TRY ();
320371 }
@@ -853,7 +904,6 @@ void table_storage::drop_table(const std::string& table_name)
853904 auto & table_data = get_table_data (table_name);
854905 auto creds = session_credentials::get_credentials ();
855906
856-
857907 try {
858908 table_data.commit (); // Ensure all changes are committed before deletion
859909 table_version_tracker::drop_table (table_data.get_table_oid ());
0 commit comments