diff --git a/include/pgduckdb/pgduckdb_xact.hpp b/include/pgduckdb/pgduckdb_xact.hpp index 6858f108..68310271 100644 --- a/include/pgduckdb/pgduckdb_xact.hpp +++ b/include/pgduckdb/pgduckdb_xact.hpp @@ -23,4 +23,5 @@ void AutocommitSingleStatementQueries(); void MarkStatementNotTopLevel(); void SetStatementTopLevel(bool top_level); bool IsStatementTopLevel(); +std::string FindAndResetPendingError(); } // namespace pgduckdb diff --git a/src/pgduckdb_node.cpp b/src/pgduckdb_node.cpp index 2eb0103d..38594b9c 100644 --- a/src/pgduckdb_node.cpp +++ b/src/pgduckdb_node.cpp @@ -5,6 +5,7 @@ #include "pgduckdb/pgduckdb_planner.hpp" #include "pgduckdb/pgduckdb_types.hpp" +#include "pgduckdb/pgduckdb_xact.hpp" #include "pgduckdb/vendor/pg_explain.hpp" extern "C" { @@ -325,6 +326,12 @@ void Duckdb_EndCustomScan_Cpp(CustomScanState *node) { DuckdbScanState *duckdb_scan_state = (DuckdbScanState *)node; CleanupDuckdbScanState(duckdb_scan_state); + + auto err = pgduckdb::FindAndResetPendingError(); + if (!err.empty() && QueryCancelHoldoffCount == 0) { + throw duckdb::Exception(duckdb::ExceptionType::EXECUTOR, err); + } + /* * BUG: In rare error casess it's possible that we call this when we are * currently accepting interupts, in those cases we should not resume them diff --git a/src/pgduckdb_xact.cpp b/src/pgduckdb_xact.cpp index f3261be7..ca3d1d84 100644 --- a/src/pgduckdb_xact.cpp +++ b/src/pgduckdb_xact.cpp @@ -10,10 +10,22 @@ #include "pgduckdb/pg/transactions.hpp" #include "pgduckdb/utility/cpp_wrapper.hpp" +extern "C" { +extern bool ExitOnAnyError; +} + namespace pgduckdb { static CommandId next_expected_command_id = FirstCommandId; static bool top_level_statement = true; +static std::string pending_error; + +std::string +FindAndResetPendingError() { + auto prev = pending_error; + pending_error = ""; + return prev; +} namespace pg { @@ -307,6 +319,7 @@ DuckdbSubXactCallback_Cpp(SubXactEvent event) { if (!DuckDBManager::IsInitialized()) { return; } + auto connection = DuckDBManager::GetConnectionUnsafe(); auto &context = *connection->context; if (!context.transaction.HasActiveTransaction()) { @@ -314,7 +327,11 @@ DuckdbSubXactCallback_Cpp(SubXactEvent event) { } if (event == SUBXACT_EVENT_START_SUB) { - throw duckdb::NotImplementedException("SAVEPOINT is not supported in DuckDB"); + if (ExitOnAnyError) { + pending_error = "SAVEPOINT is not supported in DuckDB"; + } else { + throw duckdb::NotImplementedException("SAVEPOINT is not supported in DuckDB"); + } } } diff --git a/test/regression/expected/issue_761.out b/test/regression/expected/issue_761.out new file mode 100644 index 00000000..fb4fa9fc --- /dev/null +++ b/test/regression/expected/issue_761.out @@ -0,0 +1,24 @@ +SET duckdb.force_execution = TRUE; +DO $$ +DECLARE + objtype text; +BEGIN + FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), + ('toast table column'), ('view column'), ('materialized view column') + LOOP + BEGIN + PERFORM pg_get_object_address(objtype, '{one}', '{}'); + EXCEPTION WHEN invalid_parameter_value THEN + RAISE WARNING 'error for %: %', objtype, sqlerrm; + END; + END LOOP; +END; +$$; +WARNING: error for toast table: unsupported object type "toast table" +WARNING: error for index column: unsupported object type "index column" +WARNING: error for sequence column: unsupported object type "sequence column" +WARNING: error for toast table column: unsupported object type "toast table column" +WARNING: error for view column: unsupported object type "view column" +WARNING: error for materialized view column: unsupported object type "materialized view column" +ERROR: (PGDuckDB/Duckdb_EndCustomScan_Cpp) Executor Error: SAVEPOINT is not supported in DuckDB +CONTEXT: PL/pgSQL function inline_code_block line 5 at FOR over SELECT rows diff --git a/test/regression/schedule b/test/regression/schedule index df739ea4..8d45ae1a 100644 --- a/test/regression/schedule +++ b/test/regression/schedule @@ -25,6 +25,7 @@ test: issue_410 test: issue_730 test: issue_748 test: issue_749 +test: issue_761 test: issue_789 test: issue_796 test: issue_802 diff --git a/test/regression/sql/issue_761.sql b/test/regression/sql/issue_761.sql new file mode 100644 index 00000000..da779189 --- /dev/null +++ b/test/regression/sql/issue_761.sql @@ -0,0 +1,17 @@ +SET duckdb.force_execution = TRUE; + +DO $$ +DECLARE + objtype text; +BEGIN + FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), + ('toast table column'), ('view column'), ('materialized view column') + LOOP + BEGIN + PERFORM pg_get_object_address(objtype, '{one}', '{}'); + EXCEPTION WHEN invalid_parameter_value THEN + RAISE WARNING 'error for %: %', objtype, sqlerrm; + END; + END LOOP; +END; +$$;