19SET search_path
TO provsql;
27CREATE TYPE PROVENANCE_GATE
AS
68CREATE OR REPLACE
FUNCTION create_gate(
71 children UUID[]
DEFAULT NULL)
73 'provsql',
'create_gate' LANGUAGE C PARALLEL SAFE;
80CREATE OR REPLACE
FUNCTION get_gate_type(
82 RETURNS PROVENANCE_GATE
AS
83 'provsql',
'get_gate_type' LANGUAGE C IMMUTABLE PARALLEL SAFE;
85CREATE OR REPLACE
FUNCTION get_children(
88 'provsql',
'get_children' LANGUAGE C IMMUTABLE PARALLEL SAFE;
95CREATE OR REPLACE
FUNCTION set_prob(
96 token UUID, p
DOUBLE PRECISION)
98 'provsql',
'set_prob' LANGUAGE C PARALLEL SAFE;
100CREATE OR REPLACE
FUNCTION get_prob(
102 RETURNS DOUBLE PRECISION AS
103 'provsql',
'get_prob' LANGUAGE C STABLE PARALLEL SAFE;
121CREATE OR REPLACE
FUNCTION set_infos(
122 token UUID, info1
INT, info2
INT DEFAULT NULL)
124 'provsql',
'set_infos' LANGUAGE C PARALLEL SAFE;
127CREATE OR REPLACE
FUNCTION get_infos(
128 token UUID,
OUT info1
INT,
OUT info2
INT)
130 'provsql',
'get_infos' LANGUAGE C STABLE PARALLEL SAFE;
150CREATE OR REPLACE
FUNCTION assume_boolean(token UUID)
RETURNS UUID
AS
155 IF token
IS NULL THEN
158 wrapped := public.uuid_generate_v5(uuid_ns_provsql(),
159 concat(
'assumed_boolean', token));
160 PERFORM create_gate(wrapped,
'assumed_boolean',
ARRAY[token]);
163$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public
164 SECURITY DEFINER PARALLEL SAFE;
180CREATE OR REPLACE
FUNCTION set_extra(
181 token UUID, data TEXT)
183 'provsql',
'set_extra' LANGUAGE C PARALLEL SAFE STRICT;
185CREATE OR REPLACE
FUNCTION get_extra(token UUID)
187 'provsql',
'get_extra' LANGUAGE C STABLE PARALLEL SAFE
RETURNS NULL ON NULL INPUT;
196CREATE OR REPLACE
FUNCTION get_nb_gates()
RETURNS BIGINT AS
197 'provsql',
'get_nb_gates' LANGUAGE C PARALLEL SAFE;
214CREATE OR REPLACE
FUNCTION delete_statement_trigger()
224 delete_token := public.uuid_generate_v4();
226 PERFORM create_gate(delete_token,
'input');
230 FROM pg_stat_activity
231 WHERE pid = pg_backend_pid();
233 INSERT INTO delete_provenance (delete_token, query, deleted_by, deleted_at)
234 VALUES (delete_token, query_text,
current_user,
CURRENT_TIMESTAMP);
236 EXECUTE format(
'INSERT INTO %I.%I SELECT * FROM OLD_TABLE;', TG_TABLE_SCHEMA, TG_TABLE_NAME);
238 FOR r
IN (
SELECT *
FROM OLD_TABLE) LOOP
239 old_token := r.provsql;
240 new_token := provenance_monus(old_token, delete_token);
242 EXECUTE format(
'UPDATE %I.%I SET provsql = $1 WHERE provsql = $2;', TG_TABLE_SCHEMA, TG_TABLE_NAME)
243 USING new_token, old_token;
248$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp SECURITY DEFINER;
272CREATE OR REPLACE
FUNCTION set_table_info(
273 relid OID, kind TEXT, block_key INT2[]
DEFAULT ARRAY[]::INT2[])
275 'provsql',
'set_table_info' LANGUAGE C PARALLEL SAFE;
278CREATE OR REPLACE
FUNCTION remove_table_info(relid OID)
280 'provsql',
'remove_table_info' LANGUAGE C PARALLEL SAFE;
291CREATE OR REPLACE
FUNCTION get_table_info(
292 relid OID,
OUT kind TEXT,
OUT block_key INT2[])
294 'provsql',
'get_table_info' LANGUAGE C STABLE PARALLEL SAFE;
314CREATE OR REPLACE
FUNCTION set_ancestors(
315 relid OID, ancestors OID[]
DEFAULT ARRAY[]::OID[])
317 'provsql',
'set_ancestors' LANGUAGE C PARALLEL SAFE;
321CREATE OR REPLACE
FUNCTION remove_ancestors(relid OID)
323 'provsql',
'remove_ancestors' LANGUAGE C PARALLEL SAFE;
332CREATE OR REPLACE
FUNCTION get_ancestors(relid OID)
334 'provsql',
'get_ancestors' LANGUAGE C STABLE PARALLEL SAFE;
355CREATE OR REPLACE
FUNCTION provenance_guard()
356 RETURNS TRIGGER AS $$
358 IF TG_OP =
'INSERT' THEN
359 IF NEW.provsql
IS NULL THEN
360 NEW.provsql := public.uuid_generate_v4();
362 PERFORM provsql.set_table_info(TG_RELID,
'opaque');
364 ELSIF TG_OP =
'UPDATE' THEN
365 IF NEW.provsql
IS DISTINCT FROM OLD.provsql
THEN
366 PERFORM provsql.set_table_info(TG_RELID,
'opaque');
371$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public
387CREATE OR REPLACE
FUNCTION add_provenance(_tbl REGCLASS)
397 EXECUTE format(
'ALTER TABLE %s ADD COLUMN provsql UUID', _tbl);
399 'UPDATE %s SET provsql = public.uuid_generate_v4() WHERE provsql IS NULL',
401 EXECUTE format(
'CREATE INDEX ON %s(provsql)', _tbl);
403 'CREATE TRIGGER provenance_guard BEFORE INSERT OR UPDATE OF provsql '
404 'ON %s FOR EACH ROW EXECUTE PROCEDURE provsql.provenance_guard()',
406 PERFORM provsql.set_table_info(_tbl::oid,
'tid');
411 PERFORM provsql.set_ancestors(_tbl::oid,
ARRAY[_tbl::oid]);
413$$
LANGUAGE plpgsql SECURITY DEFINER;
422CREATE OR REPLACE
FUNCTION remove_provenance(_tbl REGCLASS)
427 PERFORM provsql.remove_table_info(_tbl::oid);
432 EXECUTE format(
'DROP TRIGGER provenance_guard on %s', _tbl);
433 EXCEPTION
WHEN undefined_object
THEN
435 EXECUTE format(
'ALTER TABLE %s DROP COLUMN provsql', _tbl);
437 EXECUTE format(
'DROP TRIGGER add_gate on %s', _tbl);
438 EXCEPTION
WHEN undefined_object
THEN
441 EXECUTE format(
'DROP TRIGGER insert_statement on %s', _tbl);
442 EXECUTE format(
'DROP TRIGGER update_statement on %s', _tbl);
443 EXECUTE format(
'DROP TRIGGER delete_statement on %s', _tbl);
444 EXCEPTION
WHEN undefined_object
THEN
460CREATE OR REPLACE
FUNCTION repair_key(_tbl REGCLASS, key_att TEXT)
466 block_key_cols INT2[];
473 block_key_cols :=
ARRAY[]::INT2[];
475 SELECT array_agg(a.attnum
ORDER BY t.ord)::INT2[]
477 FROM unnest(string_to[](key_att,
','))
WITH ORDINALITY
AS t(name, ord)
480 AND a.attname = trim(t.name)
482 AND NOT a.attisdropped;
483 IF block_key_cols
IS NULL OR array_length(block_key_cols,
1)
IS NULL THEN
484 RAISE EXCEPTION
'repair_key: could not resolve key columns from "%"', key_att;
486 IF array_length(block_key_cols,
1) >
16 THEN
487 RAISE EXCEPTION
'repair_key: block key wider than 16 columns is not supported';
497 EXECUTE format(
'ALTER TABLE %s ADD COLUMN provsql_temp UUID DEFAULT public.uuid_generate_v4()', _tbl);
510 'CREATE TEMP TABLE provsql_repair_key_tmp ON COMMIT DROP AS
511 SELECT public.uuid_generate_v4() AS provsql_key_token,
512 COUNT(*) AS provsql_group_size
514 rows_query := format(
515 'SELECT t.provsql_temp,
516 k.provsql_key_token AS key_token,
517 ROW_NUMBER() OVER (ORDER BY t.ctid) AS within_group,
518 k.provsql_group_size AS group_size
519 FROM %s t CROSS JOIN provsql_repair_key_tmp k', _tbl);
522 'CREATE TEMP TABLE provsql_repair_key_tmp ON COMMIT DROP AS
524 public.uuid_generate_v4() AS provsql_key_token,
525 COUNT(*) AS provsql_group_size
527 GROUP BY %1$s', key_att, _tbl);
528 rows_query := format(
529 'SELECT t.provsql_temp,
530 k.provsql_key_token AS key_token,
531 ROW_NUMBER() OVER (PARTITION BY k.provsql_key_token
532 ORDER BY t.ctid) AS within_group,
533 k.provsql_group_size AS group_size
535 JOIN provsql_repair_key_tmp k USING (%1$s)', key_att, _tbl);
539 FOR r
IN SELECT provsql_key_token
FROM provsql_repair_key_tmp LOOP
540 PERFORM provsql.create_gate(r.provsql_key_token,
'input');
544 FOR r
IN EXECUTE rows_query LOOP
545 PERFORM provsql.create_gate(r.provsql_temp,
'mulinput',
ARRAY[r.key_token]);
546 PERFORM provsql.set_prob(r.provsql_temp,
1./r.group_size);
547 PERFORM provsql.set_infos(r.provsql_temp, r.within_group::
INT);
550 DROP TABLE provsql_repair_key_tmp;
552 EXECUTE format(
'ALTER TABLE %s ALTER COLUMN provsql_temp DROP DEFAULT', _tbl);
553 EXECUTE format(
'ALTER TABLE %s RENAME COLUMN provsql_temp TO provsql', _tbl);
554 EXECUTE format(
'CREATE INDEX ON %s(provsql)', _tbl);
556 'CREATE TRIGGER provenance_guard BEFORE INSERT OR UPDATE OF provsql '
557 'ON %s FOR EACH ROW EXECUTE PROCEDURE provsql.provenance_guard()',
559 PERFORM provsql.set_table_info(_tbl::oid,
'bid', block_key_cols);
562 PERFORM provsql.set_ancestors(_tbl::oid,
ARRAY[_tbl::oid]);
577CREATE OR REPLACE
FUNCTION cleanup_table_info()
578 RETURNS event_trigger
AS
584 SELECT objid
FROM pg_event_trigger_dropped_objects()
585 WHERE object_type
IN (
'table',
'foreign table',
'materialized view')
587 PERFORM provsql.remove_table_info(r.objid);
592DROP EVENT
TRIGGER IF EXISTS provsql_cleanup_table_info;
595CREATE EVENT
TRIGGER provsql_cleanup_table_info
ON sql_drop
596 EXECUTE PROCEDURE provsql.cleanup_table_info();
609CREATE OR REPLACE
FUNCTION create_provenance_mapping(
613 preserve_case BOOL
DEFAULT 'f'
618 EXECUTE format(
'CREATE TEMP TABLE tmp_provsql ON COMMIT DROP AS TABLE %s', oldtbl);
619 ALTER TABLE tmp_provsql RENAME provsql
TO provenance;
620 IF preserve_case
THEN
621 EXECUTE format(
'CREATE TABLE %I AS SELECT %s AS value, provenance FROM tmp_provsql', newtbl, att);
622 EXECUTE format(
'CREATE INDEX ON %I(provenance)', newtbl);
624 EXECUTE format(
'CREATE TABLE %s AS SELECT %s AS value, provenance FROM tmp_provsql', newtbl, att);
625 EXECUTE format(
'CREATE INDEX ON %s(provenance)', newtbl);
641CREATE OR REPLACE
FUNCTION create_provenance_mapping_view(
645 preserve_case BOOL
DEFAULT false
652 IF preserve_case
THEN
654 'CREATE OR REPLACE VIEW %I AS SELECT %s AS value, provsql AS provenance FROM %s',
661 'CREATE OR REPLACE VIEW %s AS SELECT %s AS value, provsql AS provenance FROM %s',
679CREATE OR REPLACE
FUNCTION uuid_ns_provsql()
RETURNS UUID
AS
682 SELECT '920d4f02-8718-5319-9532-d4ab83a64489'::UUID
683$$
LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
686CREATE OR REPLACE
FUNCTION gate_zero()
RETURNS UUID
AS
688 SELECT public.uuid_generate_v5(provsql.uuid_ns_provsql(),
'zero');
689$$
LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
692CREATE OR REPLACE
FUNCTION gate_one()
RETURNS UUID
AS
694 SELECT public.uuid_generate_v5(provsql.uuid_ns_provsql(),
'one');
695$$
LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
698CREATE OR REPLACE
FUNCTION epsilon()
RETURNS DOUBLE PRECISION AS
700 SELECT CAST(
0.
001 AS DOUBLE PRECISION)
701$$
LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
717CREATE OR REPLACE
FUNCTION provenance_times(VARIADIC tokens UUID[])
722 filtered_tokens UUID[];
724 SELECT array_agg(t)
FROM unnest(tokens) t
WHERE t
IS NOT NULL AND t <> gate_one()
INTO filtered_tokens;
731 CASE coalesce(array_length(filtered_tokens,
1),
0)
733 times_token:=gate_one();
735 times_token:=filtered_tokens[
1];
737 times_token := uuid_generate_v5(uuid_ns_provsql(),concat(
'times',filtered_tokens));
739 PERFORM create_gate(times_token,
'times', ARRAY_AGG(t))
FROM UNNEST(filtered_tokens)
AS t
WHERE t
IS NOT NULL;
744$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public SECURITY DEFINER PARALLEL SAFE;
752CREATE OR REPLACE
FUNCTION provenance_monus(token1 UUID, token2 UUID)
758 IF token1
IS NULL THEN
759 RAISE EXCEPTION
USING MESSAGE=
'provenance_monus is called with first argument NULL';
762 IF token2
IS NULL THEN
768 IF token1 = token2
THEN
770 monus_token:=gate_zero();
771 ELSIF token1 = gate_zero()
THEN
773 monus_token:=gate_zero();
774 ELSIF token2 = gate_zero()
THEN
778 monus_token:=uuid_generate_v5(uuid_ns_provsql(),concat(
'monus',token1,token2));
779 PERFORM create_gate(monus_token,
'monus',
ARRAY[token1::UUID, token2::UUID]);
784$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public SECURITY DEFINER PARALLEL SAFE IMMUTABLE;
794CREATE OR REPLACE
FUNCTION provenance_project(token UUID, VARIADIC positions
INT[])
801 project_token:=uuid_generate_v5(uuid_ns_provsql(),concat(
'project', token, positions));
802 PERFORM create_gate(project_token,
'project',
ARRAY[token]);
803 PERFORM set_extra(project_token, ARRAY_AGG(pair)::TEXT)
805 SELECT ARRAY[(
CASE WHEN info=
0 THEN NULL ELSE info
END), idx]
AS pair
806 FROM unnest(positions)
WITH ORDINALITY
AS a(info, idx)
810 RETURN project_token;
812$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public SECURITY DEFINER PARALLEL SAFE IMMUTABLE;
821CREATE OR REPLACE
FUNCTION provenance_eq(token UUID, pos1
INT, pos2
INT)
828 eq_token:=uuid_generate_v5(uuid_ns_provsql(),concat(
'eq',token,pos1,
',',pos2));
830 PERFORM create_gate(eq_token,
'eq',
ARRAY[token::UUID]);
831 PERFORM set_infos(eq_token, pos1, pos2);
834$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public SECURITY DEFINER PARALLEL SAFE IMMUTABLE;
842CREATE OR REPLACE
FUNCTION provenance_plus(tokens UUID[])
848 filtered_tokens UUID[];
850 SELECT array_agg(t)
FROM unnest(tokens) t
851 WHERE t
IS NOT NULL AND t <> gate_zero()
852 INTO filtered_tokens;
854 c:=array_length(filtered_tokens,
1);
857 plus_token := gate_zero();
859 plus_token := filtered_tokens[
1];
861 plus_token := uuid_generate_v5(
863 concat(
'plus', filtered_tokens));
865 PERFORM create_gate(plus_token,
'plus', filtered_tokens);
870$$
LANGUAGE plpgsql STRICT
SET search_path=provsql,pg_temp,public SECURITY DEFINER PARALLEL SAFE IMMUTABLE;
879CREATE OR REPLACE
FUNCTION provenance_cmp(
890 cmp_token := public.uuid_generate_v5(
892 concat(
'cmp', left_token::TEXT, comparison_op::TEXT, right_token::TEXT)
895 PERFORM create_gate(cmp_token,
'cmp',
ARRAY[left_token, right_token]);
896 PERFORM set_infos(cmp_token, comparison_op::
INTEGER);
900 SET search_path=provsql,pg_temp,public
922CREATE OR REPLACE
FUNCTION provenance_arith(
931 arith_token := public.uuid_generate_v5(
933 concat(
'arith', op::TEXT, children::TEXT)
935 PERFORM create_gate(arith_token,
'arith', children);
936 PERFORM set_infos(arith_token, op);
940 SET search_path=provsql,pg_temp,public
965CREATE OR REPLACE
FUNCTION provenance_evaluate_compiled(
967 token2value REGCLASS,
969 element_one ANYELEMENT)
971 'provsql',
'provenance_evaluate_compiled' LANGUAGE C PARALLEL SAFE STABLE;
990CREATE OR REPLACE
FUNCTION provenance_evaluate(
992 token2value REGCLASS,
993 element_one ANYELEMENT,
995 plus_function REGPROC,
996 times_function REGPROC,
997 monus_function REGPROC,
998 delta_function REGPROC)
999 RETURNS ANYELEMENT
AS
1002 gate_type PROVENANCE_GATE;
1003 result ALIAS
FOR $
0;
1009 SELECT get_gate_type(token)
INTO gate_type;
1011 IF gate_type
IS NULL THEN
1014 ELSIF gate_type =
'input' THEN
1015 EXECUTE format(
'SELECT value FROM %s WHERE provenance=%L', token2value, token)
1017 IF result IS NULL THEN
1018 result := element_one;
1020 ELSIF gate_type =
'mulinput' THEN
1021 SELECT concat(
'{',(get_children(token))[
1]::TEXT,
'=',(get_infos(token)).info1,
'}')
1023 ELSIF gate_type=
'update' THEN
1024 EXECUTE format(
'SELECT value FROM %s WHERE provenance=%L',token2value,token)
INTO result;
1025 IF result IS NULL THEN
1026 result:=element_one;
1028 ELSIF gate_type =
'plus' THEN
1029 EXECUTE format(
'SELECT %s(provsql.provenance_evaluate(t,%L,%L::%s,%L,%L,%L,%L,%L)) FROM unnest(get_children(%L)) AS t',
1030 plus_function, token2value, element_one, value_type, value_type, plus_function, times_function, monus_function, delta_function, token)
1033 ELSIF gate_type =
'times' THEN
1034 EXECUTE format(
'SELECT %s(provsql.provenance_evaluate(t,%L,%L::%s,%L,%L,%L,%L,%L)) FROM unnest(get_children(%L)) AS t',
1035 times_function, token2value, element_one, value_type, value_type, plus_function, times_function, monus_function, delta_function, token)
1038 ELSIF gate_type =
'monus' THEN
1039 IF monus_function
IS NULL THEN
1040 RAISE EXCEPTION
USING MESSAGE=
'Provenance with negation evaluated over a semiring without monus function';
1042 EXECUTE format(
'SELECT %s(a1,a2) FROM (SELECT provsql.provenance_evaluate(c[1],%L,%L::%s,%L,%L,%L,%L,%L) AS a1, ' ||
1043 'provsql.provenance_evaluate(c[2],%L,%L::%s,%L,%L,%L,%L,%L) AS a2 FROM get_children(%L) c) tmp',
1044 monus_function, token2value, element_one, value_type, value_type, plus_function, times_function, monus_function, delta_function,
1045 token2value, element_one, value_type, value_type, plus_function, times_function, monus_function, delta_function, token)
1049 ELSIF gate_type =
'eq' THEN
1050 EXECUTE format(
'SELECT provsql.provenance_evaluate((get_children(%L))[1],%L,%L::%s,%L,%L,%L,%L,%L)',
1051 token, token2value, element_one, value_type, value_type, plus_function, times_function, monus_function, delta_function)
1072 ELSIF gate_type =
'delta' THEN
1073 IF delta_function
IS NULL THEN
1074 RAISE EXCEPTION
USING MESSAGE=
'Provenance with aggregation evaluated over a semiring without delta function';
1076 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',
1077 delta_function, token, token2value, element_one, value_type, value_type, plus_function, times_function, monus_function, delta_function)
1081 ELSIF gate_type =
'zero' THEN
1082 EXECUTE format(
'SELECT %I(a) FROM (SELECT %L::%I AS a WHERE FALSE) temp', plus_function, element_one, value_type)
1085 ELSIF gate_type =
'one' THEN
1086 EXECUTE format(
'SELECT %L::%I', element_one, value_type)
1089 ELSIF gate_type =
'project' THEN
1090 EXECUTE format(
'SELECT provsql.provenance_evaluate((get_children(%L))[1],%L,%L::%s,%L,%L,%L,%L,%L)',
1091 token, token2value, element_one, value_type, value_type, plus_function, times_function, monus_function, delta_function)
1095 RAISE EXCEPTION
USING MESSAGE=
'provenance_evaluate cannot be called on formulas using ' || gate_type ||
' gates; use compiled semirings instead';
1100$$
LANGUAGE plpgsql PARALLEL SAFE STABLE;
1120CREATE OR REPLACE
FUNCTION aggregation_evaluate(
1122 token2value REGCLASS,
1123 agg_function_final REGPROC,
1124 agg_function REGPROC,
1125 semimod_function REGPROC,
1126 element_one ANYELEMENT,
1128 plus_function REGPROC,
1129 times_function REGPROC,
1130 monus_function REGPROC,
1131 delta_function REGPROC)
1132 RETURNS ANYELEMENT
AS
1136 result ALIAS
FOR $
0;
1138 SELECT get_gate_type(token)
INTO gt;
1143 EXECUTE format(
'SELECT %I(%I(provsql.aggregation_evaluate(t,%L,%L,%L,%L,%L::%s,%L,%L,%L,%L,%L)),pp.proname::varchar) FROM
1144 unnest(get_children(%L)) AS t, pg_proc pp
1145 WHERE pp.oid=(get_infos(%L)).info1
1146 GROUP BY pp.proname',
1147 agg_function_final, agg_function,token2value,agg_function_final,agg_function,semimod_function,element_one,value_type,value_type,plus_function,times_function,
1148 monus_function,delta_function,token,token)
1152 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))',
1153 semimod_function,token,token,token2value,element_one,value_type,value_type,plus_function,times_function,monus_function,delta_function)
1158$$
LANGUAGE plpgsql PARALLEL SAFE STABLE;
1174CREATE OR REPLACE
FUNCTION provenance_evaluate(
1176 token2value REGCLASS,
1177 element_one ANYELEMENT,
1178 plus_function REGPROC,
1179 times_function REGPROC,
1180 monus_function REGPROC =
NULL,
1181 delta_function REGPROC =
NULL)
1182 RETURNS ANYELEMENT
AS
1183 'provsql',
'provenance_evaluate' LANGUAGE C STABLE;
1186CREATE OR REPLACE
FUNCTION aggregation_evaluate(
1188 token2value REGCLASS,
1189 agg_function_final REGPROC,
1190 agg_function REGPROC,
1191 semimod_function REGPROC,
1192 element_one ANYELEMENT,
1193 plus_function REGPROC,
1194 times_function REGPROC,
1195 monus_function REGPROC =
NULL,
1196 delta_function REGPROC =
NULL)
1197 RETURNS ANYELEMENT
AS
1198 'provsql',
'aggregation_evaluate' LANGUAGE C STABLE;
1209CREATE TYPE GATE_WITH_DESC
AS (f UUID, t UUID, gate_type PROVENANCE_GATE, desc_str
CHARACTER VARYING, infos
INTEGER[], extra TEXT);
1221CREATE OR REPLACE
FUNCTION sub_circuit_with_desc(
1223 token2desc REGCLASS)
RETURNS SETOF GATE_WITH_DESC
AS
1226 RETURN QUERY
EXECUTE
1227 'WITH RECURSIVE transitive_closure(f,t,gate_type) AS (
1228 SELECT $1,t,provsql.get_gate_type($1) FROM unnest(provsql.get_children($1)) AS t
1230 SELECT p1.t,u,provsql.get_gate_type(p1.t) FROM transitive_closure p1, unnest(provsql.get_children(p1.t)) AS u)
1231 SELECT *, ARRAY[(get_infos(f)).info1, (get_infos(f)).info2], get_extra(f) FROM (
1232 SELECT f::UUID,t::UUID,gate_type,NULL FROM transitive_closure
1234 SELECT p2.provenance::UUID as f, NULL::UUID, ''input'', CAST (p2.value AS varchar) FROM transitive_closure p1 JOIN ' || token2desc ||
' AS p2
1237 SELECT provenance::UUID as f, NULL::UUID, ''input'', CAST (value AS varchar) FROM ' || token2desc ||
' WHERE provenance=$1
1242$$
LANGUAGE plpgsql PARALLEL SAFE;
1254CREATE OR REPLACE
FUNCTION identify_token(
1255 token UUID,
OUT table_name REGCLASS,
OUT nb_columns
INTEGER)
AS
1265 (
SELECT count(*)
FROM pg_attribute a2
WHERE a2.attrelid=a1.attrelid
AND attnum>
0 AND atttypid<>
0)-1 c
1266 FROM pg_attribute a1
JOIN pg_type
ON atttypid=pg_type.oid
1267 JOIN pg_class
ON attrelid=pg_class.oid
1268 JOIN pg_namespace
ON relnamespace=pg_namespace.oid
1269 WHERE typname=
'UUID' AND relkind=
'r'
1270 AND nspname<>
'provsql'
1271 AND attname=
'provsql'
1273 EXECUTE format(
'SELECT * FROM %I WHERE provsql=%L',t.relname,token)
INTO result;
1274 IF result IS NOT NULL THEN
1275 table_name:=t.relname;
1281$$
LANGUAGE plpgsql STRICT;
1289CREATE OR REPLACE
FUNCTION sub_circuit_for_where(token UUID)
1290 RETURNS TABLE(f UUID, t UUID, gate_type PROVENANCE_GATE, table_name REGCLASS, nb_columns
INTEGER, infos
INTEGER[], extra TEXT)
AS
1292 WITH RECURSIVE transitive_closure(f,t,idx,gate_type)
AS (
1293 SELECT $
1,t,id,provsql.get_gate_type($
1)
FROM unnest(provsql.get_children($
1))
WITH ORDINALITY
AS a(t,id)
1295 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)
1296 )
SELECT f, t, gate_type, table_name, nb_columns,
ARRAY[(get_infos(f)).info1, (get_infos(f)).info2], get_extra(f)
FROM (
1297 SELECT f, t::UUID, idx, gate_type,
NULL AS table_name,
NULL AS nb_columns
FROM transitive_closure
1299 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
1301 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
1331CREATE OR REPLACE
FUNCTION circuit_subgraph(root UUID, max_depth
INT DEFAULT 8)
1332 RETURNS TABLE(node UUID, parent UUID, child_pos
INT, gate_type TEXT, info1 TEXT, info2 TEXT, depth
INT)
AS
1334 WITH RECURSIVE bfs(node, parent, child_pos, depth)
AS (
1335 SELECT root,
NULL::UUID,
NULL::
INT,
0
1337 SELECT c.t, b.node, c.idx::
INT, b.depth +
1
1339 CROSS JOIN LATERAL unnest(provsql.get_children(b.node))
1340 WITH ORDINALITY
AS c(t, idx)
1341 WHERE b.depth < max_depth
1347 SELECT node, MIN(depth)
AS depth
FROM bfs
GROUP BY node
1353 SELECT DISTINCT parent, node
AS child, child_pos
1354 FROM bfs
WHERE parent
IS NOT NULL
1360 provsql.get_gate_type(d.node)::TEXT,
1365 LEFT JOIN edges e
ON e.child = d.node
1366 LEFT JOIN LATERAL provsql.get_infos(d.node) i
ON TRUE
1367 ORDER BY d.depth, d.node, e.parent;
1368$$
LANGUAGE sql STABLE PARALLEL SAFE;
1389CREATE OR REPLACE
FUNCTION simplified_circuit_subgraph(
1390 root UUID, max_depth
INT DEFAULT 8)
RETURNS jsonb
1391 AS 'provsql',
'simplified_circuit_subgraph'
1392 LANGUAGE C STABLE PARALLEL SAFE;
1416CREATE OR REPLACE
FUNCTION rv_histogram(
1417 token UUID, bins
INT DEFAULT 30, prov UUID
DEFAULT gate_one())
1419 AS 'provsql',
'rv_histogram'
1420 LANGUAGE C VOLATILE PARALLEL SAFE;
1447CREATE OR REPLACE
FUNCTION rv_analytical_curves(
1448 token UUID, samples
INT DEFAULT 100, prov UUID
DEFAULT gate_one())
1450 AS 'provsql',
'rv_analytical_curves'
1451 LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
1472CREATE OR REPLACE
FUNCTION rv_sample(
1473 token UUID, n
INTEGER, prov UUID
DEFAULT gate_one())
1474 RETURNS SETOF float8
1475 AS 'provsql',
'rv_sample'
1476 LANGUAGE C VOLATILE PARALLEL SAFE;
1494CREATE OR REPLACE
FUNCTION resolve_input(UUID UUID)
1495 RETURNS TABLE(relation REGCLASS, row_data JSONB)
AS
1507 SELECT c.oid::REGCLASS
AS regc
1509 JOIN pg_class c
ON a.attrelid = c.oid
1510 JOIN pg_namespace ns
ON c.relnamespace = ns.oid
1511 JOIN pg_type ty
ON a.atttypid = ty.oid
1512 WHERE a.attname =
'provsql'
1513 AND ty.typname =
'UUID'
1515 AND ns.nspname <>
'provsql'
1520 'SELECT %L::REGCLASS, to_jsonb(t) - ''provsql'', t.provsql FROM %s AS t WHERE provsql = $1',
1530$$
LANGUAGE plpgsql STABLE;
1553CREATE TYPE AGG_TOKEN;
1556CREATE OR REPLACE
FUNCTION agg_token_in(CSTRING)
1558 AS 'provsql',
'agg_token_in' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
1576CREATE OR REPLACE
FUNCTION agg_token_out(AGG_TOKEN)
1578 AS 'provsql',
'agg_token_out' LANGUAGE C STABLE STRICT PARALLEL SAFE;
1581CREATE OR REPLACE
FUNCTION agg_token_cast(AGG_TOKEN)
1583 AS 'provsql',
'agg_token_cast' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
1585CREATE TYPE AGG_TOKEN (
1586 internallength =
117,
1587 input = agg_token_in,
1588 output = agg_token_out,
1593CREATE OR REPLACE
FUNCTION agg_token_uuid(aggtok AGG_TOKEN)
1597 RETURN agg_token_cast(aggtok)::UUID;
1599$$
LANGUAGE plpgsql STRICT
SET search_path=provsql,pg_temp,public SECURITY DEFINER IMMUTABLE PARALLEL SAFE;
1602CREATE CAST (AGG_TOKEN
AS UUID)
WITH FUNCTION agg_token_uuid(AGG_TOKEN)
AS IMPLICIT;
1620CREATE OR REPLACE
FUNCTION agg_token_value_text(token UUID)
1624 WHEN provsql.get_gate_type(token) =
'agg'
1625 THEN provsql.get_extra(token) ||
' (*)'
1628$$
LANGUAGE sql STABLE STRICT PARALLEL SAFE;
1631CREATE OR REPLACE
FUNCTION agg_token_to_numeric(AGG_TOKEN)
1633 AS 'provsql',
'agg_token_to_numeric' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
1636CREATE OR REPLACE
FUNCTION agg_token_to_float8(AGG_TOKEN)
1637 RETURNS double precision
1638 AS 'provsql',
'agg_token_to_float8' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
1641CREATE OR REPLACE
FUNCTION agg_token_to_int4(AGG_TOKEN)
1643 AS 'provsql',
'agg_token_to_int4' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
1646CREATE OR REPLACE
FUNCTION agg_token_to_int8(AGG_TOKEN)
1648 AS 'provsql',
'agg_token_to_int8' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
1651CREATE OR REPLACE
FUNCTION agg_token_to_text(AGG_TOKEN)
1653 AS 'provsql',
'agg_token_to_text' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
1656CREATE CAST (AGG_TOKEN
AS NUMERIC)
WITH FUNCTION agg_token_to_numeric(AGG_TOKEN)
AS IMPLICIT;
1658CREATE CAST (AGG_TOKEN
AS double precision)
WITH FUNCTION agg_token_to_float8(AGG_TOKEN)
AS ASSIGNMENT;
1660CREATE CAST (AGG_TOKEN
AS INTEGER)
WITH FUNCTION agg_token_to_int4(AGG_TOKEN)
AS ASSIGNMENT;
1662CREATE CAST (AGG_TOKEN
AS bigint)
WITH FUNCTION agg_token_to_int8(AGG_TOKEN)
AS ASSIGNMENT;
1664CREATE CAST (AGG_TOKEN
AS TEXT)
WITH FUNCTION agg_token_to_text(AGG_TOKEN)
AS ASSIGNMENT;
1673CREATE OR REPLACE
FUNCTION agg_token_comp_numeric(a AGG_TOKEN, b
NUMERIC)
1676IMMUTABLE STRICT PARALLEL SAFE
1679 RAISE EXCEPTION
'Comparison AGG_TOKEN-NUMERIC not implemented, should be replaced by ProvSQL behavior';
1689CREATE OR REPLACE
FUNCTION numeric_comp_agg_token(a
NUMERIC, b AGG_TOKEN)
1692IMMUTABLE STRICT PARALLEL SAFE
1695 RAISE EXCEPTION
'Comparison NUMERIC-AGG_TOKEN not implemented, should be replaced by ProvSQL behavior';
1701 LEFTARG = AGG_TOKEN,
1703 PROCEDURE = agg_token_comp_numeric,
1710 RIGHTARG = AGG_TOKEN,
1711 PROCEDURE = numeric_comp_agg_token,
1718 LEFTARG = AGG_TOKEN,
1720 PROCEDURE = agg_token_comp_numeric,
1727 RIGHTARG = AGG_TOKEN,
1728 PROCEDURE = numeric_comp_agg_token,
1735 LEFTARG = AGG_TOKEN,
1737 PROCEDURE = agg_token_comp_numeric,
1744 RIGHTARG = AGG_TOKEN,
1745 PROCEDURE = numeric_comp_agg_token,
1752 LEFTARG = AGG_TOKEN,
1754 PROCEDURE = agg_token_comp_numeric,
1761 RIGHTARG = AGG_TOKEN,
1762 PROCEDURE = numeric_comp_agg_token,
1769 LEFTARG = AGG_TOKEN,
1771 PROCEDURE = agg_token_comp_numeric,
1778 RIGHTARG = AGG_TOKEN,
1779 PROCEDURE = numeric_comp_agg_token,
1786 LEFTARG = AGG_TOKEN,
1788 PROCEDURE = agg_token_comp_numeric,
1795 RIGHTARG = AGG_TOKEN,
1796 PROCEDURE = numeric_comp_agg_token,
1825CREATE TYPE random_variable;
1828CREATE OR REPLACE
FUNCTION random_variable_in(CSTRING)
1829 RETURNS random_variable
1830 AS 'provsql',
'random_variable_in' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
1833CREATE OR REPLACE
FUNCTION random_variable_out(random_variable)
1835 AS 'provsql',
'random_variable_out' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
1837CREATE TYPE random_variable (
1838 internallength =
16,
1839 input = random_variable_in,
1840 output = random_variable_out,
1845CREATE OR REPLACE
FUNCTION random_variable_make(tok UUID)
1846 RETURNS random_variable
1847 AS 'provsql',
'random_variable_make' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
1855CREATE CAST (random_variable
AS UUID)
WITHOUT FUNCTION AS IMPLICIT;
1856CREATE CAST (UUID
AS random_variable)
WITHOUT FUNCTION;
1866CREATE OR REPLACE
FUNCTION is_finite_float8(x
double precision)
1869 SELECT $
1 <>
'NaN'::float8
AND $
1 <>
'Infinity'::float8
AND $
1 <>
'-Infinity'::float8;
1870$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
1900CREATE OR REPLACE
FUNCTION normal(mu
double precision, sigma
double precision)
1901 RETURNS random_variable
AS
1906 IF NOT provsql.is_finite_float8(mu)
OR NOT provsql.is_finite_float8(sigma)
THEN
1907 RAISE EXCEPTION
'provsql.normal: parameters must be finite (got mu=%, sigma=%)', mu, sigma;
1910 RAISE EXCEPTION
'provsql.normal: sigma must be non-negative (got %)', sigma;
1913 RETURN provsql.as_random(mu);
1915 token := public.uuid_generate_v4();
1916 PERFORM provsql.create_gate(token,
'rv');
1917 PERFORM provsql.set_extra(token,
'normal:' || mu ||
',' || sigma);
1918 RETURN provsql.random_variable_make(token);
1920$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
1937CREATE OR REPLACE
FUNCTION uniform(a
double precision, b
double precision)
1938 RETURNS random_variable
AS
1943 IF NOT provsql.is_finite_float8(a)
OR NOT provsql.is_finite_float8(b)
THEN
1944 RAISE EXCEPTION
'provsql.uniform: bounds must be finite (got a=%, b=%)', a, b;
1947 RAISE EXCEPTION
'provsql.uniform: a must be <= b (got a=%, b=%)', a, b;
1950 RETURN provsql.as_random(a);
1952 token := public.uuid_generate_v4();
1953 PERFORM provsql.create_gate(token,
'rv');
1954 PERFORM provsql.set_extra(token,
'uniform:' || a ||
',' || b);
1955 RETURN provsql.random_variable_make(token);
1957$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
1972CREATE OR REPLACE
FUNCTION exponential(lambda
double precision)
1973 RETURNS random_variable
AS
1978 IF NOT provsql.is_finite_float8(lambda)
THEN
1979 RAISE EXCEPTION
'provsql.exponential: lambda must be finite (got %)', lambda;
1982 RAISE EXCEPTION
'provsql.exponential: lambda must be strictly positive (got %)', lambda;
1984 token := public.uuid_generate_v4();
1985 PERFORM provsql.create_gate(token,
'rv');
1986 PERFORM provsql.set_extra(token,
'exponential:' || lambda);
1987 RETURN provsql.random_variable_make(token);
1989$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
2014CREATE OR REPLACE
FUNCTION erlang(k
INTEGER, lambda
double precision)
2015 RETURNS random_variable
AS
2021 RAISE EXCEPTION
'provsql.erlang: k must be >= 1 (got %)', k;
2023 IF NOT provsql.is_finite_float8(lambda)
THEN
2024 RAISE EXCEPTION
'provsql.erlang: lambda must be finite (got %)', lambda;
2027 RAISE EXCEPTION
'provsql.erlang: lambda must be strictly positive (got %)', lambda;
2030 RETURN provsql.exponential(lambda);
2032 token := public.uuid_generate_v4();
2033 PERFORM provsql.create_gate(token,
'rv');
2034 PERFORM provsql.set_extra(token,
'erlang:' || k ||
',' || lambda);
2035 RETURN provsql.random_variable_make(token);
2037$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
2079CREATE OR REPLACE
FUNCTION mixture(
2080 p UUID, x random_variable, y random_variable)
2081 RETURNS random_variable
AS
2085 p_kind provsql.PROVENANCE_GATE;
2088 x_kind provsql.PROVENANCE_GATE;
2089 y_kind provsql.PROVENANCE_GATE;
2091 p_kind := provsql.get_gate_type(p);
2092 IF p_kind
NOT IN (
'input',
'mulinput',
'update',
2093 'plus',
'times',
'monus',
2094 'project',
'eq',
'cmp',
2096 RAISE EXCEPTION
'provsql.mixture: p must be a Boolean gate '
2097 '(input/mulinput/update/plus/times/monus/project/eq/cmp/zero/one), got %', p_kind;
2100 x_uuid := (x)::UUID;
2101 y_uuid := (y)::UUID;
2102 x_kind := provsql.get_gate_type(x_uuid);
2103 y_kind := provsql.get_gate_type(y_uuid);
2104 IF x_kind
NOT IN (
'rv',
'value',
'arith',
'mixture')
THEN
2105 RAISE EXCEPTION
'provsql.mixture: x must be a scalar RV root (rv / value / arith / mixture), got %', x_kind;
2107 IF y_kind
NOT IN (
'rv',
'value',
'arith',
'mixture')
THEN
2108 RAISE EXCEPTION
'provsql.mixture: y must be a scalar RV root (rv / value / arith / mixture), got %', y_kind;
2111 token := public.uuid_generate_v5(
2112 provsql.uuid_ns_provsql(),
2113 concat(
'mixture', p, x_uuid, y_uuid));
2114 PERFORM provsql.create_gate(token,
'mixture',
ARRAY[p, x_uuid, y_uuid]);
2115 RETURN provsql.random_variable_make(token);
2117$$
LANGUAGE plpgsql STRICT IMMUTABLE PARALLEL SAFE;
2144CREATE OR REPLACE
FUNCTION mixture(
2145 p_value
double precision,
2148 RETURNS random_variable
AS
2153 IF p_value
IS NULL OR p_value <> p_value
OR p_value <
0 OR p_value >
1 THEN
2154 RAISE EXCEPTION
'provsql.mixture: probability must be in [0,1] (got %)', p_value;
2156 p_token := public.uuid_generate_v4();
2157 PERFORM provsql.create_gate(p_token,
'input');
2158 PERFORM provsql.set_prob(p_token, p_value);
2159 RETURN provsql.mixture(p_token, x, y);
2161$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
2195CREATE OR REPLACE
FUNCTION categorical(
2196 probs
double precision[],
2197 outcomes
double precision[])
2198 RETURNS random_variable
AS
2202 p_sum
double precision :=
0.
0;
2207 mul_tokens UUID[] :=
ARRAY[]::UUID[];
2209 pi_i
double precision;
2210 vi_i
double precision;
2212 IF probs
IS NULL OR outcomes
IS NULL THEN
2213 RAISE EXCEPTION
'provsql.categorical: probs and outcomes must be non-null';
2215 n := array_length(probs,
1);
2216 IF n
IS NULL OR n <
1 THEN
2217 RAISE EXCEPTION
'provsql.categorical: probs must be non-empty';
2219 IF array_length(outcomes,
1) <> n
THEN
2220 RAISE EXCEPTION
'provsql.categorical: probs and outcomes must have the same length (got % and %)',
2221 n, array_length(outcomes,
1);
2226 vi_i := outcomes[i];
2231 IF pi_i
IS NULL OR pi_i =
'NaN'::float8
OR pi_i <
0 OR pi_i >
1 THEN
2232 RAISE EXCEPTION
'provsql.categorical: probs[%] must be in [0,1] (got %)', i, pi_i;
2234 IF vi_i
IS NULL OR vi_i =
'NaN'::float8
2235 OR vi_i =
'Infinity'::float8
OR vi_i =
'-Infinity'::float8
THEN
2236 RAISE EXCEPTION
'provsql.categorical: outcomes[%] must be finite (got %)', i, vi_i;
2238 p_sum := p_sum + pi_i;
2240 IF abs(p_sum -
1.
0) > 1e-9
THEN
2241 RAISE EXCEPTION
'provsql.categorical: probs must sum to 1 within 1e-9 (got %)', p_sum;
2253 nb_positive
INTEGER :=
0;
2254 only_idx
INTEGER :=
0;
2257 IF probs[i] >
0.
0 THEN
2258 nb_positive := nb_positive +
1;
2262 IF nb_positive =
1 THEN
2263 RETURN provsql.as_random(outcomes[only_idx]);
2270 key_token := public.uuid_generate_v4();
2271 PERFORM provsql.create_gate(key_token,
'input');
2272 PERFORM provsql.set_prob(key_token,
1.
0);
2279 IF pi_i <=
0.
0 THEN CONTINUE;
END IF;
2280 mul_token := public.uuid_generate_v4();
2281 PERFORM provsql.create_gate(mul_token,
'mulinput',
ARRAY[key_token]);
2282 PERFORM provsql.set_prob(mul_token, pi_i);
2283 PERFORM provsql.set_infos(mul_token, (i -
1));
2284 PERFORM provsql.set_extra(mul_token, outcomes[i]::TEXT);
2285 mul_tokens := mul_tokens || mul_token;
2288 mix_wires :=
ARRAY[key_token] || mul_tokens;
2289 mix_token := public.uuid_generate_v4();
2290 PERFORM provsql.create_gate(mix_token,
'mixture', mix_wires);
2291 RETURN provsql.random_variable_make(mix_token);
2293$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
2314CREATE OR REPLACE
FUNCTION as_random(c
double precision)
2315 RETURNS random_variable
AS
2323 c_canon
double precision := c +
0.
0;
2324 c_text
varchar :=
CAST(c_canon
AS VARCHAR);
2325 token UUID := public.uuid_generate_v5(
2326 provsql.uuid_ns_provsql(), concat(
'value', c_text));
2328 PERFORM provsql.create_gate(token,
'value');
2329 PERFORM provsql.set_extra(token, c_text);
2330 RETURN provsql.random_variable_make(token);
2332$$
LANGUAGE plpgsql STRICT IMMUTABLE PARALLEL SAFE;
2347CREATE CAST (
double precision AS random_variable)
2348 WITH FUNCTION as_random(
double precision)
AS IMPLICIT;
2351CREATE OR REPLACE
FUNCTION as_random(c
INTEGER)
2352 RETURNS random_variable
AS
2353$$
SELECT provsql.as_random(c::
double precision); $$
2354LANGUAGE sql STRICT IMMUTABLE PARALLEL SAFE;
2357CREATE OR REPLACE
FUNCTION as_random(c
NUMERIC)
2358 RETURNS random_variable
AS
2359$$
SELECT provsql.as_random(c::
double precision); $$
2360LANGUAGE sql STRICT IMMUTABLE PARALLEL SAFE;
2363CREATE CAST (
INTEGER AS random_variable)
2364 WITH FUNCTION as_random(
INTEGER)
AS IMPLICIT;
2367CREATE CAST (
NUMERIC AS random_variable)
2368 WITH FUNCTION as_random(
NUMERIC)
AS IMPLICIT;
2400CREATE OR REPLACE
FUNCTION random_variable_plus(
2401 a random_variable, b random_variable)
2402 RETURNS random_variable
AS
2404 SELECT provsql.random_variable_make(
2405 provsql.provenance_arith(
2409$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
2412CREATE OR REPLACE
FUNCTION random_variable_minus(
2413 a random_variable, b random_variable)
2414 RETURNS random_variable
AS
2416 SELECT provsql.random_variable_make(
2417 provsql.provenance_arith(
2421$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
2424CREATE OR REPLACE
FUNCTION random_variable_times(
2425 a random_variable, b random_variable)
2426 RETURNS random_variable
AS
2428 SELECT provsql.random_variable_make(
2429 provsql.provenance_arith(
2433$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
2436CREATE OR REPLACE
FUNCTION random_variable_div(
2437 a random_variable, b random_variable)
2438 RETURNS random_variable
AS
2440 SELECT provsql.random_variable_make(
2441 provsql.provenance_arith(
2445$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
2448CREATE OR REPLACE
FUNCTION random_variable_neg(a random_variable)
2449 RETURNS random_variable
AS
2451 SELECT provsql.random_variable_make(
2452 provsql.provenance_arith(
2455$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
2465CREATE OR REPLACE
FUNCTION random_variable_cmp_oid(sym TEXT)
2468 SELECT (sym ||
'(double precision,double precision)')::regoperator::oid;
2469$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
2485CREATE OR REPLACE
FUNCTION random_variable_cmp_placeholder(
2486 a random_variable, b random_variable)
2490 RAISE EXCEPTION
'random_variable comparison must be rewritten by the '
2491 'ProvSQL planner hook (is provsql.active off?)';
2493$$
LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
2495CREATE OR REPLACE
FUNCTION random_variable_lt(
2496 a random_variable, b random_variable)
RETURNS BOOLEAN AS
2497$$
SELECT provsql.random_variable_cmp_placeholder(a, b); $$
2498LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
2500CREATE OR REPLACE
FUNCTION random_variable_le(
2501 a random_variable, b random_variable)
RETURNS BOOLEAN AS
2502$$
SELECT provsql.random_variable_cmp_placeholder(a, b); $$
2503LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
2505CREATE OR REPLACE
FUNCTION random_variable_eq(
2506 a random_variable, b random_variable)
RETURNS BOOLEAN AS
2507$$
SELECT provsql.random_variable_cmp_placeholder(a, b); $$
2508LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
2510CREATE OR REPLACE
FUNCTION random_variable_ne(
2511 a random_variable, b random_variable)
RETURNS BOOLEAN AS
2512$$
SELECT provsql.random_variable_cmp_placeholder(a, b); $$
2513LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
2515CREATE OR REPLACE
FUNCTION random_variable_ge(
2516 a random_variable, b random_variable)
RETURNS BOOLEAN AS
2517$$
SELECT provsql.random_variable_cmp_placeholder(a, b); $$
2518LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
2520CREATE OR REPLACE
FUNCTION random_variable_gt(
2521 a random_variable, b random_variable)
RETURNS BOOLEAN AS
2522$$
SELECT provsql.random_variable_cmp_placeholder(a, b); $$
2523LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
2531CREATE OR REPLACE
FUNCTION rv_cmp_lt(
2532 a random_variable, b random_variable)
RETURNS UUID
AS
2534 SELECT provsql.provenance_cmp(
2536 provsql.random_variable_cmp_oid(
'<'),
2538$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
2541CREATE OR REPLACE
FUNCTION rv_cmp_le(
2542 a random_variable, b random_variable)
RETURNS UUID
AS
2544 SELECT provsql.provenance_cmp(
2546 provsql.random_variable_cmp_oid(
'<='),
2548$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
2551CREATE OR REPLACE
FUNCTION rv_cmp_eq(
2552 a random_variable, b random_variable)
RETURNS UUID
AS
2554 SELECT provsql.provenance_cmp(
2556 provsql.random_variable_cmp_oid(
'='),
2558$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
2561CREATE OR REPLACE
FUNCTION rv_cmp_ne(
2562 a random_variable, b random_variable)
RETURNS UUID
AS
2564 SELECT provsql.provenance_cmp(
2566 provsql.random_variable_cmp_oid(
'<>'),
2568$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
2571CREATE OR REPLACE
FUNCTION rv_cmp_ge(
2572 a random_variable, b random_variable)
RETURNS UUID
AS
2574 SELECT provsql.provenance_cmp(
2576 provsql.random_variable_cmp_oid(
'>='),
2578$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
2581CREATE OR REPLACE
FUNCTION rv_cmp_gt(
2582 a random_variable, b random_variable)
RETURNS UUID
AS
2584 SELECT provsql.provenance_cmp(
2586 provsql.random_variable_cmp_oid(
'>'),
2588$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
2591 LEFTARG = random_variable,
2592 RIGHTARG = random_variable,
2593 PROCEDURE = random_variable_plus,
2598 LEFTARG = random_variable,
2599 RIGHTARG = random_variable,
2600 PROCEDURE = random_variable_minus
2604 LEFTARG = random_variable,
2605 RIGHTARG = random_variable,
2606 PROCEDURE = random_variable_times,
2611 LEFTARG = random_variable,
2612 RIGHTARG = random_variable,
2613 PROCEDURE = random_variable_div
2618 RIGHTARG = random_variable,
2619 PROCEDURE = random_variable_neg
2623 LEFTARG = random_variable,
2624 RIGHTARG = random_variable,
2625 PROCEDURE = random_variable_lt,
2631 LEFTARG = random_variable,
2632 RIGHTARG = random_variable,
2633 PROCEDURE = random_variable_le,
2639 LEFTARG = random_variable,
2640 RIGHTARG = random_variable,
2641 PROCEDURE = random_variable_eq,
2647 LEFTARG = random_variable,
2648 RIGHTARG = random_variable,
2649 PROCEDURE = random_variable_ne,
2655 LEFTARG = random_variable,
2656 RIGHTARG = random_variable,
2657 PROCEDURE = random_variable_ge,
2663 LEFTARG = random_variable,
2664 RIGHTARG = random_variable,
2665 PROCEDURE = random_variable_gt,
2713CREATE OR REPLACE
FUNCTION rv_aggregate_semimod(
2714 prov UUID, rv random_variable)
2715 RETURNS random_variable
AS
2717 SELECT provsql.mixture(prov, rv, provsql.as_random(
0::
double precision));
2718$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
2729CREATE OR REPLACE
FUNCTION sum_rv_sfunc(
2730 state UUID[], rv random_variable)
2734 WHEN rv
IS NULL THEN state
2735 ELSE array_append(state, (rv)::UUID)
2737$$
LANGUAGE sql IMMUTABLE PARALLEL SAFE;
2752CREATE OR REPLACE
FUNCTION sum_rv_ffunc(state UUID[])
2753 RETURNS random_variable
AS
2758 IF state
IS NULL OR array_length(state,
1)
IS NULL THEN
2759 RETURN provsql.as_random(
0::
double precision);
2761 IF array_length(state,
1) =
1 THEN
2762 RETURN provsql.random_variable_make(state[
1]);
2764 arith_token := provsql.provenance_arith(
0, state);
2765 RETURN provsql.random_variable_make(arith_token);
2767$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE;
2769CREATE AGGREGATE sum(random_variable) (
2770 SFUNC = sum_rv_sfunc,
2773 FINALFUNC = sum_rv_ffunc
2812CREATE OR REPLACE
FUNCTION avg_rv_ffunc(state UUID[])
2813 RETURNS random_variable
AS
2820 denom_state UUID[] :=
'{}';
2822 gtype provsql.PROVENANCE_GATE;
2826 IF state
IS NULL THEN
2829 n := array_length(state,
1);
2835 provsql.as_random(
1::
double precision))::UUID;
2838 gtype := provsql.get_gate_type(state[i]);
2839 IF gtype =
'mixture'::provsql.PROVENANCE_GATE
THEN
2840 children := provsql.get_children(state[i]);
2841 prov_i := children[
1];
2842 denom_state := array_append(
2845 provsql.rv_aggregate_semimod(
2846 prov_i, provsql.as_random(
1::
double precision)))::UUID);
2848 denom_state := array_append(denom_state, one_uuid);
2853 num_token := state[
1];
2854 denom_token := denom_state[
1];
2856 num_token := provsql.provenance_arith(
0, state);
2857 denom_token := provsql.provenance_arith(
0, denom_state);
2860 RETURN provsql.random_variable_make(
2861 provsql.provenance_arith(
2863 ARRAY[num_token, denom_token]));
2865$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE;
2867CREATE AGGREGATE avg(random_variable) (
2868 SFUNC = sum_rv_sfunc,
2871 FINALFUNC = avg_rv_ffunc
2909CREATE OR REPLACE
FUNCTION product_rv_ffunc(state UUID[])
2910 RETURNS random_variable
AS
2915 prod_state UUID[] :=
'{}';
2916 one_rv provsql.random_variable;
2917 gtype provsql.PROVENANCE_GATE;
2922 one_rv := provsql.as_random(
1::
double precision);
2924 IF state
IS NULL THEN
2927 n := array_length(state,
1);
2933 gtype := provsql.get_gate_type(state[i]);
2934 IF gtype =
'mixture'::provsql.PROVENANCE_GATE
THEN
2935 children := provsql.get_children(state[i]);
2936 prov_i := children[
1];
2937 x_uuid := children[
2];
2938 prod_state := array_append(
2943 provsql.random_variable_make(x_uuid),
2946 prod_state := array_append(prod_state, state[i]);
2951 RETURN provsql.random_variable_make(prod_state[
1]);
2953 RETURN provsql.random_variable_make(
2954 provsql.provenance_arith(
1, prod_state));
2956$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE;
2958CREATE AGGREGATE product(random_variable) (
2959 SFUNC = sum_rv_sfunc,
2962 FINALFUNC = product_rv_ffunc
2981CREATE OR REPLACE
FUNCTION provenance_delta
2988 IF token = gate_zero()
OR token = gate_one()
THEN
2992 IF token
IS NULL THEN
2996 delta_token:=uuid_generate_v5(uuid_ns_provsql(),concat(
'delta',token));
2998 PERFORM create_gate(delta_token,
'delta',
ARRAY[token::UUID]);
3002$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public SECURITY DEFINER PARALLEL SAFE;
3016CREATE OR REPLACE
FUNCTION provenance_aggregate(
3021 RETURNS AGG_TOKEN
AS
3028 c:=COALESCE(array_length(tokens,
1),
0);
3030 agg_val =
CAST(val
as VARCHAR);
3033 agg_tok := gate_zero();
3040 agg_tok := uuid_generate_v5(
3042 concat(
'agg',aggfnoid,tokens));
3043 PERFORM create_gate(agg_tok,
'agg', tokens);
3044 PERFORM set_infos(agg_tok, aggfnoid, aggtype);
3045 PERFORM set_extra(agg_tok, agg_val);
3048 RETURN '( '||agg_tok||
' , '||agg_val||
' )';
3050$$
LANGUAGE plpgsql PARALLEL SAFE
SET search_path=provsql,pg_temp,public SECURITY DEFINER;
3061CREATE OR REPLACE
FUNCTION provenance_semimod(val ANYELEMENT, token UUID)
3068 SELECT uuid_generate_v5(uuid_ns_provsql(),concat(
'value',
CAST(val
AS VARCHAR)))
3070 SELECT uuid_generate_v5(uuid_ns_provsql(),concat(
'semimod',value_token,token))
3074 PERFORM create_gate(value_token,
'value');
3075 PERFORM set_extra(value_token,
CAST(val
AS VARCHAR));
3078 PERFORM create_gate(semimod_token,
'semimod',
ARRAY[token::UUID,value_token]);
3080 RETURN semimod_token;
3082$$
LANGUAGE plpgsql PARALLEL SAFE
SET search_path=provsql,pg_temp,public SECURITY DEFINER;
3103CREATE OR REPLACE
FUNCTION probability_evaluate(
3106 arguments TEXT =
NULL)
3107 RETURNS DOUBLE PRECISION AS
3108 'provsql',
'probability_evaluate' LANGUAGE C STABLE;
3131CREATE OR REPLACE
FUNCTION expected(
3133 prov UUID = gate_one(),
3135 arguments TEXT =
NULL)
3136 RETURNS DOUBLE PRECISION AS $$
3137 SELECT moment(
input,
1, prov,
method, arguments);
3138$$
LANGUAGE sql PARALLEL SAFE STABLE
SET search_path=provsql SECURITY DEFINER;
3150CREATE OR REPLACE
FUNCTION rv_moment(
3151 token UUID, k
INTEGER, central
BOOLEAN,
3152 prov UUID
DEFAULT gate_one())
3153 RETURNS double precision
3154 AS 'provsql',
'rv_moment' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
3182CREATE OR REPLACE
FUNCTION agg_raw_moment(
3185 prov UUID = gate_one(),
3187 arguments TEXT =
NULL)
3188 RETURNS DOUBLE PRECISION AS $$
3190 aggregation_function
VARCHAR;
3192 pair_children UUID[];
3199 total_probability float8;
3203 distinct_tok UUID[];
3208 IF token
IS NULL OR k
IS NULL THEN
3212 RAISE EXCEPTION
'agg_raw_moment(): k must be non-negative (got %)', k;
3214 IF get_gate_type(token) <>
'agg' THEN
3215 RAISE EXCEPTION
USING MESSAGE=
'Wrong gate type for agg_raw_moment computation';
3221 SELECT pp.proname::
varchar FROM pg_proc pp
3222 WHERE oid=(get_infos(token)).info1
3223 INTO aggregation_function;
3225 child_pairs := get_children(token);
3226 n := COALESCE(array_length(child_pairs,
1),
0);
3228 IF aggregation_function =
'sum' THEN
3237 vals :=
ARRAY[]::float8[];
3238 toks :=
ARRAY[]::UUID[];
3240 pair_children := get_children(child_pairs[i]);
3241 toks := toks || pair_children[
1];
3242 vals := vals ||
CAST(get_extra(pair_children[
2])
AS float8);
3248 tup := array_fill(
1,
ARRAY[k]);
3252 prod_v := prod_v * vals[tup[j]];
3255 SELECT array_agg(
DISTINCT toks[idx])
INTO distinct_tok
3256 FROM unnest(tup)
AS idx;
3258 IF prov <> gate_one()
THEN
3259 distinct_tok := distinct_tok || prov;
3261 conj_token := provenance_times(VARIADIC distinct_tok);
3262 prob := probability_evaluate(conj_token,
method, arguments);
3264 total := total + prod_v * prob;
3267 WHILE d >=
1 AND tup[d] = n LOOP
3272 tup[d] := tup[d] +
1;
3274 ELSIF aggregation_function =
'min' OR aggregation_function =
'max' THEN
3282 WHEN aggregation_function =
'max'
3283 THEN power(-1::float8, k)
3291 SELECT (get_children(c))[
1]
AS tok,
3292 (
CASE WHEN aggregation_function=
'max' THEN -1
ELSE 1 END)
3293 *
CAST(get_extra((get_children(c))[
2])
AS DOUBLE PRECISION)
AS v
3294 FROM UNNEST(child_pairs)
AS c
3295 )
SELECT probability_evaluate(provenance_monus(prov, provenance_plus(ARRAY_AGG(tok))))
3297 INTO total_probability;
3299 IF total_probability > epsilon()
THEN
3300 total := sign_max *
'Infinity'::float8;
3303 SELECT (get_children(c))[
1]
AS tok,
3304 (
CASE WHEN aggregation_function=
'max' THEN -1
ELSE 1 END)
3305 *
CAST(get_extra((get_children(c))[
2])
AS DOUBLE PRECISION)
AS v
3306 FROM UNNEST(child_pairs)
AS c
3307 )
SELECT sign_max * SUM(p * power(v, k))
FROM (
3309 probability_evaluate(
3310 provenance_monus(provenance_plus(ARRAY_AGG(t1.tok)),
3311 provenance_plus(ARRAY_AGG(t2.tok))),
3312 method, arguments)
AS p
3313 FROM tok_value t1
LEFT OUTER JOIN tok_value t2
ON t1.v > t2.v
3318 RAISE EXCEPTION
USING MESSAGE=
3319 'Cannot compute moment for aggregation function ' || aggregation_function;
3323 IF prov <> gate_one()
3325 AND total <>
'Infinity'::float8
3326 AND total <>
'-Infinity'::float8
THEN
3327 total := total / probability_evaluate(prov,
method, arguments);
3332$$
LANGUAGE plpgsql PARALLEL SAFE
SET search_path=provsql SECURITY DEFINER;
3345CREATE OR REPLACE
FUNCTION variance(
3347 prov UUID = gate_one(),
3349 arguments TEXT =
NULL)
3350 RETURNS DOUBLE PRECISION AS $$
3355 IF pg_typeof(
input) =
'random_variable'::REGTYPE
THEN
3356 IF input IS NULL THEN
3366 RETURN provsql.rv_moment(
3367 (
input::random_variable)::UUID,
2,
true, prov);
3370 IF pg_typeof(
input) =
'AGG_TOKEN'::REGTYPE
THEN
3371 IF input IS NULL THEN
3374 m1 := agg_raw_moment(
input::AGG_TOKEN,
1, prov,
method, arguments);
3375 m2 := agg_raw_moment(
input::AGG_TOKEN,
2, prov,
method, arguments);
3376 IF m1
IS NULL OR m2
IS NULL THEN
3379 RETURN m2 - m1 * m1;
3382 RAISE EXCEPTION
'variance() is not yet supported for input type %', pg_typeof(
input);
3384$$
LANGUAGE plpgsql PARALLEL SAFE
SET search_path=provsql SECURITY DEFINER;
3395CREATE OR REPLACE
FUNCTION moment(
3398 prov UUID = gate_one(),
3400 arguments TEXT =
NULL)
3401 RETURNS DOUBLE PRECISION AS $$
3403 IF pg_typeof(
input) =
'random_variable'::REGTYPE
THEN
3404 IF input IS NULL OR k
IS NULL THEN
3409 RETURN provsql.rv_moment(
3410 (
input::random_variable)::UUID, k,
false, prov);
3413 IF pg_typeof(
input) =
'AGG_TOKEN'::REGTYPE
THEN
3414 RETURN agg_raw_moment(
input::AGG_TOKEN, k, prov,
method, arguments);
3417 RAISE EXCEPTION
'moment() is not yet supported for input type %', pg_typeof(
input);
3419$$
LANGUAGE plpgsql PARALLEL SAFE
SET search_path=provsql SECURITY DEFINER;
3430CREATE OR REPLACE
FUNCTION rv_support(
3431 token UUID, prov UUID
DEFAULT gate_one(),
3432 OUT lo float8,
OUT hi float8)
3433 AS 'provsql',
'rv_support' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
3474CREATE OR REPLACE
FUNCTION support(
3476 prov UUID = gate_one(),
3478 arguments TEXT =
NULL,
3483 aggregation_function
VARCHAR;
3485 values_arr float8[];
3486 total_probability float8;
3488 IF input IS NULL THEN
3489 lo :=
NULL; hi :=
NULL;
RETURN;
3495 IF pg_typeof(
input)
IN (
3496 'smallint'::REGTYPE,
'INTEGER'::REGTYPE,
'bigint'::REGTYPE,
3497 'NUMERIC'::REGTYPE,
'real'::REGTYPE,
'double precision'::REGTYPE)
THEN
3498 lo :=
input::
double precision;
3499 hi :=
input::
double precision;
3511 IF pg_typeof(
input)
IN (
'random_variable'::REGTYPE,
'UUID'::REGTYPE)
THEN
3516 SELECT r.lo, r.hi
INTO lo, hi
3517 FROM provsql.rv_support(
input::UUID, prov) r;
3521 IF pg_typeof(
input) =
'AGG_TOKEN'::REGTYPE
THEN
3522 IF get_gate_type(
input::AGG_TOKEN) <>
'agg' THEN
3523 RAISE EXCEPTION
USING MESSAGE=
'Wrong gate type for support computation';
3525 SELECT pp.proname::
varchar FROM pg_proc pp
3526 WHERE oid=(get_infos(
input::AGG_TOKEN)).info1
3527 INTO aggregation_function;
3528 child_pairs := get_children(
input::AGG_TOKEN);
3530 IF aggregation_function =
'sum' THEN
3532 IF COALESCE(array_length(child_pairs,
1),
0) =
0 THEN
3533 lo :=
0; hi :=
0;
RETURN;
3535 SELECT sum(LEAST(v,
0::float8)), sum(GREATEST(v,
0::float8))
3537 FROM (
SELECT CAST(get_extra((get_children(c))[
2])
AS float8)
AS v
3538 FROM unnest(child_pairs)
AS c) sub;
3539 ELSIF aggregation_function =
'min' OR aggregation_function =
'max' THEN
3542 IF COALESCE(array_length(child_pairs,
1),
0) =
0 THEN
3543 IF aggregation_function =
'min' THEN
3544 lo :=
'Infinity'::float8; hi :=
'Infinity'::float8;
3546 lo :=
'-Infinity'::float8; hi :=
'-Infinity'::float8;
3552 SELECT (get_children(c))[
1]
AS tok,
3553 CAST(get_extra((get_children(c))[
2])
AS float8)
AS v
3554 FROM UNNEST(child_pairs)
AS c
3556 SELECT min(v), max(v),
3557 probability_evaluate(
3558 provenance_monus(prov, provenance_plus(ARRAY_AGG(tok))),
3560 INTO lo, hi, total_probability
3563 IF total_probability > epsilon()
THEN
3564 IF aggregation_function =
'min' THEN
3565 hi :=
'Infinity'::float8;
3567 lo :=
'-Infinity'::float8;
3571 RAISE EXCEPTION
USING MESSAGE=
3572 'Cannot compute support for aggregation function ' || aggregation_function;
3577 RAISE EXCEPTION
'support() is not yet supported for input type %', pg_typeof(
input);
3579$$
LANGUAGE plpgsql PARALLEL SAFE
SET search_path=provsql SECURITY DEFINER;
3592CREATE OR REPLACE
FUNCTION central_moment(
3595 prov UUID = gate_one(),
3597 arguments TEXT =
NULL)
3598 RETURNS DOUBLE PRECISION AS $$
3608 IF pg_typeof(
input) =
'random_variable'::REGTYPE
THEN
3609 IF input IS NULL OR k
IS NULL THEN
3614 RETURN provsql.rv_moment(
3615 (
input::random_variable)::UUID, k,
true, prov);
3618 IF pg_typeof(
input) =
'AGG_TOKEN'::REGTYPE
THEN
3619 IF input IS NULL OR k
IS NULL THEN
3623 RAISE EXCEPTION
'central_moment(): k must be non-negative (got %)', k;
3625 IF k =
0 THEN RETURN 1;
END IF;
3626 IF k =
1 THEN RETURN 0;
END IF;
3628 mu := agg_raw_moment(
input::AGG_TOKEN,
1, prov,
method, arguments);
3629 IF mu
IS NULL THEN RETURN NULL;
END IF;
3632 IF mu =
'Infinity'::float8
OR mu =
'-Infinity'::float8
THEN
3640 raw_i := agg_raw_moment(
input::AGG_TOKEN, i, prov,
method, arguments);
3641 IF raw_i
IS NULL THEN RETURN NULL;
END IF;
3642 total := total + binom * power(-mu, k - i) * raw_i;
3645 binom := binom * (k_double - i) / (i +
1);
3651 RAISE EXCEPTION
'central_moment() is not yet supported for input type %', pg_typeof(
input);
3653$$
LANGUAGE plpgsql PARALLEL SAFE
SET search_path=provsql SECURITY DEFINER;
3667CREATE OR REPLACE
FUNCTION shapley(
3671 arguments TEXT =
NULL,
3672 banzhaf
BOOLEAN =
'f')
3673 RETURNS DOUBLE PRECISION AS
3674 'provsql',
'shapley' LANGUAGE C STABLE;
3677CREATE OR REPLACE
FUNCTION shapley_all_vars(
3679 IN method TEXT =
NULL,
3680 IN arguments TEXT =
NULL,
3681 IN banzhaf
BOOLEAN =
'f',
3683 OUT value DOUBLE PRECISION)
3684 RETURNS SETOF RECORD
AS
3685 'provsql',
'shapley_all_vars'
3689CREATE OR REPLACE
FUNCTION banzhaf(
3693 arguments TEXT =
NULL)
3694 RETURNS DOUBLE PRECISION AS
3695 $$
SELECT provsql.shapley(token, variable,
method, arguments,
't') $$
3699CREATE OR REPLACE
FUNCTION banzhaf_all_vars(
3701 IN method TEXT =
NULL,
3702 IN arguments TEXT =
NULL,
3704 OUT value DOUBLE PRECISION)
3705 RETURNS SETOF RECORD
AS
3706 $$
SELECT *
FROM provsql.shapley_all_vars(token,
method, arguments,
't') $$
3724CREATE OR REPLACE
FUNCTION view_circuit(
3726 token2desc REGCLASS,
3729 'provsql',
'view_circuit' LANGUAGE C;
3737CREATE OR REPLACE
FUNCTION to_provxml(
3739 token2desc REGCLASS =
NULL)
3741 'provsql',
'to_provxml' LANGUAGE C;
3744CREATE OR REPLACE
FUNCTION provenance()
RETURNS UUID
AS
3745 'provsql',
'provenance' LANGUAGE C;
3753CREATE OR REPLACE
FUNCTION where_provenance(token UUID)
3755 'provsql',
'where_provenance' LANGUAGE C;
3766CREATE OR REPLACE
FUNCTION reset_constants_cache()
3768 'provsql',
'reset_constants_cache' LANGUAGE C;
3770SELECT reset_constants_cache();
3772SELECT create_gate(gate_zero(),
'zero');
3773SELECT create_gate(gate_one(),
'one');
3778CREATE TYPE QUERY_TYPE_ENUM
AS ENUM (
3791CREATE FUNCTION sr_formula(token ANYELEMENT, token2value REGCLASS)
3795 RETURN provsql.provenance_evaluate_compiled(
3802$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
3805CREATE FUNCTION sr_counting(token ANYELEMENT, token2value REGCLASS)
3809 RETURN provsql.provenance_evaluate_compiled(
3816$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
3819CREATE FUNCTION sr_why(token ANYELEMENT, token2value REGCLASS)
3823 RETURN provsql.provenance_evaluate_compiled(
3830$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
3833CREATE FUNCTION sr_how(token ANYELEMENT, token2value REGCLASS)
3837 RETURN provsql.provenance_evaluate_compiled(
3844$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
3847CREATE FUNCTION sr_which(token ANYELEMENT, token2value REGCLASS)
3851 RETURN provsql.provenance_evaluate_compiled(
3858$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
3866CREATE FUNCTION sr_boolexpr(token ANYELEMENT, token2value REGCLASS =
NULL)
3870 IF token
IS NULL THEN
3873 RETURN provsql.provenance_evaluate_compiled(
3880$$
LANGUAGE plpgsql PARALLEL SAFE STABLE;
3883CREATE FUNCTION sr_boolean(token ANYELEMENT, token2value REGCLASS)
3887 RETURN provsql.provenance_evaluate_compiled(
3894$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
3902CREATE FUNCTION sr_tropical(token ANYELEMENT, token2value REGCLASS)
3906 RETURN provsql.provenance_evaluate_compiled(
3913$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
3920CREATE FUNCTION sr_viterbi(token ANYELEMENT, token2value REGCLASS)
3924 RETURN provsql.provenance_evaluate_compiled(
3931$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
3940CREATE FUNCTION sr_lukasiewicz(token ANYELEMENT, token2value REGCLASS)
3944 RETURN provsql.provenance_evaluate_compiled(
3951$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
3968CREATE FUNCTION sr_minmax(token UUID, token2value REGCLASS, element_one ANYENUM)
3972 RETURN provsql.provenance_evaluate_compiled(
3979$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
3993CREATE FUNCTION sr_maxmin(token UUID, token2value REGCLASS, element_one ANYENUM)
3997 RETURN provsql.provenance_evaluate_compiled(
4004$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
4015CREATE FUNCTION choose_function(state ANYELEMENT, data ANYELEMENT)
4016 RETURNS ANYELEMENT
AS
4019 IF state
IS NULL THEN
4025$$
LANGUAGE plpgsql PARALLEL SAFE IMMUTABLE;
4028CREATE AGGREGATE choose(ANYELEMENT) (
4029 SFUNC = choose_function,
4035GRANT USAGE
ON SCHEMA provsql
TO PUBLIC;
4037SET search_path
TO public;
4038SET search_path
TO provsql;
4053CREATE TABLE update_provenance (
4056 query_type QUERY_TYPE_ENUM,
4058 ts
TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
4059 valid_time TSTZMULTIRANGE
DEFAULT TSTZMULTIRANGE(tstzrange(
CURRENT_TIMESTAMP,
NULL))
4065CREATE OR REPLACE
FUNCTION add_provenance(_tbl REGCLASS)
4072 EXECUTE format(
'ALTER TABLE %s ADD COLUMN provsql UUID', _tbl);
4074 'UPDATE %s SET provsql = public.uuid_generate_v4() WHERE provsql IS NULL',
4076 EXECUTE format(
'CREATE INDEX ON %s(provsql)', _tbl);
4078 'CREATE TRIGGER provenance_guard BEFORE INSERT OR UPDATE OF provsql '
4079 'ON %s FOR EACH ROW EXECUTE PROCEDURE provsql.provenance_guard()',
4082 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);
4083 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);
4084 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);
4086 PERFORM provsql.set_table_info(_tbl::oid,
'tid');
4087 PERFORM provsql.set_ancestors(_tbl::oid,
ARRAY[_tbl::oid]);
4089$$
LANGUAGE plpgsql SECURITY DEFINER;
4095CREATE OR REPLACE
FUNCTION delete_statement_trigger()
4104 enable_trigger BOOL;
4106 enable_trigger := current_setting(
'provsql.update_provenance',
true);
4107 IF enable_trigger =
'f' THEN
4110 delete_token := public.uuid_generate_v4();
4112 PERFORM create_gate(delete_token,
'update');
4116 FROM pg_stat_activity
4117 WHERE pid = pg_backend_pid();
4119 INSERT INTO update_provenance (provsql, query, query_type, username, ts, valid_time)
4120 VALUES (delete_token, query_text,
'DELETE',
current_user,
CURRENT_TIMESTAMP, TSTZMULTIRANGE(tstzrange(
CURRENT_TIMESTAMP,
NULL)));
4122 PERFORM set_config(
'provsql.update_provenance',
'off',
false);
4123 EXECUTE format(
'INSERT INTO %I.%I SELECT * FROM OLD_TABLE;', TG_TABLE_SCHEMA, TG_TABLE_NAME);
4124 PERFORM set_config(
'provsql.update_provenance',
'on',
false);
4126 FOR r
IN (
SELECT *
FROM OLD_TABLE) LOOP
4127 old_token := r.provsql;
4128 new_token := provenance_monus(old_token, delete_token);
4130 PERFORM set_config(
'provsql.update_provenance',
'off',
false);
4131 EXECUTE format(
'UPDATE %I.%I SET provsql = $1 WHERE provsql = $2;', TG_TABLE_SCHEMA, TG_TABLE_NAME)
4132 USING new_token, old_token;
4133 PERFORM set_config(
'provsql.update_provenance',
'on',
false);
4138$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp SECURITY DEFINER;
4147CREATE OR REPLACE
FUNCTION insert_statement_trigger()
4156 enable_trigger BOOL;
4158 enable_trigger := current_setting(
'provsql.update_provenance',
true);
4159 IF enable_trigger =
'f' THEN
4163 insert_token := public.uuid_generate_v4();
4165 PERFORM create_gate(insert_token,
'update');
4169 FROM pg_stat_activity
4170 WHERE pid = pg_backend_pid();
4172 INSERT INTO update_provenance (provsql, query, query_type, username, ts, valid_time)
4173 VALUES (insert_token, query_text,
'INSERT',
current_user,
CURRENT_TIMESTAMP, TSTZMULTIRANGE(tstzrange(
CURRENT_TIMESTAMP,
NULL)));
4175 FOR r
IN (
SELECT *
FROM NEW_TABLE) LOOP
4176 old_token := r.provsql;
4177 new_token := provenance_times(old_token, insert_token);
4178 PERFORM set_config(
'provsql.update_provenance',
'off',
false);
4179 EXECUTE format(
'UPDATE %I.%I SET provsql = $1 WHERE provsql = $2;', TG_TABLE_SCHEMA, TG_TABLE_NAME)
4180 USING new_token, old_token;
4181 PERFORM set_config(
'provsql.update_provenance',
'on',
false);
4186$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp SECURITY DEFINER;
4194CREATE OR REPLACE
FUNCTION update_statement_trigger()
4203 enable_trigger BOOL;
4205 enable_trigger := current_setting(
'provsql.update_provenance',
true);
4206 IF enable_trigger =
'f' THEN
4209 update_token := public.uuid_generate_v4();
4211 PERFORM create_gate(update_token,
'update');
4215 FROM pg_stat_activity
4216 WHERE pid = pg_backend_pid();
4218 INSERT INTO update_provenance (provsql, query, query_type, username, ts, valid_time)
4219 VALUES (update_token, query_text,
'UPDATE',
current_user,
CURRENT_TIMESTAMP, TSTZMULTIRANGE(tstzrange(
CURRENT_TIMESTAMP,
NULL)));
4221 FOR r
IN (
SELECT *
FROM NEW_TABLE) LOOP
4222 old_token := r.provsql;
4223 new_token := provenance_times(old_token, update_token);
4225 PERFORM set_config(
'provsql.update_provenance',
'off',
false);
4226 EXECUTE format(
'UPDATE %I.%I SET provsql = $1 WHERE provsql = $2;', TG_TABLE_SCHEMA, TG_TABLE_NAME)
4227 USING new_token, old_token;
4228 PERFORM set_config(
'provsql.update_provenance',
'on',
false);
4231 PERFORM set_config(
'provsql.update_provenance',
'off',
false);
4232 EXECUTE format(
'INSERT INTO %I.%I SELECT * FROM OLD_TABLE;', TG_TABLE_SCHEMA, TG_TABLE_NAME);
4233 PERFORM set_config(
'provsql.update_provenance',
'on',
false);
4235 FOR r
IN (
SELECT *
FROM OLD_TABLE) LOOP
4236 old_token := r.provsql;
4237 new_token := provenance_monus(old_token, update_token);
4239 PERFORM set_config(
'provsql.update_provenance',
'off',
false);
4240 EXECUTE format(
'UPDATE %I.%I SET provsql = $1 WHERE provsql = $2;', TG_TABLE_SCHEMA, TG_TABLE_NAME)
4241 USING new_token, old_token;
4242 PERFORM set_config(
'provsql.update_provenance',
'on',
false);
4247$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp SECURITY DEFINER;
4259SET search_path
TO provsql;
4273CREATE FUNCTION sr_temporal(token ANYELEMENT, token2value REGCLASS)
4274 RETURNS TSTZMULTIRANGE
AS
4277 RETURN provsql.provenance_evaluate_compiled(
4281 '{(,)}'::TSTZMULTIRANGE
4284$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
4300CREATE FUNCTION sr_interval_num(token ANYELEMENT, token2value REGCLASS)
4301 RETURNS nummultirange
AS
4304 RETURN provsql.provenance_evaluate_compiled(
4308 '{(,)}'::nummultirange
4311$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
4327CREATE FUNCTION sr_interval_int(token ANYELEMENT, token2value REGCLASS)
4328 RETURNS int4multirange
AS
4331 RETURN provsql.provenance_evaluate_compiled(
4335 '{(,)}'::int4multirange
4338$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
4349CREATE OR REPLACE
FUNCTION union_tstzintervals(
4351 token2value REGCLASS
4353RETURNS TSTZMULTIRANGE
AS
4355 SELECT sr_temporal(token, token2value)
4356$$
LANGUAGE SQL PARALLEL SAFE STABLE;
4366CREATE OR REPLACE
FUNCTION timetravel(
4375 RETURN QUERY
EXECUTE format(
4379 sr_temporal(provenance(), %2$L)
4383 sr_temporal(provenance(), %2$L) @> %3$L::TIMESTAMPTZ
4386 'provsql.time_validity_view',
4401CREATE OR REPLACE
FUNCTION timeslice(
4403 from_time TIMESTAMPTZ,
4411 RETURN QUERY
EXECUTE format(
4415 sr_temporal(provenance(), %2$L)
4419 sr_temporal(provenance(), %2$L)
4420 && tstzrange(%3$L::TIMESTAMPTZ, %4$L::TIMESTAMPTZ)
4423 'provsql.time_validity_view',
4440CREATE OR REPLACE
FUNCTION history(
4450 condition TEXT :=
'';
4453 IF array_length(col_names,
1)
IS NULL
4454 OR array_length(col_values,
1)
IS NULL
4455 OR array_length(col_names,
1) != array_length(col_values,
1)
4457 RAISE EXCEPTION
'col_names and col_values must have the same (non-null) length';
4460 FOR i
IN 1..array_length(col_names,
1)
4463 condition := condition ||
' AND ';
4465 condition := condition || format(
'%I = %L', col_names[i], col_values[i]);
4468 RETURN QUERY
EXECUTE format(
4472 sr_temporal(provenance(), %L)
4479 'provsql.time_validity_view',
4492CREATE OR REPLACE
FUNCTION get_valid_time(
4496RETURNS TSTZMULTIRANGE
4500 result TSTZMULTIRANGE;
4505 sr_temporal(provenance(), %L)
4511 'provsql.time_validity_view',
4530CREATE OR REPLACE
FUNCTION undo(
4545 SELECT query
INTO undone_query
4546 FROM update_provenance
4550 IF undone_query
IS NULL THEN
4551 RAISE NOTICE
'Unable to find % in update_provenance', c;
4557 FROM pg_stat_activity
4558 WHERE pid = pg_backend_pid();
4560 undo_token := public.uuid_generate_v4();
4561 PERFORM create_gate(undo_token,
'update');
4562 INSERT INTO update_provenance(provsql, query, query_type, username, ts, valid_time)
4569 TSTZMULTIRANGE(tstzrange(
CURRENT_TIMESTAMP,
NULL))
4572 PERFORM set_config(
'provsql.update_provenance',
'off',
false);
4577 WHERE nspname
NOT IN (
'pg_catalog',
'information_schema',
'pg_toast',
'pg_temp_1',
'pg_toast_temp_1')
4580 EXECUTE format(
'SELECT tablename AS tname FROM pg_tables WHERE schemaname = %L', schema_rec.nspname)
4584 FROM information_schema.columns
4585 WHERE table_schema = schema_rec.nspname
4586 AND table_name = table_rec.tname
4587 AND table_name <>
'update_provenance'
4588 AND column_name =
'provsql'
4591 EXECUTE format(
'SELECT provsql AS x FROM %I.%I', schema_rec.nspname, table_rec.tname)
4593 new_x := replace_the_circuit(row_rec.x, c, undo_token);
4594 EXECUTE format(
'UPDATE %I.%I SET provsql = $1 WHERE provsql = $2',
4595 schema_rec.nspname, table_rec.tname)
4596 USING new_x, row_rec.x;
4602 PERFORM set_config(
'provsql.update_provenance',
'on',
false);
4618CREATE OR REPLACE
FUNCTION replace_the_circuit(
4630 ntype PROVENANCE_GATE;
4633 RETURN provenance_monus(c, u);
4635 ELSIF get_gate_type(x) =
'update' OR get_gate_type(x) =
'input' THEN
4639 FOREACH child
IN ARRAY get_children(x)
4641 nchildren := array_append(nchildren, replace_the_circuit(child, c, u));
4644 ntoken := public.uuid_generate_v4();
4645 ntype := get_gate_type(x);
4647 PERFORM create_gate(ntoken, ntype, nchildren);
4653SELECT create_provenance_mapping_view(
'time_validity_view',
'update_provenance',
'valid_time');
4657SET search_path
TO public;