39#include "catalog/pg_type.h"
40#include "utils/uuid.h"
41#include "utils/builtins.h"
42#include "utils/lsyscache.h"
50#include <unordered_map>
76Datum text_datum(
const std::string &s) {
77 text *result = (text *) palloc(VARHDRSZ + s.size());
78 SET_VARSIZE(result, VARHDRSZ + s.size());
79 memcpy(VARDATA(result), s.c_str(), s.size());
80 return PointerGetDatum(result);
85Datum to_datum(
const semiring::Counting &,
unsigned v) {
return Int32GetDatum(
static_cast<int32
>(v)); }
93#if PG_VERSION_NUM >= 140000
115template <
typename Sem>
123 using V =
typename Sem::value_type;
124 std::unordered_map<gate_t, V> mapping;
126 [&sr](
const char *v) {
return sr.
parse_leaf(v); }, drop_table);
129 V out = c.
evaluate<Sem>(g, mapping, sr);
130 return to_datum(sr, std::move(out));
142 const std::unordered_map<gate_t, std::string> *labels)
156 if (SPI_connect() != SPI_OK_CONNECT)
159 char *table_name = get_rel_name(table);
169 const char *qualified = quote_qualified_identifier(
170 get_namespace_name(get_rel_namespace(table)), table_name);
172 constexpr size_t nb_max_uuid_value = 10000000;
174 StringInfoData join_query;
175 initStringInfo(&join_query);
176 bool drop_table =
false;
184 if(uuids.size() == 0) {
185 appendStringInfo(&join_query,
186 "SELECT value, provenance FROM %s WHERE 'f'", qualified);
187 }
else if(uuids.size() <= nb_max_uuid_value) {
188 appendStringInfo(&join_query,
189 "SELECT value, provenance FROM %s t JOIN (VALUES", qualified);
192 appendStringInfo(&join_query,
"%s('%s'::uuid)", first?
"":
",", u.c_str());
196 appendStringInfo(&join_query,
") AS u(id) ON t.provenance=u.id");
198 const char *create_temp_table =
"CREATE TEMP TABLE tmp_uuids(id uuid);";
199 if (SPI_exec(create_temp_table, 0) != SPI_OK_UTILITY) {
205 constexpr size_t batch_size = 1000;
207 for (
size_t offset = 0; offset < uuids.size(); offset += batch_size) {
208 StringInfoData insert_query;
209 initStringInfo(&insert_query);
210 appendStringInfo(&insert_query,
"INSERT INTO tmp_uuids VALUES ");
212 size_t end = std::min(offset + batch_size, uuids.size());
213 for (
size_t i = offset; i < end; ++i) {
214 appendStringInfo(&insert_query,
"('%s')%s", uuids[i].c_str(), (i + 1 == end) ?
"" :
",");
217 int retval=SPI_exec(insert_query.data, 0);
218 pfree(insert_query.data);
220 if(retval != SPI_OK_INSERT) {
227 appendStringInfo(&join_query,
228 "SELECT value, provenance FROM %s t JOIN tmp_uuids u ON t.provenance = u.id", qualified);
231 if (SPI_exec(join_query.data, 0) != SPI_OK_SELECT) {
258 if(
semiring==
"boolexpr" && !OidIsValid(table)) {
261 return pec_boolexpr(bc, root,
nullptr);
270 "Unknown element type for expectation: must be float8");
280 std::vector<std::string> inputs_uuid;
281 std::transform(inputs.begin(), inputs.end(), std::back_inserter(inputs_uuid), [&c](
auto x) {
293 std::unordered_map<gate_t, std::string> gc_labels;
295 return std::string(v);
298 std::unordered_map<gate_t, gate_t> gc_to_bc;
301 std::unordered_map<gate_t, std::string> bc_labels;
302 bc_labels.reserve(gc_labels.size());
303 for(
const auto &kv : gc_labels) {
304 auto it = gc_to_bc.find(kv.first);
305 if(it != gc_to_bc.end())
306 bc_labels[it->second] = kv.second;
308 return pec_boolexpr(bc, root, &bc_labels);
333#if PG_VERSION_NUM >= 140000
350 if (get_typtype(type) == TYPTYPE_ENUM) {
355 throw CircuitException(
"Unknown element type for provenance_evaluate_compiled");
362 Datum token = PG_GETARG_DATUM(0);
364 Oid table = PG_GETARG_OID(1);
366 text *t = PG_GETARG_TEXT_P(2);
367 std::string
semiring(VARDATA(t),VARSIZE(t)-VARHDRSZ);
369 Oid type = get_fn_expr_argtype(fcinfo->flinfo, 3);
372 }
catch(
const std::exception &e) {
375 provsql_error(
"provenance_evaluate_compiled: Unknown exception");
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 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 by enumerating possible worlds.
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().
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.
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.
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_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).
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).