35template <
typename Func>
37 requires {
typename utils::function_traits::function_traits<Func>::argument_types; } &&
45 } -> convertible_into_nullable_datum_or_set_iterator_or_void;
50 static std::optional<bool> atomic() {
52 auto ctx = calls.top()->context;
53 if (ctx !=
nullptr && IsA(ctx, CallContext)) {
54 return reinterpret_cast<::CallContext *
>(ctx)->atomic;
65 ~handle() { calls.pop(); }
73 static handle push(::FunctionCallInfo fcinfo) {
77 static void pop() { calls.pop(); }
79 static inline std::stack<::FunctionCallInfo> calls;
99 using argument_types =
typename traits::argument_types;
100 using return_type = utils::function_traits::invoke_result_from_tuple_t<Func, argument_types>;
101 static constexpr std::size_t arity = traits::arity;
109 if (arity != fc->nargs) {
110 report(ERROR,
"expected %d arguments, got %d instead", arity, fc->nargs);
114 [&]<std::size_t... Is>(std::index_sequence<Is...>) {
117 utils::remove_optional_t<std::remove_reference_t<decltype(std::get<Is>(t))>>();
118 auto typ =
type{.oid = ffi_guarded(::get_fn_expr_argtype)(fc->flinfo, Is)};
119 if (!OidIsValid(typ.oid)) {
122 if ((*cache).proargtypes.dim1 > Is) {
123 typ =
type{.oid = (*cache).proargtypes.values[Is]};
129 report(ERROR,
"unexpected type in position %d, can't convert `%s` into `%.*s`", Is,
130 typ.name().data(), utils::type_name<
decltype(ptyp)>().length(),
131 utils::type_name<
decltype(ptyp)>().data());
133 std::get<Is>(t) = from_nullable_datum<decltype(ptyp)>(
nullable_datum(fc->args[Is]));
136 }(std::make_index_sequence<utils::tuple_size_v<
decltype(t)>>{});
138 auto call_handle = current_postgres_function::push(fc);
142 auto rsinfo =
reinterpret_cast<::ReturnSetInfo *
>(fc->resultinfo);
143 if (rsinfo ==
nullptr) {
144 throw std::runtime_error(
"caller is not expecting a set");
146 using set_value_type = set_iterator_traits<return_type>::value_type;
147 constexpr auto nargs = utils::tuple_size_v<set_value_type>;
149 auto natts = rsinfo->expectedDesc->natts;
150 if (nargs != natts) {
151 throw std::runtime_error(
152 std::format(
"expected set with {} values, got {} instead", nargs, natts));
155 [&]<std::size_t... Is>(std::index_sequence<Is...>) {
157 auto oid = ffi_guarded(::SPI_gettypeid)(rsinfo->expectedDesc, Is + 1);
158 auto t =
type{.oid = oid};
159 using typ = utils::tuple_element_t<Is, set_value_type>;
161 throw std::invalid_argument(
162 std::format(
"invalid type in record's position {} ({}), got OID {}", Is,
163 utils::type_name<typ>(), oid));
167 }(std::make_index_sequence<nargs>{});
169 rsinfo->returnMode = SFRM_Materialize;
173 ::Tuplestorestate *tupstore = ffi_guarded(::tuplestore_begin_heap)(
174 (rsinfo->allowedModes & SFRM_Materialize_Random) == SFRM_Materialize_Random,
false,
176 rsinfo->setResult = tupstore;
178 auto result = std::apply(func, t);
180 for (
auto it : result) {
181 CHECK_FOR_INTERRUPTS();
182 std::array<::Datum, nargs> values = std::apply(
183 [](
auto &&...elems) -> std::array<::Datum,
sizeof...(elems)> {
184 return {into_nullable_datum(elems)...};
187 std::array<bool, nargs> isnull = std::apply(
188 [](
auto &&...elems) -> std::array<
bool,
sizeof...(elems)> {
189 return {into_nullable_datum(elems).is_null()...};
192 ffi_guarded(::tuplestore_putvalues)(tupstore, rsinfo->expectedDesc, values.data(),
199 if constexpr (std::same_as<return_type, void>) {
203 auto result = std::apply(func, t);
214 }
catch (
const std::exception &e) {
215 report(ERROR,
"exception: %s", e.what());
217 report(ERROR,
"some exception occurred");
220 __builtin_unreachable();
Definition: exception.hpp:7
Definition: function.hpp:24
Definition: datum.hpp:159
Function that operates on values of Postgres types.
Definition: function.hpp:36
Definition: datum.hpp:163
Definition: function.hpp:48
Definition: memory.hpp:189
Definition: memory.hpp:61
Postgres function implemented in C++.
Definition: function.hpp:92
auto operator()(FunctionCallInfo fc) -> ::Datum
Definition: function.hpp:106
Definition: syscache.hpp:26
Postgres type.
Definition: type.hpp:20
Definition: function_traits.hpp:37