19SET search_path
TO provsql;
27CREATE TYPE PROVENANCE_GATE
AS
96CREATE OR REPLACE
FUNCTION create_gate(
99 children UUID[]
DEFAULT NULL)
101 'provsql',
'create_gate' LANGUAGE C PARALLEL SAFE;
108CREATE OR REPLACE
FUNCTION get_gate_type(
110 RETURNS PROVENANCE_GATE
AS
111 'provsql',
'get_gate_type' LANGUAGE C IMMUTABLE PARALLEL SAFE;
113CREATE OR REPLACE
FUNCTION get_children(
116 'provsql',
'get_children' LANGUAGE C IMMUTABLE PARALLEL SAFE;
123CREATE OR REPLACE
FUNCTION set_prob(
124 token UUID, p
DOUBLE PRECISION)
126 'provsql',
'set_prob' LANGUAGE C PARALLEL SAFE;
128CREATE OR REPLACE
FUNCTION get_prob(
130 RETURNS DOUBLE PRECISION AS
131 'provsql',
'get_prob' LANGUAGE C STABLE PARALLEL SAFE;
149CREATE OR REPLACE
FUNCTION set_infos(
150 token UUID, info1
INT, info2
INT DEFAULT NULL)
152 'provsql',
'set_infos' LANGUAGE C PARALLEL SAFE;
155CREATE OR REPLACE
FUNCTION get_infos(
156 token UUID,
OUT info1
INT,
OUT info2
INT)
158 'provsql',
'get_infos' LANGUAGE C STABLE PARALLEL SAFE;
184CREATE OR REPLACE
FUNCTION provenance_assume(token UUID, assumption TEXT)
190 IF token
IS NULL THEN
193 IF assumption
NOT IN (
'BOOLEAN',
'absorptive')
THEN
194 RAISE EXCEPTION
'provenance_assume: unknown assumption %', assumption;
196 wrapped := public.uuid_generate_v5(uuid_ns_provsql(),
197 concat(
'assumed', assumption, token));
198 PERFORM create_gate(wrapped,
'assumed',
ARRAY[token]);
199 PERFORM set_extra(wrapped, assumption);
202$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public
203 SECURITY DEFINER PARALLEL SAFE;
209CREATE OR REPLACE
FUNCTION assume_boolean(token UUID)
RETURNS UUID
AS
211SELECT provsql.provenance_assume(token,
'BOOLEAN');
212$$
LANGUAGE sql SECURITY DEFINER PARALLEL SAFE;
227CREATE OR REPLACE
FUNCTION annotate(token UUID, extra TEXT)
RETURNS UUID
AS
232 IF token
IS NULL THEN
235 annotated := public.uuid_generate_v5(uuid_ns_provsql(),
236 concat(
'annotation', token, extra));
237 PERFORM create_gate(annotated,
'annotation',
ARRAY[token]);
238 PERFORM set_extra(annotated, extra);
241$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public
242 SECURITY DEFINER PARALLEL SAFE;
271CREATE OR REPLACE
FUNCTION cond(target UUID, evidence UUID)
RETURNS UUID
AS
281 IF evidence
IS NULL OR evidence = gate_one()
THEN
286 tgt := coalesce(target, gate_one());
288 IF get_gate_type(tgt) =
'conditioned' THEN
292 ch := get_children(tgt);
294 ev := provenance_times(ch[
2], evidence);
295 jnt := provenance_times(ch[
3], evidence);
298 jnt := provenance_times(tgt, evidence);
301 result := public.uuid_generate_v5(uuid_ns_provsql(),
302 concat(
'conditioned', tgt, ev, jnt));
303 PERFORM create_gate(
result,
'conditioned',
ARRAY[tgt, ev, jnt]);
306$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public
307 SECURITY DEFINER PARALLEL SAFE;
316CREATE OPERATOR | (LEFTARG=UUID, RIGHTARG=UUID,
PROCEDURE=cond);
326CREATE OR REPLACE
FUNCTION cond_predicate(target UUID, predicate
BOOLEAN)
330 RAISE EXCEPTION
'UUID | (predicate) must be rewritten by the ProvSQL '
331 'planner hook: the right operand must be a Boolean combination of '
332 'random_variable / aggregate comparisons (is provsql.active off?)';
334$$
LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
336CREATE OPERATOR | (LEFTARG=UUID, RIGHTARG=
BOOLEAN,
PROCEDURE=cond_predicate);
350CREATE OR REPLACE
FUNCTION regular_indicator(cond
BOOLEAN)
RETURNS UUID
AS
352 SELECT CASE WHEN cond
THEN provsql.gate_one()
ELSE provsql.gate_zero()
END;
353$$
LANGUAGE sql IMMUTABLE PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
377CREATE OR REPLACE
FUNCTION given(evidence UUID)
RETURNS UUID
AS
380$$
LANGUAGE sql IMMUTABLE PARALLEL SAFE;
390CREATE OPERATOR | (RIGHTARG=UUID,
PROCEDURE=given);
401CREATE OR REPLACE
FUNCTION given_predicate(predicate
BOOLEAN)
RETURNS UUID
AS
404 RAISE EXCEPTION
'prefix | (predicate) must be rewritten by the ProvSQL '
405 'planner hook: the operand must be a Boolean combination of '
406 'random_variable / aggregate comparisons (is provsql.active off?)';
408$$
LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
410CREATE OPERATOR | (RIGHTARG=
BOOLEAN,
PROCEDURE=given_predicate);
442CREATE OR REPLACE
FUNCTION provenance_not(event UUID)
RETURNS UUID
AS
444 SELECT provsql.provenance_monus(provsql.gate_one(), event);
445$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
446 SET search_path=provsql,pg_temp,public;
455CREATE OPERATOR ! (RIGHTARG=UUID,
PROCEDURE=provenance_not);
469CREATE OR REPLACE
FUNCTION inversion_free_key(root TEXT, sec TEXT, factor
INT)
471$$
SELECT 'K' || factor::TEXT ||
' '
472 || octet_length(root) ||
':' || root
473 || octet_length(sec) ||
':' || sec $$
474 LANGUAGE sql IMMUTABLE PARALLEL SAFE;
490CREATE OR REPLACE
FUNCTION set_extra(
491 token UUID, data TEXT)
493 'provsql',
'set_extra' LANGUAGE C PARALLEL SAFE STRICT;
495CREATE OR REPLACE
FUNCTION get_extra(token UUID)
497 'provsql',
'get_extra' LANGUAGE C STABLE PARALLEL SAFE
RETURNS NULL ON NULL INPUT;
506CREATE OR REPLACE
FUNCTION get_nb_gates()
RETURNS BIGINT AS
507 'provsql',
'get_nb_gates' LANGUAGE C PARALLEL SAFE;
524CREATE OR REPLACE
FUNCTION delete_statement_trigger()
534 delete_token := public.uuid_generate_v4();
536 PERFORM create_gate(delete_token,
'input');
540 FROM pg_stat_activity
541 WHERE pid = pg_backend_pid();
543 INSERT INTO delete_provenance (delete_token, query, deleted_by, deleted_at)
544 VALUES (delete_token, query_text,
current_user,
CURRENT_TIMESTAMP);
546 EXECUTE format(
'INSERT INTO %I.%I SELECT * FROM OLD_TABLE;', TG_TABLE_SCHEMA, TG_TABLE_NAME);
548 FOR r
IN (
SELECT *
FROM OLD_TABLE) LOOP
549 old_token := r.provsql;
550 new_token := provenance_monus(old_token, delete_token);
552 EXECUTE format(
'UPDATE %I.%I SET provsql = $1 WHERE provsql = $2;', TG_TABLE_SCHEMA, TG_TABLE_NAME)
553 USING new_token, old_token;
558$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp SECURITY DEFINER;
582CREATE OR REPLACE
FUNCTION set_table_info(
583 relid OID, kind TEXT, block_key INT2[]
DEFAULT ARRAY[]::INT2[])
585 'provsql',
'set_table_info' LANGUAGE C PARALLEL SAFE;
588CREATE OR REPLACE
FUNCTION remove_table_info(relid OID)
590 'provsql',
'remove_table_info' LANGUAGE C PARALLEL SAFE;
601CREATE OR REPLACE
FUNCTION get_table_info(
602 relid OID,
OUT kind TEXT,
OUT block_key INT2[])
604 'provsql',
'get_table_info' LANGUAGE C STABLE PARALLEL SAFE;
624CREATE OR REPLACE
FUNCTION set_ancestors(
625 relid OID, ancestors OID[]
DEFAULT ARRAY[]::OID[])
627 'provsql',
'set_ancestors' LANGUAGE C PARALLEL SAFE;
631CREATE OR REPLACE
FUNCTION remove_ancestors(relid OID)
633 'provsql',
'remove_ancestors' LANGUAGE C PARALLEL SAFE;
642CREATE OR REPLACE
FUNCTION get_ancestors(relid OID)
644 'provsql',
'get_ancestors' LANGUAGE C STABLE PARALLEL SAFE;
664CREATE OR REPLACE
FUNCTION provenance_guard()
665 RETURNS TRIGGER AS $$
667 IF TG_OP =
'INSERT' THEN
668 IF NEW.provsql
IS NULL THEN
669 NEW.provsql := public.uuid_generate_v4();
671 PERFORM provsql.set_table_info(TG_RELID,
'opaque');
673 ELSIF TG_OP =
'UPDATE' THEN
674 IF NEW.provsql
IS DISTINCT FROM OLD.provsql
THEN
675 PERFORM provsql.set_table_info(TG_RELID,
'opaque');
680$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public
696CREATE OR REPLACE
FUNCTION add_provenance(_tbl REGCLASS)
704 SELECT 1 FROM pg_attribute
705 WHERE attrelid = _tbl
AND attname =
'provsql' AND NOT attisdropped
707 RAISE NOTICE
'table % already has provenance tracking', _tbl;
716 EXECUTE format(
'ALTER TABLE %s ADD COLUMN provsql UUID', _tbl);
718 'UPDATE %s SET provsql = public.uuid_generate_v4() WHERE provsql IS NULL',
720 EXECUTE format(
'CREATE INDEX ON %s(provsql)', _tbl);
722 'CREATE TRIGGER provenance_guard BEFORE INSERT OR UPDATE OF provsql '
723 'ON %s FOR EACH ROW EXECUTE PROCEDURE provsql.provenance_guard()',
725 PERFORM provsql.set_table_info(_tbl::oid,
'tid');
730 PERFORM provsql.set_ancestors(_tbl::oid,
ARRAY[_tbl::oid]);
732$$
LANGUAGE plpgsql SECURITY DEFINER;
741CREATE OR REPLACE
FUNCTION remove_provenance(_tbl REGCLASS)
746 PERFORM provsql.remove_table_info(_tbl::oid);
751 EXECUTE format(
'DROP TRIGGER provenance_guard on %s', _tbl);
752 EXCEPTION
WHEN undefined_object
THEN
754 EXECUTE format(
'ALTER TABLE %s DROP COLUMN provsql', _tbl);
756 EXECUTE format(
'DROP TRIGGER add_gate on %s', _tbl);
757 EXCEPTION
WHEN undefined_object
THEN
760 EXECUTE format(
'DROP TRIGGER insert_statement on %s', _tbl);
761 EXECUTE format(
'DROP TRIGGER update_statement on %s', _tbl);
762 EXECUTE format(
'DROP TRIGGER delete_statement on %s', _tbl);
763 EXCEPTION
WHEN undefined_object
THEN
779CREATE OR REPLACE
FUNCTION repair_key(_tbl REGCLASS, key_att TEXT)
785 block_key_cols INT2[];
792 block_key_cols :=
ARRAY[]::INT2[];
794 SELECT array_agg(a.attnum
ORDER BY t.ord)::INT2[]
796 FROM unnest(string_to[](key_att,
','))
WITH ORDINALITY
AS t(name, ord)
799 AND a.attname = trim(t.name)
801 AND NOT a.attisdropped;
802 IF block_key_cols
IS NULL OR array_length(block_key_cols,
1)
IS NULL THEN
803 RAISE EXCEPTION
'repair_key: could not resolve key columns from "%"', key_att;
805 IF array_length(block_key_cols,
1) >
16 THEN
806 RAISE EXCEPTION
'repair_key: block key wider than 16 columns is not supported';
816 EXECUTE format(
'ALTER TABLE %s ADD COLUMN provsql_temp UUID DEFAULT public.uuid_generate_v4()', _tbl);
829 'CREATE TEMP TABLE provsql_repair_key_tmp ON COMMIT DROP AS
830 SELECT public.uuid_generate_v4() AS provsql_key_token,
831 COUNT(*) AS provsql_group_size
833 rows_query := format(
834 'SELECT t.provsql_temp,
835 k.provsql_key_token AS key_token,
836 ROW_NUMBER() OVER (ORDER BY t.ctid) AS within_group,
837 k.provsql_group_size AS group_size
838 FROM %s t CROSS JOIN provsql_repair_key_tmp k', _tbl);
841 'CREATE TEMP TABLE provsql_repair_key_tmp ON COMMIT DROP AS
843 public.uuid_generate_v4() AS provsql_key_token,
844 COUNT(*) AS provsql_group_size
846 GROUP BY %1$s', key_att, _tbl);
847 rows_query := format(
848 'SELECT t.provsql_temp,
849 k.provsql_key_token AS key_token,
850 ROW_NUMBER() OVER (PARTITION BY k.provsql_key_token
851 ORDER BY t.ctid) AS within_group,
852 k.provsql_group_size AS group_size
854 JOIN provsql_repair_key_tmp k USING (%1$s)', key_att, _tbl);
858 FOR r
IN SELECT provsql_key_token
FROM provsql_repair_key_tmp LOOP
859 PERFORM provsql.create_gate(r.provsql_key_token,
'input');
863 FOR r
IN EXECUTE rows_query LOOP
864 PERFORM provsql.create_gate(r.provsql_temp,
'mulinput',
ARRAY[r.key_token]);
865 PERFORM provsql.set_prob(r.provsql_temp,
1./r.group_size);
866 PERFORM provsql.set_infos(r.provsql_temp, r.within_group::
INT);
869 DROP TABLE provsql_repair_key_tmp;
871 EXECUTE format(
'ALTER TABLE %s ALTER COLUMN provsql_temp DROP DEFAULT', _tbl);
872 EXECUTE format(
'ALTER TABLE %s RENAME COLUMN provsql_temp TO provsql', _tbl);
873 EXECUTE format(
'CREATE INDEX ON %s(provsql)', _tbl);
875 'CREATE TRIGGER provenance_guard BEFORE INSERT OR UPDATE OF provsql '
876 'ON %s FOR EACH ROW EXECUTE PROCEDURE provsql.provenance_guard()',
878 PERFORM provsql.set_table_info(_tbl::oid,
'bid', block_key_cols);
881 PERFORM provsql.set_ancestors(_tbl::oid,
ARRAY[_tbl::oid]);
896CREATE OR REPLACE
FUNCTION cleanup_table_info()
897 RETURNS event_trigger
AS
903 SELECT objid
FROM pg_event_trigger_dropped_objects()
904 WHERE object_type
IN (
'table',
'foreign table',
'materialized view')
906 PERFORM provsql.remove_table_info(r.objid);
911DROP EVENT
TRIGGER IF EXISTS provsql_cleanup_table_info;
914CREATE EVENT
TRIGGER provsql_cleanup_table_info
ON sql_drop
915 EXECUTE PROCEDURE provsql.cleanup_table_info();
930CREATE OR REPLACE
FUNCTION create_provenance_mapping(
934 preserve_case BOOL
DEFAULT 'f'
942 IF (
CASE WHEN preserve_case
THEN to_regclass(format(
'%I', newtbl))
943 ELSE to_regclass(newtbl)
END)
IS NOT NULL THEN
944 RAISE NOTICE
'mapping table % already exists', newtbl;
951 IF to_regclass(
'pg_temp.tmp_provsql')
IS NOT NULL THEN
952 DROP TABLE tmp_provsql;
954 EXECUTE format(
'CREATE TEMP TABLE tmp_provsql ON COMMIT DROP AS TABLE %s', oldtbl);
955 ALTER TABLE tmp_provsql RENAME provsql
TO provenance;
956 IF preserve_case
THEN
957 EXECUTE format(
'CREATE TABLE %I AS SELECT %s AS value, provenance FROM tmp_provsql', newtbl, att);
958 EXECUTE format(
'CREATE INDEX ON %I(provenance)', newtbl);
960 EXECUTE format(
'CREATE TABLE %s AS SELECT %s AS value, provenance FROM tmp_provsql', newtbl, att);
961 EXECUTE format(
'CREATE INDEX ON %s(provenance)', newtbl);
977CREATE OR REPLACE
FUNCTION create_provenance_mapping_view(
981 preserve_case BOOL
DEFAULT false
988 IF preserve_case
THEN
990 'CREATE OR REPLACE VIEW %I AS SELECT %s AS value, provsql AS provenance FROM %s',
997 'CREATE OR REPLACE VIEW %s AS SELECT %s AS value, provsql AS provenance FROM %s',
1015CREATE OR REPLACE
FUNCTION uuid_ns_provsql()
RETURNS UUID
AS
1018 SELECT '920d4f02-8718-5319-9532-d4ab83a64489'::UUID
1019$$
LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
1022CREATE OR REPLACE
FUNCTION gate_zero()
RETURNS UUID
AS
1024 SELECT public.uuid_generate_v5(provsql.uuid_ns_provsql(),
'zero');
1025$$
LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
1028CREATE OR REPLACE
FUNCTION gate_one()
RETURNS UUID
AS
1030 SELECT public.uuid_generate_v5(provsql.uuid_ns_provsql(),
'one');
1031$$
LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
1034CREATE OR REPLACE
FUNCTION epsilon()
RETURNS DOUBLE PRECISION AS
1036 SELECT CAST(
0.
001 AS DOUBLE PRECISION)
1037$$
LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
1063CREATE OR REPLACE
FUNCTION provenance_times(VARIADIC tokens UUID[])
1068 filtered_tokens UUID[];
1071 SELECT array_agg(t)
FROM unnest(tokens) t
WHERE t
IS NOT NULL AND t <> gate_one()
INTO filtered_tokens;
1078 CASE coalesce(array_length(filtered_tokens,
1),
0)
1080 times_token:=gate_one();
1082 times_token:=filtered_tokens[
1];
1087 SELECT uuid_generate_v5(uuid_ns_provsql(),
1088 concat(
'times-canonical', array_agg(t
ORDER BY t)))
1089 FROM unnest(filtered_tokens) t
1091 IF get_gate_type(canonical) =
'times' THEN
1094 times_token := canonical;
1096 times_token := uuid_generate_v5(uuid_ns_provsql(),concat(
'times',filtered_tokens));
1098 PERFORM create_gate(times_token,
'times', ARRAY_AGG(t))
FROM UNNEST(filtered_tokens)
AS t
WHERE t
IS NOT NULL;
1104$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public SECURITY DEFINER PARALLEL SAFE;
1112CREATE OR REPLACE
FUNCTION provenance_monus(token1 UUID, token2 UUID)
1118 IF token1
IS NULL THEN
1119 RAISE EXCEPTION
USING MESSAGE=
'provenance_monus is called with first argument NULL';
1122 IF token2
IS NULL THEN
1128 IF token1 = token2
THEN
1130 monus_token:=gate_zero();
1131 ELSIF token1 = gate_zero()
THEN
1133 monus_token:=gate_zero();
1134 ELSIF token2 = gate_zero()
THEN
1136 monus_token:=token1;
1138 monus_token:=uuid_generate_v5(uuid_ns_provsql(),concat(
'monus',token1,token2));
1139 PERFORM create_gate(monus_token,
'monus',
ARRAY[token1::UUID, token2::UUID]);
1144$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public SECURITY DEFINER PARALLEL SAFE IMMUTABLE;
1154CREATE OR REPLACE
FUNCTION provenance_project(token UUID, VARIADIC positions
INT[])
1161 project_token:=uuid_generate_v5(uuid_ns_provsql(),concat(
'project', token, positions));
1162 PERFORM create_gate(project_token,
'project',
ARRAY[token]);
1163 PERFORM set_extra(project_token, ARRAY_AGG(pair)::TEXT)
1165 SELECT ARRAY[(
CASE WHEN info=
0 THEN NULL ELSE info
END), idx]
AS pair
1166 FROM unnest(positions)
WITH ORDINALITY
AS a(info, idx)
1170 RETURN project_token;
1172$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public SECURITY DEFINER PARALLEL SAFE IMMUTABLE;
1181CREATE OR REPLACE
FUNCTION provenance_eq(token UUID, pos1
INT, pos2
INT)
1188 eq_token:=uuid_generate_v5(uuid_ns_provsql(),concat(
'eq',token,pos1,
',',pos2));
1190 PERFORM create_gate(eq_token,
'eq',
ARRAY[token::UUID]);
1191 PERFORM set_infos(eq_token, pos1, pos2);
1194$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public SECURITY DEFINER PARALLEL SAFE IMMUTABLE;
1212CREATE OR REPLACE
FUNCTION provenance_plus(tokens UUID[])
1218 filtered_tokens UUID[];
1221 SELECT array_agg(t)
FROM unnest(tokens) t
1222 WHERE t
IS NOT NULL AND t <> gate_zero()
1223 INTO filtered_tokens;
1225 c:=array_length(filtered_tokens,
1);
1228 plus_token := gate_zero();
1230 plus_token := filtered_tokens[
1];
1235 SELECT uuid_generate_v5(uuid_ns_provsql(),
1236 concat(
'plus-canonical', array_agg(t
ORDER BY t)))
1237 FROM unnest(filtered_tokens) t
1239 IF get_gate_type(canonical) =
'plus' THEN
1242 plus_token := canonical;
1244 plus_token := uuid_generate_v5(
1246 concat(
'plus', filtered_tokens));
1248 PERFORM create_gate(plus_token,
'plus', filtered_tokens);
1254$$
LANGUAGE plpgsql STRICT
SET search_path=provsql,pg_temp,public SECURITY DEFINER PARALLEL SAFE IMMUTABLE;
1301CREATE OR REPLACE
FUNCTION eval_recursive(
1306 max_iter
INT DEFAULT 1000)
1323 absorptive_mode
BOOLEAN :=
1324 coalesce(current_setting(
'provsql.provenance',
true),
'semiring')
1325 IN (
'absorptive',
'BOOLEAN');
1326 truncated
BOOLEAN :=
false;
1327 ntuples
INT :=
NULL;
1329 EXECUTE format(
'DROP TABLE IF EXISTS %I', work_name);
1330 DROP TABLE IF EXISTS _new;
1334 EXECUTE format(
'CREATE TEMP TABLE %I (%s, provsql UUID)', work_name, coldef);
1335 EXECUTE format(
'CREATE TEMP TABLE _new (LIKE %I)', work_name);
1341 IF iters > max_iter
THEN
1342 RAISE EXCEPTION
'eval_recursive: no fixpoint after % rounds (cyclic data?)', max_iter;
1349 EXECUTE 'TRUNCATE _new';
1350 EXECUTE format(
'INSERT INTO _new(%s) %s', colnames, body_sql);
1351 GET DIAGNOSTICS new_count = ROW_COUNT;
1355 'SELECT EXISTS((TABLE _new EXCEPT TABLE %1$I) UNION ALL (TABLE %1$I EXCEPT TABLE _new))',
1356 work_name)
INTO changed;
1361 IF absorptive_mode
AND ntuples
IS NULL THEN
1363 'SELECT NOT EXISTS('
1364 ||
'(SELECT %2$s FROM _new EXCEPT SELECT %2$s FROM %1$I) UNION ALL '
1365 ||
'(SELECT %2$s FROM %1$I EXCEPT SELECT %2$s FROM _new))',
1366 work_name, colnames)
INTO set_stable;
1368 ntuples := new_count;
1373 EXECUTE format(
'TRUNCATE %I', work_name);
1374 EXECUTE format(
'INSERT INTO %1$I(%2$s) SELECT %2$s FROM _new', work_name, colnames);
1378 EXIT
WHEN NOT changed;
1385 IF absorptive_mode
AND ntuples
IS NOT NULL AND iters >= ntuples +
1 THEN
1395 'UPDATE %I SET provsql = provsql.provenance_assume(provsql, ''absorptive'')',
1399$$
LANGUAGE plpgsql
SET client_min_messages = warning;
1408CREATE OR REPLACE
FUNCTION provenance_cmp(
1419 cmp_token := public.uuid_generate_v5(
1421 concat(
'cmp', left_token::TEXT, comparison_op::TEXT, right_token::TEXT)
1424 PERFORM create_gate(cmp_token,
'cmp',
ARRAY[left_token, right_token]);
1425 PERFORM set_infos(cmp_token, comparison_op::
INTEGER);
1429 SET search_path=provsql,pg_temp,public
1451CREATE OR REPLACE
FUNCTION provenance_arith(
1460 arith_token := public.uuid_generate_v5(
1462 concat(
'arith', op::TEXT, children::TEXT)
1464 PERFORM create_gate(arith_token,
'arith', children);
1465 PERFORM set_infos(arith_token, op);
1469 SET search_path=provsql,pg_temp,public
1494CREATE OR REPLACE
FUNCTION provenance_evaluate_compiled(
1496 token2value REGCLASS,
1498 element_one ANYELEMENT)
1499RETURNS ANYELEMENT
AS
1500 'provsql',
'provenance_evaluate_compiled' LANGUAGE C PARALLEL SAFE STABLE;
1519CREATE OR REPLACE
FUNCTION provenance_evaluate(
1521 token2value REGCLASS,
1522 element_one ANYELEMENT,
1524 plus_function REGPROC,
1525 times_function REGPROC,
1526 monus_function REGPROC,
1527 delta_function REGPROC)
1528 RETURNS ANYELEMENT
AS
1531 gate_type PROVENANCE_GATE;
1532 result ALIAS
FOR $
0;
1538 SELECT get_gate_type(token)
INTO gate_type;
1540 IF gate_type
IS NULL THEN
1543 ELSIF gate_type =
'input' THEN
1544 EXECUTE format(
'SELECT value FROM %s WHERE provenance=%L', token2value, token)
1546 IF result IS NULL THEN
1547 result := element_one;
1549 ELSIF gate_type =
'mulinput' THEN
1550 SELECT concat(
'{',(get_children(token))[
1]::TEXT,
'=',(get_infos(token)).info1,
'}')
1552 ELSIF gate_type=
'update' THEN
1553 EXECUTE format(
'SELECT value FROM %s WHERE provenance=%L',token2value,token)
INTO result;
1554 IF result IS NULL THEN
1555 result:=element_one;
1557 ELSIF gate_type =
'plus' THEN
1558 EXECUTE format(
'SELECT %s(provsql.provenance_evaluate(t,%L,%L::%s,%L,%L,%L,%L,%L)) FROM unnest(get_children(%L)) AS t',
1559 plus_function, token2value, element_one, value_type, value_type, plus_function, times_function, monus_function, delta_function, token)
1562 ELSIF gate_type =
'times' THEN
1563 EXECUTE format(
'SELECT %s(provsql.provenance_evaluate(t,%L,%L::%s,%L,%L,%L,%L,%L)) FROM unnest(get_children(%L)) AS t',
1564 times_function, token2value, element_one, value_type, value_type, plus_function, times_function, monus_function, delta_function, token)
1567 ELSIF gate_type =
'monus' THEN
1568 IF monus_function
IS NULL THEN
1569 RAISE EXCEPTION
USING MESSAGE=
'Provenance with negation evaluated over a semiring without monus function';
1571 EXECUTE format(
'SELECT %s(a1,a2) FROM (SELECT provsql.provenance_evaluate(c[1],%L,%L::%s,%L,%L,%L,%L,%L) AS a1, ' ||
1572 'provsql.provenance_evaluate(c[2],%L,%L::%s,%L,%L,%L,%L,%L) AS a2 FROM get_children(%L) c) tmp',
1573 monus_function, token2value, element_one, value_type, value_type, plus_function, times_function, monus_function, delta_function,
1574 token2value, element_one, value_type, value_type, plus_function, times_function, monus_function, delta_function, token)
1578 ELSIF gate_type =
'eq' THEN
1579 EXECUTE format(
'SELECT provsql.provenance_evaluate((get_children(%L))[1],%L,%L::%s,%L,%L,%L,%L,%L)',
1580 token, token2value, element_one, value_type, value_type, plus_function, times_function, monus_function, delta_function)
1601 ELSIF gate_type =
'delta' THEN
1602 IF delta_function
IS NULL THEN
1603 RAISE EXCEPTION
USING MESSAGE=
'Provenance with aggregation evaluated over a semiring without delta function';
1605 EXECUTE format(
'SELECT %I(a) FROM (SELECT provsql.provenance_evaluate((get_children(%L))[1],%L,%L::%s,%L,%L,%L,%L,%L) AS a) tmp',
1606 delta_function, token, token2value, element_one, value_type, value_type, plus_function, times_function, monus_function, delta_function)
1610 ELSIF gate_type =
'zero' THEN
1611 EXECUTE format(
'SELECT %I(a) FROM (SELECT %L::%I AS a WHERE FALSE) temp', plus_function, element_one, value_type)
1614 ELSIF gate_type =
'one' THEN
1615 EXECUTE format(
'SELECT %L::%I', element_one, value_type)
1618 ELSIF gate_type =
'project' THEN
1619 EXECUTE format(
'SELECT provsql.provenance_evaluate((get_children(%L))[1],%L,%L::%s,%L,%L,%L,%L,%L)',
1620 token, token2value, element_one, value_type, value_type, plus_function, times_function, monus_function, delta_function)
1623 ELSIF gate_type =
'annotation' THEN
1627 EXECUTE format(
'SELECT provsql.provenance_evaluate((get_children(%L))[1],%L,%L::%s,%L,%L,%L,%L,%L)',
1628 token, token2value, element_one, value_type, value_type, plus_function, times_function, monus_function, delta_function)
1632 RAISE EXCEPTION
USING MESSAGE=
'provenance_evaluate cannot be called on formulas using ' || gate_type ||
' gates; use compiled semirings instead';
1637$$
LANGUAGE plpgsql PARALLEL SAFE STABLE;
1657CREATE OR REPLACE
FUNCTION aggregation_evaluate(
1659 token2value REGCLASS,
1660 agg_function_final REGPROC,
1661 agg_function REGPROC,
1662 semimod_function REGPROC,
1663 element_one ANYELEMENT,
1665 plus_function REGPROC,
1666 times_function REGPROC,
1667 monus_function REGPROC,
1668 delta_function REGPROC)
1669 RETURNS ANYELEMENT
AS
1673 result ALIAS
FOR $
0;
1675 SELECT get_gate_type(token)
INTO gt;
1680 EXECUTE format(
'SELECT %I(%I(provsql.aggregation_evaluate(t,%L,%L,%L,%L,%L::%s,%L,%L,%L,%L,%L)),pp.proname::varchar) FROM
1681 unnest(get_children(%L)) AS t, pg_proc pp
1682 WHERE pp.oid=(get_infos(%L)).info1
1683 GROUP BY pp.proname',
1684 agg_function_final, agg_function,token2value,agg_function_final,agg_function,semimod_function,element_one,value_type,value_type,plus_function,times_function,
1685 monus_function,delta_function,token,token)
1689 EXECUTE format(
'SELECT %I(get_extra((get_children(%L))[2]),provsql.provenance_evaluate((get_children(%L))[1],%L,%L::%s,%L,%L,%L,%L,%L))',
1690 semimod_function,token,token,token2value,element_one,value_type,value_type,plus_function,times_function,monus_function,delta_function)
1695$$
LANGUAGE plpgsql PARALLEL SAFE STABLE;
1711CREATE OR REPLACE
FUNCTION provenance_evaluate(
1713 token2value REGCLASS,
1714 element_one ANYELEMENT,
1715 plus_function REGPROC,
1716 times_function REGPROC,
1717 monus_function REGPROC =
NULL,
1718 delta_function REGPROC =
NULL)
1719 RETURNS ANYELEMENT
AS
1720 'provsql',
'provenance_evaluate' LANGUAGE C STABLE;
1723CREATE OR REPLACE
FUNCTION aggregation_evaluate(
1725 token2value REGCLASS,
1726 agg_function_final REGPROC,
1727 agg_function REGPROC,
1728 semimod_function REGPROC,
1729 element_one ANYELEMENT,
1730 plus_function REGPROC,
1731 times_function REGPROC,
1732 monus_function REGPROC =
NULL,
1733 delta_function REGPROC =
NULL)
1734 RETURNS ANYELEMENT
AS
1735 'provsql',
'aggregation_evaluate' LANGUAGE C STABLE;
1746CREATE TYPE GATE_WITH_DESC
AS (f UUID, t UUID, gate_type PROVENANCE_GATE, desc_str
CHARACTER VARYING, infos
INTEGER[], extra TEXT);
1758CREATE OR REPLACE
FUNCTION sub_circuit_with_desc(
1760 token2desc REGCLASS)
RETURNS SETOF GATE_WITH_DESC
AS
1763 RETURN QUERY
EXECUTE
1764 'WITH RECURSIVE transitive_closure(f,t,gate_type) AS (
1765 SELECT $1,t,provsql.get_gate_type($1) FROM unnest(provsql.get_children($1)) AS t
1767 SELECT p1.t,u,provsql.get_gate_type(p1.t) FROM transitive_closure p1, unnest(provsql.get_children(p1.t)) AS u)
1768 SELECT *, ARRAY[(get_infos(f)).info1, (get_infos(f)).info2], get_extra(f) FROM (
1769 SELECT f::UUID,t::UUID,gate_type,NULL FROM transitive_closure
1771 SELECT p2.provenance::UUID as f, NULL::UUID, ''input'', CAST (p2.value AS varchar) FROM transitive_closure p1 JOIN ' || token2desc ||
' AS p2
1774 SELECT provenance::UUID as f, NULL::UUID, ''input'', CAST (value AS varchar) FROM ' || token2desc ||
' WHERE provenance=$1
1779$$
LANGUAGE plpgsql PARALLEL SAFE;
1791CREATE OR REPLACE
FUNCTION identify_token(
1792 token UUID,
OUT table_name REGCLASS,
OUT nb_columns
INTEGER)
AS
1802 (
SELECT count(*)
FROM pg_attribute a2
WHERE a2.attrelid=a1.attrelid
AND attnum>
0 AND atttypid<>
0)-1 c
1803 FROM pg_attribute a1
JOIN pg_type
ON atttypid=pg_type.oid
1804 JOIN pg_class
ON attrelid=pg_class.oid
1805 JOIN pg_namespace
ON relnamespace=pg_namespace.oid
1806 WHERE typname=
'UUID' AND relkind=
'r'
1807 AND nspname<>
'provsql'
1808 AND attname=
'provsql'
1810 EXECUTE format(
'SELECT * FROM %I WHERE provsql=%L',t.relname,token)
INTO result;
1815 IF result.provsql
IS NOT NULL THEN
1816 table_name:=t.relname;
1822$$
LANGUAGE plpgsql STRICT;
1830CREATE OR REPLACE
FUNCTION sub_circuit_for_where(token UUID)
1831 RETURNS TABLE(f UUID, t UUID, gate_type PROVENANCE_GATE, table_name REGCLASS, nb_columns
INTEGER, infos
INTEGER[], extra TEXT)
AS
1833 WITH RECURSIVE transitive_closure(f,t,idx,gate_type)
AS (
1834 SELECT $
1,t,id,provsql.get_gate_type($
1)
FROM unnest(provsql.get_children($
1))
WITH ORDINALITY
AS a(t,id)
1836 SELECT p1.t,u,id,provsql.get_gate_type(p1.t)
FROM transitive_closure p1,
unnest(provsql.get_children(p1.t))
WITH ORDINALITY
AS a(u, id)
1837 )
SELECT f, t, gate_type, table_name, nb_columns,
ARRAY[(get_infos(f)).info1, (get_infos(f)).info2], get_extra(f)
FROM (
1847 SELECT DISTINCT f, t::UUID, idx, gate_type,
NULL::REGCLASS
AS table_name,
NULL::
INTEGER AS nb_columns
FROM transitive_closure
1849 SELECT DISTINCT t,
NULL::UUID,
NULL::
INT,
'input'::PROVENANCE_GATE, (id).table_name, (id).nb_columns
FROM transitive_closure
JOIN (
SELECT t
AS prov, provsql.identify_token(t)
as id
FROM transitive_closure
WHERE t
NOT IN (
SELECT f
FROM transitive_closure)) temp
ON t=prov
1851 SELECT DISTINCT $
1,
NULL::UUID,
NULL::
INT,
'input'::PROVENANCE_GATE, (id).table_name, (id).nb_columns
FROM (
SELECT provsql.identify_token($
1)
AS id
WHERE $
1 NOT IN (
SELECT f
FROM transitive_closure)) temp
1884CREATE OR REPLACE
FUNCTION circuit_subgraph(root UUID, max_depth
INT DEFAULT 8)
1885 RETURNS TABLE(node UUID, parent UUID, child_pos
INT, gate_type TEXT, info1 TEXT, info2 TEXT, depth
INT)
AS
1887 WITH RECURSIVE bfs(node, parent, child_pos, depth)
AS (
1888 SELECT root,
NULL::UUID,
NULL::
INT,
0
1890 SELECT c.t, b.node, c.idx::
INT, b.depth +
1
1892 CROSS JOIN LATERAL unnest(provsql.get_children(b.node))
1893 WITH ORDINALITY
AS c(t, idx)
1894 WHERE b.depth < max_depth
1902 SELECT node, MAX(depth)
AS depth
FROM bfs
GROUP BY node
1908 SELECT DISTINCT parent, node
AS child, child_pos
1909 FROM bfs
WHERE parent
IS NOT NULL
1915 provsql.get_gate_type(d.node)::TEXT,
1920 LEFT JOIN edges e
ON e.child = d.node
1921 LEFT JOIN LATERAL provsql.get_infos(d.node) i
ON TRUE
1922 ORDER BY d.depth, d.node, e.parent;
1923$$
LANGUAGE sql STABLE PARALLEL SAFE;
1944CREATE OR REPLACE
FUNCTION simplified_circuit_subgraph(
1945 root UUID, max_depth
INT DEFAULT 8)
RETURNS jsonb
1946 AS 'provsql',
'simplified_circuit_subgraph'
1947 LANGUAGE C STABLE PARALLEL SAFE;
1971CREATE OR REPLACE
FUNCTION rv_histogram(
1972 token UUID, bins
INT DEFAULT 30, prov UUID
DEFAULT gate_one())
1974 AS 'provsql',
'rv_histogram'
1975 LANGUAGE C VOLATILE PARALLEL SAFE;
2002CREATE OR REPLACE
FUNCTION rv_analytical_curves(
2003 token UUID, samples
INT DEFAULT 100, prov UUID
DEFAULT gate_one())
2005 AS 'provsql',
'rv_analytical_curves'
2006 LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
2027CREATE OR REPLACE
FUNCTION rv_sample(
2028 token UUID, n
INTEGER, prov UUID
DEFAULT gate_one())
2029 RETURNS SETOF float8
2030 AS 'provsql',
'rv_sample'
2031 LANGUAGE C VOLATILE PARALLEL SAFE;
2049CREATE OR REPLACE
FUNCTION resolve_input(UUID UUID)
2050 RETURNS TABLE(relation REGCLASS, row_data JSONB)
AS
2062 SELECT c.oid::REGCLASS
AS regc
2064 JOIN pg_class c
ON a.attrelid = c.oid
2065 JOIN pg_namespace ns
ON c.relnamespace = ns.oid
2066 JOIN pg_type ty
ON a.atttypid = ty.oid
2067 WHERE a.attname =
'provsql'
2068 AND ty.typname =
'UUID'
2070 AND ns.nspname <>
'provsql'
2075 'SELECT %L::REGCLASS, to_jsonb(t) - ''provsql'', t.provsql FROM %s AS t WHERE provsql = $1',
2085$$
LANGUAGE plpgsql STABLE;
2108CREATE TYPE AGG_TOKEN;
2111CREATE OR REPLACE
FUNCTION agg_token_in(CSTRING)
2113 AS 'provsql',
'agg_token_in' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
2131CREATE OR REPLACE
FUNCTION agg_token_out(AGG_TOKEN)
2133 AS 'provsql',
'agg_token_out' LANGUAGE C STABLE STRICT PARALLEL SAFE;
2136CREATE OR REPLACE
FUNCTION agg_token_cast(AGG_TOKEN)
2138 AS 'provsql',
'agg_token_cast' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
2140CREATE TYPE AGG_TOKEN (
2141 internallength =
117,
2142 input = agg_token_in,
2143 output = agg_token_out,
2148CREATE OR REPLACE
FUNCTION agg_token_uuid(aggtok AGG_TOKEN)
2152 RETURN agg_token_cast(aggtok)::UUID;
2154$$
LANGUAGE plpgsql STRICT
SET search_path=provsql,pg_temp,public SECURITY DEFINER IMMUTABLE PARALLEL SAFE;
2157CREATE CAST (AGG_TOKEN
AS UUID)
WITH FUNCTION agg_token_uuid(AGG_TOKEN)
AS IMPLICIT;
2176CREATE OR REPLACE
FUNCTION agg_token_value_text(token UUID)
2182 WHEN provsql.get_gate_type(token)
IN (
'agg',
'arith')
2183 THEN provsql.get_extra(token) ||
' (*)'
2186$$
LANGUAGE sql STABLE STRICT PARALLEL SAFE;
2189CREATE OR REPLACE
FUNCTION agg_token_to_numeric(AGG_TOKEN)
2191 AS 'provsql',
'agg_token_to_numeric' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
2194CREATE OR REPLACE
FUNCTION agg_token_to_float8(AGG_TOKEN)
2195 RETURNS double precision
2196 AS 'provsql',
'agg_token_to_float8' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
2199CREATE OR REPLACE
FUNCTION agg_token_to_int4(AGG_TOKEN)
2201 AS 'provsql',
'agg_token_to_int4' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
2204CREATE OR REPLACE
FUNCTION agg_token_to_int8(AGG_TOKEN)
2206 AS 'provsql',
'agg_token_to_int8' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
2209CREATE OR REPLACE
FUNCTION agg_token_to_text(AGG_TOKEN)
2211 AS 'provsql',
'agg_token_to_text' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
2220CREATE CAST (AGG_TOKEN
AS NUMERIC)
WITH FUNCTION agg_token_to_numeric(AGG_TOKEN)
AS ASSIGNMENT;
2237CREATE OR REPLACE
FUNCTION agg_token_value(AGG_TOKEN)
2239 AS 'provsql',
'agg_token_value' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
2244CREATE OR REPLACE
FUNCTION agg_token_make(tok UUID, val
NUMERIC)
2245 RETURNS AGG_TOKEN
AS
2247 SELECT format(
'( %s , %s )', tok::TEXT, val::TEXT)::provsql.AGG_TOKEN;
2248$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
2249 SET search_path=provsql,pg_temp,public;
2254CREATE OR REPLACE
FUNCTION agg_value_gate(v
NUMERIC)
2258 token UUID := public.uuid_generate_v5(
2259 provsql.uuid_ns_provsql(), concat(
'value', v::TEXT));
2261 PERFORM provsql.create_gate(token,
'value');
2262 PERFORM provsql.set_extra(token, v::TEXT);
2265$$
LANGUAGE plpgsql STRICT IMMUTABLE PARALLEL SAFE
2266 SET search_path=provsql,pg_temp,public SECURITY DEFINER;
2277CREATE OR REPLACE
FUNCTION agg_arith_make(op
INT, children UUID[], val
NUMERIC)
2278 RETURNS AGG_TOKEN
AS
2281 token UUID := provsql.provenance_arith(op, children);
2283 PERFORM provsql.set_extra(token, val::TEXT);
2284 RETURN provsql.agg_token_make(token, val);
2286$$
LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE
2287 SET search_path=provsql,pg_temp,public SECURITY DEFINER;
2291CREATE OR REPLACE
FUNCTION agg_token_plus(a AGG_TOKEN, b AGG_TOKEN)
2292 RETURNS AGG_TOKEN
AS
2293$$
SELECT provsql.agg_arith_make(
0,
ARRAY[(a)::UUID, (b)::UUID],
2294 provsql.agg_token_value(a) + provsql.agg_token_value(b)); $$
2295 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
2298CREATE OR REPLACE
FUNCTION agg_token_minus(a AGG_TOKEN, b AGG_TOKEN)
2299 RETURNS AGG_TOKEN
AS
2300$$
SELECT provsql.agg_arith_make(
2,
ARRAY[(a)::UUID, (b)::UUID],
2301 provsql.agg_token_value(a) - provsql.agg_token_value(b)); $$
2302 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
2305CREATE OR REPLACE
FUNCTION agg_token_times(a AGG_TOKEN, b AGG_TOKEN)
2306 RETURNS AGG_TOKEN
AS
2307$$
SELECT provsql.agg_arith_make(
1,
ARRAY[(a)::UUID, (b)::UUID],
2308 provsql.agg_token_value(a) * provsql.agg_token_value(b)); $$
2309 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
2312CREATE OR REPLACE
FUNCTION agg_token_div(a AGG_TOKEN, b AGG_TOKEN)
2313 RETURNS AGG_TOKEN
AS
2314$$
SELECT provsql.agg_arith_make(
3,
ARRAY[(a)::UUID, (b)::UUID],
2315 provsql.agg_token_value(a) / provsql.agg_token_value(b)); $$
2316 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
2319CREATE OR REPLACE
FUNCTION agg_token_neg(a AGG_TOKEN)
2320 RETURNS AGG_TOKEN
AS
2321$$
SELECT provsql.agg_arith_make(
4,
ARRAY[(a)::UUID],
2322 - provsql.agg_token_value(a)); $$
2323 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
2327CREATE OR REPLACE
FUNCTION agg_token_plus_numeric(a AGG_TOKEN, b
NUMERIC)
2328 RETURNS AGG_TOKEN
AS
2329$$
SELECT provsql.agg_arith_make(
0,
ARRAY[(a)::UUID, provsql.agg_value_gate(b)],
2330 provsql.agg_token_value(a) + b); $$
2331 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
2334CREATE OR REPLACE
FUNCTION agg_token_minus_numeric(a AGG_TOKEN, b
NUMERIC)
2335 RETURNS AGG_TOKEN
AS
2336$$
SELECT provsql.agg_arith_make(
2,
ARRAY[(a)::UUID, provsql.agg_value_gate(b)],
2337 provsql.agg_token_value(a) - b); $$
2338 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
2341CREATE OR REPLACE
FUNCTION agg_token_times_numeric(a AGG_TOKEN, b
NUMERIC)
2342 RETURNS AGG_TOKEN
AS
2343$$
SELECT provsql.agg_arith_make(
1,
ARRAY[(a)::UUID, provsql.agg_value_gate(b)],
2344 provsql.agg_token_value(a) * b); $$
2345 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
2348CREATE OR REPLACE
FUNCTION agg_token_div_numeric(a AGG_TOKEN, b
NUMERIC)
2349 RETURNS AGG_TOKEN
AS
2350$$
SELECT provsql.agg_arith_make(
3,
ARRAY[(a)::UUID, provsql.agg_value_gate(b)],
2351 provsql.agg_token_value(a) / b); $$
2352 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
2356CREATE OR REPLACE
FUNCTION numeric_plus_agg_token(a
NUMERIC, b AGG_TOKEN)
2357 RETURNS AGG_TOKEN
AS
2358$$
SELECT provsql.agg_arith_make(
0,
ARRAY[provsql.agg_value_gate(a), (b)::UUID],
2359 a + provsql.agg_token_value(b)); $$
2360 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
2363CREATE OR REPLACE
FUNCTION numeric_minus_agg_token(a
NUMERIC, b AGG_TOKEN)
2364 RETURNS AGG_TOKEN
AS
2365$$
SELECT provsql.agg_arith_make(
2,
ARRAY[provsql.agg_value_gate(a), (b)::UUID],
2366 a - provsql.agg_token_value(b)); $$
2367 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
2370CREATE OR REPLACE
FUNCTION numeric_times_agg_token(a
NUMERIC, b AGG_TOKEN)
2371 RETURNS AGG_TOKEN
AS
2372$$
SELECT provsql.agg_arith_make(
1,
ARRAY[provsql.agg_value_gate(a), (b)::UUID],
2373 a * provsql.agg_token_value(b)); $$
2374 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
2377CREATE OR REPLACE
FUNCTION numeric_div_agg_token(a
NUMERIC, b AGG_TOKEN)
2378 RETURNS AGG_TOKEN
AS
2379$$
SELECT provsql.agg_arith_make(
3,
ARRAY[provsql.agg_value_gate(a), (b)::UUID],
2380 a / provsql.agg_token_value(b)); $$
2381 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
2384CREATE OPERATOR + (LEFTARG=AGG_TOKEN, RIGHTARG=AGG_TOKEN,
PROCEDURE=agg_token_plus, COMMUTATOR = +);
2385CREATE OPERATOR - (LEFTARG=AGG_TOKEN, RIGHTARG=AGG_TOKEN,
PROCEDURE=agg_token_minus);
2386CREATE OPERATOR * (LEFTARG=AGG_TOKEN, RIGHTARG=AGG_TOKEN,
PROCEDURE=agg_token_times, COMMUTATOR = *);
2387CREATE OPERATOR / (LEFTARG=AGG_TOKEN, RIGHTARG=AGG_TOKEN,
PROCEDURE=agg_token_div);
2388CREATE OPERATOR - (RIGHTARG=AGG_TOKEN,
PROCEDURE=agg_token_neg);
2390CREATE OPERATOR + (LEFTARG=AGG_TOKEN, RIGHTARG=
NUMERIC,
PROCEDURE=agg_token_plus_numeric, COMMUTATOR = +);
2391CREATE OPERATOR - (LEFTARG=AGG_TOKEN, RIGHTARG=
NUMERIC,
PROCEDURE=agg_token_minus_numeric);
2392CREATE OPERATOR * (LEFTARG=AGG_TOKEN, RIGHTARG=
NUMERIC,
PROCEDURE=agg_token_times_numeric, COMMUTATOR = *);
2393CREATE OPERATOR / (LEFTARG=AGG_TOKEN, RIGHTARG=
NUMERIC,
PROCEDURE=agg_token_div_numeric);
2395CREATE OPERATOR + (LEFTARG=
NUMERIC, RIGHTARG=AGG_TOKEN,
PROCEDURE=numeric_plus_agg_token, COMMUTATOR = +);
2396CREATE OPERATOR - (LEFTARG=
NUMERIC, RIGHTARG=AGG_TOKEN,
PROCEDURE=numeric_minus_agg_token);
2397CREATE OPERATOR * (LEFTARG=
NUMERIC, RIGHTARG=AGG_TOKEN,
PROCEDURE=numeric_times_agg_token, COMMUTATOR = *);
2398CREATE OPERATOR / (LEFTARG=
NUMERIC, RIGHTARG=AGG_TOKEN,
PROCEDURE=numeric_div_agg_token);
2401CREATE CAST (AGG_TOKEN
AS double precision)
WITH FUNCTION agg_token_to_float8(AGG_TOKEN)
AS ASSIGNMENT;
2403CREATE CAST (AGG_TOKEN
AS INTEGER)
WITH FUNCTION agg_token_to_int4(AGG_TOKEN)
AS ASSIGNMENT;
2405CREATE CAST (AGG_TOKEN
AS bigint)
WITH FUNCTION agg_token_to_int8(AGG_TOKEN)
AS ASSIGNMENT;
2407CREATE CAST (AGG_TOKEN
AS TEXT)
WITH FUNCTION agg_token_to_text(AGG_TOKEN)
AS ASSIGNMENT;
2422CREATE OR REPLACE
FUNCTION agg_token_cond(a AGG_TOKEN, cond UUID)
2423 RETURNS AGG_TOKEN
AS
2431 IF cond
IS NULL OR cond = gate_one()
THEN
2436 IF get_gate_type(tok) =
'conditioned'
2437 AND array_length(get_children(tok),
1) =
2 THEN
2438 ch := get_children(tok);
2440 ev := provenance_times(ch[
2], cond);
2445 result := public.uuid_generate_v5(uuid_ns_provsql(),
2446 concat(
'conditioned', tok, ev));
2447 PERFORM create_gate(
result,
'conditioned',
ARRAY[tok, ev]);
2448 RETURN agg_token_make(
result, agg_token_value(a));
2450$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public
2451 SECURITY DEFINER PARALLEL SAFE;
2454 LEFTARG = AGG_TOKEN,
2456 PROCEDURE = agg_token_cond
2467CREATE OR REPLACE
FUNCTION agg_token_cond_predicate(
2468 a AGG_TOKEN, predicate
BOOLEAN)
RETURNS AGG_TOKEN
AS
2471 RAISE EXCEPTION
'AGG_TOKEN | (predicate) must be rewritten by the ProvSQL '
2472 'planner hook: the right operand must be a Boolean combination of '
2473 'aggregate / random_variable comparisons (is provsql.active off?)';
2475$$
LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
2478 LEFTARG = AGG_TOKEN,
2480 PROCEDURE = agg_token_cond_predicate
2492CREATE OR REPLACE
FUNCTION agg_conditioned_target(a AGG_TOKEN)
2493 RETURNS AGG_TOKEN
AS
2496 WHEN provsql.get_gate_type((a)::UUID) =
'conditioned'
2497 AND array_length(provsql.get_children((a)::UUID),
1) =
2
2498 THEN provsql.agg_token_make(
2499 (provsql.get_children((a)::UUID))[
1], provsql.agg_token_value(a))
2502$$
LANGUAGE sql STABLE PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
2511CREATE OR REPLACE
FUNCTION agg_token_comp_numeric(a AGG_TOKEN, b
NUMERIC)
2514IMMUTABLE STRICT PARALLEL SAFE
2517 RAISE EXCEPTION
'Comparison AGG_TOKEN-NUMERIC not implemented, should be replaced by ProvSQL behavior';
2527CREATE OR REPLACE
FUNCTION numeric_comp_agg_token(a
NUMERIC, b AGG_TOKEN)
2530IMMUTABLE STRICT PARALLEL SAFE
2533 RAISE EXCEPTION
'Comparison NUMERIC-AGG_TOKEN not implemented, should be replaced by ProvSQL behavior';
2539 LEFTARG = AGG_TOKEN,
2541 PROCEDURE = agg_token_comp_numeric,
2548 RIGHTARG = AGG_TOKEN,
2549 PROCEDURE = numeric_comp_agg_token,
2556 LEFTARG = AGG_TOKEN,
2558 PROCEDURE = agg_token_comp_numeric,
2565 RIGHTARG = AGG_TOKEN,
2566 PROCEDURE = numeric_comp_agg_token,
2573 LEFTARG = AGG_TOKEN,
2575 PROCEDURE = agg_token_comp_numeric,
2582 RIGHTARG = AGG_TOKEN,
2583 PROCEDURE = numeric_comp_agg_token,
2590 LEFTARG = AGG_TOKEN,
2592 PROCEDURE = agg_token_comp_numeric,
2599 RIGHTARG = AGG_TOKEN,
2600 PROCEDURE = numeric_comp_agg_token,
2607 LEFTARG = AGG_TOKEN,
2609 PROCEDURE = agg_token_comp_numeric,
2616 RIGHTARG = AGG_TOKEN,
2617 PROCEDURE = numeric_comp_agg_token,
2624 LEFTARG = AGG_TOKEN,
2626 PROCEDURE = agg_token_comp_numeric,
2633 RIGHTARG = AGG_TOKEN,
2634 PROCEDURE = numeric_comp_agg_token,
2648CREATE OR REPLACE
FUNCTION agg_token_comp_agg_token(a AGG_TOKEN, b AGG_TOKEN)
2651IMMUTABLE STRICT PARALLEL SAFE
2654 RAISE EXCEPTION
'Comparison AGG_TOKEN-AGG_TOKEN not implemented, should be replaced by ProvSQL behavior';
2660 LEFTARG=AGG_TOKEN, RIGHTARG=AGG_TOKEN,
PROCEDURE=agg_token_comp_agg_token,
2661 COMMUTATOR = >, NEGATOR = >=
2665 LEFTARG=AGG_TOKEN, RIGHTARG=AGG_TOKEN,
PROCEDURE=agg_token_comp_agg_token,
2666 COMMUTATOR = >=, NEGATOR = >
2670 LEFTARG=AGG_TOKEN, RIGHTARG=AGG_TOKEN,
PROCEDURE=agg_token_comp_agg_token,
2671 COMMUTATOR = <, NEGATOR = <=
2675 LEFTARG=AGG_TOKEN, RIGHTARG=AGG_TOKEN,
PROCEDURE=agg_token_comp_agg_token,
2676 COMMUTATOR = <=, NEGATOR = <
2680 LEFTARG=AGG_TOKEN, RIGHTARG=AGG_TOKEN,
PROCEDURE=agg_token_comp_agg_token,
2681 COMMUTATOR = =, NEGATOR = <>
2685 LEFTARG=AGG_TOKEN, RIGHTARG=AGG_TOKEN,
PROCEDURE=agg_token_comp_agg_token,
2686 COMMUTATOR = <>, NEGATOR = =
2696CREATE OR REPLACE
FUNCTION agg_token_comp_text(a AGG_TOKEN, b TEXT)
2699IMMUTABLE STRICT PARALLEL SAFE
2702 RAISE EXCEPTION
'Comparison AGG_TOKEN-TEXT not implemented, should be replaced by ProvSQL behavior';
2712CREATE OR REPLACE
FUNCTION text_comp_agg_token(a TEXT, b AGG_TOKEN)
2715IMMUTABLE STRICT PARALLEL SAFE
2718 RAISE EXCEPTION
'Comparison TEXT-AGG_TOKEN not implemented, should be replaced by ProvSQL behavior';
2724 LEFTARG = AGG_TOKEN,
2726 PROCEDURE = agg_token_comp_text,
2733 RIGHTARG = AGG_TOKEN,
2734 PROCEDURE = text_comp_agg_token,
2741 LEFTARG = AGG_TOKEN,
2743 PROCEDURE = agg_token_comp_text,
2750 RIGHTARG = AGG_TOKEN,
2751 PROCEDURE = text_comp_agg_token,
2780CREATE TYPE random_variable;
2783CREATE OR REPLACE
FUNCTION random_variable_in(CSTRING)
2784 RETURNS random_variable
2785 AS 'provsql',
'random_variable_in' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
2788CREATE OR REPLACE
FUNCTION random_variable_out(random_variable)
2790 AS 'provsql',
'random_variable_out' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
2792CREATE TYPE random_variable (
2793 internallength =
16,
2794 input = random_variable_in,
2795 output = random_variable_out,
2800CREATE OR REPLACE
FUNCTION random_variable_make(tok UUID)
2801 RETURNS random_variable
2802 AS 'provsql',
'random_variable_make' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
2815CREATE CAST (random_variable
AS UUID)
WITHOUT FUNCTION AS ASSIGNMENT;
2816CREATE CAST (UUID
AS random_variable)
WITHOUT FUNCTION;
2826CREATE OR REPLACE
FUNCTION is_finite_float8(x
double precision)
2829 SELECT $
1 <>
'NaN'::float8
AND $
1 <>
'Infinity'::float8
AND $
1 <>
'-Infinity'::float8;
2830$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
2860CREATE OR REPLACE
FUNCTION normal(mu
double precision, sigma
double precision)
2861 RETURNS random_variable
AS
2866 IF NOT provsql.is_finite_float8(mu)
OR NOT provsql.is_finite_float8(sigma)
THEN
2867 RAISE EXCEPTION
'provsql.normal: parameters must be finite (got mu=%, sigma=%)', mu, sigma;
2870 RAISE EXCEPTION
'provsql.normal: sigma must be non-negative (got %)', sigma;
2873 RETURN provsql.as_random(mu);
2875 token := public.uuid_generate_v4();
2876 PERFORM provsql.create_gate(token,
'rv');
2877 PERFORM provsql.set_extra(token,
'normal:' || mu ||
',' || sigma);
2878 RETURN provsql.random_variable_make(token);
2880$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
2897CREATE OR REPLACE
FUNCTION uniform(a
double precision, b
double precision)
2898 RETURNS random_variable
AS
2903 IF NOT provsql.is_finite_float8(a)
OR NOT provsql.is_finite_float8(b)
THEN
2904 RAISE EXCEPTION
'provsql.uniform: bounds must be finite (got a=%, b=%)', a, b;
2907 RAISE EXCEPTION
'provsql.uniform: a must be <= b (got a=%, b=%)', a, b;
2910 RETURN provsql.as_random(a);
2912 token := public.uuid_generate_v4();
2913 PERFORM provsql.create_gate(token,
'rv');
2914 PERFORM provsql.set_extra(token,
'uniform:' || a ||
',' || b);
2915 RETURN provsql.random_variable_make(token);
2917$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
2932CREATE OR REPLACE
FUNCTION exponential(lambda
double precision)
2933 RETURNS random_variable
AS
2938 IF NOT provsql.is_finite_float8(lambda)
THEN
2939 RAISE EXCEPTION
'provsql.exponential: lambda must be finite (got %)', lambda;
2942 RAISE EXCEPTION
'provsql.exponential: lambda must be strictly positive (got %)', lambda;
2944 token := public.uuid_generate_v4();
2945 PERFORM provsql.create_gate(token,
'rv');
2946 PERFORM provsql.set_extra(token,
'exponential:' || lambda);
2947 RETURN provsql.random_variable_make(token);
2949$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
2974CREATE OR REPLACE
FUNCTION erlang(k
INTEGER, lambda
double precision)
2975 RETURNS random_variable
AS
2981 RAISE EXCEPTION
'provsql.erlang: k must be >= 1 (got %)', k;
2983 IF NOT provsql.is_finite_float8(lambda)
THEN
2984 RAISE EXCEPTION
'provsql.erlang: lambda must be finite (got %)', lambda;
2987 RAISE EXCEPTION
'provsql.erlang: lambda must be strictly positive (got %)', lambda;
2990 RETURN provsql.exponential(lambda);
2992 token := public.uuid_generate_v4();
2993 PERFORM provsql.create_gate(token,
'rv');
2994 PERFORM provsql.set_extra(token,
'erlang:' || k ||
',' || lambda);
2995 RETURN provsql.random_variable_make(token);
2997$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
3039CREATE OR REPLACE
FUNCTION mixture(
3040 p UUID, x random_variable, y random_variable)
3041 RETURNS random_variable
AS
3045 p_kind provsql.PROVENANCE_GATE;
3048 x_kind provsql.PROVENANCE_GATE;
3049 y_kind provsql.PROVENANCE_GATE;
3051 p_kind := provsql.get_gate_type(p);
3052 IF p_kind
NOT IN (
'input',
'mulinput',
'update',
3053 'plus',
'times',
'monus',
3054 'project',
'eq',
'cmp',
3056 RAISE EXCEPTION
'provsql.mixture: p must be a Boolean gate '
3057 '(input/mulinput/update/plus/times/monus/project/eq/cmp/zero/one), got %', p_kind;
3060 x_uuid := (x)::UUID;
3061 y_uuid := (y)::UUID;
3062 x_kind := provsql.get_gate_type(x_uuid);
3063 y_kind := provsql.get_gate_type(y_uuid);
3064 IF x_kind
NOT IN (
'rv',
'value',
'arith',
'mixture')
THEN
3065 RAISE EXCEPTION
'provsql.mixture: x must be a scalar RV root (rv / value / arith / mixture), got %', x_kind;
3067 IF y_kind
NOT IN (
'rv',
'value',
'arith',
'mixture')
THEN
3068 RAISE EXCEPTION
'provsql.mixture: y must be a scalar RV root (rv / value / arith / mixture), got %', y_kind;
3071 token := public.uuid_generate_v5(
3072 provsql.uuid_ns_provsql(),
3073 concat(
'mixture', p, x_uuid, y_uuid));
3074 PERFORM provsql.create_gate(token,
'mixture',
ARRAY[p, x_uuid, y_uuid]);
3075 RETURN provsql.random_variable_make(token);
3077$$
LANGUAGE plpgsql STRICT IMMUTABLE PARALLEL SAFE;
3104CREATE OR REPLACE
FUNCTION mixture(
3105 p_value
double precision,
3108 RETURNS random_variable
AS
3113 IF p_value
IS NULL OR p_value <> p_value
OR p_value <
0 OR p_value >
1 THEN
3114 RAISE EXCEPTION
'provsql.mixture: probability must be in [0,1] (got %)', p_value;
3116 p_token := public.uuid_generate_v4();
3117 PERFORM provsql.create_gate(p_token,
'input');
3118 PERFORM provsql.set_prob(p_token, p_value);
3119 RETURN provsql.mixture(p_token, x, y);
3121$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
3155CREATE OR REPLACE
FUNCTION categorical(
3156 probs
double precision[],
3157 outcomes
double precision[])
3158 RETURNS random_variable
AS
3162 p_sum
double precision :=
0.
0;
3167 mul_tokens UUID[] :=
ARRAY[]::UUID[];
3169 pi_i
double precision;
3170 vi_i
double precision;
3172 IF probs
IS NULL OR outcomes
IS NULL THEN
3173 RAISE EXCEPTION
'provsql.categorical: probs and outcomes must be non-null';
3175 n := array_length(probs,
1);
3176 IF n
IS NULL OR n <
1 THEN
3177 RAISE EXCEPTION
'provsql.categorical: probs must be non-empty';
3179 IF array_length(outcomes,
1) <> n
THEN
3180 RAISE EXCEPTION
'provsql.categorical: probs and outcomes must have the same length (got % and %)',
3181 n, array_length(outcomes,
1);
3186 vi_i := outcomes[i];
3191 IF pi_i
IS NULL OR pi_i =
'NaN'::float8
OR pi_i <
0 OR pi_i >
1 THEN
3192 RAISE EXCEPTION
'provsql.categorical: probs[%] must be in [0,1] (got %)', i, pi_i;
3194 IF vi_i
IS NULL OR vi_i =
'NaN'::float8
3195 OR vi_i =
'Infinity'::float8
OR vi_i =
'-Infinity'::float8
THEN
3196 RAISE EXCEPTION
'provsql.categorical: outcomes[%] must be finite (got %)', i, vi_i;
3198 p_sum := p_sum + pi_i;
3200 IF abs(p_sum -
1.
0) > 1e-9
THEN
3201 RAISE EXCEPTION
'provsql.categorical: probs must sum to 1 within 1e-9 (got %)', p_sum;
3213 nb_positive
INTEGER :=
0;
3214 only_idx
INTEGER :=
0;
3217 IF probs[i] >
0.
0 THEN
3218 nb_positive := nb_positive +
1;
3222 IF nb_positive =
1 THEN
3223 RETURN provsql.as_random(outcomes[only_idx]);
3230 key_token := public.uuid_generate_v4();
3231 PERFORM provsql.create_gate(key_token,
'input');
3232 PERFORM provsql.set_prob(key_token,
1.
0);
3239 IF pi_i <=
0.
0 THEN CONTINUE;
END IF;
3240 mul_token := public.uuid_generate_v4();
3241 PERFORM provsql.create_gate(mul_token,
'mulinput',
ARRAY[key_token]);
3242 PERFORM provsql.set_prob(mul_token, pi_i);
3243 PERFORM provsql.set_infos(mul_token, (i -
1));
3244 PERFORM provsql.set_extra(mul_token, outcomes[i]::TEXT);
3245 mul_tokens := mul_tokens || mul_token;
3248 mix_wires :=
ARRAY[key_token] || mul_tokens;
3249 mix_token := public.uuid_generate_v4();
3250 PERFORM provsql.create_gate(mix_token,
'mixture', mix_wires);
3251 RETURN provsql.random_variable_make(mix_token);
3253$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
3274CREATE OR REPLACE
FUNCTION as_random(c
double precision)
3275 RETURNS random_variable
AS
3283 c_canon
double precision := c +
0.
0;
3284 c_text
varchar :=
CAST(c_canon
AS VARCHAR);
3285 token UUID := public.uuid_generate_v5(
3286 provsql.uuid_ns_provsql(), concat(
'value', c_text));
3288 PERFORM provsql.create_gate(token,
'value');
3289 PERFORM provsql.set_extra(token, c_text);
3290 RETURN provsql.random_variable_make(token);
3292$$
LANGUAGE plpgsql STRICT IMMUTABLE PARALLEL SAFE;
3307CREATE CAST (
double precision AS random_variable)
3308 WITH FUNCTION as_random(
double precision)
AS IMPLICIT;
3311CREATE OR REPLACE
FUNCTION as_random(c
INTEGER)
3312 RETURNS random_variable
AS
3313$$
SELECT provsql.as_random(c::
double precision); $$
3314LANGUAGE sql STRICT IMMUTABLE PARALLEL SAFE;
3317CREATE OR REPLACE
FUNCTION as_random(c
NUMERIC)
3318 RETURNS random_variable
AS
3319$$
SELECT provsql.as_random(c::
double precision); $$
3320LANGUAGE sql STRICT IMMUTABLE PARALLEL SAFE;
3323CREATE CAST (
INTEGER AS random_variable)
3324 WITH FUNCTION as_random(
INTEGER)
AS IMPLICIT;
3327CREATE CAST (
NUMERIC AS random_variable)
3328 WITH FUNCTION as_random(
NUMERIC)
AS IMPLICIT;
3360CREATE OR REPLACE
FUNCTION random_variable_plus(
3361 a random_variable, b random_variable)
3362 RETURNS random_variable
AS
3364 SELECT provsql.random_variable_make(
3365 provsql.provenance_arith(
3369$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
3372CREATE OR REPLACE
FUNCTION random_variable_minus(
3373 a random_variable, b random_variable)
3374 RETURNS random_variable
AS
3376 SELECT provsql.random_variable_make(
3377 provsql.provenance_arith(
3381$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
3384CREATE OR REPLACE
FUNCTION random_variable_times(
3385 a random_variable, b random_variable)
3386 RETURNS random_variable
AS
3388 SELECT provsql.random_variable_make(
3389 provsql.provenance_arith(
3393$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
3396CREATE OR REPLACE
FUNCTION random_variable_div(
3397 a random_variable, b random_variable)
3398 RETURNS random_variable
AS
3400 SELECT provsql.random_variable_make(
3401 provsql.provenance_arith(
3405$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
3408CREATE OR REPLACE
FUNCTION random_variable_neg(a random_variable)
3409 RETURNS random_variable
AS
3411 SELECT provsql.random_variable_make(
3412 provsql.provenance_arith(
3415$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
3425CREATE OR REPLACE
FUNCTION random_variable_cmp_oid(sym TEXT)
3428 SELECT (sym ||
'(double precision,double precision)')::regoperator::oid;
3429$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
3445CREATE OR REPLACE
FUNCTION random_variable_cmp_placeholder(
3446 a random_variable, b random_variable)
3450 RAISE EXCEPTION
'random_variable comparison must be rewritten by the '
3451 'ProvSQL planner hook (is provsql.active off?)';
3453$$
LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
3455CREATE OR REPLACE
FUNCTION random_variable_lt(
3456 a random_variable, b random_variable)
RETURNS BOOLEAN AS
3457$$
SELECT provsql.random_variable_cmp_placeholder(a, b); $$
3458LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
3460CREATE OR REPLACE
FUNCTION random_variable_le(
3461 a random_variable, b random_variable)
RETURNS BOOLEAN AS
3462$$
SELECT provsql.random_variable_cmp_placeholder(a, b); $$
3463LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
3465CREATE OR REPLACE
FUNCTION random_variable_eq(
3466 a random_variable, b random_variable)
RETURNS BOOLEAN AS
3467$$
SELECT provsql.random_variable_cmp_placeholder(a, b); $$
3468LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
3470CREATE OR REPLACE
FUNCTION random_variable_ne(
3471 a random_variable, b random_variable)
RETURNS BOOLEAN AS
3472$$
SELECT provsql.random_variable_cmp_placeholder(a, b); $$
3473LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
3475CREATE OR REPLACE
FUNCTION random_variable_ge(
3476 a random_variable, b random_variable)
RETURNS BOOLEAN AS
3477$$
SELECT provsql.random_variable_cmp_placeholder(a, b); $$
3478LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
3480CREATE OR REPLACE
FUNCTION random_variable_gt(
3481 a random_variable, b random_variable)
RETURNS BOOLEAN AS
3482$$
SELECT provsql.random_variable_cmp_placeholder(a, b); $$
3483LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
3491CREATE OR REPLACE
FUNCTION rv_cmp_lt(
3492 a random_variable, b random_variable)
RETURNS UUID
AS
3494 SELECT provsql.provenance_cmp(
3496 provsql.random_variable_cmp_oid(
'<'),
3498$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
3501CREATE OR REPLACE
FUNCTION rv_cmp_le(
3502 a random_variable, b random_variable)
RETURNS UUID
AS
3504 SELECT provsql.provenance_cmp(
3506 provsql.random_variable_cmp_oid(
'<='),
3508$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
3511CREATE OR REPLACE
FUNCTION rv_cmp_eq(
3512 a random_variable, b random_variable)
RETURNS UUID
AS
3514 SELECT provsql.provenance_cmp(
3516 provsql.random_variable_cmp_oid(
'='),
3518$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
3521CREATE OR REPLACE
FUNCTION rv_cmp_ne(
3522 a random_variable, b random_variable)
RETURNS UUID
AS
3524 SELECT provsql.provenance_cmp(
3526 provsql.random_variable_cmp_oid(
'<>'),
3528$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
3531CREATE OR REPLACE
FUNCTION rv_cmp_ge(
3532 a random_variable, b random_variable)
RETURNS UUID
AS
3534 SELECT provsql.provenance_cmp(
3536 provsql.random_variable_cmp_oid(
'>='),
3538$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
3541CREATE OR REPLACE
FUNCTION rv_cmp_gt(
3542 a random_variable, b random_variable)
RETURNS UUID
AS
3544 SELECT provsql.provenance_cmp(
3546 provsql.random_variable_cmp_oid(
'>'),
3548$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
3551 LEFTARG = random_variable,
3552 RIGHTARG = random_variable,
3553 PROCEDURE = random_variable_plus,
3558 LEFTARG = random_variable,
3559 RIGHTARG = random_variable,
3560 PROCEDURE = random_variable_minus
3564 LEFTARG = random_variable,
3565 RIGHTARG = random_variable,
3566 PROCEDURE = random_variable_times,
3571 LEFTARG = random_variable,
3572 RIGHTARG = random_variable,
3573 PROCEDURE = random_variable_div
3578 RIGHTARG = random_variable,
3579 PROCEDURE = random_variable_neg
3583 LEFTARG = random_variable,
3584 RIGHTARG = random_variable,
3585 PROCEDURE = random_variable_lt,
3591 LEFTARG = random_variable,
3592 RIGHTARG = random_variable,
3593 PROCEDURE = random_variable_le,
3599 LEFTARG = random_variable,
3600 RIGHTARG = random_variable,
3601 PROCEDURE = random_variable_eq,
3607 LEFTARG = random_variable,
3608 RIGHTARG = random_variable,
3609 PROCEDURE = random_variable_ne,
3615 LEFTARG = random_variable,
3616 RIGHTARG = random_variable,
3617 PROCEDURE = random_variable_ge,
3623 LEFTARG = random_variable,
3624 RIGHTARG = random_variable,
3625 PROCEDURE = random_variable_gt,
3646CREATE OR REPLACE
FUNCTION random_variable_cond(rv random_variable, cond UUID)
3647 RETURNS random_variable
AS
3655 IF cond
IS NULL OR cond = gate_one()
THEN
3660 IF get_gate_type(tgt) =
'conditioned'
3661 AND array_length(get_children(tgt),
1) =
2 THEN
3664 ch := get_children(tgt);
3666 ev := provenance_times(ch[
2], cond);
3671 result := public.uuid_generate_v5(uuid_ns_provsql(),
3672 concat(
'conditioned', tgt, ev));
3673 PERFORM create_gate(
result,
'conditioned',
ARRAY[tgt, ev]);
3674 RETURN (
result)::random_variable;
3676$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public
3677 SECURITY DEFINER PARALLEL SAFE;
3680 LEFTARG = random_variable,
3682 PROCEDURE = random_variable_cond
3696CREATE OR REPLACE
FUNCTION random_variable_cond_predicate(
3697 rv random_variable, predicate
BOOLEAN)
RETURNS random_variable
AS
3700 RAISE EXCEPTION
'random_variable | (predicate) must be rewritten by the '
3701 'ProvSQL planner hook: the right operand must be a Boolean combination '
3702 'of random_variable comparisons (is provsql.active off?)';
3704$$
LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
3707 LEFTARG = random_variable,
3709 PROCEDURE = random_variable_cond_predicate
3720CREATE OR REPLACE
FUNCTION rv_conditioned_target(token UUID)
RETURNS UUID
AS
3723 WHEN provsql.get_gate_type(token) =
'conditioned'
3724 AND array_length(provsql.get_children(token),
1) =
2
3725 THEN (provsql.get_children(token))[
1]
3728$$
LANGUAGE sql STABLE PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3738CREATE OR REPLACE
FUNCTION rv_conditioned_prov(token UUID, prov UUID)
3742 WHEN provsql.get_gate_type(token) =
'conditioned'
3743 AND array_length(provsql.get_children(token),
1) =
2
3744 THEN provsql.provenance_times((provsql.get_children(token))[
2], prov)
3747$$
LANGUAGE sql STABLE PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3792CREATE OR REPLACE
FUNCTION rv_aggregate_semimod(
3793 prov UUID, rv random_variable)
3794 RETURNS random_variable
AS
3796 SELECT provsql.mixture(prov, rv, provsql.as_random(
0::
double precision));
3797$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
3808CREATE OR REPLACE
FUNCTION sum_rv_sfunc(
3809 state UUID[], rv random_variable)
3813 WHEN rv
IS NULL THEN state
3814 ELSE array_append(state, (rv)::UUID)
3816$$
LANGUAGE sql IMMUTABLE PARALLEL SAFE;
3831CREATE OR REPLACE
FUNCTION sum_rv_ffunc(state UUID[])
3832 RETURNS random_variable
AS
3837 IF state
IS NULL OR array_length(state,
1)
IS NULL THEN
3838 RETURN provsql.as_random(
0::
double precision);
3840 IF array_length(state,
1) =
1 THEN
3841 RETURN provsql.random_variable_make(state[
1]);
3843 arith_token := provsql.provenance_arith(
0, state);
3844 RETURN provsql.random_variable_make(arith_token);
3846$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE;
3848CREATE AGGREGATE sum(random_variable) (
3849 SFUNC = sum_rv_sfunc,
3852 FINALFUNC = sum_rv_ffunc
3891CREATE OR REPLACE
FUNCTION avg_rv_ffunc(state UUID[])
3892 RETURNS random_variable
AS
3899 denom_state UUID[] :=
'{}';
3901 gtype provsql.PROVENANCE_GATE;
3905 IF state
IS NULL THEN
3908 n := array_length(state,
1);
3914 provsql.as_random(
1::
double precision))::UUID;
3917 gtype := provsql.get_gate_type(state[i]);
3918 IF gtype =
'mixture'::provsql.PROVENANCE_GATE
THEN
3919 children := provsql.get_children(state[i]);
3920 prov_i := children[
1];
3921 denom_state := array_append(
3924 provsql.rv_aggregate_semimod(
3925 prov_i, provsql.as_random(
1::
double precision)))::UUID);
3927 denom_state := array_append(denom_state, one_uuid);
3932 num_token := state[
1];
3933 denom_token := denom_state[
1];
3935 num_token := provsql.provenance_arith(
0, state);
3936 denom_token := provsql.provenance_arith(
0, denom_state);
3939 RETURN provsql.random_variable_make(
3940 provsql.provenance_arith(
3942 ARRAY[num_token, denom_token]));
3944$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE;
3946CREATE AGGREGATE avg(random_variable) (
3947 SFUNC = sum_rv_sfunc,
3950 FINALFUNC = avg_rv_ffunc
3988CREATE OR REPLACE
FUNCTION product_rv_ffunc(state UUID[])
3989 RETURNS random_variable
AS
3994 prod_state UUID[] :=
'{}';
3995 one_rv provsql.random_variable;
3996 gtype provsql.PROVENANCE_GATE;
4001 one_rv := provsql.as_random(
1::
double precision);
4003 IF state
IS NULL THEN
4006 n := array_length(state,
1);
4012 gtype := provsql.get_gate_type(state[i]);
4013 IF gtype =
'mixture'::provsql.PROVENANCE_GATE
THEN
4014 children := provsql.get_children(state[i]);
4015 prov_i := children[
1];
4016 x_uuid := children[
2];
4017 prod_state := array_append(
4022 provsql.random_variable_make(x_uuid),
4025 prod_state := array_append(prod_state, state[i]);
4030 RETURN provsql.random_variable_make(prod_state[
1]);
4032 RETURN provsql.random_variable_make(
4033 provsql.provenance_arith(
1, prod_state));
4035$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE;
4037CREATE AGGREGATE product(random_variable) (
4038 SFUNC = sum_rv_sfunc,
4041 FINALFUNC = product_rv_ffunc
4060CREATE OR REPLACE
FUNCTION provenance_delta
4067 IF token = gate_zero()
OR token = gate_one()
THEN
4071 IF token
IS NULL THEN
4075 delta_token:=uuid_generate_v5(uuid_ns_provsql(),concat(
'delta',token));
4077 PERFORM create_gate(delta_token,
'delta',
ARRAY[token::UUID]);
4081$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public SECURITY DEFINER PARALLEL SAFE;
4098CREATE OR REPLACE
FUNCTION provenance_aggregate(
4103 is_scalar
BOOLEAN DEFAULT false)
4104 RETURNS AGG_TOKEN
AS
4114 tokens := array_remove(tokens,
NULL);
4115 c:=COALESCE(array_length(tokens,
1),
0);
4117 agg_val =
CAST(val
as VARCHAR);
4120 agg_tok := gate_zero();
4133 agg_tok := uuid_generate_v5(
4135 concat(
'agg',aggfnoid,tokens,
CASE WHEN is_scalar
THEN 'S' ELSE '' END));
4136 PERFORM create_gate(agg_tok,
'agg', tokens);
4137 PERFORM set_infos(agg_tok, aggfnoid,
4138 CASE WHEN is_scalar
THEN aggtype | (-2147483648)
ELSE aggtype
END);
4139 PERFORM set_extra(agg_tok, agg_val);
4142 RETURN '( '||agg_tok||
' , '||agg_val||
' )';
4144$$
LANGUAGE plpgsql PARALLEL SAFE
SET search_path=provsql,pg_temp,public SECURITY DEFINER;
4155CREATE OR REPLACE
FUNCTION provenance_semimod(val ANYELEMENT, token UUID)
4170 SELECT uuid_generate_v5(uuid_ns_provsql(),concat(
'value',
CAST(val
AS VARCHAR)))
4172 SELECT uuid_generate_v5(uuid_ns_provsql(),concat(
'semimod',value_token,token))
4176 PERFORM create_gate(value_token,
'value');
4177 PERFORM set_extra(value_token,
CAST(val
AS VARCHAR));
4180 PERFORM create_gate(semimod_token,
'semimod',
ARRAY[token::UUID,value_token]);
4182 RETURN semimod_token;
4184$$
LANGUAGE plpgsql PARALLEL SAFE
SET search_path=provsql,pg_temp,public SECURITY DEFINER;
4205CREATE OR REPLACE
FUNCTION probability_evaluate(
4208 arguments TEXT =
NULL)
4209 RETURNS DOUBLE PRECISION AS
4210 'provsql',
'probability_evaluate' LANGUAGE C STABLE;
4219CREATE OR REPLACE
FUNCTION probability_bounds(
4221 OUT lower
DOUBLE PRECISION,
4222 OUT upper DOUBLE PRECISION)
AS
4223 'provsql',
'probability_bounds' LANGUAGE C STABLE;
4246CREATE OR REPLACE
FUNCTION expected(
4248 prov UUID = gate_one(),
4250 arguments TEXT =
NULL)
4251 RETURNS DOUBLE PRECISION AS $$
4252 SELECT moment(
input,
1, prov,
method, arguments);
4253$$
LANGUAGE sql PARALLEL SAFE STABLE
SET search_path=provsql SECURITY DEFINER;
4265CREATE OR REPLACE
FUNCTION rv_moment(
4266 token UUID, k
INTEGER, central
BOOLEAN,
4267 prov UUID
DEFAULT gate_one())
4268 RETURNS double precision
4269 AS 'provsql',
'rv_moment' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
4297CREATE OR REPLACE
FUNCTION agg_raw_moment(
4300 prov UUID = gate_one(),
4302 arguments TEXT =
NULL)
4303 RETURNS DOUBLE PRECISION AS $$
4305 aggregation_function
VARCHAR;
4307 pair_children UUID[];
4314 total_probability float8;
4318 distinct_tok UUID[];
4323 IF token
IS NULL OR k
IS NULL THEN
4327 RAISE EXCEPTION
'agg_raw_moment(): k must be non-negative (got %)', k;
4329 IF get_gate_type(token) <>
'agg' THEN
4330 IF get_gate_type(token)
IN (
'arith',
'conditioned')
THEN
4331 RAISE EXCEPTION
'expected / variance / moment over an arithmetic '
4332 'combination of aggregates (e.g. SUM(x) + SUM(y) or SUM(x) + 5), or a '
4333 'conditioning of one, is not yet supported: a moment can be taken only '
4334 'over a single aggregate (SUM / COUNT / MIN / MAX), optionally '
4335 'conditioned (SUM(x) | C)'
4336 USING HINT =
'Take the moment of each aggregate separately, or condition '
4337 'the bare aggregate.';
4339 RAISE EXCEPTION
USING MESSAGE=
'Wrong gate type for agg_raw_moment computation';
4346 SELECT pp.proname::
varchar FROM pg_proc pp
4347 WHERE oid=(get_infos(token)).info1
4348 INTO aggregation_function;
4350 child_pairs := get_children(token);
4351 n := COALESCE(array_length(child_pairs,
1),
0);
4353 IF aggregation_function =
'sum' OR aggregation_function =
'count' THEN
4366 vals :=
ARRAY[]::float8[];
4367 toks :=
ARRAY[]::UUID[];
4369 pair_children := get_children(child_pairs[i]);
4370 toks := toks || pair_children[
1];
4371 vals := vals ||
CAST(get_extra(pair_children[
2])
AS float8);
4377 tup := array_fill(
1,
ARRAY[k]);
4381 prod_v := prod_v * vals[tup[j]];
4384 SELECT array_agg(
DISTINCT toks[idx])
INTO distinct_tok
4385 FROM unnest(tup)
AS idx;
4387 IF prov <> gate_one()
THEN
4388 distinct_tok := distinct_tok || prov;
4390 conj_token := provenance_times(VARIADIC distinct_tok);
4391 prob := probability_evaluate(conj_token,
method, arguments);
4393 total := total + prod_v * prob;
4396 WHILE d >=
1 AND tup[d] = n LOOP
4401 tup[d] := tup[d] +
1;
4403 ELSIF aggregation_function =
'min' OR aggregation_function =
'max' THEN
4411 WHEN aggregation_function =
'max'
4412 THEN power(-1::float8, k)
4428 SELECT (get_children(c))[
1]
AS tok,
4429 (
CASE WHEN aggregation_function=
'max' THEN -1
ELSE 1 END)
4430 *
CAST(get_extra((get_children(c))[
2])
AS DOUBLE PRECISION)
AS v
4431 FROM UNNEST(child_pairs)
AS c
4432 )
SELECT sign_max * COALESCE(SUM(p * power(v, k)),
0)
FROM (
4434 probability_evaluate(
4435 CASE WHEN prov = gate_one()
4436 THEN provenance_monus(provenance_plus(ARRAY_AGG(t1.tok)),
4437 provenance_plus(ARRAY_AGG(t2.tok)))
4438 ELSE provenance_times(prov,
4439 provenance_monus(provenance_plus(ARRAY_AGG(t1.tok)),
4440 provenance_plus(ARRAY_AGG(t2.tok))))
END,
4441 method, arguments)
AS p
4442 FROM tok_value t1
LEFT OUTER JOIN tok_value t2
ON t1.v > t2.v
4447 SELECT probability_evaluate(
4448 CASE WHEN prov = gate_one()
4449 THEN provenance_plus(ARRAY_AGG(tok))
4450 ELSE provenance_times(prov, provenance_plus(ARRAY_AGG(tok)))
END,
4452 FROM (
SELECT (get_children(c))[
1]
AS tok
FROM UNNEST(child_pairs)
AS c) s
4453 INTO total_probability;
4455 IF total_probability <= epsilon()
THEN
4458 RETURN total / total_probability;
4460 RAISE EXCEPTION
USING MESSAGE=
4461 'Cannot compute moment for aggregation function ' || aggregation_function;
4465 IF prov <> gate_one()
4467 AND total <>
'Infinity'::float8
4468 AND total <>
'-Infinity'::float8
THEN
4469 total := total / probability_evaluate(prov,
method, arguments);
4474$$
LANGUAGE plpgsql PARALLEL SAFE
SET search_path=provsql SECURITY DEFINER;
4487CREATE OR REPLACE
FUNCTION variance(
4489 prov UUID = gate_one(),
4491 arguments TEXT =
NULL)
4492 RETURNS DOUBLE PRECISION AS $$
4497 IF pg_typeof(
input) =
'random_variable'::REGTYPE
THEN
4498 IF input IS NULL THEN
4508 RETURN provsql.rv_moment(
4509 rv_conditioned_target((
input::random_variable)::UUID),
2,
true,
4510 rv_conditioned_prov((
input::random_variable)::UUID, prov));
4513 IF pg_typeof(
input) =
'AGG_TOKEN'::REGTYPE
THEN
4514 IF input IS NULL THEN
4517 m1 := agg_raw_moment(agg_conditioned_target(
input::AGG_TOKEN),
1,
4518 rv_conditioned_prov(
input::UUID, prov),
method, arguments);
4519 m2 := agg_raw_moment(agg_conditioned_target(
input::AGG_TOKEN),
2,
4520 rv_conditioned_prov(
input::UUID, prov),
method, arguments);
4521 IF m1
IS NULL OR m2
IS NULL THEN
4524 RETURN m2 - m1 * m1;
4527 RAISE EXCEPTION
'variance() is not yet supported for input type %', pg_typeof(
input);
4529$$
LANGUAGE plpgsql PARALLEL SAFE
SET search_path=provsql SECURITY DEFINER;
4540CREATE OR REPLACE
FUNCTION moment(
4543 prov UUID = gate_one(),
4545 arguments TEXT =
NULL)
4546 RETURNS DOUBLE PRECISION AS $$
4548 IF pg_typeof(
input) =
'random_variable'::REGTYPE
THEN
4549 IF input IS NULL OR k
IS NULL THEN
4554 RETURN provsql.rv_moment(
4555 rv_conditioned_target((
input::random_variable)::UUID), k,
false,
4556 rv_conditioned_prov((
input::random_variable)::UUID, prov));
4559 IF pg_typeof(
input) =
'AGG_TOKEN'::REGTYPE
THEN
4560 RETURN agg_raw_moment(agg_conditioned_target(
input::AGG_TOKEN), k,
4561 rv_conditioned_prov(
input::UUID, prov),
method, arguments);
4564 RAISE EXCEPTION
'moment() is not yet supported for input type %', pg_typeof(
input);
4566$$
LANGUAGE plpgsql PARALLEL SAFE
SET search_path=provsql SECURITY DEFINER;
4577CREATE OR REPLACE
FUNCTION rv_support(
4578 token UUID, prov UUID
DEFAULT gate_one(),
4579 OUT lo float8,
OUT hi float8)
4580 AS 'provsql',
'rv_support' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
4622CREATE OR REPLACE
FUNCTION support(
4624 prov UUID = gate_one(),
4626 arguments TEXT =
NULL,
4631 aggregation_function
VARCHAR;
4633 values_arr float8[];
4634 total_probability float8;
4636 IF input IS NULL THEN
4637 lo :=
NULL; hi :=
NULL;
RETURN;
4643 IF pg_typeof(
input)
IN (
4644 'smallint'::REGTYPE,
'INTEGER'::REGTYPE,
'bigint'::REGTYPE,
4645 'NUMERIC'::REGTYPE,
'real'::REGTYPE,
'double precision'::REGTYPE)
THEN
4646 lo :=
input::
double precision;
4647 hi :=
input::
double precision;
4660 IF pg_typeof(
input)
IN (
'random_variable'::REGTYPE,
'UUID'::REGTYPE)
THEN
4665 SELECT r.lo, r.hi
INTO lo, hi
4666 FROM provsql.rv_support(
4667 rv_conditioned_target(
input::UUID),
4668 rv_conditioned_prov(
input::UUID, prov)) r;
4672 IF pg_typeof(
input) =
'AGG_TOKEN'::REGTYPE
THEN
4677 atok AGG_TOKEN := agg_conditioned_target(
input::AGG_TOKEN);
4679 IF get_gate_type(atok) <>
'agg' THEN
4680 RAISE EXCEPTION
USING MESSAGE=
'Wrong gate type for support computation';
4682 SELECT pp.proname::
varchar FROM pg_proc pp
4683 WHERE oid=(get_infos(atok)).info1
4684 INTO aggregation_function;
4685 child_pairs := get_children(atok);
4687 IF aggregation_function =
'sum' OR aggregation_function =
'count' THEN
4691 IF COALESCE(array_length(child_pairs,
1),
0) =
0 THEN
4692 lo :=
0; hi :=
0;
RETURN;
4694 SELECT sum(LEAST(v,
0::float8)), sum(GREATEST(v,
0::float8))
4696 FROM (
SELECT CAST(get_extra((get_children(c))[
2])
AS float8)
AS v
4697 FROM unnest(child_pairs)
AS c) sub;
4698 ELSIF aggregation_function =
'min' OR aggregation_function =
'max' THEN
4703 IF COALESCE(array_length(child_pairs,
1),
0) =
0 THEN
4704 lo :=
NULL; hi :=
NULL;
RETURN;
4707 SELECT min(v), max(v)
4709 FROM (
SELECT CAST(get_extra((get_children(c))[
2])
AS float8)
AS v
4710 FROM UNNEST(child_pairs)
AS c) sub;
4712 RAISE EXCEPTION
USING MESSAGE=
4713 'Cannot compute support for aggregation function ' || aggregation_function;
4719 RAISE EXCEPTION
'support() is not yet supported for input type %', pg_typeof(
input);
4721$$
LANGUAGE plpgsql PARALLEL SAFE
SET search_path=provsql SECURITY DEFINER;
4734CREATE OR REPLACE
FUNCTION central_moment(
4737 prov UUID = gate_one(),
4739 arguments TEXT =
NULL)
4740 RETURNS DOUBLE PRECISION AS $$
4750 IF pg_typeof(
input) =
'random_variable'::REGTYPE
THEN
4751 IF input IS NULL OR k
IS NULL THEN
4756 RETURN provsql.rv_moment(
4757 rv_conditioned_target((
input::random_variable)::UUID), k,
true,
4758 rv_conditioned_prov((
input::random_variable)::UUID, prov));
4761 IF pg_typeof(
input) =
'AGG_TOKEN'::REGTYPE
THEN
4762 IF input IS NULL OR k
IS NULL THEN
4766 RAISE EXCEPTION
'central_moment(): k must be non-negative (got %)', k;
4768 IF k =
0 THEN RETURN 1;
END IF;
4769 IF k =
1 THEN RETURN 0;
END IF;
4771 mu := agg_raw_moment(agg_conditioned_target(
input::AGG_TOKEN),
1,
4772 rv_conditioned_prov(
input::UUID, prov),
method, arguments);
4773 IF mu
IS NULL THEN RETURN NULL;
END IF;
4776 IF mu =
'Infinity'::float8
OR mu =
'-Infinity'::float8
THEN
4784 raw_i := agg_raw_moment(agg_conditioned_target(
input::AGG_TOKEN), i,
4785 rv_conditioned_prov(
input::UUID, prov),
method, arguments);
4786 IF raw_i
IS NULL THEN RETURN NULL;
END IF;
4787 total := total + binom * power(-mu, k - i) * raw_i;
4790 binom := binom * (k_double - i) / (i +
1);
4796 RAISE EXCEPTION
'central_moment() is not yet supported for input type %', pg_typeof(
input);
4798$$
LANGUAGE plpgsql PARALLEL SAFE
SET search_path=provsql SECURITY DEFINER;
4812CREATE OR REPLACE
FUNCTION shapley(
4816 arguments TEXT =
NULL,
4817 banzhaf
BOOLEAN =
'f')
4818 RETURNS DOUBLE PRECISION AS
4819 'provsql',
'shapley' LANGUAGE C STABLE;
4822CREATE OR REPLACE
FUNCTION shapley_all_vars(
4824 IN method TEXT =
NULL,
4825 IN arguments TEXT =
NULL,
4826 IN banzhaf
BOOLEAN =
'f',
4828 OUT value DOUBLE PRECISION)
4829 RETURNS SETOF RECORD
AS
4830 'provsql',
'shapley_all_vars'
4834CREATE OR REPLACE
FUNCTION banzhaf(
4838 arguments TEXT =
NULL)
4839 RETURNS DOUBLE PRECISION AS
4840 $$
SELECT provsql.shapley(token, variable,
method, arguments,
't') $$
4844CREATE OR REPLACE
FUNCTION banzhaf_all_vars(
4846 IN method TEXT =
NULL,
4847 IN arguments TEXT =
NULL,
4849 OUT value DOUBLE PRECISION)
4850 RETURNS SETOF RECORD
AS
4851 $$
SELECT *
FROM provsql.shapley_all_vars(token,
method, arguments,
't') $$
4886CREATE OR REPLACE
FUNCTION reachability_evaluate(
4890 probabilities
DOUBLE PRECISION[],
4894 RETURNS DOUBLE PRECISION AS
4895 'provsql',
'reachability_evaluate' LANGUAGE C IMMUTABLE PARALLEL SAFE;
4925CREATE OR REPLACE
FUNCTION reachability_compile_stats(
4927 IN destinations
INT[],
4929 IN probabilities
DOUBLE PRECISION[],
4932 IN directed
BOOLEAN,
4933 OUT probability
DOUBLE PRECISION,
4934 OUT data_treewidth
INT,
4936 OUT max_states
BIGINT,
4937 OUT nb_gates
BIGINT,
4938 OUT nb_variables
BIGINT)
4939 AS 'provsql',
'reachability_compile_stats'
4940 LANGUAGE C IMMUTABLE PARALLEL SAFE;
4976CREATE OR REPLACE
FUNCTION ucq_joint_compile_stats(
4977 IN disjunct_nvars
INT[],
4978 IN atom_disjunct
INT[],
4981 IN atom_arity
INT[],
4983 IN fact_elems
INT[],
4984 IN fact_arity
INT[],
4985 IN fact_tokens UUID[],
4986 IN fact_probs
DOUBLE PRECISION[],
4987 OUT probability
DOUBLE PRECISION,
4988 OUT joint_treewidth
INT,
4989 OUT data_treewidth_lb
INT,
4990 OUT circuit_treewidth_lb
INT,
4992 OUT max_states
BIGINT,
4994 OUT n_enumerating
INT)
4995 AS 'provsql',
'ucq_joint_compile_stats'
4996 LANGUAGE C IMMUTABLE PARALLEL SAFE;
5005CREATE OR REPLACE
FUNCTION ucq_joint_compile_stats(
5008 IN fact_elems
INT[],
5009 IN fact_arity
INT[],
5010 IN fact_tokens UUID[],
5011 IN fact_probs
DOUBLE PRECISION[],
5012 OUT probability
DOUBLE PRECISION,
5013 OUT joint_treewidth
INT,
5014 OUT data_treewidth_lb
INT,
5015 OUT circuit_treewidth_lb
INT,
5017 OUT max_states
BIGINT,
5019 OUT n_enumerating
INT)
5022 dnv
INT[] :=
'{}'; adisj
INT[] :=
'{}'; arel
INT[] :=
'{}';
5023 avars
INT[] :=
'{}'; aarity
INT[] :=
'{}';
5024 d JSONB; a JSONB; v TEXT; didx
INT :=
0;
5026 FOR d
IN SELECT *
FROM jsonb_array_elements(query->
'disjuncts') LOOP
5027 dnv := dnv || (d->>
'n_vars')::
INT;
5028 FOR a
IN SELECT *
FROM jsonb_array_elements(d->
'atoms') LOOP
5029 adisj := adisj || didx;
5030 arel := arel || (a->>
'rel')::
INT;
5031 aarity := aarity || jsonb_array_length(a->
'vars');
5032 FOR v
IN SELECT *
FROM jsonb_array_elements_text(a->
'vars') LOOP
5033 avars := avars || v::
INT;
5038 SELECT s.probability, s.joint_treewidth, s.data_treewidth_lb,
5039 s.circuit_treewidth_lb, s.n_bags, s.max_states, s.dd_size,
5041 INTO probability, joint_treewidth, data_treewidth_lb,
5042 circuit_treewidth_lb, n_bags, max_states, dd_size, n_enumerating
5043 FROM ucq_joint_compile_stats(dnv, adisj, arel, avars, aarity,
5044 fact_rel, fact_elems, fact_arity, fact_tokens, fact_probs) s;
5046$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE;
5067CREATE OR REPLACE
FUNCTION ucq_joint_compile_stats_tracked(
5068 IN disjunct_nvars
INT[],
5069 IN atom_disjunct
INT[],
5072 IN atom_arity
INT[],
5074 IN fact_elems
INT[],
5075 IN fact_arity
INT[],
5076 IN fact_tokens UUID[],
5077 OUT probability
DOUBLE PRECISION,
5078 OUT joint_treewidth
INT,
5079 OUT data_treewidth_lb
INT,
5080 OUT circuit_treewidth_lb
INT,
5082 OUT max_states
BIGINT,
5084 OUT n_enumerating
INT)
5085 AS 'provsql',
'ucq_joint_compile_stats_tracked'
5086 LANGUAGE C STABLE PARALLEL SAFE;
5092CREATE OR REPLACE
FUNCTION ucq_joint_compile_stats_tracked(
5095 IN fact_elems
INT[],
5096 IN fact_arity
INT[],
5097 IN fact_tokens UUID[],
5098 OUT probability
DOUBLE PRECISION,
5099 OUT joint_treewidth
INT,
5100 OUT data_treewidth_lb
INT,
5101 OUT circuit_treewidth_lb
INT,
5103 OUT max_states
BIGINT,
5105 OUT n_enumerating
INT)
5108 dnv
INT[] :=
'{}'; adisj
INT[] :=
'{}'; arel
INT[] :=
'{}';
5109 avars
INT[] :=
'{}'; aarity
INT[] :=
'{}';
5110 d JSONB; a JSONB; v TEXT; didx
INT :=
0;
5112 FOR d
IN SELECT *
FROM jsonb_array_elements(query->
'disjuncts') LOOP
5113 dnv := dnv || (d->>
'n_vars')::
INT;
5114 FOR a
IN SELECT *
FROM jsonb_array_elements(d->
'atoms') LOOP
5115 adisj := adisj || didx;
5116 arel := arel || (a->>
'rel')::
INT;
5117 aarity := aarity || jsonb_array_length(a->
'vars');
5118 FOR v
IN SELECT *
FROM jsonb_array_elements_text(a->
'vars') LOOP
5119 avars := avars || v::
INT;
5124 SELECT s.probability, s.joint_treewidth, s.data_treewidth_lb,
5125 s.circuit_treewidth_lb, s.n_bags, s.max_states, s.dd_size,
5127 INTO probability, joint_treewidth, data_treewidth_lb,
5128 circuit_treewidth_lb, n_bags, max_states, dd_size, n_enumerating
5129 FROM ucq_joint_compile_stats_tracked(dnv, adisj, arel, avars, aarity,
5130 fact_rel, fact_elems, fact_arity, fact_tokens) s;
5132$$
LANGUAGE plpgsql STABLE PARALLEL SAFE;
5147CREATE OR REPLACE
FUNCTION ucq_joint_materialize_tracked(
5148 disjunct_nvars
INT[],
5149 atom_disjunct
INT[],
5158 'provsql',
'ucq_joint_materialize_tracked' LANGUAGE C VOLATILE;
5168CREATE OR REPLACE
FUNCTION ucq_joint_materialize_tracked(
5176 dnv
INT[] :=
'{}'; adisj
INT[] :=
'{}'; arel
INT[] :=
'{}';
5177 avars
INT[] :=
'{}'; aarity
INT[] :=
'{}';
5178 d JSONB; a JSONB; v TEXT; didx
INT :=
0;
5180 FOR d
IN SELECT *
FROM jsonb_array_elements(query->
'disjuncts') LOOP
5181 dnv := dnv || (d->>
'n_vars')::
INT;
5182 FOR a
IN SELECT *
FROM jsonb_array_elements(d->
'atoms') LOOP
5183 adisj := adisj || didx;
5184 arel := arel || (a->>
'rel')::
INT;
5185 aarity := aarity || jsonb_array_length(a->
'vars');
5186 FOR v
IN SELECT *
FROM jsonb_array_elements_text(a->
'vars') LOOP
5187 avars := avars || v::
INT;
5192 RETURN ucq_joint_materialize_tracked(dnv, adisj, arel, avars, aarity,
5193 fact_rel, fact_elems, fact_arity, fact_tokens);
5195$$
LANGUAGE plpgsql VOLATILE;
5229CREATE OR REPLACE
FUNCTION ucq_joint_provenance(
5230 descriptor JSONB, fallback UUID
DEFAULT NULL)
5233 legs TEXT;
sql TEXT; saved TEXT;
5234 fact_rel
INT[]; fact_elems
INT[]; fact_arity
INT[]; fact_tokens UUID[];
5235 dnv
INT[]:=
'{}'; adisj
INT[]:=
'{}'; arel
INT[]:=
'{}';
5236 avars
INT[]:=
'{}'; aarity
INT[]:=
'{}';
5237 d jsonb; a jsonb; v TEXT; didx
INT:=
0;
5240 FOR d
IN SELECT *
FROM jsonb_array_elements(descriptor->
'disjuncts') LOOP
5241 dnv := dnv || (d->>
'n_vars')::
INT;
5242 FOR a
IN SELECT *
FROM jsonb_array_elements(d->
'atoms') LOOP
5243 adisj := adisj || didx; arel := arel || (a->>
'rel')::
INT;
5244 aarity := aarity || jsonb_array_length(a->
'vars');
5245 FOR v
IN SELECT *
FROM jsonb_array_elements_text(a->
'vars') LOOP
5246 avars := avars || v::
INT;
5256 format(
'SELECT %s, ARRAY[%s]::TEXT[], provsql FROM %s%s',
5258 (
SELECT string_agg(format(
'(%I)::TEXT', c),
',')
5259 FROM jsonb_array_elements_text(descriptor->
'elem_cols'->(rn-1)::
INT) c),
5263 CASE WHEN coalesce(descriptor->
'rel_where'->>(rn-1)::
INT,
'') <>
''
5264 THEN ' WHERE '||(descriptor->
'rel_where'->>(rn-1)::
INT)
5268 FROM jsonb_array_elements_text(descriptor->
'relations')
WITH ORDINALITY t(rel, rn);
5271 WITH facts(rel,elems,tok)
AS (%s),
5272 ord
AS (
SELECT row_number()
OVER ()
AS ord, rel, elems, tok
FROM facts),
5273 dict
AS (
SELECT val, (dense_rank()
OVER (
ORDER BY val))-1
AS id
5274 FROM (
SELECT DISTINCT unnest(elems)
AS val
FROM facts) u)
5275 SELECT (
SELECT array_agg(rel
ORDER BY ord)
FROM ord),
5276 (
SELECT array_agg(cardinality(elems)
ORDER BY ord)
FROM ord),
5277 (
SELECT array_agg(tok
ORDER BY ord)
FROM ord),
5278 (
SELECT array_agg(dd.id
ORDER BY o.ord, e.k)
5279 FROM ord o,
LATERAL unnest(o.elems)
WITH ORDINALITY e(val,k)
5280 JOIN dict dd
ON dd.val = e.val)
5285 saved := current_setting(
'provsql.active',
true);
5286 PERFORM set_config(
'provsql.active',
'off',
true);
5287 EXECUTE sql INTO fact_rel, fact_arity, fact_tokens, fact_elems;
5288 PERFORM set_config(
'provsql.active', saved,
true);
5290 RETURN ucq_joint_materialize_tracked(dnv,adisj,arel,avars,aarity,
5291 fact_rel,fact_elems,fact_arity,fact_tokens);
5292EXCEPTION
WHEN OTHERS
THEN
5298$$
LANGUAGE plpgsql VOLATILE;
5316CREATE OR REPLACE
FUNCTION ucq_mobius_materialize_tracked(
5317 disjunct_nvars
INT[],
5318 atom_disjunct
INT[],
5326 lineage UUID
DEFAULT NULL)
5328 'provsql',
'ucq_mobius_materialize_tracked' LANGUAGE C VOLATILE;
5337CREATE OR REPLACE
FUNCTION ucq_mobius_compile_stats(
5338 IN disjunct_nvars
INT[],
5339 IN atom_disjunct
INT[],
5342 IN atom_arity
INT[],
5344 IN fact_elems
INT[],
5345 IN fact_arity
INT[],
5346 IN fact_tokens UUID[],
5347 OUT probability
DOUBLE PRECISION,
5348 OUT n_components
INT,
5349 OUT n_cnf_conjuncts
INT,
5350 OUT lattice_size
INT,
5352 OUT n_cancelled
INT,
5353 OUT cancelled_hard
BOOLEAN,
5355 OUT memo_hits
BIGINT)
5356 AS 'provsql',
'ucq_mobius_compile_stats'
5357 LANGUAGE C VOLATILE;
5371CREATE OR REPLACE
FUNCTION mobius_or_null(tok UUID)
5373 SELECT CASE WHEN tok
IS NOT NULL AND provsql.get_gate_type(tok) =
'mobius'
5375$$
LANGUAGE sql STABLE;
5383CREATE OR REPLACE
FUNCTION ucq_mobius_provenance(
5384 descriptor JSONB, fallback UUID
DEFAULT NULL)
5387 legs TEXT;
sql TEXT; saved TEXT;
5388 fact_rel
INT[]; fact_elems
INT[]; fact_arity
INT[]; fact_tokens UUID[];
5389 dnv
INT[]:=
'{}'; adisj
INT[]:=
'{}'; arel
INT[]:=
'{}';
5390 avars
INT[]:=
'{}'; aarity
INT[]:=
'{}';
5391 d jsonb; a jsonb; v TEXT; didx
INT:=
0;
5393 FOR d
IN SELECT *
FROM jsonb_array_elements(descriptor->
'disjuncts') LOOP
5394 dnv := dnv || (d->>
'n_vars')::
INT;
5395 FOR a
IN SELECT *
FROM jsonb_array_elements(d->
'atoms') LOOP
5396 adisj := adisj || didx; arel := arel || (a->>
'rel')::
INT;
5397 aarity := aarity || jsonb_array_length(a->
'vars');
5398 FOR v
IN SELECT *
FROM jsonb_array_elements_text(a->
'vars') LOOP
5399 avars := avars || v::
INT;
5406 format(
'SELECT %s, ARRAY[%s]::TEXT[], provsql FROM %s%s',
5408 (
SELECT string_agg(format(
'(%I)::TEXT', c),
',')
5409 FROM jsonb_array_elements_text(descriptor->
'elem_cols'->(rn-1)::
INT) c),
5411 CASE WHEN coalesce(descriptor->
'rel_where'->>(rn-1)::
INT,
'') <>
''
5412 THEN ' WHERE '||(descriptor->
'rel_where'->>(rn-1)::
INT)
5416 FROM jsonb_array_elements_text(descriptor->
'relations')
WITH ORDINALITY t(rel, rn);
5419 WITH facts(rel,elems,tok)
AS (%s),
5420 ord
AS (
SELECT row_number()
OVER ()
AS ord, rel, elems, tok
FROM facts),
5421 dict
AS (
SELECT val, (dense_rank()
OVER (
ORDER BY val))-1
AS id
5422 FROM (
SELECT DISTINCT unnest(elems)
AS val
FROM facts) u)
5423 SELECT (
SELECT array_agg(rel
ORDER BY ord)
FROM ord),
5424 (
SELECT array_agg(cardinality(elems)
ORDER BY ord)
FROM ord),
5425 (
SELECT array_agg(tok
ORDER BY ord)
FROM ord),
5426 (
SELECT array_agg(dd.id
ORDER BY o.ord, e.k)
5427 FROM ord o,
LATERAL unnest(o.elems)
WITH ORDINALITY e(val,k)
5428 JOIN dict dd
ON dd.val = e.val)
5431 saved := current_setting(
'provsql.active',
true);
5432 PERFORM set_config(
'provsql.active',
'off',
true);
5433 EXECUTE sql INTO fact_rel, fact_arity, fact_tokens, fact_elems;
5434 PERFORM set_config(
'provsql.active', saved,
true);
5439 RETURN ucq_mobius_materialize_tracked(dnv,adisj,arel,avars,aarity,
5440 fact_rel,fact_elems,fact_arity,fact_tokens, fallback);
5441EXCEPTION
WHEN OTHERS
THEN
5444$$
LANGUAGE plpgsql VOLATILE;
5452CREATE OR REPLACE
FUNCTION mobius_compile_stats(
5453 IN descriptor JSONB,
5454 OUT probability
DOUBLE PRECISION,
5455 OUT n_components
INT,
5456 OUT n_cnf_conjuncts
INT,
5457 OUT lattice_size
INT,
5459 OUT n_cancelled
INT,
5460 OUT cancelled_hard
BOOLEAN,
5462 OUT memo_hits
BIGINT)
5465 legs TEXT;
sql TEXT; saved TEXT;
5466 fact_rel
INT[]; fact_elems
INT[]; fact_arity
INT[]; fact_tokens UUID[];
5467 dnv
INT[]:=
'{}'; adisj
INT[]:=
'{}'; arel
INT[]:=
'{}';
5468 avars
INT[]:=
'{}'; aarity
INT[]:=
'{}';
5469 d jsonb; a jsonb; v TEXT; didx
INT:=
0;
5471 FOR d
IN SELECT *
FROM jsonb_array_elements(descriptor->
'disjuncts') LOOP
5472 dnv := dnv || (d->>
'n_vars')::
INT;
5473 FOR a
IN SELECT *
FROM jsonb_array_elements(d->
'atoms') LOOP
5474 adisj := adisj || didx; arel := arel || (a->>
'rel')::
INT;
5475 aarity := aarity || jsonb_array_length(a->
'vars');
5476 FOR v
IN SELECT *
FROM jsonb_array_elements_text(a->
'vars') LOOP
5477 avars := avars || v::
INT;
5484 format(
'SELECT %s, ARRAY[%s]::TEXT[], provsql FROM %s%s',
5486 (
SELECT string_agg(format(
'(%I)::TEXT', c),
',')
5487 FROM jsonb_array_elements_text(descriptor->
'elem_cols'->(rn-1)::
INT) c),
5489 CASE WHEN coalesce(descriptor->
'rel_where'->>(rn-1)::
INT,
'') <>
''
5490 THEN ' WHERE '||(descriptor->
'rel_where'->>(rn-1)::
INT)
5494 FROM jsonb_array_elements_text(descriptor->
'relations')
WITH ORDINALITY t(rel, rn);
5497 WITH facts(rel,elems,tok)
AS (%s),
5498 ord
AS (
SELECT row_number()
OVER ()
AS ord, rel, elems, tok
FROM facts),
5499 dict
AS (
SELECT val, (dense_rank()
OVER (
ORDER BY val))-1
AS id
5500 FROM (
SELECT DISTINCT unnest(elems)
AS val
FROM facts) u)
5501 SELECT (
SELECT array_agg(rel
ORDER BY ord)
FROM ord),
5502 (
SELECT array_agg(cardinality(elems)
ORDER BY ord)
FROM ord),
5503 (
SELECT array_agg(tok
ORDER BY ord)
FROM ord),
5504 (
SELECT array_agg(dd.id
ORDER BY o.ord, e.k)
5505 FROM ord o,
LATERAL unnest(o.elems)
WITH ORDINALITY e(val,k)
5506 JOIN dict dd
ON dd.val = e.val)
5509 saved := current_setting(
'provsql.active',
true);
5510 PERFORM set_config(
'provsql.active',
'off',
true);
5511 EXECUTE sql INTO fact_rel, fact_arity, fact_tokens, fact_elems;
5512 PERFORM set_config(
'provsql.active', saved,
true);
5514 SELECT s.probability, s.n_components, s.n_cnf_conjuncts, s.lattice_size,
5515 s.n_nonzero, s.n_cancelled, s.cancelled_hard, s.dd_size, s.memo_hits
5516 INTO probability, n_components, n_cnf_conjuncts, lattice_size,
5517 n_nonzero, n_cancelled, cancelled_hard, dd_size, memo_hits
5518 FROM ucq_mobius_compile_stats(dnv,adisj,arel,avars,aarity,
5519 fact_rel,fact_elems,fact_arity,fact_tokens) s;
5521$$
LANGUAGE plpgsql VOLATILE;
5534CREATE OR REPLACE
FUNCTION ucq_joint_gather(
5536 OUT disjunct_nvars
INT[],
OUT atom_disjunct
INT[],
OUT atom_rel
INT[],
5537 OUT atom_vars
INT[],
OUT atom_arity
INT[],
5538 OUT fact_rel
INT[],
OUT fact_elems
INT[],
OUT fact_arity
INT[],
5539 OUT fact_tokens UUID[],
OUT val_by_id TEXT[])
5542 legs TEXT;
sql TEXT; saved TEXT; d jsonb; a jsonb; v TEXT; didx
INT :=
0;
5544 disjunct_nvars:=
'{}'; atom_disjunct:=
'{}'; atom_rel:=
'{}';
5545 atom_vars:=
'{}'; atom_arity:=
'{}';
5546 FOR d
IN SELECT *
FROM jsonb_array_elements(descriptor->
'disjuncts') LOOP
5547 disjunct_nvars := disjunct_nvars || (d->>
'n_vars')::
INT;
5548 FOR a
IN SELECT *
FROM jsonb_array_elements(d->
'atoms') LOOP
5549 atom_disjunct := atom_disjunct || didx;
5550 atom_rel := atom_rel || (a->>
'rel')::
INT;
5551 atom_arity := atom_arity || jsonb_array_length(a->
'vars');
5552 FOR v
IN SELECT *
FROM jsonb_array_elements_text(a->
'vars') LOOP
5553 atom_vars := atom_vars || v::
INT;
5560 format(
'SELECT %s, ARRAY[%s]::TEXT[], provsql FROM %s%s', rn -
1,
5561 (
SELECT string_agg(format(
'(%I)::TEXT', c),
',')
5562 FROM jsonb_array_elements_text(descriptor->
'elem_cols'->(rn-1)::
INT) c),
5564 CASE WHEN coalesce(descriptor->
'rel_where'->>(rn-1)::
INT,
'') <>
''
5565 THEN ' WHERE '||(descriptor->
'rel_where'->>(rn-1)::
INT)
5569 FROM jsonb_array_elements_text(descriptor->
'relations')
WITH ORDINALITY t(rel, rn);
5572 WITH facts(rel,elems,tok)
AS (%s),
5573 ord
AS (
SELECT row_number()
OVER ()
AS ord, rel, elems, tok
FROM facts),
5574 dict
AS (
SELECT val, (dense_rank()
OVER (
ORDER BY val))-1
AS id
5575 FROM (
SELECT DISTINCT unnest(elems)
AS val
FROM facts) u)
5576 SELECT (
SELECT array_agg(rel
ORDER BY ord)
FROM ord),
5577 (
SELECT array_agg(cardinality(elems)
ORDER BY ord)
FROM ord),
5578 (
SELECT array_agg(tok
ORDER BY ord)
FROM ord),
5579 (
SELECT array_agg(dd.id
ORDER BY o.ord, e.k)
5580 FROM ord o,
LATERAL unnest(o.elems)
WITH ORDINALITY e(val,k)
5581 JOIN dict dd
ON dd.val = e.val),
5582 (
SELECT array_agg(val
ORDER BY id)
FROM dict)
5585 saved := current_setting(
'provsql.active',
true);
5586 PERFORM set_config(
'provsql.active',
'off',
true);
5587 EXECUTE sql INTO fact_rel, fact_arity, fact_tokens, fact_elems, val_by_id;
5588 PERFORM set_config(
'provsql.active', saved,
true);
5590$$
LANGUAGE plpgsql VOLATILE;
5607CREATE OR REPLACE
FUNCTION ucq_joint_provenance_answer(
5608 descriptor JSONB, head_vars
INT[], head_vals TEXT[], fallback UUID
DEFAULT NULL)
5609RETURNS UUID
AS 'provsql',
'ucq_joint_provenance_answer'
5620CREATE OR REPLACE
FUNCTION ucq_mobius_provenance_answer(
5621 descriptor JSONB, head_vars
INT[], head_vals TEXT[], fallback UUID
DEFAULT NULL)
5622RETURNS UUID
AS 'provsql',
'ucq_mobius_provenance_answer'
5663CREATE OR REPLACE
FUNCTION reachability_materialize(
5665 IN destinations
INT[],
5667 IN probabilities
DOUBLE PRECISION[],
5668 IN block_keys UUID[],
5669 IN block_indices
INT[],
5670 IN source_vertices
INT[],
5671 IN source_tokens UUID[],
5672 IN source_probabilities
DOUBLE PRECISION[],
5673 IN directed
BOOLEAN,
5676 RETURNS SETOF RECORD
AS
5677 'provsql',
'reachability_materialize' LANGUAGE C VOLATILE;
5710CREATE OR REPLACE
FUNCTION reachability_materialize_hops(
5712 IN destinations
INT[],
5714 IN probabilities
DOUBLE PRECISION[],
5715 IN block_keys UUID[],
5716 IN block_indices
INT[],
5717 IN source_vertices
INT[],
5718 IN source_tokens UUID[],
5719 IN source_probabilities
DOUBLE PRECISION[],
5720 IN directed
BOOLEAN,
5726 RETURNS SETOF RECORD
AS
5727 'provsql',
'reachability_materialize_hops' LANGUAGE C VOLATILE;
5759CREATE OR REPLACE
FUNCTION reachability_materialize_any(
5761 IN destinations
INT[],
5763 IN probabilities
DOUBLE PRECISION[],
5764 IN block_keys UUID[],
5765 IN block_indices
INT[],
5766 IN source_vertices
INT[],
5767 IN source_tokens UUID[],
5768 IN source_probabilities
DOUBLE PRECISION[],
5769 IN directed
BOOLEAN,
5771 IN member_vertices
INT[],
5774 RETURNS SETOF RECORD
AS
5775 'provsql',
'reachability_materialize_any' LANGUAGE C VOLATILE;
5805CREATE OR REPLACE
FUNCTION reachability_materialize_cover(
5809 probabilities
DOUBLE PRECISION[],
5811 block_indices
INT[],
5812 source_vertices
INT[],
5813 source_tokens UUID[],
5814 source_probabilities
DOUBLE PRECISION[],
5816 member_vertices
INT[])
5818 'provsql',
'reachability_materialize_cover' LANGUAGE C VOLATILE;
5855CREATE OR REPLACE
FUNCTION plant_reach_any_groups(
5857 node_attribute TEXT,
5858 member_rel REGCLASS,
5859 member_attribute TEXT,
5860 group_attribute TEXT,
5862 source_attribute TEXT,
5863 destination_attribute TEXT,
5866 edge_quals TEXT
DEFAULT NULL,
5867 source_rel REGCLASS
DEFAULT NULL,
5868 source_rel_attribute TEXT
DEFAULT NULL,
5869 edge_sql TEXT
DEFAULT NULL,
5870 member_quals TEXT
DEFAULT NULL)
5879 sp
double precision[];
5880 gids
INT[] :=
ARRAY[]::
INT[];
5881 mids
INT[] :=
ARRAY[]::
INT[];
5884 verbosity
INT := coalesce(current_setting(
'provsql.verbose_level',
true)::
INT,
0);
5889 IF EXISTS (
SELECT 1 FROM pg_attribute
5890 WHERE attrelid = member_rel
AND attname =
'provsql'
5891 AND atttypid =
'UUID'::REGTYPE
AND NOT attisdropped)
THEN
5895 IF source_rel
IS NOT NULL THEN
5896 SELECT g.source_values, g.source_tokens, g.source_probabilities
5898 FROM provsql.gather_reachability_sources(source_rel,
5899 source_rel_attribute) g;
5901 sv :=
ARRAY[]::TEXT[];
5902 st :=
ARRAY[]::UUID[];
5903 sp :=
ARRAY[]::float8[];
5906 sv :=
ARRAY[source_value];
5907 st :=
ARRAY[
'00000000-0000-0000-0000-000000000000'::UUID];
5908 sp :=
ARRAY[
1.
0::float8];
5911 e := provsql.gather_reachability_edges(edge_rel, source_attribute,
5912 destination_attribute,
5913 sv, edge_quals, edge_sql);
5925 DROP TABLE IF EXISTS provsql_reach_any_flat_tmp;
5927 'CREATE TEMP TABLE provsql_reach_any_flat_tmp AS '
5928 ||
'SELECT w.%1$I::TEXT AS node_val, provsql.provenance() AS tok, '
5929 ||
' t.%5$I AS grp_key '
5930 ||
'FROM %2$I w JOIN %3$s t ON w.%1$I = t.%4$I'
5934 || coalesce(
' WHERE ' || member_quals,
''),
5935 node_attribute, work_name, member_rel::TEXT, member_attribute,
5937 PERFORM provsql.remove_provenance(
'provsql_reach_any_flat_tmp');
5938 DROP TABLE IF EXISTS provsql_reach_any_groups_tmp;
5939 CREATE TEMP
TABLE provsql_reach_any_groups_tmp
AS
5940 SELECT (row_number()
OVER ())::
INT AS gid, members, toks
FROM (
5941 SELECT array_agg(node_val)
AS members, array_agg(tok)
AS toks
5942 FROM provsql_reach_any_flat_tmp
5943 GROUP BY grp_key
HAVING count(*) >=
2) g;
5944 DROP TABLE provsql_reach_any_flat_tmp;
5946 FOR grp
IN SELECT gid, members
FROM provsql_reach_any_groups_tmp LOOP
5947 FOR m
IN SELECT DISTINCT unnest(grp.members)
AS val LOOP
5948 vid := array_position(e.vertices, m.val);
5949 IF vid
IS NOT NULL THEN
5950 gids := gids || grp.gid;
5951 mids := mids || vid;
5955 IF cardinality(gids) =
0 THEN
5956 DROP TABLE provsql_reach_any_groups_tmp;
5961 SELECT a.group_id, a.token
AS any_token, t.toks
5962 FROM provsql.reachability_materialize_any(
5963 e.sources, e.destinations, e.tokens, e.probabilities,
5964 e.block_keys, e.block_indices, e.extra_ids, st, sp,
5965 directed, gids, mids) a
5966 JOIN provsql_reach_any_groups_tmp t
ON t.gid = a.group_id
5968 canonical := public.uuid_generate_v5(
5969 provsql.uuid_ns_provsql(),
5970 concat(
'plus-canonical',
5971 (
SELECT array_agg(tok
ORDER BY tok)
5972 FROM unnest(grp.toks) tok)));
5973 PERFORM provsql.create_gate(canonical,
'plus',
ARRAY[grp.any_token]);
5974 PERFORM provsql.set_infos(canonical,
1);
5976 DROP TABLE provsql_reach_any_groups_tmp;
5977 IF verbosity >=
20 THEN
5980 PERFORM set_config(
'client_min_messages',
'notice',
true);
5981 RAISE NOTICE
'ProvSQL: certified any-member gates planted for the aggregation of "%" by %.%',
5982 work_name, member_rel, group_attribute;
5983 PERFORM set_config(
'client_min_messages',
'warning',
true);
5985 EXCEPTION
WHEN OTHERS
THEN
5986 IF verbosity >=
10 THEN
5987 PERFORM set_config(
'client_min_messages',
'notice',
true);
5988 RAISE NOTICE
'ProvSQL: any-member planting for "%" skipped (%)',
5990 PERFORM set_config(
'client_min_messages',
'warning',
true);
5996$$
LANGUAGE plpgsql
SET client_min_messages = warning;
6032CREATE OR REPLACE
FUNCTION plant_reach_cover(
6034 node_attribute TEXT,
6036 source_attribute TEXT,
6037 destination_attribute TEXT,
6041 edge_quals TEXT
DEFAULT NULL,
6042 source_rel REGCLASS
DEFAULT NULL,
6043 source_rel_attribute TEXT
DEFAULT NULL,
6044 edge_sql TEXT
DEFAULT NULL)
6051 sp
double precision[];
6054 vids
INT[] :=
ARRAY[]::
INT[];
6056 toks UUID[] :=
ARRAY[]::UUID[];
6059 verbosity
INT := coalesce(current_setting(
'provsql.verbose_level',
true)::
INT,
0);
6062 IF source_rel
IS NOT NULL THEN
6063 SELECT g.source_values, g.source_tokens, g.source_probabilities
6065 FROM provsql.gather_reachability_sources(source_rel,
6066 source_rel_attribute) g;
6068 sv :=
ARRAY[]::TEXT[];
6069 st :=
ARRAY[]::UUID[];
6070 sp :=
ARRAY[]::float8[];
6073 sv :=
ARRAY[source_value];
6074 st :=
ARRAY[
'00000000-0000-0000-0000-000000000000'::UUID];
6075 sp :=
ARRAY[
1.
0::float8];
6078 e := provsql.gather_reachability_edges(edge_rel, source_attribute,
6079 destination_attribute,
6080 sv, edge_quals, edge_sql);
6086 FOREACH val
IN ARRAY node_values LOOP
6087 vid := array_position(e.vertices, val);
6091 vids := vids || vid;
6092 EXECUTE format(
'SELECT provsql FROM %I WHERE %I::TEXT = $1',
6093 work_name, node_attribute)
6098 toks := toks || tok;
6101 cover_token := provsql.reachability_materialize_cover(
6102 e.sources, e.destinations, e.tokens, e.probabilities,
6103 e.block_keys, e.block_indices, e.extra_ids, st, sp,
6106 SELECT public.uuid_generate_v5(
6107 provsql.uuid_ns_provsql(),
6108 concat(
'times-canonical', array_agg(t
ORDER BY t)))
6111 PERFORM provsql.create_gate(canonical,
'times',
ARRAY[cover_token]);
6112 PERFORM provsql.set_infos(canonical,
1);
6113 IF verbosity >=
20 THEN
6116 PERFORM set_config(
'client_min_messages',
'notice',
true);
6117 RAISE NOTICE
'ProvSQL: certified all-members gate planted for the self-join of "%"',
6119 PERFORM set_config(
'client_min_messages',
'warning',
true);
6121 EXCEPTION
WHEN OTHERS
THEN
6122 IF verbosity >=
10 THEN
6123 PERFORM set_config(
'client_min_messages',
'notice',
true);
6124 RAISE NOTICE
'ProvSQL: all-members planting for "%" skipped (%)',
6126 PERFORM set_config(
'client_min_messages',
'warning',
true);
6132$$
LANGUAGE plpgsql
SET client_min_messages = warning;
6147CREATE OR REPLACE
FUNCTION token_conjunctive_leaves(token UUID)
6150WITH RECURSIVE walk(g)
AS (
6153 SELECT c
FROM walk w,
unnest(provsql.get_children(w.g))
AS c
6154 WHERE provsql.get_gate_type(w.g)
IN (
'times',
'project',
'eq')
6156SELECT CASE WHEN bool_and(provsql.get_gate_type(g)
6157 IN (
'times',
'project',
'eq',
'input'))
6158 THEN array_agg(
DISTINCT g)
6159 FILTER (
WHERE provsql.get_gate_type(g) =
'input')
6162$$
LANGUAGE sql STABLE;
6203CREATE OR REPLACE
FUNCTION gather_reachability_edges(
6205 IN source_attribute TEXT,
6206 IN destination_attribute TEXT,
6207 IN extra_vertices TEXT[],
6208 IN edge_quals TEXT
DEFAULT NULL,
6209 IN rel_sql TEXT
DEFAULT NULL,
6211 OUT destinations
INT[],
6213 OUT probabilities
DOUBLE PRECISION[],
6214 OUT block_keys UUID[],
6215 OUT block_indices
INT[],
6216 OUT extra_ids
INT[],
6217 OUT vertices TEXT[])
6226 verbosity
INT := coalesce(current_setting(
'provsql.verbose_level',
true)::
INT,
0);
6234 IF rel
IS NOT NULL AND rel_sql
IS NULL THEN
6235 tkind := (provsql.get_table_info(rel::oid)).kind;
6237 IF tkind
NOT IN (
'tid',
'bid')
THEN
6240 IF tkind =
'bid' THEN
6241 SELECT string_agg(quote_ident(a.attname) ||
'::TEXT',
' || '','' || '
6244 FROM unnest((provsql.get_table_info(rel::oid)).block_key)
6245 WITH ORDINALITY
AS k(attnum, ord)
6246 JOIN pg_attribute a
ON a.attrelid = rel
AND a.attnum = k.attnum;
6248 bkey_expr := coalesce(bkey_expr, quote_literal(
''));
6250 IF tkind
IS NOT NULL AND verbosity >=
20 THEN
6255 PERFORM set_config(
'client_min_messages',
'notice',
true);
6256 RAISE NOTICE
'ProvSQL: catalog characterises % as %', rel,
upper(tkind);
6257 PERFORM set_config(
'client_min_messages',
'warning',
true);
6266 DROP TABLE IF EXISTS provsql_reachability_edges_tmp;
6268 'CREATE TEMP TABLE provsql_reachability_edges_tmp AS '
6269 ||
'SELECT %1$I::TEXT AS u, %2$I::TEXT AS v, provsql.provenance() AS token%5$s '
6270 ||
'FROM %3$s WHERE %1$I IS NOT NULL AND %2$I IS NOT NULL%4$s',
6271 source_attribute, destination_attribute,
6272 CASE WHEN rel_sql
IS NULL THEN rel::TEXT
6273 ELSE '(' || rel_sql ||
') AS provsql_edge_subquery' END,
6274 CASE WHEN edge_quals
IS NULL THEN ''
6275 ELSE ' AND (' || edge_quals ||
')' END,
6276 CASE WHEN tkind =
'bid'
6277 THEN ', public.uuid_generate_v5(provsql.uuid_ns_provsql(), '
6278 || quote_literal(
'bidblock' || rel::TEXT ||
':')
6279 ||
' || ' || bkey_expr ||
') AS bkey'
6280 ELSE ', NULL::UUID AS bkey' END);
6281 PERFORM provsql.remove_provenance(
'provsql_reachability_edges_tmp');
6283 DROP TABLE IF EXISTS provsql_reachability_support_tmp;
6284 IF tkind
IS NULL THEN
6287 IF EXISTS (
SELECT 1 FROM provsql_reachability_edges_tmp
6288 WHERE provsql.get_gate_type(token)
NOT IN (
'input',
'mulinput',
'times',
6289 'project',
'eq'))
THEN
6290 DROP TABLE provsql_reachability_edges_tmp;
6291 RAISE EXCEPTION
'reachability: the provenance of % must consist of base input, repair_key, or conjunctive join tokens', coalesce(rel::TEXT,
'the edge query');
6293 CREATE TEMP
TABLE provsql_reachability_support_tmp
AS
6294 SELECT t.token, l.leaf
6295 FROM (
SELECT DISTINCT token
FROM provsql_reachability_edges_tmp
6296 WHERE provsql.get_gate_type(token)
IN (
'times',
'project',
'eq')) t,
6297 LATERAL unnest(provsql.token_conjunctive_leaves(t.token))
AS l(leaf);
6299 FROM (
SELECT DISTINCT token
FROM provsql_reachability_edges_tmp) t
6300 WHERE provsql.get_gate_type(t.token)
IN (
'times',
'project',
'eq')
6301 AND provsql.token_conjunctive_leaves(t.token)
IS NULL)
THEN
6302 DROP TABLE provsql_reachability_support_tmp;
6303 DROP TABLE provsql_reachability_edges_tmp;
6304 RAISE EXCEPTION
'reachability: a join-defined edge token is not a pure conjunction of base tuples';
6306 IF EXISTS (
SELECT 1 FROM (
6307 SELECT leaf
FROM provsql_reachability_support_tmp
6309 SELECT DISTINCT token
FROM provsql_reachability_edges_tmp
6310 WHERE provsql.get_gate_type(token) =
'input'
6312 GROUP BY leaf
HAVING count(*) >
1)
THEN
6313 DROP TABLE provsql_reachability_support_tmp;
6314 DROP TABLE provsql_reachability_edges_tmp;
6315 RAISE EXCEPTION
'reachability: join-defined edges share base tuples (their supports overlap), so they are not independent';
6324 IF tkind =
'tid' THEN
6325 sel_probs :=
'coalesce(provsql.get_prob(e.token), 1.0)';
6326 sel_bkeys := $
sql$
'00000000-0000-0000-0000-000000000000'::UUID$
sql$;
6328 ELSIF tkind =
'bid' THEN
6329 sel_probs :=
'coalesce(provsql.get_prob(e.token), 1.0)';
6330 sel_bkeys := $
sql$
CASE WHEN provsql.get_gate_type(e.token) =
'mulinput'
6332 ELSE '00000000-0000-0000-0000-000000000000'::UUID
END$
sql$;
6333 sel_bidx :=
'e.bidx';
6335 sel_probs := $
sql$
CASE WHEN provsql.get_gate_type(e.token)
IN (
'times',
'project',
'eq')
6336 THEN (
SELECT CASE WHEN bool_or(coalesce(provsql.get_prob(s.leaf),
1.
0) =
0)
6338 ELSE exp(sum(ln(coalesce(provsql.get_prob(s.leaf),
1.
0))))
END
6339 FROM provsql_reachability_support_tmp s
6340 WHERE s.token = e.token)
6341 ELSE coalesce(provsql.get_prob(e.token),
1.
0)
END$
sql$;
6342 sel_bkeys := $
sql$
CASE WHEN provsql.get_gate_type(e.token) =
'mulinput'
6343 THEN (provsql.get_children(e.token))[
1]
6344 ELSE '00000000-0000-0000-0000-000000000000'::UUID
END$
sql$;
6345 sel_bidx := $
sql$
CASE WHEN provsql.get_gate_type(e.token) =
'mulinput'
6346 THEN (provsql.get_infos(e.token)).info1
ELSE 0 END$
sql$;
6352 SELECT u
AS x
FROM provsql_reachability_edges_tmp
6353 UNION SELECT v
FROM provsql_reachability_edges_tmp
6354 UNION SELECT unnest($
1)),
6356 SELECT x, (row_number()
OVER (
ORDER BY x))::
INT AS id
FROM verts)
6357 SELECT array_agg(iu.id), array_agg(iv.id),
6362 (
SELECT array_agg(i.id
ORDER BY ev.ord)
6363 FROM unnest($
1)
WITH ORDINALITY
AS ev(x, ord)
6364 JOIN ids i
ON i.x = ev.x),
6365 (
SELECT array_agg(x
ORDER BY id)
FROM ids)
6367 (row_number()
OVER (
PARTITION BY t.bkey))::
INT AS bidx
6368 FROM provsql_reachability_edges_tmp t) e
6369 JOIN ids iu
ON iu.x = e.u
6370 JOIN ids iv
ON iv.x = e.v
6371 $
sql$, sel_probs, sel_bkeys, sel_bidx)
6372 INTO sources, destinations, tokens, probabilities, block_keys,
6373 block_indices, extra_ids, vertices
6374 USING extra_vertices;
6376 DROP TABLE provsql_reachability_edges_tmp;
6377 DROP TABLE IF EXISTS provsql_reachability_support_tmp;
6382$$
LANGUAGE plpgsql
SET client_min_messages = warning;
6401CREATE OR REPLACE
FUNCTION gather_reachability_sources(
6403 IN source_attribute TEXT,
6404 OUT source_values TEXT[],
6405 OUT source_tokens UUID[],
6406 OUT source_probabilities
DOUBLE PRECISION[])
6414 SELECT 1 FROM pg_attribute
6415 WHERE attrelid = rel
AND attname =
'provsql'
6416 AND atttypid =
'UUID'::REGTYPE
AND NOT attisdropped)
6424 tkind := (get_table_info(rel::oid)).kind;
6425 IF tkind =
'bid' THEN
6426 RAISE EXCEPTION
'reachability: % is block-independent (repair_key); block-correlated source sets are not supported', rel;
6430 DROP TABLE IF EXISTS provsql_reachability_sources_tmp;
6433 'CREATE TEMP TABLE provsql_reachability_sources_tmp AS '
6434 ||
'SELECT %1$I::TEXT AS x, provenance() AS token '
6435 ||
'FROM %2$s WHERE %1$I IS NOT NULL',
6436 source_attribute, rel);
6437 PERFORM remove_provenance(
'provsql_reachability_sources_tmp');
6438 IF tkind
IS DISTINCT FROM 'tid'
6439 AND EXISTS (
SELECT 1 FROM provsql_reachability_sources_tmp
6440 WHERE get_gate_type(token) <>
'input')
THEN
6441 DROP TABLE provsql_reachability_sources_tmp;
6442 RAISE EXCEPTION
'reachability: the provenance of % must consist of base input tokens (independent tuples); views or query results are not supported', rel;
6444 SELECT array_agg(x), array_agg(token),
6445 array_agg(coalesce(get_prob(token),
1.
0))
6446 INTO source_values, source_tokens, source_probabilities
6447 FROM provsql_reachability_sources_tmp;
6448 DROP TABLE provsql_reachability_sources_tmp;
6451 'CREATE TEMP TABLE provsql_reachability_sources_tmp AS '
6452 ||
'SELECT DISTINCT %1$I::TEXT AS x FROM %2$s WHERE %1$I IS NOT NULL',
6453 source_attribute, rel);
6454 SELECT array_agg(x),
6455 array_agg(
'00000000-0000-0000-0000-000000000000'::UUID),
6456 array_agg(
1.
0::float8)
6457 INTO source_values, source_tokens, source_probabilities
6458 FROM provsql_reachability_sources_tmp;
6459 DROP TABLE provsql_reachability_sources_tmp;
6462$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public
SET client_min_messages = warning;
6506CREATE OR REPLACE
FUNCTION eval_reachability(
6508 source_attribute TEXT,
6509 destination_attribute TEXT,
6517 edge_quals TEXT
DEFAULT NULL,
6518 source_rel REGCLASS
DEFAULT NULL,
6519 source_rel_attribute TEXT
DEFAULT NULL,
6520 edge_sql TEXT
DEFAULT NULL,
6521 hop_bound
INT DEFAULT NULL,
6522 hop_seed
INT DEFAULT NULL,
6523 hops_position
INT DEFAULT NULL)
6530 sp
double precision[];
6531 verbosity
INT := coalesce(current_setting(
'provsql.verbose_level',
true)::
INT,
0);
6534 IF source_rel
IS NOT NULL THEN
6537 SELECT g.source_values, g.source_tokens, g.source_probabilities
6539 FROM provsql.gather_reachability_sources(source_rel,
6540 source_rel_attribute) g;
6542 sv :=
ARRAY[]::TEXT[];
6543 st :=
ARRAY[]::UUID[];
6544 sp :=
ARRAY[]::float8[];
6548 sv :=
ARRAY[source_value];
6549 st :=
ARRAY[
'00000000-0000-0000-0000-000000000000'::UUID];
6550 sp :=
ARRAY[
1.
0::float8];
6553 e := provsql.gather_reachability_edges(edge_rel, source_attribute,
6554 destination_attribute,
6555 sv, edge_quals, edge_sql);
6556 IF to_regclass(work_name)
IS NOT NULL THEN
6557 EXECUTE format(
'DROP TABLE %I', work_name);
6559 EXECUTE format(
'CREATE TEMP TABLE %I (%s, provsql UUID)', work_name, coldef);
6560 IF hop_bound
IS NULL THEN
6562 'INSERT INTO %I SELECT ($1::TEXT[])[m.vertex]::%s, m.token '
6563 ||
'FROM provsql.reachability_materialize($2, $3, $4, $5, $6, $7, $8, $9, $10, $11) m',
6565 USING e.vertices, e.sources, e.destinations, e.tokens, e.probabilities,
6566 e.block_keys, e.block_indices, e.extra_ids, st, sp, directed;
6571 'INSERT INTO %I SELECT %s, m.token '
6572 ||
'FROM provsql.reachability_materialize_hops($2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) m',
6574 CASE WHEN hops_position =
1
6575 THEN format(
'm.hops, ($1::TEXT[])[m.vertex]::%s', coltype)
6576 ELSE format(
'($1::TEXT[])[m.vertex]::%s, m.hops', coltype)
END)
6577 USING e.vertices, e.sources, e.destinations, e.tokens, e.probabilities,
6578 e.block_keys, e.block_indices, e.extra_ids, st, sp, directed,
6579 hop_bound, hop_seed;
6581 IF verbosity >=
20 THEN
6582 RAISE NOTICE
'ProvSQL: recursive CTE "%" compiled along a tree decomposition of %',
6583 work_name, coalesce(edge_rel::TEXT,
'the join-defined edge query');
6585 EXCEPTION
WHEN OTHERS
THEN
6586 IF verbosity >=
10 THEN
6587 RAISE NOTICE
'ProvSQL: reachability route for "%" fell back to the generic fixpoint (%)',
6590 PERFORM provsql.eval_recursive(body_sql, work_name, colnames, coldef);
6612CREATE OR REPLACE
FUNCTION view_circuit(
6614 token2desc REGCLASS,
6617 'provsql',
'view_circuit' LANGUAGE C;
6630CREATE OR REPLACE
FUNCTION compile_to_ddnnf_dot(
6634 'provsql',
'compile_to_ddnnf_dot' LANGUAGE C;
6649CREATE OR REPLACE
FUNCTION compile_to_ddnnf(
6653 'provsql',
'compile_to_ddnnf' LANGUAGE C;
6670CREATE OR REPLACE
FUNCTION ddnnf_stats(
6674 'provsql',
'ddnnf_stats' LANGUAGE C;
6688CREATE OR REPLACE
FUNCTION tseytin_cnf(
6690 weighted
BOOLEAN =
TRUE,
6691 mapping
BOOLEAN =
TRUE)
6693 'provsql',
'tseytin_cnf' LANGUAGE C;
6707CREATE OR REPLACE
FUNCTION tseytin_cnf_mapping_json(token UUID)
6709 'provsql',
'tseytin_cnf_mapping_json' LANGUAGE C;
6711CREATE OR REPLACE
FUNCTION tseytin_cnf_mapping(token UUID)
6712 RETURNS TABLE(variable
INT, gate UUID, probability FLOAT8)
AS $$
6713 SELECT variable, gate, probability
6714 FROM jsonb_to_recordset(tseytin_cnf_mapping_json(token))
6715 AS x(variable
INT, gate UUID, probability FLOAT8)
6717$$
LANGUAGE SQL STABLE;
6729CREATE OR REPLACE
FUNCTION tree_decomposition_dot(
6732 'provsql',
'tree_decomposition_dot' LANGUAGE C;
6752CREATE OR REPLACE
FUNCTION tool_available(name TEXT)
6754 'provsql',
'tool_available' LANGUAGE C STRICT;
6784CREATE TABLE IF NOT EXISTS tool_overrides(
6785 name TEXT
PRIMARY KEY,
6786 removed
BOOLEAN NOT NULL DEFAULT false,
6790 input_formats TEXT[],
6795 dependencies TEXT[],
6797 argtpl_circuit TEXT,
6800SELECT pg_catalog.pg_extension_config_dump(
'tool_overrides',
'');
6812CREATE OR REPLACE
FUNCTION tool_registry_list()
6813 RETURNS TABLE(name TEXT, kind TEXT, executable TEXT, operations TEXT[],
6814 input_formats TEXT[], output_format TEXT, parser TEXT,
6815 preference
INT, enabled
BOOLEAN, argtpl TEXT,
6816 argtpl_circuit TEXT, endpoint TEXT, available
BOOLEAN)
AS
6817 'provsql',
'tool_registry_list' LANGUAGE C STABLE;
6822CREATE OR REPLACE VIEW tools
AS
6823 SELECT name, kind, executable, operations, input_formats, output_format,
6824 parser, preference, enabled, argtpl, argtpl_circuit, endpoint,
6826 FROM tool_registry_list();
6861CREATE OR REPLACE
FUNCTION register_tool(
6863 executable TEXT
DEFAULT NULL,
6864 kind TEXT
DEFAULT 'cli',
6865 operations TEXT[]
DEFAULT NULL,
6866 input_formats TEXT[]
DEFAULT NULL,
6867 output_format TEXT
DEFAULT NULL,
6868 parser TEXT
DEFAULT NULL,
6869 argtpl TEXT
DEFAULT NULL,
6870 argtpl_circuit TEXT
DEFAULT NULL,
6871 preference
INT DEFAULT 0,
6872 enabled
BOOLEAN DEFAULT true,
6873 endpoint TEXT
DEFAULT NULL)
6875 'provsql',
'tool_registry_register' LANGUAGE C;
6878CREATE OR REPLACE
FUNCTION unregister_tool(name TEXT)
6880 'provsql',
'tool_registry_unregister' LANGUAGE C STRICT;
6883CREATE OR REPLACE
FUNCTION set_tool_enabled(name TEXT, enabled
BOOLEAN)
6885 'provsql',
'tool_registry_set_enabled' LANGUAGE C STRICT;
6888CREATE OR REPLACE
FUNCTION set_tool_preference(name TEXT, preference
INT)
6890 'provsql',
'tool_registry_set_preference' LANGUAGE C STRICT;
6894REVOKE ALL ON FUNCTION register_tool(TEXT, TEXT, TEXT, TEXT[], TEXT[], TEXT, TEXT, TEXT, TEXT,
INT,
BOOLEAN, TEXT)
FROM PUBLIC;
6895REVOKE ALL ON FUNCTION unregister_tool(TEXT)
FROM PUBLIC;
6896REVOKE ALL ON FUNCTION set_tool_enabled(TEXT,
BOOLEAN)
FROM PUBLIC;
6897REVOKE ALL ON FUNCTION set_tool_preference(TEXT,
INT)
FROM PUBLIC;
6905CREATE OR REPLACE
FUNCTION to_provxml(
6907 token2desc REGCLASS =
NULL)
6909 'provsql',
'to_provxml' LANGUAGE C;
6912CREATE OR REPLACE
FUNCTION provenance()
RETURNS UUID
AS
6913 'provsql',
'provenance' LANGUAGE C;
6921CREATE OR REPLACE
FUNCTION where_provenance(token UUID)
6923 'provsql',
'where_provenance' LANGUAGE C;
6934CREATE OR REPLACE
FUNCTION reset_constants_cache()
6936 'provsql',
'reset_constants_cache' LANGUAGE C;
6938SELECT reset_constants_cache();
6940SELECT create_gate(gate_zero(),
'zero');
6941SELECT create_gate(gate_one(),
'one');
6946CREATE TYPE QUERY_TYPE_ENUM
AS ENUM (
6959CREATE FUNCTION sr_formula(token ANYELEMENT, token2value REGCLASS)
6963 RETURN provsql.provenance_evaluate_compiled(
6970$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
6973CREATE FUNCTION sr_counting(token ANYELEMENT, token2value REGCLASS)
6977 RETURN provsql.provenance_evaluate_compiled(
6984$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
6987CREATE FUNCTION sr_why(token ANYELEMENT, token2value REGCLASS)
6991 RETURN provsql.provenance_evaluate_compiled(
6998$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
7001CREATE FUNCTION sr_how(token ANYELEMENT, token2value REGCLASS)
7005 RETURN provsql.provenance_evaluate_compiled(
7012$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
7015CREATE FUNCTION sr_which(token ANYELEMENT, token2value REGCLASS)
7019 RETURN provsql.provenance_evaluate_compiled(
7026$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
7034CREATE FUNCTION sr_boolexpr(token ANYELEMENT, token2value REGCLASS =
NULL)
7038 IF token
IS NULL THEN
7041 RETURN provsql.provenance_evaluate_compiled(
7048$$
LANGUAGE plpgsql PARALLEL SAFE STABLE;
7051CREATE FUNCTION sr_boolean(token ANYELEMENT, token2value REGCLASS)
7055 RETURN provsql.provenance_evaluate_compiled(
7062$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
7076CREATE FUNCTION sr_tropical(token ANYELEMENT, token2value REGCLASS,
7077 nonnegative
BOOLEAN =
false)
7081 RETURN provsql.provenance_evaluate_compiled(
7084 CASE WHEN nonnegative
THEN 'tropical_nonneg' ELSE 'tropical' END,
7088$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
7095CREATE FUNCTION sr_viterbi(token ANYELEMENT, token2value REGCLASS)
7099 RETURN provsql.provenance_evaluate_compiled(
7106$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
7115CREATE FUNCTION sr_lukasiewicz(token ANYELEMENT, token2value REGCLASS)
7119 RETURN provsql.provenance_evaluate_compiled(
7126$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
7143CREATE FUNCTION sr_minmax(token UUID, token2value REGCLASS, element_one ANYENUM)
7147 RETURN provsql.provenance_evaluate_compiled(
7154$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
7168CREATE FUNCTION sr_maxmin(token UUID, token2value REGCLASS, element_one ANYENUM)
7172 RETURN provsql.provenance_evaluate_compiled(
7179$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
7190CREATE FUNCTION choose_function(state ANYELEMENT, data ANYELEMENT)
7191 RETURNS ANYELEMENT
AS
7194 IF state
IS NULL THEN
7200$$
LANGUAGE plpgsql PARALLEL SAFE IMMUTABLE;
7203CREATE AGGREGATE choose(ANYELEMENT) (
7204 SFUNC = choose_function,
7220CREATE OR REPLACE
FUNCTION explode_table(_tbl TEXT, AGG_TOKEN TEXT)
7228 SELECT n.nspname
INTO _nsp
7229 FROM pg_class c
JOIN pg_namespace n
ON n.oid = c.relnamespace
7230 WHERE c.oid = _tbl::REGCLASS;
7233 CREATE TABLE %1$I.temp_exploded AS
7236 provsql.get_extra(children[2]) AS new_t,
7237 provsql.provenance_times(children[1], provsql) AS new_provsql
7240 SELECT provsql.get_children(sm) AS children
7241 FROM UNNEST(provsql.get_children(%3$I)) AS sm
7242 ) AS sub', _nsp, _tbl, AGG_TOKEN);
7243 EXECUTE format(
'DROP TABLE %I.%I', _nsp, _tbl);
7244 EXECUTE format(
'ALTER TABLE %I.temp_exploded DROP COLUMN %I, DROP COLUMN provsql', _nsp, AGG_TOKEN);
7245 EXECUTE format(
'ALTER TABLE %I.temp_exploded RENAME COLUMN new_t TO %I', _nsp, AGG_TOKEN);
7246 EXECUTE format(
'ALTER TABLE %I.temp_exploded RENAME COLUMN new_provsql TO provsql', _nsp);
7247 EXECUTE format(
'ALTER TABLE %I.temp_exploded RENAME TO %I', _nsp, _tbl);
7273CREATE OR REPLACE
FUNCTION setup_search_path()
7275 LANGUAGE plpgsql
AS $$
7277 db TEXT := current_database();
7283 SELECT s.setconfig
INTO cfg
7284 FROM pg_db_role_setting s
7285 JOIN pg_database d
ON d.oid = s.setdatabase
7286 WHERE d.datname = db
AND s.setrole =
0;
7288 IF cfg
IS NOT NULL THEN
7289 SELECT substr(e, length(
'search_path=') +
1)
INTO cur
7290 FROM unnest(cfg)
AS e
7291 WHERE e
LIKE 'search_path=%';
7297 new_path :=
'"$user", public, provsql';
7298 EXECUTE format(
'ALTER DATABASE %I SET search_path = %s', db, new_path);
7299 RAISE NOTICE
'ProvSQL: set search_path = % for database "%" (no previous database-level setting). Only new sessions are affected.',
7306 SELECT 1 FROM unnest(string_to[](cur,
','))
AS p
7307 WHERE btrim(btrim(p),
'"') =
'provsql')
7309 RAISE NOTICE
'ProvSQL: search_path for database "%" already contains provsql (= %); no change.',
7314 new_path := cur ||
', provsql';
7315 EXECUTE format(
'ALTER DATABASE %I SET search_path = %s', db, new_path);
7316 RAISE NOTICE
'ProvSQL: appended provsql to search_path for database "%" (now: %). Only new sessions are affected.',
7322GRANT USAGE
ON SCHEMA provsql
TO PUBLIC;
7324SET search_path
TO public;
7339 has_provsql
BOOLEAN;
7341 SELECT reset_val
INTO rp
FROM pg_settings
WHERE name =
'search_path';
7342 SELECT bool_or(btrim(btrim(p),
'"') =
'provsql')
7344 FROM unnest(string_to[](coalesce(rp,
''),
','))
AS p;
7345 IF NOT coalesce(has_provsql,
false)
THEN
7346 SET LOCAL client_min_messages = notice;
7347 RAISE NOTICE
'ProvSQL: schema "provsql" is not in your default search_path (currently: %).', rp;
7348 RAISE NOTICE
'ProvSQL operators and functions are resolved through search_path. Run "SELECT provsql.setup_search_path();" to add it, or set it manually (e.g. ALTER DATABASE % SET search_path = "$user", public, provsql).', quote_ident(current_database());
7362SELECT provsql.reset_constants_cache();
7363SET search_path
TO provsql;
7378CREATE TABLE update_provenance (
7381 query_type QUERY_TYPE_ENUM,
7383 ts
TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
7384 valid_time TSTZMULTIRANGE
DEFAULT TSTZMULTIRANGE(tstzrange(
CURRENT_TIMESTAMP,
NULL))
7390CREATE OR REPLACE
FUNCTION add_provenance(_tbl REGCLASS)
7398 SELECT 1 FROM pg_attribute
7399 WHERE attrelid = _tbl
AND attname =
'provsql' AND NOT attisdropped
7401 RAISE NOTICE
'table % already has provenance tracking', _tbl;
7407 EXECUTE format(
'ALTER TABLE %s ADD COLUMN provsql UUID', _tbl);
7409 'UPDATE %s SET provsql = public.uuid_generate_v4() WHERE provsql IS NULL',
7411 EXECUTE format(
'CREATE INDEX ON %s(provsql)', _tbl);
7413 'CREATE TRIGGER provenance_guard BEFORE INSERT OR UPDATE OF provsql '
7414 'ON %s FOR EACH ROW EXECUTE PROCEDURE provsql.provenance_guard()',
7417 EXECUTE format(
'CREATE TRIGGER insert_statement AFTER INSERT ON %s REFERENCING NEW TABLE AS NEW_TABLE FOR EACH STATEMENT EXECUTE PROCEDURE provsql.insert_statement_trigger()', _tbl);
7418 EXECUTE format(
'CREATE TRIGGER delete_statement AFTER DELETE ON %s REFERENCING OLD TABLE AS OLD_TABLE FOR EACH STATEMENT EXECUTE PROCEDURE provsql.delete_statement_trigger()', _tbl);
7419 EXECUTE format(
'CREATE TRIGGER update_statement AFTER UPDATE ON %s REFERENCING OLD TABLE AS OLD_TABLE NEW TABLE AS NEW_TABLE FOR EACH STATEMENT EXECUTE PROCEDURE provsql.update_statement_trigger()', _tbl);
7421 PERFORM provsql.set_table_info(_tbl::oid,
'tid');
7422 PERFORM provsql.set_ancestors(_tbl::oid,
ARRAY[_tbl::oid]);
7424$$
LANGUAGE plpgsql SECURITY DEFINER;
7430CREATE OR REPLACE
FUNCTION delete_statement_trigger()
7439 enable_trigger BOOL;
7441 enable_trigger := current_setting(
'provsql.update_provenance',
true);
7442 IF enable_trigger =
'f' THEN
7445 delete_token := public.uuid_generate_v4();
7447 PERFORM create_gate(delete_token,
'update');
7451 FROM pg_stat_activity
7452 WHERE pid = pg_backend_pid();
7454 INSERT INTO update_provenance (provsql, query, query_type, username, ts, valid_time)
7455 VALUES (delete_token, query_text,
'DELETE',
current_user,
CURRENT_TIMESTAMP, TSTZMULTIRANGE(tstzrange(
CURRENT_TIMESTAMP,
NULL)));
7457 PERFORM set_config(
'provsql.update_provenance',
'off',
false);
7458 EXECUTE format(
'INSERT INTO %I.%I SELECT * FROM OLD_TABLE;', TG_TABLE_SCHEMA, TG_TABLE_NAME);
7459 PERFORM set_config(
'provsql.update_provenance',
'on',
false);
7461 FOR r
IN (
SELECT *
FROM OLD_TABLE) LOOP
7462 old_token := r.provsql;
7463 new_token := provenance_monus(old_token, delete_token);
7465 PERFORM set_config(
'provsql.update_provenance',
'off',
false);
7466 EXECUTE format(
'UPDATE %I.%I SET provsql = $1 WHERE provsql = $2;', TG_TABLE_SCHEMA, TG_TABLE_NAME)
7467 USING new_token, old_token;
7468 PERFORM set_config(
'provsql.update_provenance',
'on',
false);
7473$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp SECURITY DEFINER;
7482CREATE OR REPLACE
FUNCTION insert_statement_trigger()
7491 enable_trigger BOOL;
7493 enable_trigger := current_setting(
'provsql.update_provenance',
true);
7494 IF enable_trigger =
'f' THEN
7498 insert_token := public.uuid_generate_v4();
7500 PERFORM create_gate(insert_token,
'update');
7504 FROM pg_stat_activity
7505 WHERE pid = pg_backend_pid();
7507 INSERT INTO update_provenance (provsql, query, query_type, username, ts, valid_time)
7508 VALUES (insert_token, query_text,
'INSERT',
current_user,
CURRENT_TIMESTAMP, TSTZMULTIRANGE(tstzrange(
CURRENT_TIMESTAMP,
NULL)));
7510 FOR r
IN (
SELECT *
FROM NEW_TABLE) LOOP
7511 old_token := r.provsql;
7512 new_token := provenance_times(old_token, insert_token);
7513 PERFORM set_config(
'provsql.update_provenance',
'off',
false);
7514 EXECUTE format(
'UPDATE %I.%I SET provsql = $1 WHERE provsql = $2;', TG_TABLE_SCHEMA, TG_TABLE_NAME)
7515 USING new_token, old_token;
7516 PERFORM set_config(
'provsql.update_provenance',
'on',
false);
7521$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp SECURITY DEFINER;
7529CREATE OR REPLACE
FUNCTION update_statement_trigger()
7538 enable_trigger BOOL;
7540 enable_trigger := current_setting(
'provsql.update_provenance',
true);
7541 IF enable_trigger =
'f' THEN
7544 update_token := public.uuid_generate_v4();
7546 PERFORM create_gate(update_token,
'update');
7550 FROM pg_stat_activity
7551 WHERE pid = pg_backend_pid();
7553 INSERT INTO update_provenance (provsql, query, query_type, username, ts, valid_time)
7554 VALUES (update_token, query_text,
'UPDATE',
current_user,
CURRENT_TIMESTAMP, TSTZMULTIRANGE(tstzrange(
CURRENT_TIMESTAMP,
NULL)));
7556 FOR r
IN (
SELECT *
FROM NEW_TABLE) LOOP
7557 old_token := r.provsql;
7558 new_token := provenance_times(old_token, update_token);
7560 PERFORM set_config(
'provsql.update_provenance',
'off',
false);
7561 EXECUTE format(
'UPDATE %I.%I SET provsql = $1 WHERE provsql = $2;', TG_TABLE_SCHEMA, TG_TABLE_NAME)
7562 USING new_token, old_token;
7563 PERFORM set_config(
'provsql.update_provenance',
'on',
false);
7566 PERFORM set_config(
'provsql.update_provenance',
'off',
false);
7567 EXECUTE format(
'INSERT INTO %I.%I SELECT * FROM OLD_TABLE;', TG_TABLE_SCHEMA, TG_TABLE_NAME);
7568 PERFORM set_config(
'provsql.update_provenance',
'on',
false);
7570 FOR r
IN (
SELECT *
FROM OLD_TABLE) LOOP
7571 old_token := r.provsql;
7572 new_token := provenance_monus(old_token, update_token);
7574 PERFORM set_config(
'provsql.update_provenance',
'off',
false);
7575 EXECUTE format(
'UPDATE %I.%I SET provsql = $1 WHERE provsql = $2;', TG_TABLE_SCHEMA, TG_TABLE_NAME)
7576 USING new_token, old_token;
7577 PERFORM set_config(
'provsql.update_provenance',
'on',
false);
7582$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp SECURITY DEFINER;
7594SET search_path
TO provsql;
7608CREATE FUNCTION sr_temporal(token ANYELEMENT, token2value REGCLASS)
7609 RETURNS TSTZMULTIRANGE
AS
7612 RETURN provsql.provenance_evaluate_compiled(
7616 '{(,)}'::TSTZMULTIRANGE
7619$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
7635CREATE FUNCTION sr_interval_num(token ANYELEMENT, token2value REGCLASS)
7636 RETURNS nummultirange
AS
7639 RETURN provsql.provenance_evaluate_compiled(
7643 '{(,)}'::nummultirange
7646$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
7662CREATE FUNCTION sr_interval_int(token ANYELEMENT, token2value REGCLASS)
7663 RETURNS int4multirange
AS
7666 RETURN provsql.provenance_evaluate_compiled(
7670 '{(,)}'::int4multirange
7673$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
7684CREATE OR REPLACE
FUNCTION union_tstzintervals(
7686 token2value REGCLASS
7688RETURNS TSTZMULTIRANGE
AS
7690 SELECT sr_temporal(token, token2value)
7691$$
LANGUAGE SQL PARALLEL SAFE STABLE;
7701CREATE OR REPLACE
FUNCTION timetravel(
7710 RETURN QUERY
EXECUTE format(
7714 sr_temporal(provenance(), %2$L)
7718 sr_temporal(provenance(), %2$L) @> %3$L::TIMESTAMPTZ
7721 'provsql.time_validity_view',
7736CREATE OR REPLACE
FUNCTION timeslice(
7738 from_time TIMESTAMPTZ,
7746 RETURN QUERY
EXECUTE format(
7750 sr_temporal(provenance(), %2$L)
7754 sr_temporal(provenance(), %2$L)
7755 && tstzrange(%3$L::TIMESTAMPTZ, %4$L::TIMESTAMPTZ)
7758 'provsql.time_validity_view',
7775CREATE OR REPLACE
FUNCTION history(
7785 condition TEXT :=
'';
7788 IF array_length(col_names,
1)
IS NULL
7789 OR array_length(col_values,
1)
IS NULL
7790 OR array_length(col_names,
1) != array_length(col_values,
1)
7792 RAISE EXCEPTION
'col_names and col_values must have the same (non-null) length';
7795 FOR i
IN 1..array_length(col_names,
1)
7798 condition := condition ||
' AND ';
7800 condition := condition || format(
'%I = %L', col_names[i], col_values[i]);
7803 RETURN QUERY
EXECUTE format(
7807 sr_temporal(provenance(), %L)
7814 'provsql.time_validity_view',
7827CREATE OR REPLACE
FUNCTION get_valid_time(
7831RETURNS TSTZMULTIRANGE
7835 result TSTZMULTIRANGE;
7840 sr_temporal(provenance(), %L)
7846 'provsql.time_validity_view',
7865CREATE OR REPLACE
FUNCTION undo(
7880 SELECT query
INTO undone_query
7881 FROM update_provenance
7885 IF undone_query
IS NULL THEN
7886 RAISE NOTICE
'Unable to find % in update_provenance', c;
7892 FROM pg_stat_activity
7893 WHERE pid = pg_backend_pid();
7895 undo_token := public.uuid_generate_v4();
7896 PERFORM create_gate(undo_token,
'update');
7897 INSERT INTO update_provenance(provsql, query, query_type, username, ts, valid_time)
7904 TSTZMULTIRANGE(tstzrange(
CURRENT_TIMESTAMP,
NULL))
7907 PERFORM set_config(
'provsql.update_provenance',
'off',
false);
7912 WHERE nspname
NOT IN (
'pg_catalog',
'information_schema',
'pg_toast',
'pg_temp_1',
'pg_toast_temp_1')
7915 EXECUTE format(
'SELECT tablename AS tname FROM pg_tables WHERE schemaname = %L', schema_rec.nspname)
7919 FROM information_schema.columns
7920 WHERE table_schema = schema_rec.nspname
7921 AND table_name = table_rec.tname
7922 AND table_name <>
'update_provenance'
7923 AND column_name =
'provsql'
7926 EXECUTE format(
'SELECT provsql AS x FROM %I.%I', schema_rec.nspname, table_rec.tname)
7928 new_x := replace_the_circuit(row_rec.x, c, undo_token);
7929 EXECUTE format(
'UPDATE %I.%I SET provsql = $1 WHERE provsql = $2',
7930 schema_rec.nspname, table_rec.tname)
7931 USING new_x, row_rec.x;
7937 PERFORM set_config(
'provsql.update_provenance',
'on',
false);
7953CREATE OR REPLACE
FUNCTION replace_the_circuit(
7965 ntype PROVENANCE_GATE;
7968 RETURN provenance_monus(c, u);
7970 ELSIF get_gate_type(x) =
'update' OR get_gate_type(x) =
'input' THEN
7974 FOREACH child
IN ARRAY get_children(x)
7976 nchildren := array_append(nchildren, replace_the_circuit(child, c, u));
7979 ntoken := public.uuid_generate_v4();
7980 ntype := get_gate_type(x);
7982 PERFORM create_gate(ntoken, ntype, nchildren);
7988SELECT create_provenance_mapping_view(
'time_validity_view',
'update_provenance',
'valid_time');
7992SET search_path
TO public;
7999SELECT provsql.reset_constants_cache();