39#include "catalog/pg_type.h"
40#include "utils/uuid.h"
41#include "utils/builtins.h"
42#include "utils/lsyscache.h"
52#include <unordered_map>
78Datum text_datum(
const std::string &s) {
79 text *result = (text *) palloc(VARHDRSZ + s.size());
80 SET_VARSIZE(result, VARHDRSZ + s.size());
81 memcpy(VARDATA(result), s.c_str(), s.size());
82 return PointerGetDatum(result);
87Datum to_datum(
const semiring::Counting &,
unsigned v) {
return Int32GetDatum(
static_cast<int32
>(v)); }
95#if PG_VERSION_NUM >= 140000
117template <
typename Sem>
125 using V =
typename Sem::value_type;
126 std::unordered_map<gate_t, V> mapping;
128 [&sr](
const char *v) {
return sr.
parse_leaf(v); }, drop_table);
131 V out = c.
evaluate<Sem>(g, mapping, sr);
132 return to_datum(sr, std::move(out));
144 const std::unordered_map<gate_t, std::string> *labels)
158 if (SPI_connect() != SPI_OK_CONNECT)
164 if (!OidIsValid(table)) {
165 if (SPI_exec(
"SELECT ''::text AS value, NULL::uuid AS provenance WHERE false",
166 0) != SPI_OK_SELECT) {
173 char *table_name = get_rel_name(table);
183 const char *qualified = quote_qualified_identifier(
184 get_namespace_name(get_rel_namespace(table)), table_name);
186 constexpr size_t nb_max_uuid_value = 10000000;
188 StringInfoData join_query;
189 initStringInfo(&join_query);
190 bool drop_table =
false;
198 if(uuids.size() == 0) {
199 appendStringInfo(&join_query,
200 "SELECT value, provenance FROM %s WHERE 'f'", qualified);
201 }
else if(uuids.size() <= nb_max_uuid_value) {
202 appendStringInfo(&join_query,
203 "SELECT value, provenance FROM %s t JOIN (VALUES", qualified);
206 appendStringInfo(&join_query,
"%s('%s'::uuid)", first?
"":
",", u.c_str());
210 appendStringInfo(&join_query,
") AS u(id) ON t.provenance=u.id");
212 const char *create_temp_table =
"CREATE TEMP TABLE tmp_uuids(id uuid);";
213 if (SPI_exec(create_temp_table, 0) != SPI_OK_UTILITY) {
219 constexpr size_t batch_size = 1000;
221 for (
size_t offset = 0; offset < uuids.size(); offset += batch_size) {
222 StringInfoData insert_query;
223 initStringInfo(&insert_query);
224 appendStringInfo(&insert_query,
"INSERT INTO tmp_uuids VALUES ");
226 size_t end = std::min(offset + batch_size, uuids.size());
227 for (
size_t i = offset; i < end; ++i) {
228 appendStringInfo(&insert_query,
"('%s')%s", uuids[i].c_str(), (i + 1 == end) ?
"" :
",");
231 int retval=SPI_exec(insert_query.data, 0);
232 pfree(insert_query.data);
234 if(retval != SPI_OK_INSERT) {
241 appendStringInfo(&join_query,
242 "SELECT value, provenance FROM %s t JOIN tmp_uuids u ON t.provenance = u.id", qualified);
245 if (SPI_exec(join_query.data, 0) != SPI_OK_SELECT) {
272 if(
semiring==
"boolexpr" && !OidIsValid(table)) {
275 return pec_boolexpr(bc, root,
nullptr);
284 "Unknown element type for expectation: must be float8");
294 std::vector<std::string> inputs_uuid;
295 std::transform(inputs.begin(), inputs.end(), std::back_inserter(inputs_uuid), [&c](
auto x) {
307 std::unordered_map<gate_t, std::string> gc_labels;
309 return std::string(v);
312 std::unordered_map<gate_t, gate_t> gc_to_bc;
315 std::unordered_map<gate_t, std::string> bc_labels;
316 bc_labels.reserve(gc_labels.size());
317 for(
const auto &kv : gc_labels) {
318 auto it = gc_to_bc.find(kv.first);
319 if(it != gc_to_bc.end())
320 bc_labels[it->second] = kv.second;
322 return pec_boolexpr(bc, root, &bc_labels);
349#if PG_VERSION_NUM >= 140000
366 if (get_typtype(type) == TYPTYPE_ENUM) {
371 throw CircuitException(
"Unknown element type for provenance_evaluate_compiled");
381 if (PG_ARGISNULL(0) || PG_ARGISNULL(2))
385 Datum token = PG_GETARG_DATUM(0);
387 Oid table = PG_GETARG_OID(1);
389 text *t = PG_GETARG_TEXT_P(2);
390 std::string
semiring(VARDATA(t),VARSIZE(t)-VARHDRSZ);
392 Oid type = get_fn_expr_argtype(fcinfo->flinfo, 3);
395 }
catch(
const std::exception &e) {
398 provsql_error(
"provenance_evaluate_compiled: Unknown exception");
409std::unordered_map<std::string, bool> plain_truth_memo;
410constexpr size_t plain_truth_memo_max = 1000000;
414int quick_plain_truth(
const pg_uuid_t &token,
unsigned depth)
417 auto it = plain_truth_memo.find(key);
418 if (it != plain_truth_memo.end())
423 unsigned nb_children = 0;
437 res = is_times ? 1 : 0;
438 for (
unsigned i = 0; i < nb_children; ++i) {
439 int c = quick_plain_truth(children[i], depth + 1);
440 if (c < 0) { res = -1;
break; }
441 if (is_times && !c) { res = 0;
break; }
442 if (!is_times && c) { res = 1;
break; }
447 if (nb_children == 2) {
448 int a = quick_plain_truth(children[0], depth + 1);
449 int b = a == 1 ? quick_plain_truth(children[1], depth + 1) : 0;
450 res = a < 0 || b < 0 ? -1 : (a && !b);
455 if (nb_children >= 1)
456 res = quick_plain_truth(children[0], depth + 1);
476#if PG_VERSION_NUM >= 120000
477 LOCAL_FCINFO(fcinfo, 1);
479 FunctionCallInfoData fcinfo_data;
480 FunctionCallInfo fcinfo = &fcinfo_data;
485 InitFunctionCallInfoData(*fcinfo, &flinfo, 1, InvalidOid, NULL, NULL);
486#if PG_VERSION_NUM >= 120000
487 fcinfo->args[0].value = UUIDPGetDatum(&token);
488 fcinfo->args[0].isnull =
false;
490 fcinfo->arg[0] = UUIDPGetDatum(&token);
491 fcinfo->argnull[0] =
false;
493 d = FunctionCallInvoke(fcinfo);
495 res = DatumGetBool(d) ? 1 : 0;
505 if (plain_truth_memo.size() >= plain_truth_memo_max)
506 plain_truth_memo.clear();
507 plain_truth_memo.emplace(std::move(key), res == 1);
531 PG_RETURN_BOOL(
true);
532 token = *PG_GETARG_UUID_P(0);
534 int quick = quick_plain_truth(token, 0);
536 PG_RETURN_BOOL(quick == 1);
546 std::unordered_map<gate_t, bool> mapping;
549 }
catch(
const std::exception &) {
552 if (plain_truth_memo.size() >= plain_truth_memo_max)
553 plain_truth_memo.clear();
Boolean-expression (lineage formula) semiring.
Boolean semiring ({false, true}, ∨, ∧, false, true).
BooleanCircuit getBooleanCircuit(GenericCircuit &gc, pg_uuid_t token, gate_t &gate, std::unordered_map< gate_t, gate_t > &gc_to_bc)
Build a BooleanCircuit from an already-loaded GenericCircuit.
GenericCircuit getGenericCircuit(pg_uuid_t token)
Build a GenericCircuit from the mmap store rooted at token.
gate_t
Strongly-typed gate identifier.
Counting semiring (ℕ, +, ×, 0, 1).
Analytical expectation / variance / moment evaluator over RV circuits.
How-provenance m-semiring (canonical polynomial provenance ℕ[X]).
Interval-union m-semiring over PostgreSQL multirange types.
Łukasiewicz fuzzy m-semiring over .
Min-max and max-min m-semirings over PostgreSQL enum types.
Tropical (min-plus) m-semiring over .
Viterbi (max-times) m-semiring over .
Which-provenance (lineage) m-semiring.
Why-provenance semiring (set of witness sets).
Boolean circuit for provenance formula evaluation.
virtual std::string toString(gate_t g) const override
Return a textual description of gate g for debugging.
Exception type thrown by circuit operations on invalid input.
gate_t getGate(const uuid &u)
Return (or create) the gate associated with UUID u.
In-memory provenance circuit with semiring-generic evaluation.
S::value_type evaluate(gate_t g, std::unordered_map< gate_t, typename S::value_type > &provenance_mapping, S semiring) const
Evaluate the sub-circuit rooted at gate g over semiring semiring.
const std::set< gate_t > & getInputs() const
Return the set of input (leaf) gates.
The Boolean semiring over bool.
The counting semiring over unsigned.
How-provenance m-semiring over .
Interval-union m-semiring with Datum carrier, parameterised by a multirange type OID.
The Łukasiewicz fuzzy m-semiring over double.
Min-max / max-min m-semiring with Datum carrier over a PostgreSQL enum type.
Tropical (min-plus) m-semiring restricted to nonnegative costs.
Tropical (min-plus) m-semiring over double.
The Viterbi (max-times) m-semiring over double.
Which-provenance (lineage) semiring.
Provenance evaluation helper for HAVING-clause circuits.
void provsql_having(GenericCircuit &c, gate_t g, MapT &mapping, SemiringT S=SemiringT{})
Rewrite HAVING comparison gates in the circuit into their possible-world provenance (world enumeratio...
double compute_expectation(const GenericCircuit &gc, gate_t root, std::optional< gate_t > event_root)
Compute (or if event_root is set) over the scalar sub-circuit rooted at root.
std::map< how_monomial_t, unsigned > how_provenance_t
How-provenance value: each monomial mapped to its (positive) coefficient.
std::set< label_set > why_provenance_t
Why-provenance value: the full set of all witnesses.
std::optional< std::set< std::string > > which_provenance_t
Which-provenance value: a set of labels, or (empty optional).
static Datum provenance_evaluate_compiled_internal(pg_uuid_t token, Oid table, const std::string &semiring, Oid type)
Core implementation of compiled provenance evaluation.
const char * drop_temp_table
DROP TABLE statement for the per-query temporary provenance mapping table.
bool join_with_temp_uuids(Oid table, const std::vector< std::string > &uuids)
Join a provenance mapping table with a set of UUIDs using SPI.
Datum provenance_evaluate_compiled(PG_FUNCTION_ARGS)
PostgreSQL-callable wrapper for provenance_evaluate_compiled().
Datum plain_truth(PG_FUNCTION_ARGS)
Whether a token holds in the database as it is, every input tuple present: sr_boolean without a mappi...
Template helper for populating provenance mappings from SPI results.
void initialize_provenance_mapping(const constants_t &constants, GenericCircuit &c, std::unordered_map< gate_t, T > &provenance_mapping, const std::function< T(const char *)> &charp_to_value, bool drop_table)
Populate a provenance mapping from the current SPI result set.
#define provsql_error(fmt,...)
Report a fatal ProvSQL error and abort the current transaction.
gate_type provsql_fetch_gate(const pg_uuid_t *token, unsigned *nb_children_out, pg_uuid_t **children_out)
PostgreSQL-callable wrapper for get_gate_type().
Background worker and IPC primitives for mmap-backed circuit storage.
constants_t get_constants(bool failure_if_not_possible)
Retrieve the cached OID constants for the current database.
Core types, constants, and utilities shared across ProvSQL.
@ gate_annotation
Transparent single-child wrapper carrying a query-level annotation in extra (inversion-free certifica...
@ gate_assumed
Structural marker over a single child whose sub-circuit was computed under a Boolean-provenance assum...
string uuid2string(pg_uuid_t uuid)
Format a pg_uuid_t as a std::string.
Structure to store the value of various constants.
Oid OID_TYPE_VARCHAR
OID of the VARCHAR TYPE.
Oid OID_FUNCTION_AGG_GUARD_HOLDS
OID of agg_guard_holds(), the truth of a comparison of aggregate results in the database as it is,...
Oid OID_TYPE_FLOAT
OID of the FLOAT TYPE.
Oid OID_TYPE_INT
OID of the INT TYPE.
Oid OID_TYPE_TSTZMULTIRANGE
OID of the tstzmultirange TYPE (PG14+, InvalidOid otherwise).
bool ok
true if constants were loaded
Oid OID_TYPE_BOOL
OID of the BOOL TYPE.
Oid OID_TYPE_NUMMULTIRANGE
OID of the nummultirange TYPE (PG14+, InvalidOid otherwise).
Oid OID_TYPE_INT4MULTIRANGE
OID of the int4multirange TYPE (PG14+, InvalidOid otherwise).