Skip to content

Commit

Permalink
Transform elog(ERROR to C++ exceptions
Browse files Browse the repository at this point in the history
  • Loading branch information
Y-- committed Oct 10, 2024
1 parent 90fd673 commit 2c0729c
Show file tree
Hide file tree
Showing 9 changed files with 82 additions and 94 deletions.
4 changes: 2 additions & 2 deletions include/pgduckdb/pgduckdb_duckdb.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ class DuckDBManager {
return *Get().database;
}

static duckdb::unique_ptr<duckdb::Connection>
CreateConnection();
static duckdb::unique_ptr<duckdb::Connection> CreateConnection();

private:
DuckDBManager();

Expand Down
1 change: 0 additions & 1 deletion include/pgduckdb/pgduckdb_ruleutils.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#include "postgres.h"

char *pgduckdb_relation_name(Oid relid);
char *pgduckdb_function_name(Oid function_oid);
char *pgduckdb_get_tabledef(Oid relation_id);
22 changes: 21 additions & 1 deletion include/pgduckdb/pgduckdb_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ PostgresFunctionGuard(FuncType postgres_function, FuncArgs... args) {

template <typename FuncRetT, typename FuncType, typename... FuncArgs>
FuncRetT
DuckDBFunctionGuard(FuncType duckdb_function, const char* function_name, FuncArgs... args) {
DuckDBFunctionGuard(FuncType duckdb_function, const char *function_name, FuncArgs... args) {
const char *error_message = nullptr;
try {
return duckdb_function(args...);
Expand Down Expand Up @@ -111,4 +111,24 @@ DuckDBQueryOrThrow(duckdb::ClientContext &context, const std::string &query) {
return res;
}

inline duckdb::unique_ptr<duckdb::QueryResult>
DuckDBQueryOrThrow(duckdb::Connection &connection, const std::string &query) {
auto res = connection.context->Query(query, false);
if (res->HasError()) {
res->ThrowError();
}
return res;
}

inline duckdb::unique_ptr<duckdb::QueryResult>
DuckDBQueryOrThrow(const std::string &query) {
auto connection = pgduckdb::DuckDBManager::CreateConnection();
auto &context = *connection->context;
auto res = context.Query(query, false);
if (res->HasError()) {
res->ThrowError();
}
return res;
}

} // namespace pgduckdb
80 changes: 31 additions & 49 deletions src/pgduckdb_ddl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ extern "C" {
}

#include "pgduckdb/pgduckdb_duckdb.hpp"
#include "pgduckdb/pgduckdb_utils.hpp"
#include "pgduckdb/vendor/pg_list.hpp"
#include <inttypes.h>

Expand All @@ -30,13 +31,7 @@ extern "C" {
*/
void
DuckdbTruncateTable(Oid relation_oid) {
auto connection = pgduckdb::DuckDBManager::CreateConnection();
auto &context = *connection->context;
auto query = std::string("TRUNCATE ") + pgduckdb_relation_name(relation_oid);
auto result = context.Query(query, false);
if (result->HasError()) {
elog(ERROR, "(PGDuckDB/DuckdbTruncateTable) Could not truncate table: %s", result->GetError().c_str());
}
pgduckdb::DuckDBQueryOrThrow(std::string("TRUNCATE ") + pgduckdb_relation_name(relation_oid));
}

void
Expand All @@ -49,7 +44,7 @@ DuckdbHandleDDL(Node *parsetree, const char *queryString) {
return;
}

elog(ERROR, "DuckDB does not support CREATE TABLE AS yet");
throw duckdb::NotImplementedException("DuckDB does not support CREATE TABLE AS yet");
}
}

Expand All @@ -69,9 +64,9 @@ CheckOnCommitSupport(OnCommitAction on_commit) {
case ONCOMMIT_DELETE_ROWS:
break;
case ONCOMMIT_DROP:
elog(ERROR, "DuckDB does not support ON COMMIT DROP");
throw duckdb::NotImplementedException("DuckDB does not support ON COMMIT DROP");
default:
elog(ERROR, "Unsupported ON COMMIT clause: %d", on_commit);
throw duckdb::NotImplementedException("Unsupported ON COMMIT clause: ", on_commit);
}
}

Expand All @@ -80,8 +75,10 @@ extern "C" {
PG_FUNCTION_INFO_V1(duckdb_create_table_trigger);
Datum
duckdb_create_table_trigger(PG_FUNCTION_ARGS) {
if (!CALLED_AS_EVENT_TRIGGER(fcinfo)) /* internal error */
elog(ERROR, "not fired by event trigger manager");
if (!CALLED_AS_EVENT_TRIGGER(fcinfo)) {
/* internal error */
throw std::runtime_error("not fired by event trigger manager");
}

EventTriggerData *trigdata = (EventTriggerData *)fcinfo->context;
Node *parsetree = trigdata->parsetree;
Expand Down Expand Up @@ -121,8 +118,9 @@ duckdb_create_table_trigger(PG_FUNCTION_ARGS) {
SetUserIdAndSecContext(saved_userid, sec_context);
AtEOXact_GUC(false, save_nestlevel);

if (ret != SPI_OK_INSERT_RETURNING)
elog(ERROR, "SPI_exec failed: error code %s", SPI_result_code_string(ret));
if (ret != SPI_OK_INSERT_RETURNING) {
throw std::runtime_error(std::string("SPI_exec failed: error code ") + SPI_result_code_string(ret));
}

/* if we inserted a row it was a duckdb table */
auto is_duckdb_table = SPI_processed > 0;
Expand All @@ -132,14 +130,16 @@ duckdb_create_table_trigger(PG_FUNCTION_ARGS) {
}

if (SPI_processed != 1) {
elog(ERROR, "Expected single table to be created, but found %" PRIu64, SPI_processed);
throw std::runtime_error("Expected single table to be created, but found " + std::to_string(SPI_processed));
}

HeapTuple tuple = SPI_tuptable->vals[0];
bool isnull;
Datum relid_datum = SPI_getbinval(tuple, SPI_tuptable->tupdesc, 1, &isnull);
if (isnull) {
elog(ERROR, "Expected relid to be returned, but found NULL");
throw std::runtime_error("Expected relid to be returned, but found NULL");
}

Oid relid = DatumGetObjectId(relid_datum);
SPI_finish();

Expand All @@ -157,26 +157,18 @@ duckdb_create_table_trigger(PG_FUNCTION_ARGS) {
auto stmt = castNode(CreateTableAsStmt, parsetree);
CheckOnCommitSupport(stmt->into->onCommit);
} else {
elog(ERROR, "Unexpected parsetree type: %d", nodeTag(parsetree));
}

std::string query_string(pgduckdb_get_tabledef(relid));

auto connection = pgduckdb::DuckDBManager::CreateConnection();
auto &context = *connection->context;
auto result = context.Query(query_string, false);
if (result->HasError()) {
elog(ERROR, "(PGDuckDB/duckdb_create_table_trigger) Could not create table: %s", result->GetError().c_str());
throw std::runtime_error("Unexpected parsetree type: " + std::to_string(nodeTag(parsetree)));
}

pgduckdb::DuckDBQueryOrThrow(pgduckdb_get_tabledef(relid));
PG_RETURN_NULL();
}

PG_FUNCTION_INFO_V1(duckdb_drop_table_trigger);
Datum
duckdb_drop_table_trigger(PG_FUNCTION_ARGS) {
if (!CALLED_AS_EVENT_TRIGGER(fcinfo)) /* internal error */
elog(ERROR, "not fired by event trigger manager");
throw std::runtime_error("not fired by event trigger manager");

SPI_connect();

Expand Down Expand Up @@ -214,8 +206,9 @@ duckdb_drop_table_trigger(PG_FUNCTION_ARGS) {
SetUserIdAndSecContext(saved_userid, sec_context);
AtEOXact_GUC(false, save_nestlevel);

if (ret != SPI_OK_DELETE_RETURNING)
elog(ERROR, "SPI_exec failed: error code %s", SPI_result_code_string(ret));
if (ret != SPI_OK_DELETE_RETURNING) {
throw std::runtime_error("SPI_exec failed: error code '" + std::string(SPI_result_code_string(ret)) + "'");
}

if (SPI_processed == 0) {
/* No duckdb tables were dropped */
Expand All @@ -231,40 +224,29 @@ duckdb_drop_table_trigger(PG_FUNCTION_ARGS) {
PreventInTransactionBlock(true, "DuckDB queries");

auto connection = pgduckdb::DuckDBManager::CreateConnection();
auto &context = *connection->context;

auto result = context.Query("BEGIN TRANSACTION", false);
if (result->HasError()) {
elog(ERROR, "(PGDuckDB/duckdb_drop_table_trigger) Could not start transaction");
}
pgduckdb::DuckDBQueryOrThrow(*connection, "BEGIN TRANSACTION");

for (auto proc = 0; proc < SPI_processed; proc++) {
for (auto proc = 0; proc < SPI_processed; ++proc) {
HeapTuple tuple = SPI_tuptable->vals[proc];

char *object_identity = SPI_getvalue(tuple, SPI_tuptable->tupdesc, 1);
// TODO: Handle std::string creation in a safe way for allocation failures
auto result = context.Query("DROP TABLE IF EXISTS " + std::string(object_identity), false);
if (result->HasError()) {
elog(ERROR, "(PGDuckDB/duckdb_drop_table_trigger) Could not drop table %s: %s", object_identity,
result->GetError().c_str());
}
pgduckdb::DuckDBQueryOrThrow(*connection, "DROP TABLE IF EXISTS " + std::string(object_identity));
}

SPI_finish();

result = context.Query("COMMIT", false);
if (result->HasError()) {
elog(ERROR, "(PGDuckDB/duckdb_drop_table_trigger) Could not commit transaction");
}

pgduckdb::DuckDBQueryOrThrow(*connection, "COMMIT");
PG_RETURN_NULL();
}

PG_FUNCTION_INFO_V1(duckdb_alter_table_trigger);
Datum
duckdb_alter_table_trigger(PG_FUNCTION_ARGS) {
if (!CALLED_AS_EVENT_TRIGGER(fcinfo)) /* internal error */
elog(ERROR, "not fired by event trigger manager");
if (!CALLED_AS_EVENT_TRIGGER(fcinfo)) { /* internal error */
throw std::runtime_error("not fired by event trigger manager");
}

SPI_connect();

Expand Down Expand Up @@ -308,7 +290,7 @@ duckdb_alter_table_trigger(PG_FUNCTION_ARGS) {
AtEOXact_GUC(false, save_nestlevel);

if (ret != SPI_OK_SELECT)
elog(ERROR, "SPI_exec failed: error code %s", SPI_result_code_string(ret));
throw std::runtime_error("SPI_exec failed: error code '" + std::string(SPI_result_code_string(ret)) + "'");

/* if we inserted a row it was a duckdb table */
auto is_duckdb_table = SPI_processed > 0;
Expand All @@ -317,7 +299,7 @@ duckdb_alter_table_trigger(PG_FUNCTION_ARGS) {
PG_RETURN_NULL();
}

elog(ERROR, "DuckDB does not support ALTER TABLE yet");
throw duckdb::NotImplementedException("DuckDB does not support ALTER TABLE yet");

PG_RETURN_NULL();
}
Expand Down
8 changes: 2 additions & 6 deletions src/pgduckdb_duckdb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,13 +167,9 @@ DuckDBManager::LoadSecrets(duckdb::ClientContext &context) {

void
DuckDBManager::DropSecrets(duckdb::ClientContext &context) {

for (auto secret_id = 0; secret_id < secret_table_num_rows; secret_id++) {
auto drop_secret_cmd = duckdb::StringUtil::Format("DROP SECRET pgduckb_secret_%d;", secret_id);
auto res = context.Query(drop_secret_cmd, false);
if (res->HasError()) {
elog(ERROR, "(PGDuckDB/DropSecrets) secret `%d` could not be dropped.", secret_id);
}
pgduckdb::DuckDBQueryOrThrow(drop_secret_cmd);
}
secret_table_num_rows = 0;
}
Expand All @@ -191,7 +187,7 @@ DuckDBManager::LoadExtensions(duckdb::ClientContext &context) {

duckdb::unique_ptr<duckdb::Connection>
DuckDBManager::CreateConnection() {
auto& instance = Get();
auto &instance = Get();
auto connection = duckdb::make_uniq<duckdb::Connection>(GetDatabase());
if (instance.CheckSecretsSeq()) {
auto &context = *connection->context;
Expand Down
7 changes: 4 additions & 3 deletions src/pgduckdb_hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,8 @@ DuckdbPlannerHook_Unsafe(Query *parse, const char *query_string, int cursor_opti

static PlannedStmt *
DuckdbPlannerHook(Query *parse, const char *query_string, int cursor_options, ParamListInfo bound_params) {
return pgduckdb::DuckDBFunctionGuard<PlannedStmt *>(DuckdbPlannerHook_Unsafe, __FUNCTION__, parse, query_string, cursor_options, bound_params);
return pgduckdb::DuckDBFunctionGuard<PlannedStmt *>(DuckdbPlannerHook_Unsafe, __FUNCTION__, parse, query_string,
cursor_options, bound_params);
}

static void
Expand Down Expand Up @@ -225,8 +226,8 @@ DuckdbUtilityHook_Unsafe(PlannedStmt *pstmt, const char *query_string, bool read
static void
DuckdbUtilityHook(PlannedStmt *pstmt, const char *query_string, bool read_only_tree, ProcessUtilityContext context,
ParamListInfo params, struct QueryEnvironment *query_env, DestReceiver *dest, QueryCompletion *qc) {
pgduckdb::DuckDBFunctionGuard<void>(DuckdbUtilityHook_Unsafe, __FUNCTION__, pstmt, query_string, read_only_tree, context, params,
query_env, dest, qc);
pgduckdb::DuckDBFunctionGuard<void>(DuckdbUtilityHook_Unsafe, __FUNCTION__, pstmt, query_string, read_only_tree,
context, params, query_env, dest, qc);
}

extern "C" {
Expand Down
3 changes: 2 additions & 1 deletion src/pgduckdb_options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,8 @@ install_extension(PG_FUNCTION_ARGS) {
PG_RETURN_BOOL(result);
}

const char* pgduckdb_raw_query_unsafe(const char *query) {
const char *
pgduckdb_raw_query_unsafe(const char *query) {
auto connection = pgduckdb::DuckDBManager::CreateConnection();
auto result = pgduckdb::DuckDBQueryOrThrow(*connection->context, query);
return strdup(result->ToString().c_str());
Expand Down
2 changes: 1 addition & 1 deletion src/pgduckdb_planner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ CreatePlan(Query *query) {
PlannedStmt *
DuckdbPlanNode(Query *parse, int cursor_options) {
/* We need to check can we DuckDB create plan */
Plan *plan = pgduckdb::DuckDBFunctionGuard<Plan*>(CreatePlan, "CreatePlan", parse);
Plan *plan = pgduckdb::DuckDBFunctionGuard<Plan *>(CreatePlan, "CreatePlan", parse);
Plan *duckdb_plan = (Plan *)castNode(CustomScan, plan);

if (!duckdb_plan) {
Expand Down
Loading

0 comments on commit 2c0729c

Please sign in to comment.