18#include "catalog/namespace.h"
19#include "catalog/pg_type.h"
20#include "parser/parse_coerce.h"
21#include "lib/stringinfo.h"
22#include "utils/array.h"
23#include "utils/builtins.h"
24#include "utils/hsearch.h"
25#include "utils/lsyscache.h"
26#include "utils/memutils.h"
27#include "utils/uuid.h"
35 0x92, 0x0d, 0x4f, 0x02, 0x87, 0x18, 0x53, 0x19,
36 0x95, 0x32, 0xd4, 0xab, 0x83, 0xa6, 0x44, 0x89
45static void name_begin(StringInfo buf,
const char *prefix) {
47 appendBinaryStringInfo(buf, (
const char *)
provsql_ns, UUID_LEN);
48 appendStringInfoString(buf, prefix);
53 static const char hex[] =
"0123456789abcdef";
57 for (i = 0; i < UUID_LEN; ++i) {
58 if (i == 4 || i == 6 || i == 8 || i == 10)
60 out[p++] = hex[u->
data[i] >> 4];
61 out[p++] = hex[u->
data[i] & 0xF];
63 appendBinaryStringInfo(buf, out, 36);
70 appendStringInfoChar(buf,
'{');
71 for (i = 0; i < n; ++i) {
73 appendStringInfoChar(buf,
',');
76 appendStringInfoChar(buf,
'}');
81 unsigned char digest[20];
84 provsql_sha1((
const unsigned char *)buf->data, buf->len, digest);
85 memcpy(u.
data, digest, UUID_LEN);
86 u.
data[6] = (
unsigned char)((u.
data[6] & 0x0F) | 0x50);
87 u.
data[8] = (
unsigned char)((u.
data[8] & 0x3F) | 0x80);
94 return *DatumGetUUIDP(DirectFunctionCall1(uuid_in, CStringGetDatum(text)));
99 static bool known =
false;
106 static bool known =
false;
112 return memcmp(a, b, UUID_LEN);
117 memcpy(r, u, UUID_LEN);
118 return UUIDPGetDatum(r);
131 deconstruct_array(arr, UUIDOID, UUID_LEN,
false,
'c', &elems, &nulls, &n);
133 for (i = 0; i < n; ++i) {
137 u = DatumGetUUIDP(elems[i]);
138 if (memcmp(u->
data, neutral->
data, UUID_LEN) == 0)
152 memcpy(sorted, children,
sizeof(
pg_uuid_t) * n);
208 Oid nsp = LookupExplicitNamespace(
"pg_temp",
true);
209 return OidIsValid(nsp) ? get_relname_relid(name, nsp) : InvalidOid;
219 while ((e = (
PlantedEntry *)hash_seq_search(&seq)) != NULL)
224 if (*link == scope) {
243 if (strcmp(s->
name, name) == 0) {
252 found = (
PlantedScope *)MemoryContextAllocZero(TopMemoryContext,
255 strlcpy(found->
name, name, NAMEDATALEN);
264 return hash_search(
planted, address, HASH_FIND, NULL) != NULL;
270 unsigned info1,
unsigned info2) {
281 provsql_error(
"planting a gate outside the lowering of a recursive CTE");
287 true, info1, info2, NULL);
291 memset(&ctl, 0,
sizeof(ctl));
294 ctl.hcxt = TopMemoryContext;
295 planted = hash_create(
"ProvSQL planted gates", 256, &ctl,
296 HASH_ELEM | HASH_BLOBS | HASH_CONTEXT);
307 char *name = text_to_cstring(PG_GETARG_TEXT_PP(0));
315 char *name = text_to_cstring(PG_GETARG_TEXT_PP(0));
316 char *type_name = text_to_cstring(PG_GETARG_TEXT_PP(1));
321 memset(¬hing, 0xFF,
sizeof(nothing));
324 name, strcmp(type_name,
"plus") == 0 ?
gate_plus :
326 children, n, PG_GETARG_UUID_P(3),
327 (
unsigned)PG_GETARG_INT32(4), (
unsigned)PG_GETARG_INT32(5));
336 const char *canonical_prefix,
422 Oid type = get_fn_expr_argtype(fcinfo->flinfo, argno);
423 Datum val = PG_GETARG_DATUM(argno);
425 if (!OidIsValid(type))
427 if (cast == NULL || cast->
type != type) {
428 Oid funcid = InvalidOid;
431 cast = (
VarcharCast *)MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt,
433 cast->
path = find_coercion_pathway(VARCHAROID, type, COERCION_EXPLICIT,
435 if (cast->
path == COERCION_PATH_FUNC) {
436 fmgr_info_cxt(funcid, &cast->
fn, fcinfo->flinfo->fn_mcxt);
437 cast->
nargs = get_func_nargs(funcid);
438 }
else if (cast->
path != COERCION_PATH_RELABELTYPE) {
440 cast->
path = COERCION_PATH_COERCEVIAIO;
441 getTypeOutputInfo(type, &funcid, &is_varlena);
442 fmgr_info_cxt(funcid, &cast->
fn, fcinfo->flinfo->fn_mcxt);
445 fcinfo->flinfo->fn_extra = cast;
448 switch (cast->
path) {
449 case COERCION_PATH_FUNC: {
451 if (cast->
nargs == 1)
452 r = FunctionCall1(&cast->
fn, val);
453 else if (cast->
nargs == 2)
454 r = FunctionCall2(&cast->
fn, val, Int32GetDatum(-1));
456 r = FunctionCall3(&cast->
fn, val, Int32GetDatum(-1), BoolGetDatum(
true));
457 return text_to_cstring(DatumGetTextPP(r));
459 case COERCION_PATH_RELABELTYPE:
460 return text_to_cstring(DatumGetTextPP(val));
462 return OutputFunctionCall(&cast->
fn, val);
471#define WRITTEN_VALUES_MAX 65536
491 appendStringInfoString(&buf, suffix);
501 memset(&ctl, 0,
sizeof(ctl));
504 ctl.hcxt = TopMemoryContext;
505 written_values = hash_create(
"ProvSQL value gates written", 256, &ctl,
506 HASH_ELEM | HASH_BLOBS | HASH_CONTEXT);
508 if (hash_search(
written_values, &token, HASH_FIND, NULL) == NULL) {
525 children[0] = *token;
526 children[1] = *value_token;
533 provsql_error(
"provenance_semimod: the provenance token must not be NULL");
534 return PG_GETARG_UUID_P(1);
600 aggtok = (
agg_token *)PG_GETARG_POINTER(0);
601 inner = *DatumGetUUIDP(DirectFunctionCall1(uuid_in,
602 CStringGetDatum(aggtok->
tok)));
624 PG_RETURN_ARRAYTYPE_P(construct_empty_array(UUIDOID));
625 aggtok = (
agg_token *)PG_GETARG_POINTER(0);
626 agg = *DatumGetUUIDP(DirectFunctionCall1(uuid_in,
627 CStringGetDatum(aggtok->
tok)));
630 provsql_error(
"provenance_semimod_flat: not the result of an aggregate");
633 for (i = 0; i < n; ++i) {
635 pg_uuid_t *wires = NULL, scaled, pair[2];
638 provsql_error(
"provenance_semimod_flat: unexpected contribution");
647 out[i] = *DatumGetUUIDP(
semimod_gate(&wires[1], &scaled));
652 Datum *elems = (Datum *)palloc(
sizeof(Datum) * (n > 0 ? n : 1));
653 for (i = 0; i < n; ++i)
654 elems[i] = UUIDPGetDatum(&out[i]);
655 PG_RETURN_ARRAYTYPE_P(construct_array(elems, (
int)n, UUIDOID, UUID_LEN,
677 int32 aggfnoid, aggtype;
678 bool is_scalar = !PG_ARGISNULL(4) && PG_GETARG_BOOL(4);
684 if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
685 provsql_error(
"provenance_aggregate: the aggregate function and its "
686 "result type must not be NULL");
687 aggfnoid = PG_GETARG_INT32(0);
688 aggtype = PG_GETARG_INT32(1);
689 if (!PG_ARGISNULL(2))
691 if (!PG_ARGISNULL(3)) {
692 memset(¬hing, 0xFF,
sizeof(nothing));
698 if (n == 0 && !is_scalar)
704 appendStringInfo(&buf,
"%d", aggfnoid);
707 appendStringInfoChar(&buf,
'S');
708 appendStringInfo(&buf,
":%d", aggtype);
710 appendStringInfo(&buf,
":%s", val);
713 true, (
unsigned)aggfnoid,
714 is_scalar ? ((
unsigned)aggtype | 0x80000000u)
723 if (val == NULL && n == 0)
730 memcpy(result->
tok, t.data, 36);
735 PG_RETURN_POINTER(result);
739 return memcmp(a->
data, b->
data, UUID_LEN) == 0;
758 (errmsg(
"provenance_monus is called with first argument NULL")));
759 token1 = PG_GETARG_UUID_P(0);
762 token2 = PG_GETARG_UUID_P(1);
773 children[0] = *token1;
774 children[1] = *token2;
791 token = PG_GETARG_UUID_P(0);
816 if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2))
818 left = PG_GETARG_UUID_P(0);
819 op = PG_GETARG_OID(1);
820 right = PG_GETARG_UUID_P(2);
824 appendStringInfo(&buf,
"%u", op);
828 children[1] = *right;
830 true, (
unsigned)op, 0, NULL);
849 token = PG_GETARG_UUID_P(0);
850 if (!PG_ARGISNULL(1))
851 extra = text_to_cstring(PG_GETARG_TEXT_PP(1));
856 appendStringInfoString(&buf, extra);
869 text *root = PG_GETARG_TEXT_PP(0), *sec = PG_GETARG_TEXT_PP(1);
872 initStringInfo(&buf);
873 appendStringInfo(&buf,
"K%d %d:", PG_GETARG_INT32(2),
874 (
int)VARSIZE_ANY_EXHDR(root));
875 appendBinaryStringInfo(&buf, VARDATA_ANY(root), VARSIZE_ANY_EXHDR(root));
876 appendStringInfo(&buf,
"%d:", (
int)VARSIZE_ANY_EXHDR(sec));
877 appendBinaryStringInfo(&buf, VARDATA_ANY(sec), VARSIZE_ANY_EXHDR(sec));
878 PG_RETURN_TEXT_P(cstring_to_text_with_len(buf.data, buf.len));
894 if (strcmp(assumption,
"boolean") != 0 && strcmp(assumption,
"absorptive") != 0)
895 ereport(ERROR, (errmsg(
"provenance_assume: unknown assumption %s", assumption)));
897 appendStringInfoString(&buf, assumption);
901 info1 != 0, info1, 0, assumption);
914 ereport(ERROR, (errmsg(
"provenance_assume: unknown assumption NULL")));
916 text_to_cstring(PG_GETARG_TEXT_PP(1)), 0);
941 ArrayType *positions;
945 StringInfoData buf, extra;
948 if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
950 token = PG_GETARG_UUID_P(0);
951 positions = PG_GETARG_ARRAYTYPE_P(1);
952 deconstruct_array(positions, INT4OID,
sizeof(int32),
true,
'i',
958 appendStringInfoChar(&buf,
'{');
959 initStringInfo(&extra);
960 appendStringInfoChar(&extra,
'{');
961 for (i = 0; i < n; ++i) {
963 appendStringInfoChar(&buf,
',');
964 appendStringInfoChar(&extra,
',');
967 appendStringInfoString(&buf,
"NULL");
968 appendStringInfo(&extra,
"{NULL,%d}", i + 1);
970 int32 pos = DatumGetInt32(elems[i]);
971 appendStringInfo(&buf,
"%d", pos);
973 appendStringInfo(&extra,
"{NULL,%d}", i + 1);
975 appendStringInfo(&extra,
"{%d,%d}", pos, i + 1);
978 appendStringInfoChar(&buf,
'}');
979 appendStringInfoChar(&extra,
'}');
982 false, 0, 0, n > 0 ? extra.
data : NULL);
993 int32 pos1 = PG_ARGISNULL(1) ? 0 : PG_GETARG_INT32(1);
994 int32 pos2 = PG_ARGISNULL(2) ? 0 : PG_GETARG_INT32(2);
998 token = PG_GETARG_UUID_P(0);
1001 if (!PG_ARGISNULL(1))
1002 appendStringInfo(&buf,
"%d", pos1);
1003 appendStringInfoChar(&buf,
',');
1004 if (!PG_ARGISNULL(2))
1005 appendStringInfo(&buf,
"%d", pos2);
1008 true, (
unsigned)pos1, (
unsigned)pos2, NULL);
1017 pg_uuid_t arith, *children = NULL, nothing;
1019 int32 op = PG_ARGISNULL(0) ? 0 : PG_GETARG_INT32(0);
1022 if (!PG_ARGISNULL(0))
1023 appendStringInfo(&buf,
"%d", op);
1024 if (!PG_ARGISNULL(1)) {
1025 ArrayType *arr = PG_GETARG_ARRAYTYPE_P(1);
1026 if (array_contains_nulls(arr))
1027 provsql_error(
"provenance_arith: children array must not contain NULL elements");
1028 memset(¬hing, 0xFF,
sizeof(nothing));
1034 true, (
unsigned)op, 0, NULL);
void provsql_sha1(const unsigned char *data, size_t len, unsigned char out[20])
SHA-1 of len bytes of data (RFC 3174).
void agg_token_set_value(agg_token *aggtok, const char *val, size_t len)
Set the value of aggtok to the len first bytes of val.
Aggregate-provenance token type used in SQL aggregate functions.
Datum provenance_monus(PG_FUNCTION_ARGS)
token1 ⊖ token2.
Datum provenance_semimod_flat(PG_FUNCTION_ARGS)
The contributions semimod(v_i, token ⊗ k_i) of the aggregate result val, whose gate aggregates the co...
Datum provenance_semimod_nested(PG_FUNCTION_ARGS)
The semimodule gate of a row whose value is itself an aggregate result: semimod(the inner aggregate's...
Datum provenance_times(PG_FUNCTION_ARGS)
⊗ of a list of tokens.
static void name_begin(StringInfo buf, const char *prefix)
Start the name of a gate address.
Datum provenance_arith(PG_FUNCTION_ARGS)
The arith gate applying operator op (a provsql_arith_op, its info1) to children, in order.
static HTAB * written_values
Datum provenance_eq(PG_FUNCTION_ARGS)
The where-provenance eq gate of token, equating positions pos1 and pos2 (its infos).
static pg_uuid_t value_gate(const char *prefix, const char *suffix, const char *extra)
The value gate of the text str, at the address named name ("value" followed by str,...
Datum inversion_free_key(PG_FUNCTION_ARGS)
The order key of an input on the inversion-free route, "K<factor> <bytes of root>:<root><bytes of sec...
pg_uuid_t provsql_plant_canonical(const char *work_name, gate_type type, const pg_uuid_t *children, int n, const pg_uuid_t *target, unsigned info1, unsigned info2)
Pre-create ("plant") a gate at the canonical address of a multiset of tokens, for the working table o...
static const pg_uuid_t * address_of_zero(void)
static pg_uuid_t nary_gate(gate_type type, const char *plain_prefix, const char *canonical_prefix, const pg_uuid_t *children, int n)
A gate of type type over children, unless this backend planted one at the canonical address of their ...
Datum annotate(PG_FUNCTION_ARGS)
A transparent annotation gate over token, carrying extra.
static const pg_uuid_t * address_of_one(void)
static pg_uuid_t name_end(StringInfo buf)
The version-5 UUID of the name accumulated in buf.
static pg_uuid_t constant_uuid(const char *text)
The UUID text (one of the constants of provsql_utils.h).
static pg_uuid_t assumed_gate(const pg_uuid_t *token, const char *assumption, unsigned info1)
The assumed wrapper of token under assumption, with info1 as the route tag (0 for none).
Datum provenance_aggregate(PG_FUNCTION_ARGS)
The agg gate of a group, paired with the aggregate's value.
static Datum semimod_gate(const pg_uuid_t *value_token, const pg_uuid_t *token)
The semimod gate value_token ⊗ token.
static void name_add_uuid_array(StringInfo buf, const pg_uuid_t *u, int n)
Append the text form of a uuid[], "{u1,u2,...}".
Datum provenance_plus(PG_FUNCTION_ARGS)
⊕ of an array of tokens.
static PlantedScope * planted_current
Datum planted_scope(PG_FUNCTION_ARGS)
SQL entry point of planted_open_scope(), called by the drivers of recursive CTEs right after they (re...
void provsql_gate_builders_forget(void)
Forget what gate_builders.c remembers of the store (planted gates, value gates written).
Datum provenance_cmp(PG_FUNCTION_ARGS)
The comparison gate left op right of a HAVING condition.
static int token_cmp(const void *a, const void *b)
Datum provenance_assume(PG_FUNCTION_ARGS)
Wrap token in the assumption marker assumption ('boolean' or 'absorptive').
static int filtered_tokens(ArrayType *arr, const pg_uuid_t *neutral, pg_uuid_t **out)
The elements of a uuid[] that are neither NULL nor neutral, in order.
#define WRITTEN_VALUES_MAX
static pg_uuid_t canonical_address(const char *canonical_prefix, const pg_uuid_t *children, int n)
The canonical address, "<prefix>{sorted children}".
static bool is_planted(const pg_uuid_t *address)
Datum provenance_semimod(PG_FUNCTION_ARGS)
The semimodule gate val ⊗ token of an aggregated row.
static Oid temp_table_oid(const char *name)
OID of the temporary table name of this backend, if any.
static int planted_next_id
Datum assume_boolean(PG_FUNCTION_ARGS)
The Boolean-assumption wrapper the safe-query rewriter puts on every per-row root,...
static void planted_forget(PlantedScope *scope)
Datum provenance_project(PG_FUNCTION_ARGS)
The where-provenance project gate of token: its text lists, for each output position,...
Datum plant_canonical(PG_FUNCTION_ARGS)
SQL entry point of provsql_plant_canonical().
static Datum uuid_result(const pg_uuid_t *u)
static const unsigned char provsql_ns[UUID_LEN]
uuid_ns_provsql(), the namespace of every gate address.
Datum provenance_delta(PG_FUNCTION_ARGS)
δ(token).
static const pg_uuid_t * semimod_token_argument(FunctionCallInfo fcinfo)
static PlantedScope * planted_open_scope(const char *name, bool reset)
Open the scope of the working table name, just (re)created: forget what was planted for the table it ...
static PlantedScope * planted_scopes
static char * varchar_of_argument(FunctionCallInfo fcinfo, int argno)
CAST(val AS varchar) of argument argno, as a C string.
static bool same_token(const pg_uuid_t *a, const pg_uuid_t *b)
static void name_add_uuid(StringInfo buf, const pg_uuid_t *u)
Append a UUID in the text form of uuid_out.
Datum provenance_semimod_nullable(PG_FUNCTION_ARGS)
provenance_semimod for the aggregates that see their NULL inputs (array_agg, json_agg,...
#define provsql_error(fmt,...)
Report a fatal ProvSQL error and abort the current transaction.
void provsql_internal_create_gate(const pg_uuid_t *token, gate_type type, unsigned nb_children, const pg_uuid_t *children_data)
Internal entry point behind create_gate(): cache + worker IPC.
void provsql_internal_create_gate_with(const pg_uuid_t *token, gate_type type, unsigned nb_children, const pg_uuid_t *children, bool has_infos, unsigned info1, unsigned info2, const char *extra)
Create a gate together with its infos and its text, in one message that is not answered.
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.
Core types, constants, and utilities shared across ProvSQL.
#define PROVSQL_GATE_ZERO_UUID
UUID of the semiring zero gate: the result of the SQL function gate_zero(), created with the extensio...
#define PROVSQL_GATE_ONE_UUID
UUID of the semiring one gate, the result of gate_one().
@ gate_annotation
Transparent single-child wrapper carrying a query-level annotation in extra (inversion-free certifica...
@ gate_arith
n-ary arithmetic gate over scalar-valued children (info1 holds operator tag)
@ gate_assumed
Structural marker over a single child whose sub-circuit was computed under a Boolean-provenance assum...
@ PROVSQL_ROUTE_SQ_REWRITE
Hierarchical-CQ read-once rewrite (src/safe_query.c).
pg_uuid_t address
Hash key.
A working table with planted gates.
struct PlantedScope * next
Oid relid
The table, as created by the lowering.
Aggregate token bundling a provenance UUID with a running value.
char tok[2 *UUID_LEN+5]
Provenance UUID as a text string.