Cppgres
Build Postgres extensions in C++
Loading...
Searching...
No Matches
guard.hpp
Go to the documentation of this file.
1
4#pragma once
5
6extern "C" {
7#include <setjmp.h>
8}
9
10#include <exception>
11#include <iostream>
12#include <utility>
13
14#include "error.hpp"
15#include "exception.hpp"
17
18namespace cppgres {
19
20template <typename Func> struct ffi_guard {
21 Func func;
22
23 explicit ffi_guard(Func f) : func(std::move(f)) {}
24
25 template <typename... Args>
26 auto operator()(Args &&...args) -> decltype(func(std::forward<Args>(args)...)) {
27 int state;
28 sigjmp_buf *pbuf;
29 ::ErrorContextCallback *cb;
30 sigjmp_buf buf;
31 ::MemoryContext mcxt = ::CurrentMemoryContext;
32
33 pbuf = ::PG_exception_stack;
34 cb = ::error_context_stack;
35 ::PG_exception_stack = &buf;
36
37 // restore state upon exit
38 std::shared_ptr<void> defer(nullptr, [&](...) {
39 ::error_context_stack = cb;
40 ::PG_exception_stack = pbuf;
41 });
42
43 state = sigsetjmp(buf, 1);
44
45 if (state == 0) {
46 return func(std::forward<Args>(args)...);
47 } else if (state == 1) {
48 throw pg_exception(mcxt);
49 }
50 __builtin_unreachable();
51 }
52};
53
65template <typename Func> void ffi_guard_noexcept(Func f, const char *warning_message) noexcept {
66 try {
67 ffi_guard{std::move(f)}();
68 } catch (...) {
69 elog(WARNING, "%s", warning_message);
70 }
71}
72
82template <typename Func> struct scope_fail {
83 Func func;
84 const char *warning_message;
85 int uncaught = std::uncaught_exceptions();
86
87 scope_fail(Func f, const char *warning_message)
88 : func(std::move(f)), warning_message(warning_message) {}
89
90 ~scope_fail() {
91 if (std::uncaught_exceptions() > uncaught) {
92 ffi_guard_noexcept(func, warning_message);
93 }
94 }
95
96 scope_fail(const scope_fail &) = delete;
97 scope_fail &operator=(const scope_fail &) = delete;
98 scope_fail(scope_fail &&) = delete;
99 scope_fail &operator=(scope_fail &&) = delete;
100};
101
102template <typename Func> scope_fail(Func, const char *) -> scope_fail<Func>;
103
112template <typename Func> struct scope_exit {
113 Func func;
114 const char *warning_message;
115
116 scope_exit(Func f, const char *warning_message)
117 : func(std::move(f)), warning_message(warning_message) {}
118
119 ~scope_exit() { ffi_guard_noexcept(func, warning_message); }
120
121 scope_exit(const scope_exit &) = delete;
122 scope_exit &operator=(const scope_exit &) = delete;
123 scope_exit(scope_exit &&) = delete;
124 scope_exit &operator=(scope_exit &&) = delete;
125};
126
127template <typename Func> scope_exit(Func, const char *) -> scope_exit<Func>;
128
142template <typename Func> struct exception_guard {
143 Func func;
144
145 explicit exception_guard(Func f) : func(std::move(f)) {}
146
147 template <typename... Args>
148 auto operator()(Args &&...args) -> decltype(func(std::forward<Args>(args)...)) {
149 try {
150 return func(std::forward<Args>(args)...);
151 } catch (pg_exception &e) {
152 e.rethrow();
153 } catch (const std::exception &e) {
154 report(ERROR, "exception: %s", e.what());
155 } catch (...) {
156 report(ERROR, "some exception occurred");
157 }
158 __builtin_unreachable();
159 }
160};
161
162} // namespace cppgres
Definition: exception.hpp:7
void rethrow()
Re-throws the captured error as a Postgres error, with every field (SQLSTATE, detail,...
Definition: exception_impl.hpp:22
void ffi_guard_noexcept(Func f, const char *warning_message) noexcept
Runs a callable under cppgres::ffi_guard, degrading any failure to a warning.
Definition: guard.hpp:65
Wraps a C++ function to catch exceptions and report them as Postgres errors.
Definition: guard.hpp:142
Definition: guard.hpp:20
Scope guard that always runs the callable on scope exit.
Definition: guard.hpp:112
Scope guard that runs the callable only when the scope is left via an exception.
Definition: guard.hpp:82