19SET search_path
TO provsql;
27CREATE TYPE PROVENANCE_GATE
AS
112CREATE OR REPLACE
FUNCTION create_gate(
114 type PROVENANCE_GATE,
115 children UUID[]
DEFAULT NULL)
117 'provsql',
'create_gate' LANGUAGE C PARALLEL SAFE;
124CREATE OR REPLACE
FUNCTION get_gate_type(
126 RETURNS PROVENANCE_GATE
AS
127 'provsql',
'get_gate_type' LANGUAGE C IMMUTABLE PARALLEL SAFE;
129CREATE OR REPLACE
FUNCTION get_children(
132 'provsql',
'get_children' LANGUAGE C IMMUTABLE PARALLEL SAFE;
152CREATE OR REPLACE
FUNCTION set_prob(
153 token UUID, p
DOUBLE PRECISION)
155 'provsql',
'set_prob' LANGUAGE C PARALLEL RESTRICTED;
165CREATE OR REPLACE
FUNCTION probability_is_set(token UUID)
167 'provsql',
'probability_is_set' LANGUAGE C STABLE PARALLEL SAFE;
178CREATE OR REPLACE
FUNCTION note_fresh_leaf(token UUID)
180 'provsql',
'note_fresh_leaf' LANGUAGE C;
184CREATE OR REPLACE
FUNCTION is_fresh_leaf(token UUID)
186 'provsql',
'is_fresh_leaf' LANGUAGE C VOLATILE;
213CREATE OR REPLACE
FUNCTION replace_input(
old UUID, p
DOUBLE PRECISION)
218 tp provsql.PROVENANCE_GATE;
220 IF old IS NULL OR p
IS NULL THEN
221 RAISE EXCEPTION
'replace_input: neither argument may be NULL';
223 tp := provsql.get_gate_type(
old);
224 IF tp =
'mulinput' THEN
225 RAISE EXCEPTION
'replace_input: % belongs to a repair_key block',
old
226 USING HINT =
'A block''s values share one key gate and their masses '
227 'are meaningful together, so they are replaced together: '
228 'use provsql.replace_block().';
229 ELSIF tp =
'update' THEN
230 RAISE EXCEPTION
'replace_input: % is an update gate',
old
231 USING HINT =
'Use provsql.replace_update() to give a recorded data '
232 'modification a different probability.';
233 ELSIF tp <>
'input' THEN
234 RAISE EXCEPTION
'replace_input: % is a gate of type %, not an input',
old, tp
235 USING HINT =
'Only a leaf carries a probability of its own; a derived '
236 'gate''s is computed from its leaves.';
238 t := public.uuid_generate_v4();
239 PERFORM provsql.create_gate(t,
'input');
240 PERFORM provsql.set_prob(t, p);
241 PERFORM provsql.note_fresh_leaf(t);
258CREATE OR REPLACE
FUNCTION replace_input(
259 _tbl REGCLASS,
old UUID, p
DOUBLE PRECISION)
266 t := provsql.replace_input(
old, p);
267 EXECUTE format(
'UPDATE %s SET provsql = $1 WHERE provsql = $2', _tbl)
269 GET DIAGNOSTICS n = ROW_COUNT;
271 RAISE EXCEPTION
'replace_input: no row of % carries the token %', _tbl,
old;
295CREATE OR REPLACE
FUNCTION replace_block(
296 _tbl REGCLASS, old_key UUID, probs
DOUBLE PRECISION[]
DEFAULT NULL)
307 IF provsql.get_gate_type(old_key) <>
'input' THEN
308 RAISE EXCEPTION
'replace_block: % is not a block key gate', old_key;
315 was_active := coalesce(current_setting(
'provsql.active',
true),
'on');
316 PERFORM set_config(
'provsql.active',
'off',
true);
319 'CREATE TEMP TABLE provsql_replace_block_tmp ON COMMIT DROP AS
320 SELECT t.provsql AS old_token,
321 NULL::UUID AS new_token,
322 (provsql.get_infos(t.provsql)).info1 AS ord
324 WHERE provsql.get_gate_type(t.provsql) = ''mulinput''
325 AND (provsql.get_children(t.provsql))[1] = %L', _tbl, old_key);
327 SELECT count(*)
INTO n
FROM provsql_replace_block_tmp;
329 RAISE EXCEPTION
'replace_block: no row of % belongs to block %', _tbl, old_key;
331 IF probs
IS NOT NULL AND array_length(probs,
1) <> n
THEN
332 RAISE EXCEPTION
'replace_block: block % has % rows but % probabilities were given',
333 old_key, n, array_length(probs,
1);
336 new_key := public.uuid_generate_v4();
337 PERFORM provsql.create_gate(new_key,
'input');
339 FOR r
IN SELECT old_token, ord
FROM provsql_replace_block_tmp
ORDER BY ord LOOP
341 new_tok := public.uuid_generate_v4();
342 PERFORM provsql.create_gate(new_tok,
'mulinput',
ARRAY[new_key]);
343 PERFORM provsql.set_infos(new_tok, r.ord, n);
344 IF probs
IS NOT NULL THEN
345 PERFORM provsql.set_prob(new_tok, probs[i]);
347 PERFORM provsql.note_fresh_leaf(new_tok);
348 UPDATE provsql_replace_block_tmp
SET new_token = new_tok
349 WHERE old_token = r.old_token;
353 'UPDATE %s t SET provsql = b.new_token
354 FROM provsql_replace_block_tmp b WHERE t.provsql = b.old_token', _tbl);
356 DROP TABLE provsql_replace_block_tmp;
357 PERFORM set_config(
'provsql.active', was_active,
true);
361CREATE OR REPLACE
FUNCTION get_prob(
363 RETURNS DOUBLE PRECISION AS
364 'provsql',
'get_prob' LANGUAGE C STABLE PARALLEL SAFE;
382CREATE OR REPLACE
FUNCTION set_infos(
383 token UUID, info1
INT, info2
INT DEFAULT NULL)
385 'provsql',
'set_infos' LANGUAGE C PARALLEL SAFE;
388CREATE OR REPLACE
FUNCTION get_infos(
389 token UUID,
OUT info1
INT,
OUT info2
INT)
391 'provsql',
'get_infos' LANGUAGE C STABLE PARALLEL SAFE;
417CREATE OR REPLACE
FUNCTION provenance_assume(token UUID, assumption TEXT)
423 IF token
IS NULL THEN
426 IF assumption
NOT IN (
'BOOLEAN',
'absorptive')
THEN
427 RAISE EXCEPTION
'provenance_assume: unknown assumption %', assumption;
429 wrapped := public.uuid_generate_v5(uuid_ns_provsql(),
430 concat(
'assumed', assumption, token));
431 PERFORM create_gate(wrapped,
'assumed',
ARRAY[token]);
432 PERFORM set_extra(wrapped, assumption);
435$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public
436 SECURITY DEFINER PARALLEL SAFE;
450CREATE OR REPLACE
FUNCTION assume_boolean(token UUID)
RETURNS UUID
AS
455 wrapped := provenance_assume(token,
'BOOLEAN');
456 IF wrapped
IS NOT NULL THEN
458 PERFORM set_infos(wrapped,
1,
0);
462$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public
463 SECURITY DEFINER PARALLEL SAFE;
478CREATE OR REPLACE
FUNCTION annotate(token UUID, extra TEXT)
RETURNS UUID
AS
483 IF token
IS NULL THEN
486 annotated := public.uuid_generate_v5(uuid_ns_provsql(),
487 concat(
'annotation', token, extra));
488 PERFORM create_gate(annotated,
'annotation',
ARRAY[token]);
489 PERFORM set_extra(annotated, extra);
492$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public
493 SECURITY DEFINER PARALLEL SAFE;
506CREATE OR REPLACE
FUNCTION strip_annotations(token UUID)
RETURNS UUID
AS
508WITH RECURSIVE peel(g)
AS (
511 SELECT (provsql.get_children(p.g))[
1]
FROM peel p
512 WHERE provsql.get_gate_type(p.g) =
'annotation'
514SELECT g
FROM peel
WHERE provsql.get_gate_type(g) <>
'annotation' LIMIT
1;
515$$
LANGUAGE sql STABLE PARALLEL SAFE;
544CREATE OR REPLACE
FUNCTION cond(target UUID, evidence UUID)
RETURNS UUID
AS
554 IF evidence
IS NULL OR evidence = gate_one()
THEN
559 tgt := coalesce(target, gate_one());
561 IF get_gate_type(tgt) =
'conditioned' THEN
565 ch := get_children(tgt);
567 ev := provenance_times(ch[
2], evidence);
568 jnt := provenance_times(ch[
3], evidence);
571 jnt := provenance_times(tgt, evidence);
574 result := public.uuid_generate_v5(uuid_ns_provsql(),
575 concat(
'conditioned', tgt, ev, jnt));
576 PERFORM create_gate(
result,
'conditioned',
ARRAY[tgt, ev, jnt]);
579$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public
580 SECURITY DEFINER PARALLEL SAFE;
589CREATE OPERATOR | (LEFTARG=UUID, RIGHTARG=UUID,
PROCEDURE=cond);
599CREATE OR REPLACE
FUNCTION cond_predicate(target UUID, predicate
BOOLEAN)
603 RAISE EXCEPTION
'UUID | (predicate) must be rewritten by the ProvSQL '
604 'planner hook: the right operand must be a Boolean combination of '
605 'random_variable / aggregate comparisons (is provsql.active off?)';
607$$
LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
609CREATE OPERATOR | (LEFTARG=UUID, RIGHTARG=
BOOLEAN,
PROCEDURE=cond_predicate);
625CREATE OR REPLACE
FUNCTION predicate_cond_predicate(target
BOOLEAN, evidence
BOOLEAN)
629 RAISE EXCEPTION
'(predicate) | (predicate) must be rewritten by the ProvSQL '
630 'planner hook: both operands must be Boolean combinations of '
631 'random_variable / aggregate comparisons (is provsql.active off?)';
633$$
LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
635CREATE OPERATOR | (LEFTARG=
BOOLEAN, RIGHTARG=
BOOLEAN,
PROCEDURE=predicate_cond_predicate);
649CREATE OR REPLACE
FUNCTION regular_indicator(cond
BOOLEAN)
RETURNS UUID
AS
651 SELECT CASE WHEN cond
THEN provsql.gate_one()
ELSE provsql.gate_zero()
END;
652$$
LANGUAGE sql IMMUTABLE PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
682CREATE OR REPLACE
FUNCTION given(evidence UUID)
RETURNS UUID
AS
685 RETURN provsql.evidence_as_observation(evidence);
687$$
LANGUAGE plpgsql VOLATILE PARALLEL SAFE
688 SET search_path=provsql,pg_temp,public SECURITY DEFINER;
698CREATE OPERATOR | (RIGHTARG=UUID,
PROCEDURE=given);
716CREATE OR REPLACE
FUNCTION given(predicate
BOOLEAN)
RETURNS UUID
AS
719 RAISE EXCEPTION
'given(predicate) / prefix | (predicate) must be rewritten '
720 'by the ProvSQL planner hook: the operand must be a Boolean combination '
721 'of random_variable / aggregate comparisons (is provsql.active off?)';
723$$
LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
725CREATE OPERATOR | (RIGHTARG=
BOOLEAN,
PROCEDURE=given);
757CREATE OR REPLACE
FUNCTION provenance_not(event UUID)
RETURNS UUID
AS
759 SELECT provsql.provenance_monus(provsql.gate_one(), event);
760$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
761 SET search_path=provsql,pg_temp,public;
770CREATE OPERATOR ! (RIGHTARG=UUID,
PROCEDURE=provenance_not);
784CREATE OR REPLACE
FUNCTION inversion_free_key(root TEXT, sec TEXT, factor
INT)
786$$
SELECT 'K' || factor::TEXT ||
' '
787 || octet_length(root) ||
':' || root
788 || octet_length(sec) ||
':' || sec $$
789 LANGUAGE sql IMMUTABLE PARALLEL SAFE;
805CREATE OR REPLACE
FUNCTION set_extra(
806 token UUID, data TEXT)
808 'provsql',
'set_extra' LANGUAGE C PARALLEL SAFE STRICT;
810CREATE OR REPLACE
FUNCTION get_extra(token UUID)
812 'provsql',
'get_extra' LANGUAGE C STABLE PARALLEL SAFE
RETURNS NULL ON NULL INPUT;
821CREATE OR REPLACE
FUNCTION get_nb_gates()
RETURNS BIGINT AS
822 'provsql',
'get_nb_gates' LANGUAGE C PARALLEL SAFE;
846CREATE OR REPLACE
FUNCTION check_store(
847 OUT unclean_shutdown
BOOLEAN,
849 OUT nb_tokens
BIGINT,
850 OUT next_index
BIGINT,
851 OUT dangling_indices
BIGINT,
852 OUT unreferenced
BIGINT,
853 OUT bad_wires
BIGINT,
854 OUT bad_extra
BIGINT)
856 'provsql',
'check_store' LANGUAGE C;
898CREATE OR REPLACE
FUNCTION circuit_cleanup(
899 dry_run
BOOLEAN DEFAULT false,
900 OUT gates_before
BIGINT,
901 OUT gates_after
BIGINT,
902 OUT wires_before
BIGINT,
903 OUT wires_after
BIGINT,
904 OUT extra_bytes_before
BIGINT,
905 OUT extra_bytes_after
BIGINT)
907 'provsql',
'circuit_cleanup' LANGUAGE C;
924CREATE OR REPLACE
FUNCTION delete_statement_trigger()
934 delete_token := public.uuid_generate_v4();
936 PERFORM create_gate(delete_token,
'input');
940 FROM pg_stat_activity
941 WHERE pid = pg_backend_pid();
943 INSERT INTO delete_provenance (delete_token, query, deleted_by, deleted_at)
944 VALUES (delete_token, query_text,
current_user,
CURRENT_TIMESTAMP);
946 EXECUTE format(
'INSERT INTO %I.%I SELECT * FROM OLD_TABLE;', TG_TABLE_SCHEMA, TG_TABLE_NAME);
948 FOR r
IN (
SELECT *
FROM OLD_TABLE) LOOP
949 old_token := r.provsql;
950 new_token := provenance_monus(old_token, delete_token);
952 EXECUTE format(
'UPDATE %I.%I SET provsql = $1 WHERE provsql = $2;', TG_TABLE_SCHEMA, TG_TABLE_NAME)
953 USING new_token, old_token;
958$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp SECURITY DEFINER;
980CREATE TABLE IF NOT EXISTS table_info(
981 relid REGCLASS
PRIMARY KEY,
983 block_key int2[]
NOT NULL DEFAULT ARRAY[]::int2[],
984 ancestors oid[]
NOT NULL DEFAULT ARRAY[]::oid[]
986SELECT pg_catalog.pg_extension_config_dump(
'table_info',
'');
998CREATE OR REPLACE
FUNCTION table_info_invalidate()
1000 'provsql',
'provsql_table_info_invalidate' LANGUAGE C;
1002DROP TRIGGER IF EXISTS table_info_invalidate
ON table_info;
1003CREATE TRIGGER table_info_invalidate
1004 AFTER
INSERT OR UPDATE OR DELETE ON table_info
1005 FOR EACH ROW EXECUTE PROCEDURE provsql.table_info_invalidate();
1029CREATE OR REPLACE
FUNCTION set_table_info(
1030 relid OID, kind TEXT, block_key INT2[]
DEFAULT ARRAY[]::INT2[])
1032 'provsql',
'set_table_info' LANGUAGE C SECURITY DEFINER;
1036CREATE OR REPLACE
FUNCTION remove_table_info(relid OID)
1038 'provsql',
'remove_table_info' LANGUAGE C SECURITY DEFINER;
1049CREATE OR REPLACE
FUNCTION get_table_info(
1050 relid OID,
OUT kind TEXT,
OUT block_key INT2[])
1052 'provsql',
'get_table_info' LANGUAGE C STABLE PARALLEL SAFE;
1071CREATE OR REPLACE
FUNCTION set_ancestors(
1072 relid OID, ancestors OID[]
DEFAULT ARRAY[]::OID[])
1074 'provsql',
'set_ancestors' LANGUAGE C SECURITY DEFINER;
1078CREATE OR REPLACE
FUNCTION remove_ancestors(relid OID)
1080 'provsql',
'remove_ancestors' LANGUAGE C SECURITY DEFINER;
1094CREATE OR REPLACE
FUNCTION migrate_table_info()
1096 'provsql',
'migrate_table_info' LANGUAGE C SECURITY DEFINER;
1105CREATE OR REPLACE
FUNCTION get_ancestors(relid OID)
1107 'provsql',
'get_ancestors' LANGUAGE C STABLE PARALLEL SAFE;
1131CREATE OR REPLACE
FUNCTION provenance_guard()
1132 RETURNS TRIGGER AS $$
1136 IF TG_OP =
'INSERT' THEN
1137 IF NEW.provsql
IS NULL THEN
1145 NEW.provsql := public.uuid_generate_v4();
1146 FOR _m
IN SELECT mapping, attribute
1147 FROM provsql.provenance_mapping_registry
1148 WHERE source = TG_RELID
AND maintained
1151 'INSERT INTO %s(value, provenance) SELECT ($1).%I, $2',
1152 _m.mapping::REGCLASS, _m.attribute)
1153 USING NEW,
NEW.provsql;
1156 PERFORM provsql.set_table_info(TG_RELID,
'opaque');
1158 ELSIF TG_OP =
'UPDATE' THEN
1159 IF NEW.provsql
IS DISTINCT FROM OLD.provsql
THEN
1160 IF provsql.is_fresh_leaf(
NEW.provsql)
THEN
1166 FOR _m
IN SELECT mapping, attribute
1167 FROM provsql.provenance_mapping_registry
WHERE source = TG_RELID
1170 'INSERT INTO %1$s(value, provenance) '
1171 'SELECT value, $2 FROM %1$s WHERE provenance = $1',
1172 _m.mapping::REGCLASS)
1173 USING OLD.provsql,
NEW.provsql;
1176 PERFORM provsql.set_table_info(TG_RELID,
'opaque');
1182$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public
1198CREATE OR REPLACE
FUNCTION add_provenance(_tbl REGCLASS)
1206 SELECT 1 FROM pg_attribute
1207 WHERE attrelid = _tbl
AND attname =
'provsql' AND NOT attisdropped
1209 RAISE NOTICE
'table % already has provenance tracking', _tbl;
1218 EXECUTE format(
'ALTER TABLE %s ADD COLUMN provsql UUID', _tbl);
1220 'UPDATE %s SET provsql = public.uuid_generate_v4() WHERE provsql IS NULL',
1222 EXECUTE format(
'CREATE INDEX ON %s(provsql)', _tbl);
1224 'CREATE TRIGGER provenance_guard BEFORE INSERT OR UPDATE OF provsql '
1225 'ON %s FOR EACH ROW EXECUTE PROCEDURE provsql.provenance_guard()',
1227 PERFORM provsql.set_table_info(_tbl::oid,
'tid');
1232 PERFORM provsql.set_ancestors(_tbl::oid,
ARRAY[_tbl::oid]);
1234$$
LANGUAGE plpgsql SECURITY DEFINER;
1243CREATE OR REPLACE
FUNCTION remove_provenance(_tbl REGCLASS)
1248 PERFORM provsql.remove_table_info(_tbl::oid);
1254 SELECT 1 FROM pg_attribute
1255 WHERE attrelid = _tbl
AND attname =
'provsql' AND NOT attisdropped
1257 RAISE NOTICE
'table % does not have provenance tracking', _tbl;
1264 EXECUTE format(
'DROP TRIGGER provenance_guard on %s', _tbl);
1265 EXCEPTION
WHEN undefined_object
THEN
1267 EXECUTE format(
'ALTER TABLE %s DROP COLUMN provsql', _tbl);
1269 EXECUTE format(
'DROP TRIGGER add_gate on %s', _tbl);
1270 EXCEPTION
WHEN undefined_object
THEN
1273 EXECUTE format(
'DROP TRIGGER insert_statement on %s', _tbl);
1274 EXECUTE format(
'DROP TRIGGER update_statement on %s', _tbl);
1275 EXECUTE format(
'DROP TRIGGER delete_statement on %s', _tbl);
1276 EXCEPTION
WHEN undefined_object
THEN
1295CREATE OR REPLACE
FUNCTION repair_key(_tbl REGCLASS, key_att TEXT)
1301 block_key_cols INT2[];
1307 IF key_att =
'' THEN
1308 block_key_cols :=
ARRAY[]::INT2[];
1310 SELECT array_agg(a.attnum
ORDER BY t.ord)::INT2[]
1312 FROM unnest(string_to[](key_att,
','))
WITH ORDINALITY
AS t(name, ord)
1314 ON a.attrelid = _tbl
1315 AND a.attname = trim(t.name)
1317 AND NOT a.attisdropped;
1318 IF block_key_cols
IS NULL OR array_length(block_key_cols,
1)
IS NULL THEN
1319 RAISE EXCEPTION
'repair_key: could not resolve key columns from "%"', key_att;
1321 IF array_length(block_key_cols,
1) >
16 THEN
1322 RAISE EXCEPTION
'repair_key: block key wider than 16 columns is not supported';
1332 EXECUTE format(
'ALTER TABLE %s ADD COLUMN provsql_temp UUID DEFAULT public.uuid_generate_v4()', _tbl);
1343 IF key_att =
'' THEN
1345 'CREATE TEMP TABLE provsql_repair_key_tmp ON COMMIT DROP AS
1346 SELECT public.uuid_generate_v4() AS provsql_key_token,
1347 COUNT(*) AS provsql_group_size
1349 rows_query := format(
1350 'SELECT t.provsql_temp,
1351 k.provsql_key_token AS key_token,
1352 ROW_NUMBER() OVER (ORDER BY t.ctid) AS within_group,
1353 k.provsql_group_size AS group_size
1354 FROM %s t CROSS JOIN provsql_repair_key_tmp k', _tbl);
1357 'CREATE TEMP TABLE provsql_repair_key_tmp ON COMMIT DROP AS
1359 public.uuid_generate_v4() AS provsql_key_token,
1360 COUNT(*) AS provsql_group_size
1362 GROUP BY %1$s', key_att, _tbl);
1363 rows_query := format(
1364 'SELECT t.provsql_temp,
1365 k.provsql_key_token AS key_token,
1366 ROW_NUMBER() OVER (PARTITION BY k.provsql_key_token
1367 ORDER BY t.ctid) AS within_group,
1368 k.provsql_group_size AS group_size
1370 JOIN provsql_repair_key_tmp k USING (%1$s)', key_att, _tbl);
1374 FOR r
IN SELECT provsql_key_token
FROM provsql_repair_key_tmp LOOP
1375 PERFORM provsql.create_gate(r.provsql_key_token,
'input');
1385 FOR r
IN EXECUTE rows_query LOOP
1386 PERFORM provsql.create_gate(r.provsql_temp,
'mulinput',
ARRAY[r.key_token]);
1387 PERFORM provsql.set_infos(r.provsql_temp, r.within_group::
INT,
1391 DROP TABLE provsql_repair_key_tmp;
1393 EXECUTE format(
'ALTER TABLE %s ALTER COLUMN provsql_temp DROP DEFAULT', _tbl);
1394 EXECUTE format(
'ALTER TABLE %s RENAME COLUMN provsql_temp TO provsql', _tbl);
1395 EXECUTE format(
'CREATE INDEX ON %s(provsql)', _tbl);
1397 'CREATE TRIGGER provenance_guard BEFORE INSERT OR UPDATE OF provsql '
1398 'ON %s FOR EACH ROW EXECUTE PROCEDURE provsql.provenance_guard()',
1400 PERFORM provsql.set_table_info(_tbl::oid,
'bid', block_key_cols);
1403 PERFORM provsql.set_ancestors(_tbl::oid,
ARRAY[_tbl::oid]);
1420CREATE OR REPLACE
FUNCTION cleanup_table_info()
1421 RETURNS event_trigger
AS
1427 SELECT objid
FROM pg_event_trigger_dropped_objects()
1428 WHERE object_type
IN (
'table',
'foreign table',
'materialized view')
1430 PERFORM provsql.remove_table_info(r.objid);
1432 DELETE FROM provsql.provenance_mapping_registry
1433 WHERE source = r.objid
OR mapping = r.objid;
1438DROP EVENT
TRIGGER IF EXISTS provsql_cleanup_table_info;
1441CREATE EVENT
TRIGGER provsql_cleanup_table_info
ON sql_drop
1442 EXECUTE PROCEDURE provsql.cleanup_table_info();
1459CREATE TABLE IF NOT EXISTS provsql.provenance_mapping_registry(
1460 mapping oid
PRIMARY KEY,
1461 source oid
NOT NULL,
1462 attribute name
NOT NULL,
1463 maintained
BOOLEAN NOT NULL DEFAULT false
1465ALTER TABLE provsql.provenance_mapping_registry
1466 ADD COLUMN IF NOT EXISTS maintained
BOOLEAN NOT NULL DEFAULT false;
1467CREATE INDEX
IF NOT EXISTS provenance_mapping_registry_source_idx
1468 ON provsql.provenance_mapping_registry(source);
1491CREATE OR REPLACE
FUNCTION create_provenance_mapping(
1495 preserve_case BOOL
DEFAULT 'f',
1496 maintained BOOL
DEFAULT false
1504 IF (
CASE WHEN preserve_case
THEN to_regclass(format(
'%I', newtbl))
1505 ELSE to_regclass(newtbl)
END)
IS NOT NULL THEN
1506 RAISE NOTICE
'mapping table % already exists', newtbl;
1513 IF to_regclass(
'pg_temp.tmp_provsql')
IS NOT NULL THEN
1514 DROP TABLE tmp_provsql;
1516 EXECUTE format(
'CREATE TEMP TABLE tmp_provsql ON COMMIT DROP AS TABLE %s', oldtbl);
1517 ALTER TABLE tmp_provsql RENAME provsql
TO provenance;
1521 UPDATE tmp_provsql
SET provenance = provsql.strip_annotations(provenance)
1522 WHERE provsql.get_gate_type(provenance) =
'annotation';
1523 IF preserve_case
THEN
1524 EXECUTE format(
'CREATE TABLE %I AS SELECT %s AS value, provenance FROM tmp_provsql', newtbl, att);
1525 EXECUTE format(
'CREATE INDEX ON %I(provenance)', newtbl);
1527 EXECUTE format(
'CREATE TABLE %s AS SELECT %s AS value, provenance FROM tmp_provsql', newtbl, att);
1528 EXECUTE format(
'CREATE INDEX ON %s(provenance)', newtbl);
1536 INSERT INTO provsql.provenance_mapping_registry(mapping, source, attribute, maintained)
1538 (
CASE WHEN preserve_case
THEN to_regclass(format(
'%I', newtbl))
1539 ELSE to_regclass(newtbl)
END)::oid,
1540 oldtbl::oid, att, maintained)
1541 ON CONFLICT (mapping)
1542 DO
UPDATE SET source = EXCLUDED.source, attribute = EXCLUDED.attribute,
1543 maintained = EXCLUDED.maintained;
1556CREATE OR REPLACE
FUNCTION uuid_ns_provsql()
RETURNS UUID
AS
1559 SELECT '920d4f02-8718-5319-9532-d4ab83a64489'::UUID
1560$$
LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
1563CREATE OR REPLACE
FUNCTION gate_zero()
RETURNS UUID
AS
1565 SELECT public.uuid_generate_v5(provsql.uuid_ns_provsql(),
'zero');
1566$$
LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
1569CREATE OR REPLACE
FUNCTION gate_one()
RETURNS UUID
AS
1571 SELECT public.uuid_generate_v5(provsql.uuid_ns_provsql(),
'one');
1572$$
LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
1575CREATE OR REPLACE
FUNCTION epsilon()
RETURNS DOUBLE PRECISION AS
1577 SELECT CAST(
0.
001 AS DOUBLE PRECISION)
1578$$
LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
1615CREATE OR REPLACE
FUNCTION provenance_times(VARIADIC tokens UUID[])
1620 filtered_tokens UUID[];
1630 SELECT array_agg(t)
FROM unnest(tokens) t
WHERE t
IS NOT NULL AND t <> gate_one()
INTO filtered_tokens;
1637 CASE coalesce(array_length(filtered_tokens,
1),
0)
1639 times_token:=gate_one();
1641 times_token:=filtered_tokens[
1];
1646 SELECT uuid_generate_v5(uuid_ns_provsql(),
1647 concat(
'times-canonical', array_agg(t
ORDER BY t)))
1648 FROM unnest(filtered_tokens) t
1650 IF get_gate_type(canonical) =
'times' THEN
1653 times_token := canonical;
1655 times_token := uuid_generate_v5(uuid_ns_provsql(),concat(
'times',filtered_tokens));
1657 PERFORM create_gate(times_token,
'times', ARRAY_AGG(t))
FROM UNNEST(filtered_tokens)
AS t
WHERE t
IS NOT NULL;
1663$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public SECURITY DEFINER PARALLEL SAFE IMMUTABLE;
1671CREATE OR REPLACE
FUNCTION provenance_monus(token1 UUID, token2 UUID)
1677 IF token1
IS NULL THEN
1678 RAISE EXCEPTION
USING MESSAGE=
'provenance_monus is called with first argument NULL';
1681 IF token2
IS NULL THEN
1689 IF token1 = token2
THEN
1691 monus_token:=gate_zero();
1692 ELSIF token1 = gate_zero()
THEN
1694 monus_token:=gate_zero();
1695 ELSIF token2 = gate_zero()
THEN
1697 monus_token:=token1;
1699 monus_token:=uuid_generate_v5(uuid_ns_provsql(),concat(
'monus',token1,token2));
1700 PERFORM create_gate(monus_token,
'monus',
ARRAY[token1::UUID, token2::UUID]);
1705$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public SECURITY DEFINER PARALLEL SAFE IMMUTABLE;
1715CREATE OR REPLACE
FUNCTION provenance_project(token UUID, VARIADIC positions
INT[])
1722 project_token:=uuid_generate_v5(uuid_ns_provsql(),concat(
'project', token, positions));
1723 PERFORM create_gate(project_token,
'project',
ARRAY[token]);
1724 PERFORM set_extra(project_token, ARRAY_AGG(pair)::TEXT)
1726 SELECT ARRAY[(
CASE WHEN info=
0 THEN NULL ELSE info
END), idx]
AS pair
1727 FROM unnest(positions)
WITH ORDINALITY
AS a(info, idx)
1731 RETURN project_token;
1733$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public SECURITY DEFINER PARALLEL SAFE IMMUTABLE;
1742CREATE OR REPLACE
FUNCTION provenance_eq(token UUID, pos1
INT, pos2
INT)
1749 eq_token:=uuid_generate_v5(uuid_ns_provsql(),concat(
'eq',token,pos1,
',',pos2));
1751 PERFORM create_gate(eq_token,
'eq',
ARRAY[token::UUID]);
1752 PERFORM set_infos(eq_token, pos1, pos2);
1755$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public SECURITY DEFINER PARALLEL SAFE IMMUTABLE;
1773CREATE OR REPLACE
FUNCTION provenance_plus(tokens UUID[])
1779 filtered_tokens UUID[];
1787 SELECT array_agg(t)
FROM unnest(tokens) t
1788 WHERE t
IS NOT NULL AND t <> gate_zero()
1789 INTO filtered_tokens;
1791 c:=array_length(filtered_tokens,
1);
1794 plus_token := gate_zero();
1796 plus_token := filtered_tokens[
1];
1801 SELECT uuid_generate_v5(uuid_ns_provsql(),
1802 concat(
'plus-canonical', array_agg(t
ORDER BY t)))
1803 FROM unnest(filtered_tokens) t
1805 IF get_gate_type(canonical) =
'plus' THEN
1808 plus_token := canonical;
1810 plus_token := uuid_generate_v5(
1812 concat(
'plus', filtered_tokens));
1814 PERFORM create_gate(plus_token,
'plus', filtered_tokens);
1820$$
LANGUAGE plpgsql STRICT
SET search_path=provsql,pg_temp,public SECURITY DEFINER PARALLEL SAFE IMMUTABLE;
1867CREATE OR REPLACE
FUNCTION eval_recursive(
1872 max_iter
INT DEFAULT 1000)
1889 absorptive_mode
BOOLEAN :=
1890 coalesce(current_setting(
'provsql.provenance',
true),
'semiring')
1891 IN (
'absorptive',
'BOOLEAN');
1892 truncated
BOOLEAN :=
false;
1893 ntuples
INT :=
NULL;
1895 EXECUTE format(
'DROP TABLE IF EXISTS %I', work_name);
1896 DROP TABLE IF EXISTS _new;
1900 EXECUTE format(
'CREATE TEMP TABLE %I (%s, provsql UUID)', work_name, coldef);
1901 EXECUTE format(
'CREATE TEMP TABLE _new (LIKE %I)', work_name);
1907 IF iters > max_iter
THEN
1908 RAISE EXCEPTION
'eval_recursive: no fixpoint after % rounds (cyclic data?)', max_iter;
1915 EXECUTE 'TRUNCATE _new';
1916 EXECUTE format(
'INSERT INTO _new(%s) %s', colnames, body_sql);
1917 GET DIAGNOSTICS new_count = ROW_COUNT;
1921 'SELECT EXISTS((TABLE _new EXCEPT TABLE %1$I) UNION ALL (TABLE %1$I EXCEPT TABLE _new))',
1922 work_name)
INTO changed;
1927 IF absorptive_mode
AND ntuples
IS NULL THEN
1929 'SELECT NOT EXISTS('
1930 ||
'(SELECT %2$s FROM _new EXCEPT SELECT %2$s FROM %1$I) UNION ALL '
1931 ||
'(SELECT %2$s FROM %1$I EXCEPT SELECT %2$s FROM _new))',
1932 work_name, colnames)
INTO set_stable;
1934 ntuples := new_count;
1939 EXECUTE format(
'TRUNCATE %I', work_name);
1940 EXECUTE format(
'INSERT INTO %1$I(%2$s) SELECT %2$s FROM _new', work_name, colnames);
1944 EXIT
WHEN NOT changed;
1951 IF absorptive_mode
AND ntuples
IS NOT NULL AND iters >= ntuples +
1 THEN
1961 'UPDATE %I SET provsql = provsql.provenance_assume(provsql, ''absorptive'')',
1965$$
LANGUAGE plpgsql
SET client_min_messages = warning;
1974CREATE OR REPLACE
FUNCTION provenance_cmp(
1990 IF left_token
IS NULL OR right_token
IS NULL OR comparison_op
IS NULL THEN
1994 cmp_token := public.uuid_generate_v5(
1996 concat(
'cmp', left_token::TEXT, comparison_op::TEXT, right_token::TEXT)
1999 PERFORM create_gate(cmp_token,
'cmp',
ARRAY[left_token, right_token]);
2000 PERFORM set_infos(cmp_token, comparison_op::
INTEGER);
2004 SET search_path=provsql,pg_temp,public
2019CREATE FUNCTION cmp_surviving_factors(tokens UUID[], cmp UUID)
2021 'provsql',
'cmp_surviving_factors' LANGUAGE C PARALLEL SAFE STABLE;
2031CREATE OR REPLACE
FUNCTION provenance_cmp_times(cmp UUID, tokens UUID[])
2037 kept := provsql.cmp_surviving_factors(tokens, cmp);
2038 IF kept
IS NULL OR array_length(kept,
1)
IS NULL THEN
2041 RETURN provsql.provenance_times(VARIADIC kept || cmp);
2043$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE;
2061CREATE OR REPLACE
FUNCTION provenance_arith(
2070 arith_token := public.uuid_generate_v5(
2072 concat(
'arith', op::TEXT, children::TEXT)
2074 PERFORM create_gate(arith_token,
'arith', children);
2075 PERFORM set_infos(arith_token, op);
2079 SET search_path=provsql,pg_temp,public
2101CREATE OR REPLACE
FUNCTION provenance_case(
2109 IF array_length(children,
1)
IS NULL OR array_length(children,
1) %
2 =
0 THEN
2110 RAISE EXCEPTION
'provenance_case expects an odd number of children '
2111 '(guard/value pairs followed by a default), got %',
2112 coalesce(array_length(children,
1),
0);
2114 case_token := public.uuid_generate_v5(
2116 concat(
'case', children::TEXT)
2118 PERFORM create_gate(case_token,
'case', children);
2122 SET search_path=provsql,pg_temp,public
2147CREATE OR REPLACE
FUNCTION provenance_evaluate_compiled(
2149 token2value REGCLASS,
2151 element_one ANYELEMENT)
2152RETURNS ANYELEMENT
AS
2153 'provsql',
'provenance_evaluate_compiled' LANGUAGE C PARALLEL SAFE STABLE;
2172CREATE OR REPLACE
FUNCTION provenance_evaluate(
2174 token2value REGCLASS,
2175 element_one ANYELEMENT,
2177 plus_function REGPROC,
2178 times_function REGPROC,
2179 monus_function REGPROC,
2180 delta_function REGPROC)
2181 RETURNS ANYELEMENT
AS
2184 gate_type PROVENANCE_GATE;
2185 result ALIAS
FOR $
0;
2191 SELECT get_gate_type(token)
INTO gate_type;
2193 IF gate_type
IS NULL THEN
2196 ELSIF gate_type =
'input' THEN
2197 EXECUTE format(
'SELECT value FROM %s WHERE provenance=%L', token2value, token)
2199 IF result IS NULL THEN
2200 result := element_one;
2202 ELSIF gate_type =
'mulinput' THEN
2203 SELECT concat(
'{',(get_children(token))[
1]::TEXT,
'=',(get_infos(token)).info1,
'}')
2205 ELSIF gate_type=
'update' THEN
2206 EXECUTE format(
'SELECT value FROM %s WHERE provenance=%L',token2value,token)
INTO result;
2207 IF result IS NULL THEN
2208 result:=element_one;
2210 ELSIF gate_type =
'plus' THEN
2211 EXECUTE format(
'SELECT %s(provsql.provenance_evaluate(t,%L,%L::%s,%L,%L,%L,%L,%L)) FROM unnest(get_children(%L)) AS t',
2212 plus_function, token2value, element_one, value_type, value_type, plus_function, times_function, monus_function, delta_function, token)
2215 ELSIF gate_type =
'times' THEN
2216 EXECUTE format(
'SELECT %s(provsql.provenance_evaluate(t,%L,%L::%s,%L,%L,%L,%L,%L)) FROM unnest(get_children(%L)) AS t',
2217 times_function, token2value, element_one, value_type, value_type, plus_function, times_function, monus_function, delta_function, token)
2220 ELSIF gate_type =
'monus' THEN
2221 IF monus_function
IS NULL THEN
2222 RAISE EXCEPTION
USING MESSAGE=
'Provenance with negation evaluated over a semiring without monus function';
2224 EXECUTE format(
'SELECT %s(a1,a2) FROM (SELECT provsql.provenance_evaluate(c[1],%L,%L::%s,%L,%L,%L,%L,%L) AS a1, ' ||
2225 'provsql.provenance_evaluate(c[2],%L,%L::%s,%L,%L,%L,%L,%L) AS a2 FROM get_children(%L) c) tmp',
2226 monus_function, token2value, element_one, value_type, value_type, plus_function, times_function, monus_function, delta_function,
2227 token2value, element_one, value_type, value_type, plus_function, times_function, monus_function, delta_function, token)
2231 ELSIF gate_type =
'eq' THEN
2232 EXECUTE format(
'SELECT provsql.provenance_evaluate((get_children(%L))[1],%L,%L::%s,%L,%L,%L,%L,%L)',
2233 token, token2value, element_one, value_type, value_type, plus_function, times_function, monus_function, delta_function)
2254 ELSIF gate_type =
'delta' THEN
2255 IF delta_function
IS NULL THEN
2256 RAISE EXCEPTION
USING MESSAGE=
'Provenance with aggregation evaluated over a semiring without delta function';
2258 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',
2259 delta_function, token, token2value, element_one, value_type, value_type, plus_function, times_function, monus_function, delta_function)
2263 ELSIF gate_type =
'zero' THEN
2264 EXECUTE format(
'SELECT %I(a) FROM (SELECT %L::%I AS a WHERE FALSE) temp', plus_function, element_one, value_type)
2267 ELSIF gate_type =
'one' THEN
2268 EXECUTE format(
'SELECT %L::%I', element_one, value_type)
2271 ELSIF gate_type =
'project' THEN
2272 EXECUTE format(
'SELECT provsql.provenance_evaluate((get_children(%L))[1],%L,%L::%s,%L,%L,%L,%L,%L)',
2273 token, token2value, element_one, value_type, value_type, plus_function, times_function, monus_function, delta_function)
2276 ELSIF gate_type =
'annotation' THEN
2280 EXECUTE format(
'SELECT provsql.provenance_evaluate((get_children(%L))[1],%L,%L::%s,%L,%L,%L,%L,%L)',
2281 token, token2value, element_one, value_type, value_type, plus_function, times_function, monus_function, delta_function)
2285 RAISE EXCEPTION
USING MESSAGE=
'provenance_evaluate cannot be called on formulas using ' || gate_type ||
' gates; use compiled semirings instead';
2290$$
LANGUAGE plpgsql PARALLEL SAFE STABLE;
2307CREATE OR REPLACE
FUNCTION provenance_evaluate(
2309 token2value REGCLASS,
2310 element_one ANYELEMENT,
2311 plus_function REGPROC,
2312 times_function REGPROC,
2313 monus_function REGPROC =
NULL,
2314 delta_function REGPROC =
NULL)
2315 RETURNS ANYELEMENT
AS
2316 'provsql',
'provenance_evaluate' LANGUAGE C STABLE;
2327CREATE TYPE GATE_WITH_DESC
AS (f UUID, t UUID, gate_type PROVENANCE_GATE, desc_str
CHARACTER VARYING, infos
INTEGER[], extra TEXT);
2339CREATE OR REPLACE
FUNCTION sub_circuit_with_desc(
2341 token2desc REGCLASS)
RETURNS SETOF GATE_WITH_DESC
AS
2344 RETURN QUERY
EXECUTE
2345 'WITH RECURSIVE transitive_closure(f,t,gate_type) AS (
2346 SELECT $1,t,provsql.get_gate_type($1) FROM unnest(provsql.get_children($1)) AS t
2348 SELECT p1.t,u,provsql.get_gate_type(p1.t) FROM transitive_closure p1, unnest(provsql.get_children(p1.t)) AS u)
2349 SELECT *, ARRAY[(get_infos(f)).info1, (get_infos(f)).info2], get_extra(f) FROM (
2350 SELECT f::UUID,t::UUID,gate_type,NULL FROM transitive_closure
2352 SELECT p2.provenance::UUID as f, NULL::UUID, ''input'', CAST (p2.value AS varchar) FROM transitive_closure p1 JOIN ' || token2desc ||
' AS p2
2355 SELECT provenance::UUID as f, NULL::UUID, ''input'', CAST (value AS varchar) FROM ' || token2desc ||
' WHERE provenance=$1
2360$$
LANGUAGE plpgsql PARALLEL SAFE;
2372CREATE OR REPLACE
FUNCTION identify_token(
2373 token UUID,
OUT table_name REGCLASS,
OUT nb_columns
INTEGER)
AS
2383 (
SELECT count(*)
FROM pg_attribute a2
WHERE a2.attrelid=a1.attrelid
AND attnum>
0 AND atttypid<>
0)-1 c
2384 FROM pg_attribute a1
JOIN pg_type
ON atttypid=pg_type.oid
2385 JOIN pg_class
ON attrelid=pg_class.oid
2386 JOIN pg_namespace
ON relnamespace=pg_namespace.oid
2387 WHERE typname=
'UUID' AND relkind=
'r'
2388 AND nspname<>
'provsql'
2389 AND attname=
'provsql'
2391 EXECUTE format(
'SELECT * FROM %I WHERE provsql=%L',t.relname,token)
INTO result;
2396 IF result.provsql
IS NOT NULL THEN
2397 table_name:=t.relname;
2403$$
LANGUAGE plpgsql STRICT;
2411CREATE OR REPLACE
FUNCTION sub_circuit_for_where(token UUID)
2412 RETURNS TABLE(f UUID, t UUID, gate_type PROVENANCE_GATE, table_name REGCLASS, nb_columns
INTEGER, infos
INTEGER[], extra TEXT)
AS
2414 WITH RECURSIVE transitive_closure(f,t,idx,gate_type)
AS (
2415 SELECT $
1,t,id,provsql.get_gate_type($
1)
FROM unnest(provsql.get_children($
1))
WITH ORDINALITY
AS a(t,id)
2417 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)
2418 )
SELECT f, t, gate_type, table_name, nb_columns,
ARRAY[(get_infos(f)).info1, (get_infos(f)).info2], get_extra(f)
FROM (
2428 SELECT DISTINCT f, t::UUID, idx, gate_type,
NULL::REGCLASS
AS table_name,
NULL::
INTEGER AS nb_columns
FROM transitive_closure
2430 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
2432 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
2467CREATE OR REPLACE
FUNCTION circuit_subgraph(root UUID, max_depth
INT DEFAULT 8)
2468 RETURNS TABLE(node UUID, parent UUID, child_pos
INT, gate_type TEXT, info1 TEXT, info2 TEXT, depth
INT)
AS
2470 WITH RECURSIVE bfs(node, parent, child_pos, depth)
AS (
2471 SELECT root,
NULL::UUID,
NULL::
INT,
0
2473 SELECT c.t, b.node, c.idx::
INT, b.depth +
1
2475 CROSS JOIN LATERAL unnest(provsql.get_children(b.node))
2476 WITH ORDINALITY
AS c(t, idx)
2477 WHERE b.depth < max_depth
2485 SELECT node, MAX(depth)
AS depth
FROM bfs
GROUP BY node
2491 SELECT DISTINCT parent, node
AS child, child_pos
2492 FROM bfs
WHERE parent
IS NOT NULL
2498 provsql.get_gate_type(d.node)::TEXT,
2503 LEFT JOIN edges e
ON e.child = d.node
2504 LEFT JOIN LATERAL provsql.get_infos(d.node) i
ON TRUE
2505 ORDER BY d.depth, d.node, e.parent;
2506$$
LANGUAGE sql STABLE PARALLEL SAFE;
2527CREATE OR REPLACE
FUNCTION simplified_circuit_subgraph(
2528 root UUID, max_depth
INT DEFAULT 8)
RETURNS jsonb
2529 AS 'provsql',
'simplified_circuit_subgraph'
2530 LANGUAGE C STABLE PARALLEL SAFE;
2554CREATE OR REPLACE
FUNCTION rv_histogram(
2555 token UUID, bins
INT DEFAULT 30, prov UUID
DEFAULT gate_one())
2557 AS 'provsql',
'rv_histogram'
2558 LANGUAGE C VOLATILE PARALLEL SAFE;
2585CREATE OR REPLACE
FUNCTION rv_analytical_curves(
2586 token UUID, samples
INT DEFAULT 100, prov UUID
DEFAULT gate_one())
2588 AS 'provsql',
'rv_analytical_curves'
2589 LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
2610CREATE OR REPLACE
FUNCTION rv_sample(
2611 token UUID, n
INTEGER, prov UUID
DEFAULT gate_one())
2612 RETURNS SETOF float8
2613 AS 'provsql',
'rv_sample'
2614 LANGUAGE C VOLATILE PARALLEL SAFE;
2632CREATE OR REPLACE
FUNCTION resolve_input(UUID UUID)
2633 RETURNS TABLE(relation REGCLASS, row_data JSONB)
AS
2645 SELECT c.oid::REGCLASS
AS regc
2647 JOIN pg_class c
ON a.attrelid = c.oid
2648 JOIN pg_namespace ns
ON c.relnamespace = ns.oid
2649 JOIN pg_type ty
ON a.atttypid = ty.oid
2650 WHERE a.attname =
'provsql'
2651 AND ty.typname =
'UUID'
2653 AND ns.nspname <>
'provsql'
2658 'SELECT %L::REGCLASS, to_jsonb(t) - ''provsql'', t.provsql FROM %s AS t WHERE provsql = $1',
2668$$
LANGUAGE plpgsql STABLE;
2691CREATE TYPE AGG_TOKEN;
2694CREATE OR REPLACE
FUNCTION agg_token_in(CSTRING)
2696 AS 'provsql',
'agg_token_in' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
2714CREATE OR REPLACE
FUNCTION agg_token_out(AGG_TOKEN)
2716 AS 'provsql',
'agg_token_out' LANGUAGE C STABLE STRICT PARALLEL SAFE;
2719CREATE OR REPLACE
FUNCTION agg_token_cast(AGG_TOKEN)
2721 AS 'provsql',
'agg_token_cast' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
2723CREATE TYPE AGG_TOKEN (
2724 internallength =
117,
2725 input = agg_token_in,
2726 output = agg_token_out,
2731CREATE OR REPLACE
FUNCTION agg_token_uuid(aggtok AGG_TOKEN)
2735 RETURN agg_token_cast(aggtok)::UUID;
2737$$
LANGUAGE plpgsql STRICT
SET search_path=provsql,pg_temp,public SECURITY DEFINER IMMUTABLE PARALLEL SAFE;
2740CREATE CAST (AGG_TOKEN
AS UUID)
WITH FUNCTION agg_token_uuid(AGG_TOKEN)
AS IMPLICIT;
2754CREATE OR REPLACE
FUNCTION agg_guard_holds(token UUID)
2758 gt PROVENANCE_GATE := get_gate_type(token);
2769 ELSIF gt =
'zero' THEN
2771 ELSIF gt
IN (
'times',
'plus')
THEN
2772 SELECT bool_and(h), bool_or(h), bool_or(h
IS NULL)
2773 INTO all_true, any_true, any_null
2774 FROM (
SELECT provsql.agg_guard_holds(c)
AS h
2775 FROM unnest(get_children(token))
AS c)
AS s;
2776 IF gt =
'times' THEN
2779 RETURN CASE WHEN NOT all_true
THEN false
2780 WHEN any_null
THEN NULL
2784 RETURN CASE WHEN any_true
THEN true
2785 WHEN any_null
THEN NULL
2788 ELSIF gt =
'cmp' THEN
2789 ch := get_children(token);
2790 l := agg_gate_value(ch[
1]);
2791 r := agg_gate_value(ch[
2]);
2792 IF l
IS NULL OR r
IS NULL THEN
2795 SELECT oprname
INTO opname
2796 FROM pg_catalog.pg_operator
WHERE oid = (get_infos(token)).info1;
2799 WHEN '<=' THEN l <= r
2801 WHEN '<>' THEN l <> r
2802 WHEN '>=' THEN l >= r
2808$$
LANGUAGE plpgsql STABLE STRICT PARALLEL SAFE
2809 SET search_path=provsql,pg_temp,public;
2825CREATE OR REPLACE
FUNCTION agg_gate_value(token UUID)
2829 gt PROVENANCE_GATE := get_gate_type(token);
2834 IF gt
IN (
'agg',
'arith',
'value')
THEN
2836 RETURN get_extra(token)::
NUMERIC;
2837 EXCEPTION
WHEN others
THEN
2840 ELSIF gt =
'semimod' THEN
2841 RETURN agg_gate_value((get_children(token))[
2]);
2842 ELSIF gt =
'conditioned' THEN
2843 RETURN agg_gate_value((get_children(token))[
1]);
2844 ELSIF gt =
'case' THEN
2845 ch := get_children(token);
2846 n := array_length(ch,
1);
2847 FOR i
IN 1 .. (n -
1) /
2 LOOP
2848 holds := agg_guard_holds(ch[
2 * i -
1]);
2849 IF holds
IS NULL THEN
2852 RETURN agg_gate_value(ch[
2 * i]);
2855 RETURN agg_gate_value(ch[n]);
2859$$
LANGUAGE plpgsql STABLE STRICT PARALLEL SAFE
2860 SET search_path=provsql,pg_temp,public;
2881CREATE OR REPLACE
FUNCTION agg_token_value_text(token UUID)
2887 WHEN provsql.get_gate_type(token)
IN (
'agg',
'arith')
2888 THEN provsql.get_extra(token) ||
' (*)'
2891 WHEN provsql.get_gate_type(token)
IN (
'case',
'conditioned',
'semimod',
'value')
2892 THEN provsql.agg_gate_value(token)::TEXT ||
' (*)'
2895$$
LANGUAGE sql STABLE STRICT PARALLEL SAFE;
2898CREATE OR REPLACE
FUNCTION agg_token_to_numeric(AGG_TOKEN)
2900 AS 'provsql',
'agg_token_to_numeric' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
2903CREATE OR REPLACE
FUNCTION agg_token_to_float8(AGG_TOKEN)
2904 RETURNS double precision
2905 AS 'provsql',
'agg_token_to_float8' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
2908CREATE OR REPLACE
FUNCTION agg_token_to_int4(AGG_TOKEN)
2910 AS 'provsql',
'agg_token_to_int4' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
2913CREATE OR REPLACE
FUNCTION agg_token_to_int8(AGG_TOKEN)
2915 AS 'provsql',
'agg_token_to_int8' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
2918CREATE OR REPLACE
FUNCTION agg_token_to_text(AGG_TOKEN)
2920 AS 'provsql',
'agg_token_to_text' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
2929CREATE CAST (AGG_TOKEN
AS NUMERIC)
WITH FUNCTION agg_token_to_numeric(AGG_TOKEN)
AS ASSIGNMENT;
2946CREATE OR REPLACE
FUNCTION agg_token_value(AGG_TOKEN)
2948 AS 'provsql',
'agg_token_value' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
2953CREATE OR REPLACE
FUNCTION agg_token_make(tok UUID, val
NUMERIC)
2954 RETURNS AGG_TOKEN
AS
2956 SELECT format(
'( %s , %s )', tok::TEXT, val::TEXT)::provsql.AGG_TOKEN;
2957$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
2958 SET search_path=provsql,pg_temp,public;
2963CREATE OR REPLACE
FUNCTION agg_value_gate(v
NUMERIC)
2967 token UUID := public.uuid_generate_v5(
2968 provsql.uuid_ns_provsql(), concat(
'value', v::TEXT));
2970 PERFORM provsql.create_gate(token,
'value');
2971 PERFORM provsql.set_extra(token, v::TEXT);
2974$$
LANGUAGE plpgsql STRICT IMMUTABLE PARALLEL SAFE
2975 SET search_path=provsql,pg_temp,public SECURITY DEFINER;
2986CREATE OR REPLACE
FUNCTION agg_arith_make(op
INT, children UUID[], val
NUMERIC)
2987 RETURNS AGG_TOKEN
AS
2990 token UUID := provsql.provenance_arith(op, children);
2992 PERFORM provsql.set_extra(token, val::TEXT);
2993 RETURN provsql.agg_token_make(token, val);
2995$$
LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE
2996 SET search_path=provsql,pg_temp,public SECURITY DEFINER;
3000CREATE OR REPLACE
FUNCTION agg_token_plus(a AGG_TOKEN, b AGG_TOKEN)
3001 RETURNS AGG_TOKEN
AS
3002$$
SELECT provsql.agg_arith_make(
0,
ARRAY[(a)::UUID, (b)::UUID],
3003 provsql.agg_token_value(a) + provsql.agg_token_value(b)); $$
3004 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3007CREATE OR REPLACE
FUNCTION agg_token_minus(a AGG_TOKEN, b AGG_TOKEN)
3008 RETURNS AGG_TOKEN
AS
3009$$
SELECT provsql.agg_arith_make(
2,
ARRAY[(a)::UUID, (b)::UUID],
3010 provsql.agg_token_value(a) - provsql.agg_token_value(b)); $$
3011 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3014CREATE OR REPLACE
FUNCTION agg_token_times(a AGG_TOKEN, b AGG_TOKEN)
3015 RETURNS AGG_TOKEN
AS
3016$$
SELECT provsql.agg_arith_make(
1,
ARRAY[(a)::UUID, (b)::UUID],
3017 provsql.agg_token_value(a) * provsql.agg_token_value(b)); $$
3018 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3021CREATE OR REPLACE
FUNCTION agg_token_div(a AGG_TOKEN, b AGG_TOKEN)
3022 RETURNS AGG_TOKEN
AS
3023$$
SELECT provsql.agg_arith_make(
3,
ARRAY[(a)::UUID, (b)::UUID],
3024 provsql.agg_token_value(a) / provsql.agg_token_value(b)); $$
3025 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3028CREATE OR REPLACE
FUNCTION agg_token_neg(a AGG_TOKEN)
3029 RETURNS AGG_TOKEN
AS
3030$$
SELECT provsql.agg_arith_make(
4,
ARRAY[(a)::UUID],
3031 - provsql.agg_token_value(a)); $$
3032 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3036CREATE OR REPLACE
FUNCTION agg_token_plus_numeric(a AGG_TOKEN, b
NUMERIC)
3037 RETURNS AGG_TOKEN
AS
3038$$
SELECT provsql.agg_arith_make(
0,
ARRAY[(a)::UUID, provsql.agg_value_gate(b)],
3039 provsql.agg_token_value(a) + b); $$
3040 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3043CREATE OR REPLACE
FUNCTION agg_token_minus_numeric(a AGG_TOKEN, b
NUMERIC)
3044 RETURNS AGG_TOKEN
AS
3045$$
SELECT provsql.agg_arith_make(
2,
ARRAY[(a)::UUID, provsql.agg_value_gate(b)],
3046 provsql.agg_token_value(a) - b); $$
3047 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3050CREATE OR REPLACE
FUNCTION agg_token_times_numeric(a AGG_TOKEN, b
NUMERIC)
3051 RETURNS AGG_TOKEN
AS
3052$$
SELECT provsql.agg_arith_make(
1,
ARRAY[(a)::UUID, provsql.agg_value_gate(b)],
3053 provsql.agg_token_value(a) * b); $$
3054 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3057CREATE OR REPLACE
FUNCTION agg_token_div_numeric(a AGG_TOKEN, b
NUMERIC)
3058 RETURNS AGG_TOKEN
AS
3059$$
SELECT provsql.agg_arith_make(
3,
ARRAY[(a)::UUID, provsql.agg_value_gate(b)],
3060 provsql.agg_token_value(a) / b); $$
3061 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3065CREATE OR REPLACE
FUNCTION numeric_plus_agg_token(a
NUMERIC, b AGG_TOKEN)
3066 RETURNS AGG_TOKEN
AS
3067$$
SELECT provsql.agg_arith_make(
0,
ARRAY[provsql.agg_value_gate(a), (b)::UUID],
3068 a + provsql.agg_token_value(b)); $$
3069 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3072CREATE OR REPLACE
FUNCTION numeric_minus_agg_token(a
NUMERIC, b AGG_TOKEN)
3073 RETURNS AGG_TOKEN
AS
3074$$
SELECT provsql.agg_arith_make(
2,
ARRAY[provsql.agg_value_gate(a), (b)::UUID],
3075 a - provsql.agg_token_value(b)); $$
3076 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3079CREATE OR REPLACE
FUNCTION numeric_times_agg_token(a
NUMERIC, b AGG_TOKEN)
3080 RETURNS AGG_TOKEN
AS
3081$$
SELECT provsql.agg_arith_make(
1,
ARRAY[provsql.agg_value_gate(a), (b)::UUID],
3082 a * provsql.agg_token_value(b)); $$
3083 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3086CREATE OR REPLACE
FUNCTION numeric_div_agg_token(a
NUMERIC, b AGG_TOKEN)
3087 RETURNS AGG_TOKEN
AS
3088$$
SELECT provsql.agg_arith_make(
3,
ARRAY[provsql.agg_value_gate(a), (b)::UUID],
3089 a / provsql.agg_token_value(b)); $$
3090 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3093CREATE OPERATOR + (LEFTARG=AGG_TOKEN, RIGHTARG=AGG_TOKEN,
PROCEDURE=agg_token_plus, COMMUTATOR = +);
3094CREATE OPERATOR - (LEFTARG=AGG_TOKEN, RIGHTARG=AGG_TOKEN,
PROCEDURE=agg_token_minus);
3095CREATE OPERATOR * (LEFTARG=AGG_TOKEN, RIGHTARG=AGG_TOKEN,
PROCEDURE=agg_token_times, COMMUTATOR = *);
3096CREATE OPERATOR / (LEFTARG=AGG_TOKEN, RIGHTARG=AGG_TOKEN,
PROCEDURE=agg_token_div);
3097CREATE OPERATOR - (RIGHTARG=AGG_TOKEN,
PROCEDURE=agg_token_neg);
3099CREATE OPERATOR + (LEFTARG=AGG_TOKEN, RIGHTARG=
NUMERIC,
PROCEDURE=agg_token_plus_numeric, COMMUTATOR = +);
3100CREATE OPERATOR - (LEFTARG=AGG_TOKEN, RIGHTARG=
NUMERIC,
PROCEDURE=agg_token_minus_numeric);
3101CREATE OPERATOR * (LEFTARG=AGG_TOKEN, RIGHTARG=
NUMERIC,
PROCEDURE=agg_token_times_numeric, COMMUTATOR = *);
3102CREATE OPERATOR / (LEFTARG=AGG_TOKEN, RIGHTARG=
NUMERIC,
PROCEDURE=agg_token_div_numeric);
3104CREATE OPERATOR + (LEFTARG=
NUMERIC, RIGHTARG=AGG_TOKEN,
PROCEDURE=numeric_plus_agg_token, COMMUTATOR = +);
3105CREATE OPERATOR - (LEFTARG=
NUMERIC, RIGHTARG=AGG_TOKEN,
PROCEDURE=numeric_minus_agg_token);
3106CREATE OPERATOR * (LEFTARG=
NUMERIC, RIGHTARG=AGG_TOKEN,
PROCEDURE=numeric_times_agg_token, COMMUTATOR = *);
3107CREATE OPERATOR / (LEFTARG=
NUMERIC, RIGHTARG=AGG_TOKEN,
PROCEDURE=numeric_div_agg_token);
3110CREATE CAST (AGG_TOKEN
AS double precision)
WITH FUNCTION agg_token_to_float8(AGG_TOKEN)
AS ASSIGNMENT;
3112CREATE CAST (AGG_TOKEN
AS INTEGER)
WITH FUNCTION agg_token_to_int4(AGG_TOKEN)
AS ASSIGNMENT;
3114CREATE CAST (AGG_TOKEN
AS bigint)
WITH FUNCTION agg_token_to_int8(AGG_TOKEN)
AS ASSIGNMENT;
3116CREATE CAST (AGG_TOKEN
AS TEXT)
WITH FUNCTION agg_token_to_text(AGG_TOKEN)
AS ASSIGNMENT;
3131CREATE OR REPLACE
FUNCTION agg_token_cond(a AGG_TOKEN, cond UUID)
3132 RETURNS AGG_TOKEN
AS
3140 IF cond
IS NULL OR cond = gate_one()
THEN
3145 IF get_gate_type(tok) =
'conditioned'
3146 AND array_length(get_children(tok),
1) =
2 THEN
3147 ch := get_children(tok);
3149 ev := provenance_times(ch[
2], cond);
3154 result := public.uuid_generate_v5(uuid_ns_provsql(),
3155 concat(
'conditioned', tok, ev));
3156 PERFORM create_gate(
result,
'conditioned',
ARRAY[tok, ev]);
3157 RETURN agg_token_make(
result, agg_token_value(a));
3159$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public
3160 SECURITY DEFINER PARALLEL SAFE;
3163 LEFTARG = AGG_TOKEN,
3165 PROCEDURE = agg_token_cond
3176CREATE OR REPLACE
FUNCTION agg_token_cond_predicate(
3177 a AGG_TOKEN, predicate
BOOLEAN)
RETURNS AGG_TOKEN
AS
3180 RAISE EXCEPTION
'AGG_TOKEN | (predicate) must be rewritten by the ProvSQL '
3181 'planner hook: the right operand must be a Boolean combination of '
3182 'aggregate / random_variable comparisons (is provsql.active off?)';
3184$$
LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
3187 LEFTARG = AGG_TOKEN,
3189 PROCEDURE = agg_token_cond_predicate
3201CREATE OR REPLACE
FUNCTION agg_conditioned_target(a AGG_TOKEN)
3202 RETURNS AGG_TOKEN
AS
3205 WHEN provsql.get_gate_type((a)::UUID) =
'conditioned'
3206 AND array_length(provsql.get_children((a)::UUID),
1) =
2
3207 THEN provsql.agg_token_make(
3208 (provsql.get_children((a)::UUID))[
1], provsql.agg_token_value(a))
3211$$
LANGUAGE sql STABLE PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3220CREATE OR REPLACE
FUNCTION agg_token_comp_numeric(a AGG_TOKEN, b
NUMERIC)
3223IMMUTABLE STRICT PARALLEL SAFE
3226 RAISE EXCEPTION
'Comparison AGG_TOKEN-NUMERIC not implemented, should be replaced by ProvSQL behavior';
3236CREATE OR REPLACE
FUNCTION numeric_comp_agg_token(a
NUMERIC, b AGG_TOKEN)
3239IMMUTABLE STRICT PARALLEL SAFE
3242 RAISE EXCEPTION
'Comparison NUMERIC-AGG_TOKEN not implemented, should be replaced by ProvSQL behavior';
3248 LEFTARG = AGG_TOKEN,
3250 PROCEDURE = agg_token_comp_numeric,
3257 RIGHTARG = AGG_TOKEN,
3258 PROCEDURE = numeric_comp_agg_token,
3265 LEFTARG = AGG_TOKEN,
3267 PROCEDURE = agg_token_comp_numeric,
3274 RIGHTARG = AGG_TOKEN,
3275 PROCEDURE = numeric_comp_agg_token,
3282 LEFTARG = AGG_TOKEN,
3284 PROCEDURE = agg_token_comp_numeric,
3291 RIGHTARG = AGG_TOKEN,
3292 PROCEDURE = numeric_comp_agg_token,
3299 LEFTARG = AGG_TOKEN,
3301 PROCEDURE = agg_token_comp_numeric,
3308 RIGHTARG = AGG_TOKEN,
3309 PROCEDURE = numeric_comp_agg_token,
3316 LEFTARG = AGG_TOKEN,
3318 PROCEDURE = agg_token_comp_numeric,
3325 RIGHTARG = AGG_TOKEN,
3326 PROCEDURE = numeric_comp_agg_token,
3333 LEFTARG = AGG_TOKEN,
3335 PROCEDURE = agg_token_comp_numeric,
3342 RIGHTARG = AGG_TOKEN,
3343 PROCEDURE = numeric_comp_agg_token,
3357CREATE OR REPLACE
FUNCTION agg_token_comp_agg_token(a AGG_TOKEN, b AGG_TOKEN)
3360IMMUTABLE STRICT PARALLEL SAFE
3363 RAISE EXCEPTION
'Comparison AGG_TOKEN-AGG_TOKEN not implemented, should be replaced by ProvSQL behavior';
3369 LEFTARG=AGG_TOKEN, RIGHTARG=AGG_TOKEN,
PROCEDURE=agg_token_comp_agg_token,
3370 COMMUTATOR = >, NEGATOR = >=
3374 LEFTARG=AGG_TOKEN, RIGHTARG=AGG_TOKEN,
PROCEDURE=agg_token_comp_agg_token,
3375 COMMUTATOR = >=, NEGATOR = >
3379 LEFTARG=AGG_TOKEN, RIGHTARG=AGG_TOKEN,
PROCEDURE=agg_token_comp_agg_token,
3380 COMMUTATOR = <, NEGATOR = <=
3384 LEFTARG=AGG_TOKEN, RIGHTARG=AGG_TOKEN,
PROCEDURE=agg_token_comp_agg_token,
3385 COMMUTATOR = <=, NEGATOR = <
3389 LEFTARG=AGG_TOKEN, RIGHTARG=AGG_TOKEN,
PROCEDURE=agg_token_comp_agg_token,
3390 COMMUTATOR = =, NEGATOR = <>
3394 LEFTARG=AGG_TOKEN, RIGHTARG=AGG_TOKEN,
PROCEDURE=agg_token_comp_agg_token,
3395 COMMUTATOR = <>, NEGATOR = =
3405CREATE OR REPLACE
FUNCTION agg_token_comp_text(a AGG_TOKEN, b TEXT)
3408IMMUTABLE STRICT PARALLEL SAFE
3411 RAISE EXCEPTION
'Comparison AGG_TOKEN-TEXT not implemented, should be replaced by ProvSQL behavior';
3421CREATE OR REPLACE
FUNCTION text_comp_agg_token(a TEXT, b AGG_TOKEN)
3424IMMUTABLE STRICT PARALLEL SAFE
3427 RAISE EXCEPTION
'Comparison TEXT-AGG_TOKEN not implemented, should be replaced by ProvSQL behavior';
3433 LEFTARG = AGG_TOKEN,
3435 PROCEDURE = agg_token_comp_text,
3442 RIGHTARG = AGG_TOKEN,
3443 PROCEDURE = text_comp_agg_token,
3450 LEFTARG = AGG_TOKEN,
3452 PROCEDURE = agg_token_comp_text,
3459 RIGHTARG = AGG_TOKEN,
3460 PROCEDURE = text_comp_agg_token,
3498CREATE TYPE random_variable;
3501CREATE OR REPLACE
FUNCTION random_variable_in(CSTRING)
3502 RETURNS random_variable
3503 AS 'provsql',
'random_variable_in' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
3506CREATE OR REPLACE
FUNCTION random_variable_out(random_variable)
3508 AS 'provsql',
'random_variable_out' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
3510CREATE TYPE random_variable (
3511 internallength =
16,
3512 input = random_variable_in,
3513 output = random_variable_out,
3518CREATE OR REPLACE
FUNCTION random_variable_make(tok UUID)
3519 RETURNS random_variable
3520 AS 'provsql',
'random_variable_make' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
3533CREATE CAST (random_variable
AS UUID)
WITHOUT FUNCTION AS ASSIGNMENT;
3534CREATE CAST (UUID
AS random_variable)
WITHOUT FUNCTION;
3549CREATE OR REPLACE
FUNCTION agg_token_to_random_variable(a AGG_TOKEN)
3550 RETURNS random_variable
AS
3551$$
SELECT provsql.random_variable_make(provsql.agg_token_uuid($
1)); $$
3552 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
3553CREATE CAST (AGG_TOKEN
AS random_variable)
3554 WITH FUNCTION agg_token_to_random_variable(AGG_TOKEN)
AS IMPLICIT;
3564CREATE OR REPLACE
FUNCTION is_finite_float8(x
double precision)
3567 SELECT $
1 <>
'NaN'::float8
AND $
1 <>
'Infinity'::float8
AND $
1 <>
'-Infinity'::float8;
3568$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
3596CREATE OR REPLACE
FUNCTION rv_parametric2(
3598 p1_tok UUID, p1_lit
double precision,
3599 p2_tok UUID, p2_lit
double precision)
3600 RETURNS random_variable
AS
3604 wires UUID[] :=
ARRAY[]::UUID[];
3608 IF p1_tok
IS NOT NULL THEN
3609 wires := wires || p1_tok;
3610 s1 :=
'$' || (array_length(wires,
1) -
1);
3612 IF NOT provsql.is_finite_float8(p1_lit)
THEN
3613 RAISE EXCEPTION
'provsql.%: literal parameter must be finite (got %)',
3618 IF p2_tok
IS NOT NULL THEN
3619 wires := wires || p2_tok;
3620 s2 :=
'$' || (array_length(wires,
1) -
1);
3622 IF NOT provsql.is_finite_float8(p2_lit)
THEN
3623 RAISE EXCEPTION
'provsql.%: literal parameter must be finite (got %)',
3628 token := public.uuid_generate_v4();
3629 PERFORM provsql.create_gate(token,
'rv', wires);
3630 PERFORM provsql.set_extra(token, family ||
':' || s1 ||
',' || s2);
3631 RETURN provsql.random_variable_make(token);
3633$$
LANGUAGE plpgsql VOLATILE PARALLEL SAFE;
3638CREATE OR REPLACE
FUNCTION rv_parametric1(family TEXT, p_tok UUID)
3639 RETURNS random_variable
AS
3644 token := public.uuid_generate_v4();
3645 PERFORM provsql.create_gate(token,
'rv',
ARRAY[p_tok]);
3646 PERFORM provsql.set_extra(token, family ||
':$0');
3647 RETURN provsql.random_variable_make(token);
3649$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
3662CREATE OR REPLACE
FUNCTION normal(mu random_variable, sigma
double precision)
3663 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'normal', ($
1)::UUID,
NULL,
NULL, $
2); $$
3664 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
3665CREATE OR REPLACE
FUNCTION normal(mu
double precision, sigma random_variable)
3666 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'normal',
NULL, $
1, ($
2)::UUID,
NULL); $$
3667 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
3668CREATE OR REPLACE
FUNCTION normal(mu random_variable, sigma random_variable)
3669 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'normal', ($
1)::UUID,
NULL, ($
2)::UUID,
NULL); $$
3670 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
3673CREATE OR REPLACE
FUNCTION logistic(mu random_variable, s
double precision)
3674 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'logistic', ($
1)::UUID,
NULL,
NULL, $
2); $$
3675 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
3676CREATE OR REPLACE
FUNCTION logistic(mu
double precision, s random_variable)
3677 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'logistic',
NULL, $
1, ($
2)::UUID,
NULL); $$
3678 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
3679CREATE OR REPLACE
FUNCTION logistic(mu random_variable, s random_variable)
3680 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'logistic', ($
1)::UUID,
NULL, ($
2)::UUID,
NULL); $$
3681 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
3684CREATE OR REPLACE
FUNCTION uniform(a random_variable, b
double precision)
3685 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'uniform', ($
1)::UUID,
NULL,
NULL, $
2); $$
3686 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
3687CREATE OR REPLACE
FUNCTION uniform(a
double precision, b random_variable)
3688 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'uniform',
NULL, $
1, ($
2)::UUID,
NULL); $$
3689 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
3690CREATE OR REPLACE
FUNCTION uniform(a random_variable, b random_variable)
3691 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'uniform', ($
1)::UUID,
NULL, ($
2)::UUID,
NULL); $$
3692 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
3695CREATE OR REPLACE
FUNCTION exponential(lambda random_variable)
3696 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric1(
'exponential', ($
1)::UUID); $$
3697 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
3700CREATE OR REPLACE
FUNCTION gamma(k random_variable, lambda
double precision)
3701 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'gamma', ($
1)::UUID,
NULL,
NULL, $
2); $$
3702 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
3703CREATE OR REPLACE
FUNCTION gamma(k
double precision, lambda random_variable)
3704 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'gamma',
NULL, $
1, ($
2)::UUID,
NULL); $$
3705 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
3706CREATE OR REPLACE
FUNCTION gamma(k random_variable, lambda random_variable)
3707 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'gamma', ($
1)::UUID,
NULL, ($
2)::UUID,
NULL); $$
3708 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
3711CREATE OR REPLACE
FUNCTION lognormal(mu random_variable, sigma
double precision)
3712 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'lognormal', ($
1)::UUID,
NULL,
NULL, $
2); $$
3713 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
3714CREATE OR REPLACE
FUNCTION lognormal(mu
double precision, sigma random_variable)
3715 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'lognormal',
NULL, $
1, ($
2)::UUID,
NULL); $$
3716 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
3717CREATE OR REPLACE
FUNCTION lognormal(mu random_variable, sigma random_variable)
3718 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'lognormal', ($
1)::UUID,
NULL, ($
2)::UUID,
NULL); $$
3719 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
3722CREATE OR REPLACE
FUNCTION weibull(k random_variable, lambda
double precision)
3723 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'weibull', ($
1)::UUID,
NULL,
NULL, $
2); $$
3724 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
3725CREATE OR REPLACE
FUNCTION weibull(k
double precision, lambda random_variable)
3726 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'weibull',
NULL, $
1, ($
2)::UUID,
NULL); $$
3727 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
3728CREATE OR REPLACE
FUNCTION weibull(k random_variable, lambda random_variable)
3729 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'weibull', ($
1)::UUID,
NULL, ($
2)::UUID,
NULL); $$
3730 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
3733CREATE OR REPLACE
FUNCTION pareto(xm random_variable, alpha
double precision)
3734 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'pareto', ($
1)::UUID,
NULL,
NULL, $
2); $$
3735 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
3736CREATE OR REPLACE
FUNCTION pareto(xm
double precision, alpha random_variable)
3737 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'pareto',
NULL, $
1, ($
2)::UUID,
NULL); $$
3738 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
3739CREATE OR REPLACE
FUNCTION pareto(xm random_variable, alpha random_variable)
3740 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'pareto', ($
1)::UUID,
NULL, ($
2)::UUID,
NULL); $$
3741 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
3744CREATE OR REPLACE
FUNCTION beta(alpha random_variable, beta
double precision)
3745 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'beta', ($
1)::UUID,
NULL,
NULL, $
2); $$
3746 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
3747CREATE OR REPLACE
FUNCTION beta(alpha
double precision, beta random_variable)
3748 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'beta',
NULL, $
1, ($
2)::UUID,
NULL); $$
3749 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
3750CREATE OR REPLACE
FUNCTION beta(alpha random_variable, beta random_variable)
3751 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'beta', ($
1)::UUID,
NULL, ($
2)::UUID,
NULL); $$
3752 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
3755CREATE OR REPLACE
FUNCTION inverse_gamma(alpha random_variable, beta
double precision)
3756 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'inverse_gamma', ($
1)::UUID,
NULL,
NULL, $
2); $$
3757 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
3758CREATE OR REPLACE
FUNCTION inverse_gamma(alpha
double precision, beta random_variable)
3759 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'inverse_gamma',
NULL, $
1, ($
2)::UUID,
NULL); $$
3760 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
3761CREATE OR REPLACE
FUNCTION inverse_gamma(alpha random_variable, beta random_variable)
3762 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'inverse_gamma', ($
1)::UUID,
NULL, ($
2)::UUID,
NULL); $$
3763 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
3766CREATE OR REPLACE
FUNCTION inverse_gaussian(mu random_variable, lambda
double precision)
3767 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'inverse_gaussian', ($
1)::UUID,
NULL,
NULL, $
2); $$
3768 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
3769CREATE OR REPLACE
FUNCTION inverse_gaussian(mu
double precision, lambda random_variable)
3770 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'inverse_gaussian',
NULL, $
1, ($
2)::UUID,
NULL); $$
3771 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
3772CREATE OR REPLACE
FUNCTION inverse_gaussian(mu random_variable, lambda random_variable)
3773 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'inverse_gaussian', ($
1)::UUID,
NULL, ($
2)::UUID,
NULL); $$
3774 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
3804CREATE OR REPLACE
FUNCTION normal(mu
double precision, sigma
double precision)
3805 RETURNS random_variable
AS
3810 IF NOT provsql.is_finite_float8(mu)
OR NOT provsql.is_finite_float8(sigma)
THEN
3811 RAISE EXCEPTION
'provsql.normal: parameters must be finite (got mu=%, sigma=%)', mu, sigma;
3814 RAISE EXCEPTION
'provsql.normal: sigma must be non-negative (got %)', sigma;
3817 RETURN provsql.as_random(mu);
3819 token := public.uuid_generate_v4();
3820 PERFORM provsql.create_gate(token,
'rv');
3821 PERFORM provsql.set_extra(token,
'normal:' || mu ||
',' || sigma);
3822 RETURN provsql.random_variable_make(token);
3824$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
3845CREATE OR REPLACE
FUNCTION logistic(mu
double precision, s
double precision)
3846 RETURNS random_variable
AS
3851 IF NOT provsql.is_finite_float8(mu)
OR NOT provsql.is_finite_float8(s)
THEN
3852 RAISE EXCEPTION
'provsql.logistic: parameters must be finite (got mu=%, s=%)', mu, s;
3855 RAISE EXCEPTION
'provsql.logistic: scale s must be non-negative (got %)', s;
3858 RETURN provsql.as_random(mu);
3860 token := public.uuid_generate_v4();
3861 PERFORM provsql.create_gate(token,
'rv');
3862 PERFORM provsql.set_extra(token,
'logistic:' || mu ||
',' || s);
3863 RETURN provsql.random_variable_make(token);
3865$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
3882CREATE OR REPLACE
FUNCTION uniform(a
double precision, b
double precision)
3883 RETURNS random_variable
AS
3888 IF NOT provsql.is_finite_float8(a)
OR NOT provsql.is_finite_float8(b)
THEN
3889 RAISE EXCEPTION
'provsql.uniform: bounds must be finite (got a=%, b=%)', a, b;
3892 RAISE EXCEPTION
'provsql.uniform: a must be <= b (got a=%, b=%)', a, b;
3895 RETURN provsql.as_random(a);
3897 token := public.uuid_generate_v4();
3898 PERFORM provsql.create_gate(token,
'rv');
3899 PERFORM provsql.set_extra(token,
'uniform:' || a ||
',' || b);
3900 RETURN provsql.random_variable_make(token);
3902$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
3917CREATE OR REPLACE
FUNCTION exponential(lambda
double precision)
3918 RETURNS random_variable
AS
3923 IF NOT provsql.is_finite_float8(lambda)
THEN
3924 RAISE EXCEPTION
'provsql.exponential: lambda must be finite (got %)', lambda;
3927 RAISE EXCEPTION
'provsql.exponential: lambda must be strictly positive (got %)', lambda;
3929 token := public.uuid_generate_v4();
3930 PERFORM provsql.create_gate(token,
'rv');
3931 PERFORM provsql.set_extra(token,
'exponential:' || lambda);
3932 RETURN provsql.random_variable_make(token);
3934$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
3959CREATE OR REPLACE
FUNCTION erlang(k
INTEGER, lambda
double precision)
3960 RETURNS random_variable
AS
3966 RAISE EXCEPTION
'provsql.erlang: k must be >= 1 (got %)', k;
3968 IF NOT provsql.is_finite_float8(lambda)
THEN
3969 RAISE EXCEPTION
'provsql.erlang: lambda must be finite (got %)', lambda;
3972 RAISE EXCEPTION
'provsql.erlang: lambda must be strictly positive (got %)', lambda;
3975 RETURN provsql.exponential(lambda);
3977 token := public.uuid_generate_v4();
3978 PERFORM provsql.create_gate(token,
'rv');
3979 PERFORM provsql.set_extra(token,
'erlang:' || k ||
',' || lambda);
3980 RETURN provsql.random_variable_make(token);
3982$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
4005CREATE OR REPLACE
FUNCTION gamma(k
double precision, lambda
double precision)
4006 RETURNS random_variable
AS
4011 IF NOT provsql.is_finite_float8(k)
THEN
4012 RAISE EXCEPTION
'provsql.gamma: k must be finite (got %)', k;
4015 RAISE EXCEPTION
'provsql.gamma: k must be strictly positive (got %)', k;
4017 IF NOT provsql.is_finite_float8(lambda)
THEN
4018 RAISE EXCEPTION
'provsql.gamma: lambda must be finite (got %)', lambda;
4021 RAISE EXCEPTION
'provsql.gamma: lambda must be strictly positive (got %)', lambda;
4023 IF k = floor(k)
AND k <=
2147483647 THEN
4024 RETURN provsql.erlang(k::
INTEGER, lambda);
4026 token := public.uuid_generate_v4();
4027 PERFORM provsql.create_gate(token,
'rv');
4028 PERFORM provsql.set_extra(token,
'gamma:' || k ||
',' || lambda);
4029 RETURN provsql.random_variable_make(token);
4031$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
4046CREATE OR REPLACE
FUNCTION chi_squared(k
double precision)
4047 RETURNS random_variable
AS
4050 IF NOT provsql.is_finite_float8(k)
THEN
4051 RAISE EXCEPTION
'provsql.chi_squared: k must be finite (got %)', k;
4054 RAISE EXCEPTION
'provsql.chi_squared: k must be strictly positive (got %)', k;
4056 RETURN provsql.gamma(k /
2,
0.
5);
4058$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
4080CREATE OR REPLACE
FUNCTION lognormal(mu
double precision, sigma
double precision)
4081 RETURNS random_variable
AS
4086 IF NOT provsql.is_finite_float8(mu)
OR NOT provsql.is_finite_float8(sigma)
THEN
4087 RAISE EXCEPTION
'provsql.lognormal: parameters must be finite (got mu=%, sigma=%)', mu, sigma;
4090 RAISE EXCEPTION
'provsql.lognormal: sigma must be non-negative (got %)', sigma;
4093 RETURN provsql.as_random(exp(mu));
4095 token := public.uuid_generate_v4();
4096 PERFORM provsql.create_gate(token,
'rv');
4097 PERFORM provsql.set_extra(token,
'lognormal:' || mu ||
',' || sigma);
4098 RETURN provsql.random_variable_make(token);
4100$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
4121CREATE OR REPLACE
FUNCTION weibull(k
double precision, lambda
double precision)
4122 RETURNS random_variable
AS
4127 IF NOT provsql.is_finite_float8(k)
OR NOT provsql.is_finite_float8(lambda)
THEN
4128 RAISE EXCEPTION
'provsql.weibull: parameters must be finite (got k=%, lambda=%)', k, lambda;
4130 IF k <=
0 OR lambda <=
0 THEN
4131 RAISE EXCEPTION
'provsql.weibull: parameters must be strictly positive (got k=%, lambda=%)', k, lambda;
4134 RETURN provsql.exponential(
1 / lambda);
4136 token := public.uuid_generate_v4();
4137 PERFORM provsql.create_gate(token,
'rv');
4138 PERFORM provsql.set_extra(token,
'weibull:' || k ||
',' || lambda);
4139 RETURN provsql.random_variable_make(token);
4141$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
4161CREATE OR REPLACE
FUNCTION pareto(xm
double precision, alpha
double precision)
4162 RETURNS random_variable
AS
4167 IF NOT provsql.is_finite_float8(xm)
OR NOT provsql.is_finite_float8(alpha)
THEN
4168 RAISE EXCEPTION
'provsql.pareto: parameters must be finite (got xm=%, alpha=%)', xm, alpha;
4170 IF xm <=
0 OR alpha <=
0 THEN
4171 RAISE EXCEPTION
'provsql.pareto: parameters must be strictly positive (got xm=%, alpha=%)', xm, alpha;
4173 token := public.uuid_generate_v4();
4174 PERFORM provsql.create_gate(token,
'rv');
4175 PERFORM provsql.set_extra(token,
'pareto:' || xm ||
',' || alpha);
4176 RETURN provsql.random_variable_make(token);
4178$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
4199CREATE OR REPLACE
FUNCTION inverse_gamma(alpha
double precision, beta
double precision)
4200 RETURNS random_variable
AS
4205 IF NOT provsql.is_finite_float8(alpha)
OR NOT provsql.is_finite_float8(beta)
THEN
4206 RAISE EXCEPTION
'provsql.inverse_gamma: parameters must be finite (got alpha=%, beta=%)', alpha, beta;
4208 IF alpha <=
0 OR beta <=
0 THEN
4209 RAISE EXCEPTION
'provsql.inverse_gamma: parameters must be strictly positive (got alpha=%, beta=%)', alpha, beta;
4211 token := public.uuid_generate_v4();
4212 PERFORM provsql.create_gate(token,
'rv');
4213 PERFORM provsql.set_extra(token,
'inverse_gamma:' || alpha ||
',' || beta);
4214 RETURN provsql.random_variable_make(token);
4216$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
4237CREATE OR REPLACE
FUNCTION inverse_gaussian(mu
double precision, lambda
double precision)
4238 RETURNS random_variable
AS
4243 IF NOT provsql.is_finite_float8(mu)
OR NOT provsql.is_finite_float8(lambda)
THEN
4244 RAISE EXCEPTION
'provsql.inverse_gaussian: parameters must be finite (got mu=%, lambda=%)', mu, lambda;
4246 IF mu <=
0 OR lambda <=
0 THEN
4247 RAISE EXCEPTION
'provsql.inverse_gaussian: parameters must be strictly positive (got mu=%, lambda=%)', mu, lambda;
4249 token := public.uuid_generate_v4();
4250 PERFORM provsql.create_gate(token,
'rv');
4251 PERFORM provsql.set_extra(token,
'inverse_gaussian:' || mu ||
',' || lambda);
4252 RETURN provsql.random_variable_make(token);
4254$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
4261CREATE OR REPLACE
FUNCTION wald(mu
double precision, lambda
double precision)
4262 RETURNS random_variable
AS
4264 SELECT provsql.inverse_gaussian(mu, lambda);
4265$$
LANGUAGE sql VOLATILE PARALLEL SAFE;
4285CREATE OR REPLACE
FUNCTION categorical_from_log_pmf(
4286 outcomes
double precision[], log_pmf
double precision[])
4287 RETURNS random_variable
AS
4290 n
INT := array_length(outcomes,
1);
4291 max_lp
double precision :=
'-Infinity';
4292 kept_o
double precision[] :=
'{}';
4293 kept_p
double precision[] :=
'{}';
4294 total
double precision :=
0;
4298 IF n
IS NULL OR n =
0 OR n <> coalesce(array_length(log_pmf,
1),
0)
THEN
4299 RAISE EXCEPTION
'provsql.categorical_from_log_pmf: outcomes and log_pmf must be non-empty arrays of the same length';
4302 IF log_pmf[i] > max_lp
THEN max_lp := log_pmf[i];
END IF;
4304 IF max_lp =
'-Infinity' THEN
4305 RAISE EXCEPTION
'provsql.categorical_from_log_pmf: all masses are zero';
4308 v := exp(log_pmf[i] - max_lp);
4310 kept_o := array_append(kept_o, outcomes[i]);
4311 kept_p := array_append(kept_p, v);
4315 FOR i
IN 1..array_length(kept_p,
1) LOOP
4316 kept_p[i] := kept_p[i] / total;
4318 RETURN provsql.categorical(kept_p, kept_o);
4320$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
4337CREATE OR REPLACE
FUNCTION poisson(lambda
double precision)
4338 RETURNS random_variable
AS
4343 outcomes
double precision[] :=
'{}';
4344 lps
double precision[] :=
'{}';
4345 lp
double precision :=
0;
4348 IF NOT provsql.is_finite_float8(lambda)
OR lambda <
0 THEN
4349 RAISE EXCEPTION
'provsql.poisson: lambda must be finite and non-negative (got %)', lambda;
4352 RETURN provsql.as_random(
0);
4354 lo := greatest(
0, floor(lambda -
12 * sqrt(lambda)))::
INT;
4355 hi := ceil(lambda +
12 * sqrt(lambda))::
INT +
30;
4356 IF hi - lo +
1 >
10000 THEN
4357 RAISE EXCEPTION
'provsql.poisson: support window of % outcomes exceeds 10000; approximate with normal(%, sqrt(%))', hi - lo +
1, lambda, lambda;
4362 lp := lp + ln(lambda) - ln(k::
double precision);
4364 outcomes := array_append(outcomes, k::
double precision);
4365 lps := array_append(lps, lp);
4369 outcomes := array_prepend(
0::
double precision, outcomes);
4370 lps := array_prepend(-lambda, lps);
4372 RETURN provsql.categorical_from_log_pmf(outcomes, lps);
4374$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
4387CREATE OR REPLACE
FUNCTION poisson(lambda random_variable)
4388 RETURNS random_variable
AS
4389$$
SELECT provsql.rv_parametric1(
'poisson', ($
1)::UUID); $$
4390 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
4409CREATE OR REPLACE
FUNCTION beta(alpha
double precision, beta
double precision)
4410 RETURNS random_variable
AS
4415 IF NOT provsql.is_finite_float8(alpha)
OR NOT provsql.is_finite_float8(beta)
THEN
4416 RAISE EXCEPTION
'provsql.beta: parameters must be finite (got alpha=%, beta=%)', alpha, beta;
4418 IF alpha <=
0 OR beta <=
0 THEN
4419 RAISE EXCEPTION
'provsql.beta: parameters must be strictly positive (got alpha=%, beta=%)', alpha, beta;
4421 IF alpha =
1 AND beta =
1 THEN
4422 RETURN provsql.uniform(
0,
1);
4424 token := public.uuid_generate_v4();
4425 PERFORM provsql.create_gate(token,
'rv');
4426 PERFORM provsql.set_extra(token,
'beta:' || alpha ||
',' || beta);
4427 RETURN provsql.random_variable_make(token);
4429$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
4442CREATE OR REPLACE
FUNCTION binomial(n
INTEGER, p
double precision)
4443 RETURNS random_variable
AS
4446 outcomes
double precision[] :=
'{}';
4447 lps
double precision[] :=
'{}';
4448 lp
double precision;
4451 IF n
IS NULL OR n <
0 THEN
4452 RAISE EXCEPTION
'provsql.binomial: n must be non-negative (got %)', n;
4454 IF NOT provsql.is_finite_float8(p)
OR p <
0 OR p >
1 THEN
4455 RAISE EXCEPTION
'provsql.binomial: p must be in [0, 1] (got %)', p;
4458 RAISE EXCEPTION
'provsql.binomial: n = % exceeds 10000; approximate with normal(n*p, sqrt(n*p*(1-p)))', n;
4460 IF n =
0 OR p =
0 THEN
4461 RETURN provsql.as_random(
0);
4464 RETURN provsql.as_random(n);
4466 lp := n * ln(
1 - p);
4467 outcomes := array_append(outcomes,
0::
double precision);
4468 lps := array_append(lps, lp);
4469 FOR k
IN 0..(n -
1) LOOP
4470 lp := lp + ln((n - k)::
double precision / (k +
1)) + ln(p / (
1 - p));
4471 outcomes := array_append(outcomes, (k +
1)::
double precision);
4472 lps := array_append(lps, lp);
4474 RETURN provsql.categorical_from_log_pmf(outcomes, lps);
4476$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
4489CREATE OR REPLACE
FUNCTION binomial(n
INTEGER, p random_variable)
4490 RETURNS random_variable
AS
4491$$
SELECT provsql.rv_parametric2(
'binomial',
NULL, $
1::
double precision,
4492 ($
2)::UUID,
NULL); $$
4493 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
4505CREATE OR REPLACE
FUNCTION geometric(p
double precision)
4506 RETURNS random_variable
AS
4510 outcomes
double precision[] :=
'{}';
4511 lps
double precision[] :=
'{}';
4514 IF NOT provsql.is_finite_float8(p)
OR p <=
0 OR p >
1 THEN
4515 RAISE EXCEPTION
'provsql.geometric: p must be in (0, 1] (got %)', p;
4518 RETURN provsql.as_random(
1);
4520 k_max :=
1 + ceil(ln(1e-15) / ln(
1 - p))::
INT;
4521 IF k_max >
10000 THEN
4522 RAISE EXCEPTION
'provsql.geometric: support window of % outcomes exceeds 10000 (p = % is too small); approximate with exponential(%)', k_max, p, p;
4524 FOR k
IN 1..k_max LOOP
4525 outcomes := array_append(outcomes, k::
double precision);
4526 lps := array_append(lps, (k -
1) * ln(
1 - p) + ln(p));
4528 RETURN provsql.categorical_from_log_pmf(outcomes, lps);
4530$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
4540CREATE OR REPLACE
FUNCTION geometric(p random_variable)
4541 RETURNS random_variable
AS
4542$$
SELECT provsql.rv_parametric1(
'geometric', ($
1)::UUID); $$
4543 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
4559CREATE OR REPLACE
FUNCTION hypergeometric(pop_n
INTEGER, k_marked
INTEGER, n
INTEGER)
4560 RETURNS random_variable
AS
4565 outcomes
double precision[] :=
'{}';
4566 lps
double precision[] :=
'{}';
4567 lp
double precision :=
0;
4570 IF pop_n
IS NULL OR k_marked
IS NULL OR n
IS NULL
4571 OR pop_n <
0 OR k_marked <
0 OR n <
0
4572 OR k_marked > pop_n
OR n > pop_n
THEN
4573 RAISE EXCEPTION
'provsql.hypergeometric: need 0 <= k_marked, n <= pop_n (got pop_n=%, k_marked=%, n=%)', pop_n, k_marked, n;
4575 lo := greatest(
0, n - (pop_n - k_marked));
4576 hi := least(n, k_marked);
4577 IF hi - lo +
1 >
10000 THEN
4578 RAISE EXCEPTION
'provsql.hypergeometric: support window of % outcomes exceeds 10000', hi - lo +
1;
4580 outcomes := array_append(outcomes, lo::
double precision);
4581 lps := array_append(lps, lp);
4582 FOR k
IN lo..(hi -
1) LOOP
4584 lp := lp + ln((k_marked - k)::
double precision * (n - k))
4585 - ln((k +
1)::
double precision * (pop_n - k_marked - n + k +
1));
4586 outcomes := array_append(outcomes, (k +
1)::
double precision);
4587 lps := array_append(lps, lp);
4589 RETURN provsql.categorical_from_log_pmf(outcomes, lps);
4591$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
4606CREATE OR REPLACE
FUNCTION negative_binomial(r
double precision, p
double precision)
4607 RETURNS random_variable
AS
4610 outcomes
double precision[] :=
'{}';
4611 lps
double precision[] :=
'{}';
4612 lp
double precision;
4613 max_lp
double precision;
4614 mean
double precision;
4617 IF NOT provsql.is_finite_float8(r)
OR r <=
0 THEN
4618 RAISE EXCEPTION
'provsql.negative_binomial: r must be finite and strictly positive (got %)', r;
4620 IF NOT provsql.is_finite_float8(p)
OR p <=
0 OR p >
1 THEN
4621 RAISE EXCEPTION
'provsql.negative_binomial: p must be in (0, 1] (got %)', p;
4624 RETURN provsql.as_random(
0);
4626 mean := r * (
1 - p) / p;
4629 outcomes := array_append(outcomes,
0::
double precision);
4630 lps := array_append(lps, lp);
4632 lp := lp + ln((k + r) / (k +
1)) + ln(
1 - p);
4634 IF lp > max_lp
THEN max_lp := lp;
END IF;
4635 outcomes := array_append(outcomes, k::
double precision);
4636 lps := array_append(lps, lp);
4637 EXIT
WHEN k > mean
AND lp < max_lp + ln(1e-15);
4639 RAISE EXCEPTION
'provsql.negative_binomial: support window exceeds 10000 outcomes (r=%, p=%)', r, p;
4642 RETURN provsql.categorical_from_log_pmf(outcomes, lps);
4644$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
4653CREATE OR REPLACE
FUNCTION negative_binomial(r
double precision, p random_variable)
4654 RETURNS random_variable
AS
4655$$
SELECT provsql.rv_parametric2(
'negative_binomial',
NULL, $
1, ($
2)::UUID,
NULL); $$
4656 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
4657CREATE OR REPLACE
FUNCTION negative_binomial(r random_variable, p
double precision)
4658 RETURNS random_variable
AS
4659$$
SELECT provsql.rv_parametric2(
'negative_binomial', ($
1)::UUID,
NULL,
NULL, $
2); $$
4660 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
4661CREATE OR REPLACE
FUNCTION negative_binomial(r random_variable, p random_variable)
4662 RETURNS random_variable
AS
4663$$
SELECT provsql.rv_parametric2(
'negative_binomial', ($
1)::UUID,
NULL, ($
2)::UUID,
NULL); $$
4664 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
4678CREATE OR REPLACE
FUNCTION rv_families()
4679 RETURNS TABLE(name TEXT, nparams
INT, param_names TEXT[], label TEXT)
AS
4680 'provsql',
'rv_families' LANGUAGE C STABLE PARALLEL SAFE;
4722CREATE OR REPLACE
FUNCTION mixture(
4723 p UUID, x random_variable, y random_variable)
4724 RETURNS random_variable
AS
4728 p_kind provsql.PROVENANCE_GATE;
4731 x_kind provsql.PROVENANCE_GATE;
4732 y_kind provsql.PROVENANCE_GATE;
4734 p_kind := provsql.get_gate_type(p);
4735 IF p_kind
NOT IN (
'input',
'mulinput',
'update',
4736 'plus',
'times',
'monus',
4737 'project',
'eq',
'cmp',
4739 RAISE EXCEPTION
'provsql.mixture: p must be a Boolean gate '
4740 '(input/mulinput/update/plus/times/monus/project/eq/cmp/zero/one), got %', p_kind;
4743 x_uuid := (x)::UUID;
4744 y_uuid := (y)::UUID;
4745 x_kind := provsql.get_gate_type(x_uuid);
4746 y_kind := provsql.get_gate_type(y_uuid);
4747 IF x_kind
NOT IN (
'rv',
'value',
'arith',
'mixture')
THEN
4748 RAISE EXCEPTION
'provsql.mixture: x must be a scalar RV root (rv / value / arith / mixture), got %', x_kind;
4750 IF y_kind
NOT IN (
'rv',
'value',
'arith',
'mixture')
THEN
4751 RAISE EXCEPTION
'provsql.mixture: y must be a scalar RV root (rv / value / arith / mixture), got %', y_kind;
4754 token := public.uuid_generate_v5(
4755 provsql.uuid_ns_provsql(),
4756 concat(
'mixture', p, x_uuid, y_uuid));
4757 PERFORM provsql.create_gate(token,
'mixture',
ARRAY[p, x_uuid, y_uuid]);
4758 RETURN provsql.random_variable_make(token);
4760$$
LANGUAGE plpgsql STRICT IMMUTABLE PARALLEL SAFE;
4787CREATE OR REPLACE
FUNCTION mixture(
4788 p_value
double precision,
4791 RETURNS random_variable
AS
4796 IF p_value
IS NULL OR p_value <> p_value
OR p_value <
0 OR p_value >
1 THEN
4797 RAISE EXCEPTION
'provsql.mixture: probability must be in [0,1] (got %)', p_value;
4799 p_token := public.uuid_generate_v4();
4800 PERFORM provsql.create_gate(p_token,
'input');
4801 PERFORM provsql.set_prob(p_token, p_value);
4802 RETURN provsql.mixture(p_token, x, y);
4804$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
4838CREATE OR REPLACE
FUNCTION categorical(
4839 probs
double precision[],
4840 outcomes
double precision[])
4841 RETURNS random_variable
AS
4845 p_sum
double precision :=
0.
0;
4850 mul_tokens UUID[] :=
ARRAY[]::UUID[];
4852 pi_i
double precision;
4853 vi_i
double precision;
4855 IF probs
IS NULL OR outcomes
IS NULL THEN
4856 RAISE EXCEPTION
'provsql.categorical: probs and outcomes must be non-null';
4858 n := array_length(probs,
1);
4859 IF n
IS NULL OR n <
1 THEN
4860 RAISE EXCEPTION
'provsql.categorical: probs must be non-empty';
4862 IF array_length(outcomes,
1) <> n
THEN
4863 RAISE EXCEPTION
'provsql.categorical: probs and outcomes must have the same length (got % and %)',
4864 n, array_length(outcomes,
1);
4869 vi_i := outcomes[i];
4874 IF pi_i
IS NULL OR pi_i =
'NaN'::float8
OR pi_i <
0 OR pi_i >
1 THEN
4875 RAISE EXCEPTION
'provsql.categorical: probs[%] must be in [0,1] (got %)', i, pi_i;
4877 IF vi_i
IS NULL OR vi_i =
'NaN'::float8
4878 OR vi_i =
'Infinity'::float8
OR vi_i =
'-Infinity'::float8
THEN
4879 RAISE EXCEPTION
'provsql.categorical: outcomes[%] must be finite (got %)', i, vi_i;
4881 p_sum := p_sum + pi_i;
4883 IF abs(p_sum -
1.
0) > 1e-9
THEN
4884 RAISE EXCEPTION
'provsql.categorical: probs must sum to 1 within 1e-9 (got %)', p_sum;
4896 nb_positive
INTEGER :=
0;
4897 only_idx
INTEGER :=
0;
4900 IF probs[i] >
0.
0 THEN
4901 nb_positive := nb_positive +
1;
4905 IF nb_positive =
1 THEN
4906 RETURN provsql.as_random(outcomes[only_idx]);
4913 key_token := public.uuid_generate_v4();
4914 PERFORM provsql.create_gate(key_token,
'input');
4915 PERFORM provsql.set_prob(key_token,
1.
0);
4922 IF pi_i <=
0.
0 THEN CONTINUE;
END IF;
4923 mul_token := public.uuid_generate_v4();
4924 PERFORM provsql.create_gate(mul_token,
'mulinput',
ARRAY[key_token]);
4925 PERFORM provsql.set_prob(mul_token, pi_i);
4926 PERFORM provsql.set_infos(mul_token, (i -
1));
4927 PERFORM provsql.set_extra(mul_token, outcomes[i]::TEXT);
4928 mul_tokens := mul_tokens || mul_token;
4931 mix_wires :=
ARRAY[key_token] || mul_tokens;
4932 mix_token := public.uuid_generate_v4();
4933 PERFORM provsql.create_gate(mix_token,
'mixture', mix_wires);
4934 RETURN provsql.random_variable_make(mix_token);
4936$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
4969CREATE OR REPLACE
FUNCTION gmm(
4970 weights
double precision[],
4971 means
double precision[],
4972 stddevs
double precision[])
4973 RETURNS random_variable
AS
4977 w_sum
double precision :=
0.
0;
4979 acc random_variable :=
NULL;
4980 remaining
double precision :=
0.
0;
4982 IF weights
IS NULL OR means
IS NULL OR stddevs
IS NULL THEN
4983 RAISE EXCEPTION
'provsql.gmm: weights, means, and stddevs must be non-null';
4985 n := array_length(weights,
1);
4986 IF n
IS NULL OR n <
1 THEN
4987 RAISE EXCEPTION
'provsql.gmm: weights must be non-empty';
4989 IF array_length(means,
1) <> n
OR array_length(stddevs,
1) <> n
THEN
4990 RAISE EXCEPTION
'provsql.gmm: weights, means, and stddevs must have the same length (got %, %, %)',
4991 n, array_length(means,
1), array_length(stddevs,
1);
4994 IF weights[i]
IS NULL OR weights[i] =
'NaN'::float8
4995 OR weights[i] <
0 OR weights[i] >
1 THEN
4996 RAISE EXCEPTION
'provsql.gmm: weights[%] must be in [0,1] (got %)',
4999 w_sum := w_sum + weights[i];
5001 IF abs(w_sum -
1.
0) > 1e-9
THEN
5002 RAISE EXCEPTION
'provsql.gmm: weights must sum to 1 within 1e-9 (got %)', w_sum;
5008 FOR i
IN REVERSE n..
1 LOOP
5009 IF weights[i] <=
0.
0 THEN
5013 acc := provsql.normal(means[i], stddevs[i]);
5014 remaining := weights[i];
5016 remaining := remaining + weights[i];
5017 acc := provsql.mixture(least(
1.
0, weights[i] / remaining),
5018 provsql.normal(means[i], stddevs[i]), acc);
5023$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
5050CREATE OR REPLACE
FUNCTION empirical_samples(samples
double precision[])
5051 RETURNS random_variable
AS
5055 sorted
double precision[];
5056 outcomes
double precision[] :=
'{}';
5057 probs
double precision[] :=
'{}';
5059 prev
double precision;
5061 started
BOOLEAN :=
false;
5063 n := array_length(samples,
1);
5064 IF n
IS NULL OR n <
1 THEN
5065 RAISE EXCEPTION
'provsql.empirical_samples: samples must be non-empty';
5067 sorted :=
ARRAY(
SELECT s
FROM unnest(samples)
AS s
ORDER BY 1);
5068 FOREACH v
IN ARRAY sorted LOOP
5069 IF v
IS NULL OR v =
'NaN'::float8
5070 OR v =
'Infinity'::float8
OR v =
'-Infinity'::float8
THEN
5072 'provsql.empirical_samples: samples must be finite (got %)', v;
5074 IF started
AND v = prev
THEN
5078 outcomes := outcomes || prev;
5079 probs := probs || (run::
double precision / n);
5086 outcomes := outcomes || prev;
5087 probs := probs || (run::
double precision / n);
5088 IF array_length(outcomes,
1) >
10000 THEN
5090 'provsql.empirical_samples: at most 10000 distinct values are '
5091 'supported (got %); thin the chain or bin the samples (e.g. with '
5092 'width_bucket)', array_length(outcomes,
1);
5094 RETURN provsql.categorical(probs, outcomes);
5096$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
5126CREATE OR REPLACE
FUNCTION empirical_cdf(grid
double precision[],
5127 cdf
double precision[])
5128 RETURNS random_variable
AS
5133 acc random_variable :=
NULL;
5134 remaining
double precision :=
0.
0;
5136 comp random_variable;
5138 n := array_length(grid,
1);
5139 IF n
IS NULL OR n <
2 THEN
5140 RAISE EXCEPTION
'provsql.empirical_cdf: grid must have at least two entries';
5142 IF array_length(cdf,
1) <> n
THEN
5143 RAISE EXCEPTION
'provsql.empirical_cdf: grid and cdf must have the same length (got % and %)',
5144 n, array_length(cdf,
1);
5147 RAISE EXCEPTION
'provsql.empirical_cdf: at most 10000 grid points are supported (got %)', n;
5150 IF grid[i]
IS NULL OR grid[i] =
'NaN'::float8
5151 OR grid[i] =
'Infinity'::float8
OR grid[i] =
'-Infinity'::float8
THEN
5152 RAISE EXCEPTION
'provsql.empirical_cdf: grid[%] must be finite (got %)', i, grid[i];
5154 IF i >
1 AND NOT grid[i] > grid[i-1]
THEN
5155 RAISE EXCEPTION
'provsql.empirical_cdf: grid must be strictly increasing (grid[%] = %, grid[%] = %)',
5156 i-1, grid[i-1], i, grid[i];
5158 IF cdf[i]
IS NULL OR cdf[i] =
'NaN'::float8
OR cdf[i] <
0 OR cdf[i] >
1 THEN
5159 RAISE EXCEPTION
'provsql.empirical_cdf: cdf[%] must be in [0,1] (got %)', i, cdf[i];
5161 IF i >
1 AND cdf[i] < cdf[i-1]
THEN
5162 RAISE EXCEPTION
'provsql.empirical_cdf: cdf must be non-decreasing (cdf[%] = %, cdf[%] = %)',
5163 i-1, cdf[i-1], i, cdf[i];
5166 IF abs(cdf[n] -
1.
0) > 1e-9
THEN
5167 RAISE EXCEPTION
'provsql.empirical_cdf: cdf must end at 1 within 1e-9 (got %)', cdf[n];
5173 FOR i
IN REVERSE n..
1 LOOP
5174 w :=
CASE WHEN i =
1 THEN cdf[
1]
ELSE cdf[i] - cdf[i-1]
END;
5178 comp :=
CASE WHEN i =
1 THEN provsql.as_random(grid[
1])
5179 ELSE provsql.uniform(grid[i-1], grid[i])
END;
5184 remaining := remaining + w;
5185 acc := provsql.mixture(least(
1.
0, w / remaining), comp, acc);
5190$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
5211CREATE OR REPLACE
FUNCTION as_random(c
double precision)
5212 RETURNS random_variable
AS
5220 c_canon
double precision := c +
0.
0;
5221 c_text
varchar :=
CAST(c_canon
AS VARCHAR);
5222 token UUID := public.uuid_generate_v5(
5223 provsql.uuid_ns_provsql(), concat(
'value', c_text));
5225 PERFORM provsql.create_gate(token,
'value');
5226 PERFORM provsql.set_extra(token, c_text);
5227 RETURN provsql.random_variable_make(token);
5229$$
LANGUAGE plpgsql STRICT IMMUTABLE PARALLEL SAFE;
5244CREATE CAST (
double precision AS random_variable)
5245 WITH FUNCTION as_random(
double precision)
AS IMPLICIT;
5248CREATE OR REPLACE
FUNCTION as_random(c
INTEGER)
5249 RETURNS random_variable
AS
5250$$
SELECT provsql.as_random(c::
double precision); $$
5251LANGUAGE sql STRICT IMMUTABLE PARALLEL SAFE;
5254CREATE OR REPLACE
FUNCTION as_random(c
NUMERIC)
5255 RETURNS random_variable
AS
5256$$
SELECT provsql.as_random(c::
double precision); $$
5257LANGUAGE sql STRICT IMMUTABLE PARALLEL SAFE;
5260CREATE CAST (
INTEGER AS random_variable)
5261 WITH FUNCTION as_random(
INTEGER)
AS IMPLICIT;
5264CREATE CAST (
NUMERIC AS random_variable)
5265 WITH FUNCTION as_random(
NUMERIC)
AS IMPLICIT;
5297CREATE OR REPLACE
FUNCTION random_variable_plus(
5298 a random_variable, b random_variable)
5299 RETURNS random_variable
AS
5301 SELECT provsql.random_variable_make(
5302 provsql.provenance_arith(
5306$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
5309CREATE OR REPLACE
FUNCTION random_variable_minus(
5310 a random_variable, b random_variable)
5311 RETURNS random_variable
AS
5313 SELECT provsql.random_variable_make(
5314 provsql.provenance_arith(
5318$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
5321CREATE OR REPLACE
FUNCTION random_variable_times(
5322 a random_variable, b random_variable)
5323 RETURNS random_variable
AS
5325 SELECT provsql.random_variable_make(
5326 provsql.provenance_arith(
5330$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
5333CREATE OR REPLACE
FUNCTION random_variable_div(
5334 a random_variable, b random_variable)
5335 RETURNS random_variable
AS
5337 SELECT provsql.random_variable_make(
5338 provsql.provenance_arith(
5342$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
5345CREATE OR REPLACE
FUNCTION random_variable_neg(a random_variable)
5346 RETURNS random_variable
AS
5348 SELECT provsql.random_variable_make(
5349 provsql.provenance_arith(
5352$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
5361CREATE OR REPLACE
FUNCTION random_variable_pow(
5362 a random_variable, b random_variable)
5363 RETURNS random_variable
AS
5365 SELECT provsql.random_variable_make(
5366 provsql.provenance_arith(
5370$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
5379CREATE OR REPLACE
FUNCTION ln(a random_variable)
5380 RETURNS random_variable
AS
5382 SELECT provsql.random_variable_make(
5383 provsql.provenance_arith(
5386$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
5389CREATE OR REPLACE
FUNCTION exp(a random_variable)
5390 RETURNS random_variable
AS
5392 SELECT provsql.random_variable_make(
5393 provsql.provenance_arith(
5396$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
5404CREATE OR REPLACE
FUNCTION pow(a random_variable, b random_variable)
5405 RETURNS random_variable
AS
5407 SELECT provsql.random_variable_pow(a, b);
5408$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
5410CREATE OR REPLACE
FUNCTION power(a random_variable, b random_variable)
5411 RETURNS random_variable
AS
5413 SELECT provsql.random_variable_pow(a, b);
5414$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
5421CREATE OR REPLACE
FUNCTION sqrt(a random_variable)
5422 RETURNS random_variable
AS
5424 SELECT provsql.random_variable_pow(a, provsql.as_random(
0.
5));
5425$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
5435CREATE OR REPLACE
FUNCTION random_variable_cmp_oid(sym TEXT)
5438 SELECT (sym ||
'(double precision,double precision)')::regoperator::oid;
5439$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
5455CREATE OR REPLACE
FUNCTION random_variable_cmp_placeholder(
5456 a random_variable, b random_variable)
5460 RAISE EXCEPTION
'random_variable comparison must be rewritten by the '
5461 'ProvSQL planner hook (is provsql.active off?)';
5463$$
LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
5465CREATE OR REPLACE
FUNCTION random_variable_lt(
5466 a random_variable, b random_variable)
RETURNS BOOLEAN AS
5467$$
SELECT provsql.random_variable_cmp_placeholder(a, b); $$
5468LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
5470CREATE OR REPLACE
FUNCTION random_variable_le(
5471 a random_variable, b random_variable)
RETURNS BOOLEAN AS
5472$$
SELECT provsql.random_variable_cmp_placeholder(a, b); $$
5473LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
5475CREATE OR REPLACE
FUNCTION random_variable_eq(
5476 a random_variable, b random_variable)
RETURNS BOOLEAN AS
5477$$
SELECT provsql.random_variable_cmp_placeholder(a, b); $$
5478LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
5480CREATE OR REPLACE
FUNCTION random_variable_ne(
5481 a random_variable, b random_variable)
RETURNS BOOLEAN AS
5482$$
SELECT provsql.random_variable_cmp_placeholder(a, b); $$
5483LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
5485CREATE OR REPLACE
FUNCTION random_variable_ge(
5486 a random_variable, b random_variable)
RETURNS BOOLEAN AS
5487$$
SELECT provsql.random_variable_cmp_placeholder(a, b); $$
5488LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
5490CREATE OR REPLACE
FUNCTION random_variable_gt(
5491 a random_variable, b random_variable)
RETURNS BOOLEAN AS
5492$$
SELECT provsql.random_variable_cmp_placeholder(a, b); $$
5493LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
5501CREATE OR REPLACE
FUNCTION rv_cmp_lt(
5502 a random_variable, b random_variable)
RETURNS UUID
AS
5504 SELECT provsql.provenance_cmp(
5506 provsql.random_variable_cmp_oid(
'<'),
5508$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
5511CREATE OR REPLACE
FUNCTION rv_cmp_le(
5512 a random_variable, b random_variable)
RETURNS UUID
AS
5514 SELECT provsql.provenance_cmp(
5516 provsql.random_variable_cmp_oid(
'<='),
5518$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
5521CREATE OR REPLACE
FUNCTION rv_cmp_eq(
5522 a random_variable, b random_variable)
RETURNS UUID
AS
5524 SELECT provsql.provenance_cmp(
5526 provsql.random_variable_cmp_oid(
'='),
5528$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
5531CREATE OR REPLACE
FUNCTION rv_cmp_ne(
5532 a random_variable, b random_variable)
RETURNS UUID
AS
5534 SELECT provsql.provenance_cmp(
5536 provsql.random_variable_cmp_oid(
'<>'),
5538$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
5541CREATE OR REPLACE
FUNCTION rv_cmp_ge(
5542 a random_variable, b random_variable)
RETURNS UUID
AS
5544 SELECT provsql.provenance_cmp(
5546 provsql.random_variable_cmp_oid(
'>='),
5548$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
5551CREATE OR REPLACE
FUNCTION rv_cmp_gt(
5552 a random_variable, b random_variable)
RETURNS UUID
AS
5554 SELECT provsql.provenance_cmp(
5556 provsql.random_variable_cmp_oid(
'>'),
5558$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
5561 LEFTARG = random_variable,
5562 RIGHTARG = random_variable,
5563 PROCEDURE = random_variable_plus,
5568 LEFTARG = random_variable,
5569 RIGHTARG = random_variable,
5570 PROCEDURE = random_variable_minus
5574 LEFTARG = random_variable,
5575 RIGHTARG = random_variable,
5576 PROCEDURE = random_variable_times,
5581 LEFTARG = random_variable,
5582 RIGHTARG = random_variable,
5583 PROCEDURE = random_variable_div
5588 RIGHTARG = random_variable,
5589 PROCEDURE = random_variable_neg
5593 LEFTARG = random_variable,
5594 RIGHTARG = random_variable,
5595 PROCEDURE = random_variable_pow
5599 LEFTARG = random_variable,
5600 RIGHTARG = random_variable,
5601 PROCEDURE = random_variable_lt,
5607 LEFTARG = random_variable,
5608 RIGHTARG = random_variable,
5609 PROCEDURE = random_variable_le,
5615 LEFTARG = random_variable,
5616 RIGHTARG = random_variable,
5617 PROCEDURE = random_variable_eq,
5623 LEFTARG = random_variable,
5624 RIGHTARG = random_variable,
5625 PROCEDURE = random_variable_ne,
5631 LEFTARG = random_variable,
5632 RIGHTARG = random_variable,
5633 PROCEDURE = random_variable_ge,
5639 LEFTARG = random_variable,
5640 RIGHTARG = random_variable,
5641 PROCEDURE = random_variable_gt,
5660CREATE OR REPLACE
FUNCTION random_variable_btree_cmp(
5661 a random_variable, b random_variable)
RETURNS INTEGER AS
5664 RAISE EXCEPTION
'comparison or ordering of random_variable values is '
5665 'meaningless: a random_variable is a distribution, not a scalar'
5667 'Compare them as a probabilistic event -- in a WHERE / JOIN clause or '
5668 'with probability(x > y); take order statistics with provsql.greatest / '
5669 'provsql.least (or the min / max aggregates); summarise numerically with '
5670 'expected / variance / support.';
5672$$
LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
5679CREATE OPERATOR CLASS random_variable_ops
5680 DEFAULT FOR TYPE random_variable
USING btree
AS
5686 FUNCTION 1 random_variable_btree_cmp(random_variable, random_variable);
5704CREATE OR REPLACE
FUNCTION random_variable_cond(rv random_variable, cond UUID)
5705 RETURNS random_variable
AS
5713 IF cond
IS NULL OR cond = gate_one()
THEN
5723 cond := provsql.evidence_as_observation(cond);
5726 IF get_gate_type(tgt) =
'conditioned'
5727 AND array_length(get_children(tgt),
1) =
2 THEN
5730 ch := get_children(tgt);
5732 ev := provenance_times(ch[
2], cond);
5737 result := public.uuid_generate_v5(uuid_ns_provsql(),
5738 concat(
'conditioned', tgt, ev));
5739 PERFORM create_gate(
result,
'conditioned',
ARRAY[tgt, ev]);
5740 RETURN (
result)::random_variable;
5742$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public
5743 SECURITY DEFINER PARALLEL SAFE;
5746 LEFTARG = random_variable,
5748 PROCEDURE = random_variable_cond
5762CREATE OR REPLACE
FUNCTION random_variable_cond_predicate(
5763 rv random_variable, predicate
BOOLEAN)
RETURNS random_variable
AS
5766 RAISE EXCEPTION
'random_variable | (predicate) must be rewritten by the '
5767 'ProvSQL planner hook: the right operand must be a Boolean combination '
5768 'of random_variable comparisons (is provsql.active off?)';
5770$$
LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
5773 LEFTARG = random_variable,
5775 PROCEDURE = random_variable_cond_predicate
5786CREATE OR REPLACE
FUNCTION rv_conditioned_target(token UUID)
RETURNS UUID
AS
5789 WHEN provsql.get_gate_type(token) =
'conditioned'
5790 AND array_length(provsql.get_children(token),
1) =
2
5791 THEN (provsql.get_children(token))[
1]
5794$$
LANGUAGE sql STABLE PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
5804CREATE OR REPLACE
FUNCTION rv_conditioned_prov(token UUID, prov UUID)
5808 WHEN provsql.get_gate_type(token) =
'conditioned'
5809 AND array_length(provsql.get_children(token),
1) =
2
5810 THEN provsql.provenance_times((provsql.get_children(token))[
2], prov)
5813$$
LANGUAGE sql STABLE PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
5845CREATE OR REPLACE
FUNCTION evidence_as_observation(ev UUID)
RETURNS UUID
AS
5853 IF ev
IS NULL OR provsql.get_gate_type(ev) <>
'cmp' THEN
5856 ch := provsql.get_children(ev);
5857 IF array_length(ch,
1) <>
2 THEN
5863 SELECT info1
INTO i1
FROM provsql.get_infos(ev);
5864 IF (
SELECT oprname
FROM pg_catalog.pg_operator
WHERE oid = i1)
IS DISTINCT FROM '=' THEN
5867 IF provsql.get_gate_type(ch[
1]) =
'rv'
5868 AND provsql.get_gate_type(ch[
2]) =
'value' THEN
5869 leaf := ch[
1]; datum_gate := ch[
2];
5870 ELSIF provsql.get_gate_type(ch[
2]) =
'rv'
5871 AND provsql.get_gate_type(ch[
1]) =
'value' THEN
5872 leaf := ch[
2]; datum_gate := ch[
1];
5876 RETURN provsql.observe((leaf)::random_variable,
5877 provsql.get_extra(datum_gate)::
double precision);
5879$$
LANGUAGE plpgsql VOLATILE
5880 SET search_path=provsql,pg_temp,public SECURITY DEFINER PARALLEL SAFE;
5903CREATE OR REPLACE
FUNCTION observe(x random_variable, datum
double precision)
5907 leaf UUID := (x)::UUID;
5910 IF provsql.get_gate_type(leaf) <>
'rv' THEN
5911 RAISE EXCEPTION
'provsql.observe: the argument must be a bare '
5912 'random-variable leaf (a gate_rv), got a % gate', provsql.get_gate_type(leaf)
5913 USING HINT =
'observe binds a datum to a single distribution leaf; '
5914 'observing a derived quantity (a sum, product, or comparison) needs '
5915 'a change-of-variables density and is out of scope.';
5917 IF NOT provsql.is_finite_float8(datum)
THEN
5918 RAISE EXCEPTION
'provsql.observe: datum must be finite (got %)', datum;
5920 result := public.uuid_generate_v4();
5921 PERFORM provsql.create_gate(
result,
'observe',
ARRAY[leaf]);
5922 PERFORM provsql.set_extra(
result, datum::TEXT);
5925$$
LANGUAGE plpgsql VOLATILE
5926 SET search_path=provsql,pg_temp,public SECURITY DEFINER PARALLEL SAFE;
5935CREATE OR REPLACE
FUNCTION and_agg_sfunc(state UUID, ev UUID)
5938 SELECT provsql.provenance_times(state, ev);
5939$$
LANGUAGE sql PARALLEL SAFE;
5949CREATE AGGREGATE and_agg(UUID) (
5950 SFUNC = and_agg_sfunc,
5962CREATE OR REPLACE
FUNCTION evidence(evidence UUID)
5963 RETURNS double precision
5964 AS 'provsql',
'rv_evidence' LANGUAGE C STRICT PARALLEL SAFE;
5975CREATE OR REPLACE
FUNCTION observe_atoms(evidence UUID)
5978 WITH RECURSIVE walk(tok)
AS (
5982 FROM walk,
LATERAL unnest(provsql.get_children(walk.tok))
AS c
5983 WHERE provsql.get_gate_type(walk.tok) =
'times'
5985 SELECT array_agg(tok
ORDER BY tok)
5987 WHERE provsql.get_gate_type(tok) =
'observe';
5988$$
LANGUAGE sql STABLE PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
6012CREATE OR REPLACE
FUNCTION shapley_observe(
6013 target UUID, evidence UUID, payoff TEXT
DEFAULT 'expected')
6014 RETURNS TABLE(observation UUID,
value double precision)
AS
6020 pv
double precision[];
6022 fact
double precision[];
6029 sh
double precision;
6033 IF payoff
NOT IN (
'expected',
'variance')
THEN
6034 RAISE EXCEPTION
'provsql.shapley_observe: payoff must be ''expected'' or '
6035 '''variance'' (got %)', payoff;
6037 atoms := provsql.observe_atoms(evidence);
6038 n := coalesce(array_length(atoms,
1),
0);
6040 RAISE EXCEPTION
'provsql.shapley_observe: evidence contains no observe() '
6041 'atoms (got a % gate)', provsql.get_gate_type(evidence);
6044 RAISE EXCEPTION
'provsql.shapley_observe: exact attribution over % '
6045 'observations is exponential; capped at 12 (sampling-based '
6046 'attribution is future work)', n;
6050 fact :=
ARRAY[
1::
double precision];
6051 FOR i
IN 1..n LOOP fact := fact || (fact[i] * i);
END LOOP;
6054 pv := array_fill(
NULL::
double precision,
ARRAY[nmasks]);
6055 popc := array_fill(
0,
ARRAY[nmasks]);
6058 FOR mask
IN 0 .. nmasks -
1 LOOP
6059 subset :=
ARRAY[]::UUID[];
6061 FOR i
IN 0 .. n -
1 LOOP
6062 IF (mask >> i) &
1 =
1 THEN
6063 subset := subset || atoms[i +
1];
6067 popc[mask +
1] := cnt;
6069 ev_s := provsql.gate_one();
6071 ev_s := provsql.provenance_times(VARIADIC subset);
6073 IF payoff =
'expected' THEN
6074 pv[mask +
1] := provsql.rv_moment(target,
1,
false, ev_s);
6076 pv[mask +
1] := provsql.rv_moment(target,
2,
true, ev_s);
6081 FOR i
IN 0 .. n -
1 LOOP
6084 FOR mask
IN 0 .. nmasks -
1 LOOP
6085 IF (mask >> i) &
1 =
0 THEN
6086 s_size := popc[mask +
1];
6088 sh := sh + (fact[s_size +
1] * fact[n - s_size] / fact[n +
1])
6089 * (pv[(mask | bit) +
1] - pv[mask +
1]);
6092 observation := atoms[i +
1];
6097$$
LANGUAGE plpgsql VOLATILE
6098 SET search_path=provsql,pg_temp,public SECURITY DEFINER;
6128CREATE OR REPLACE
FUNCTION "greatest"(VARIADIC args random_variable[])
6129 RETURNS random_variable
AS
6134 IF args
IS NULL THEN
6137 SELECT array_agg(
DISTINCT (a)::UUID)
INTO children
6138 FROM unnest(args) a
WHERE a
IS NOT NULL;
6139 IF children
IS NULL OR array_length(children,
1)
IS NULL THEN
6142 IF array_length(children,
1) =
1 THEN
6143 RETURN provsql.random_variable_make(children[
1]);
6145 RETURN provsql.random_variable_make(
6146 provsql.provenance_arith(
5, children));
6148$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE;
6150CREATE OR REPLACE
FUNCTION "least"(VARIADIC args random_variable[])
6151 RETURNS random_variable
AS
6156 IF args
IS NULL THEN
6159 SELECT array_agg(
DISTINCT (a)::UUID)
INTO children
6160 FROM unnest(args) a
WHERE a
IS NOT NULL;
6161 IF children
IS NULL OR array_length(children,
1)
IS NULL THEN
6164 IF array_length(children,
1) =
1 THEN
6165 RETURN provsql.random_variable_make(children[
1]);
6167 RETURN provsql.random_variable_make(
6168 provsql.provenance_arith(
6, children));
6170$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE;
6181CREATE OR REPLACE
FUNCTION rv_case(
6184RETURNS random_variable
AS
6186 SELECT provsql.random_variable_make(provsql.provenance_case(children));
6187$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
6203CREATE OR REPLACE
FUNCTION agg_case(
6208 SELECT provsql.agg_token_make(t, coalesce(provsql.agg_gate_value(t),
0))
6209 FROM (
SELECT provsql.provenance_case(children)
AS t)
AS s;
6210$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
6255CREATE OR REPLACE
FUNCTION rv_aggregate_semimod(
6256 prov UUID, rv random_variable)
6257 RETURNS random_variable
AS
6259 SELECT provsql.mixture(prov, rv, provsql.as_random(
0::
double precision));
6260$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
6274CREATE OR REPLACE
FUNCTION rv_aggregate_semimod(
6275 prov UUID, rv random_variable,
identity double precision)
6276 RETURNS random_variable
AS
6278 SELECT provsql.mixture(prov, rv, provsql.as_random(
identity));
6279$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
6293CREATE OR REPLACE
FUNCTION rv_aggregate_indicator(prov UUID)
6294 RETURNS random_variable
AS
6296 SELECT provsql.rv_aggregate_semimod(prov, provsql.as_random(
1::
double precision));
6297$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
6310CREATE OR REPLACE
FUNCTION rv_aggregate_indicator(prov UUID, rv random_variable)
6311 RETURNS random_variable
AS
6313 SELECT CASE WHEN rv
IS NULL THEN NULL
6314 ELSE provsql.rv_aggregate_indicator(prov)
END;
6315$$
LANGUAGE sql IMMUTABLE PARALLEL SAFE;
6326CREATE OR REPLACE
FUNCTION sum_rv_sfunc(
6327 state UUID[], rv random_variable)
6331 WHEN rv
IS NULL THEN state
6332 ELSE array_append(state, (rv)::UUID)
6334$$
LANGUAGE sql IMMUTABLE PARALLEL SAFE;
6349CREATE OR REPLACE
FUNCTION sum_rv_ffunc(state UUID[])
6350 RETURNS random_variable
AS
6355 IF state
IS NULL OR array_length(state,
1)
IS NULL THEN
6358 IF array_length(state,
1) =
1 THEN
6359 RETURN provsql.random_variable_make(state[
1]);
6361 arith_token := provsql.provenance_arith(
0, state);
6362 RETURN provsql.random_variable_make(arith_token);
6364$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE;
6366CREATE AGGREGATE sum(random_variable) (
6367 SFUNC = sum_rv_sfunc,
6370 FINALFUNC = sum_rv_ffunc
6386CREATE OR REPLACE
FUNCTION rv_sum_or_null_ffunc(state UUID[])
6387 RETURNS random_variable
AS
6390 IF state
IS NULL OR array_length(state,
1)
IS NULL THEN
6393 IF array_length(state,
1) =
1 THEN
6394 RETURN provsql.random_variable_make(state[
1]);
6396 RETURN provsql.random_variable_make(
6397 provsql.provenance_arith(
0, state));
6399$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE;
6401CREATE AGGREGATE rv_sum_or_null(random_variable) (
6402 SFUNC = sum_rv_sfunc,
6405 FINALFUNC = rv_sum_or_null_ffunc
6432CREATE OR REPLACE
FUNCTION avg_rv_ffunc(state UUID[])
6433 RETURNS random_variable
AS
6440 denom_state UUID[] :=
'{}';
6443 IF state
IS NULL THEN
6446 n := array_length(state,
1);
6451 one_uuid := (provsql.as_random(
1::
double precision))::UUID;
6453 denom_state := array_append(denom_state, one_uuid);
6457 num_token := state[
1];
6458 denom_token := denom_state[
1];
6460 num_token := provsql.provenance_arith(
0, state);
6461 denom_token := provsql.provenance_arith(
0, denom_state);
6464 RETURN provsql.random_variable_make(
6465 provsql.provenance_arith(
6467 ARRAY[num_token, denom_token]));
6469$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE;
6471CREATE AGGREGATE avg(random_variable) (
6472 SFUNC = sum_rv_sfunc,
6475 FINALFUNC = avg_rv_ffunc
6503CREATE OR REPLACE
FUNCTION product_rv_ffunc(state UUID[])
6504 RETURNS random_variable
AS
6507 IF state
IS NULL OR array_length(state,
1)
IS NULL THEN
6510 IF array_length(state,
1) =
1 THEN
6511 RETURN provsql.random_variable_make(state[
1]);
6513 RETURN provsql.random_variable_make(
6514 provsql.provenance_arith(
1, state));
6516$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE;
6518CREATE AGGREGATE product(random_variable) (
6519 SFUNC = sum_rv_sfunc,
6522 FINALFUNC = product_rv_ffunc
6550CREATE OR REPLACE
FUNCTION extremum_rv_ffunc(
6551 state UUID[], op
INTEGER,
identity double precision)
6552 RETURNS random_variable
AS
6555 IF state
IS NULL OR array_length(state,
1)
IS NULL THEN
6558 IF array_length(state,
1) =
1 THEN
6559 RETURN provsql.random_variable_make(state[
1]);
6561 RETURN provsql.random_variable_make(
6562 provsql.provenance_arith(op, state));
6564$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE;
6566CREATE OR REPLACE
FUNCTION max_rv_ffunc(state UUID[])
6567 RETURNS random_variable
AS
6570 SELECT provsql.extremum_rv_ffunc(state,
5,
'-Infinity'::
double precision);
6571$$
LANGUAGE sql IMMUTABLE PARALLEL SAFE;
6573CREATE OR REPLACE
FUNCTION min_rv_ffunc(state UUID[])
6574 RETURNS random_variable
AS
6577 SELECT provsql.extremum_rv_ffunc(state,
6,
'Infinity'::
double precision);
6578$$
LANGUAGE sql IMMUTABLE PARALLEL SAFE;
6580CREATE AGGREGATE max(random_variable) (
6581 SFUNC = sum_rv_sfunc,
6584 FINALFUNC = max_rv_ffunc
6587CREATE AGGREGATE min(random_variable) (
6588 SFUNC = sum_rv_sfunc,
6591 FINALFUNC = min_rv_ffunc
6619CREATE OR REPLACE
FUNCTION rv_stat1_sfunc(state UUID[], x random_variable)
6623 WHEN x
IS NULL THEN state
6624 ELSE state ||
ARRAY[(provsql.as_random(
1::
double precision))::UUID,
6627$$
LANGUAGE sql IMMUTABLE PARALLEL SAFE;
6633CREATE OR REPLACE
FUNCTION rv_stat2_sfunc(
6634 state UUID[], x random_variable, y random_variable)
6638 WHEN x
IS NULL OR y
IS NULL THEN state
6639 ELSE state ||
ARRAY[(provsql.as_random(
1::
double precision))::UUID,
6640 (x)::UUID, (y)::UUID]
6642$$
LANGUAGE sql IMMUTABLE PARALLEL SAFE;
6647CREATE OR REPLACE
FUNCTION rv_stat1_impl_sfunc(
6648 state UUID[], ind random_variable, x random_variable)
6652 WHEN x
IS NULL THEN state
6653 ELSE state ||
ARRAY[coalesce((ind)::UUID,
6654 (provsql.as_random(
1::
double precision))::UUID),
6657$$
LANGUAGE sql IMMUTABLE PARALLEL SAFE;
6661CREATE OR REPLACE
FUNCTION rv_stat2_impl_sfunc(
6662 state UUID[], ind random_variable, x random_variable, y random_variable)
6666 WHEN x
IS NULL OR y
IS NULL THEN state
6667 ELSE state ||
ARRAY[coalesce((ind)::UUID,
6668 (provsql.as_random(
1::
double precision))::UUID),
6669 (x)::UUID, (y)::UUID]
6671$$
LANGUAGE sql IMMUTABLE PARALLEL SAFE;
6688CREATE OR REPLACE
FUNCTION rv_stat_sum_tokens(
6689 state UUID[], stride
INTEGER,
6690 OUT n_tok UUID,
OUT sx_tok UUID,
OUT sxx_tok UUID,
6691 OUT sy_tok UUID,
OUT sxy_tok UUID,
OUT syy_tok UUID)
6695 nrows
INTEGER := coalesce(array_length(state,
1),
0) / stride;
6696 inds UUID[] :=
'{}';
6706 FOR i
IN 1..nrows LOOP
6707 ind := state[(i-1) * stride +
1];
6708 x := state[(i-1) * stride +
2];
6709 inds := array_append(inds, ind);
6710 xs := array_append(xs, provenance_arith(
1,
ARRAY[ind, x]));
6711 xxs := array_append(xxs, provenance_arith(
1,
ARRAY[ind, x, x]));
6713 y := state[(i-1) * stride +
3];
6714 ys := array_append(ys, provenance_arith(
1,
ARRAY[ind, y]));
6715 xys := array_append(xys, provenance_arith(
1,
ARRAY[ind, x, y]));
6716 yys := array_append(yys, provenance_arith(
1,
ARRAY[ind, y, y]));
6719 n_tok := provenance_arith(
0, inds);
6720 sx_tok := provenance_arith(
0, xs);
6721 sxx_tok := provenance_arith(
0, xxs);
6723 sy_tok := provenance_arith(
0, ys);
6724 sxy_tok := provenance_arith(
0, xys);
6725 syy_tok := provenance_arith(
0, yys);
6728$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE
6729 SET search_path=provsql,pg_temp,public SECURITY DEFINER;
6733CREATE OR REPLACE
FUNCTION rv_stat_var_pop_token(
6734 n_tok UUID, s_tok UUID, ss_tok UUID)
6737 SELECT provsql.provenance_arith(
2,
ARRAY[
6738 provsql.provenance_arith(
3,
ARRAY[ss_tok, n_tok]),
6739 provsql.provenance_arith(
1,
ARRAY[
6740 provsql.provenance_arith(
3,
ARRAY[s_tok, n_tok]),
6741 provsql.provenance_arith(
3,
ARRAY[s_tok, n_tok])])]);
6742$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
6747CREATE OR REPLACE
FUNCTION rv_stat_var_samp_token(
6748 n_tok UUID, s_tok UUID, ss_tok UUID)
6751 SELECT provsql.provenance_arith(
3,
ARRAY[
6752 provsql.provenance_arith(
2,
ARRAY[
6754 provsql.provenance_arith(
3,
ARRAY[
6755 provsql.provenance_arith(
1,
ARRAY[s_tok, s_tok]), n_tok])]),
6756 provsql.provenance_arith(
2,
ARRAY[
6757 n_tok, (provsql.as_random(
1::
double precision))::UUID])]);
6758$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
6763CREATE OR REPLACE
FUNCTION rv_stat_sqrt_token(v_tok UUID)
6766 SELECT provsql.provenance_arith(
7,
ARRAY[
6767 provsql.provenance_arith(
5,
ARRAY[
6768 v_tok, (provsql.as_random(
0::
double precision))::UUID]),
6769 (provsql.as_random(
0.
5::
double precision))::UUID]);
6770$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
6774CREATE OR REPLACE
FUNCTION rv_stat_covar_pop_token(
6775 n_tok UUID, sx_tok UUID, sy_tok UUID, sxy_tok UUID)
6778 SELECT provsql.provenance_arith(
2,
ARRAY[
6779 provsql.provenance_arith(
3,
ARRAY[sxy_tok, n_tok]),
6780 provsql.provenance_arith(
1,
ARRAY[
6781 provsql.provenance_arith(
3,
ARRAY[sx_tok, n_tok]),
6782 provsql.provenance_arith(
3,
ARRAY[sy_tok, n_tok])])]);
6783$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
6786CREATE OR REPLACE
FUNCTION covar_pop_rv_ffunc(state UUID[])
6787 RETURNS random_variable
AS
6792 IF state
IS NULL OR array_length(state,
1)
IS NULL THEN
6795 SELECT *
INTO t
FROM rv_stat_sum_tokens(state,
3);
6796 RETURN random_variable_make(
6797 rv_stat_covar_pop_token(t.n_tok, t.sx_tok, t.sy_tok, t.sxy_tok));
6799$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE
6800 SET search_path=provsql,pg_temp,public SECURITY DEFINER;
6804CREATE OR REPLACE
FUNCTION covar_samp_rv_ffunc(state UUID[])
6805 RETURNS random_variable
AS
6810 IF state
IS NULL OR array_length(state,
1)
IS NULL THEN
6813 SELECT *
INTO t
FROM rv_stat_sum_tokens(state,
3);
6814 RETURN random_variable_make(
6815 provenance_arith(
3,
ARRAY[
6816 provenance_arith(
2,
ARRAY[
6818 provenance_arith(
3,
ARRAY[
6819 provenance_arith(
1,
ARRAY[t.sx_tok, t.sy_tok]), t.n_tok])]),
6820 provenance_arith(
2,
ARRAY[
6821 t.n_tok, (as_random(
1::
double precision))::UUID])]));
6823$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE
6824 SET search_path=provsql,pg_temp,public SECURITY DEFINER;
6830CREATE OR REPLACE
FUNCTION corr_rv_ffunc(state UUID[])
6831 RETURNS random_variable
AS
6838 IF state
IS NULL OR array_length(state,
1)
IS NULL THEN
6841 SELECT *
INTO t
FROM rv_stat_sum_tokens(state,
3);
6842 vx := rv_stat_var_pop_token(t.n_tok, t.sx_tok, t.sxx_tok);
6843 vy := rv_stat_var_pop_token(t.n_tok, t.sy_tok, t.syy_tok);
6844 RETURN random_variable_make(
6845 provenance_arith(
3,
ARRAY[
6846 rv_stat_covar_pop_token(t.n_tok, t.sx_tok, t.sy_tok, t.sxy_tok),
6847 rv_stat_sqrt_token(provenance_arith(
1,
ARRAY[vx, vy]))]));
6849$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE
6850 SET search_path=provsql,pg_temp,public SECURITY DEFINER;
6853CREATE OR REPLACE
FUNCTION stddev_pop_rv_ffunc(state UUID[])
6854 RETURNS random_variable
AS
6859 IF state
IS NULL OR array_length(state,
1)
IS NULL THEN
6862 SELECT *
INTO t
FROM rv_stat_sum_tokens(state,
2);
6863 RETURN random_variable_make(
6865 rv_stat_var_pop_token(t.n_tok, t.sx_tok, t.sxx_tok)));
6867$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE
6868 SET search_path=provsql,pg_temp,public SECURITY DEFINER;
6871CREATE OR REPLACE
FUNCTION stddev_samp_rv_ffunc(state UUID[])
6872 RETURNS random_variable
AS
6877 IF state
IS NULL OR array_length(state,
1)
IS NULL THEN
6880 SELECT *
INTO t
FROM rv_stat_sum_tokens(state,
2);
6881 RETURN random_variable_make(
6883 rv_stat_var_samp_token(t.n_tok, t.sx_tok, t.sxx_tok)));
6885$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE
6886 SET search_path=provsql,pg_temp,public SECURITY DEFINER;
6888CREATE AGGREGATE covar_pop(random_variable, random_variable) (
6889 SFUNC = rv_stat2_sfunc,
6892 FINALFUNC = covar_pop_rv_ffunc
6895CREATE AGGREGATE covar_samp(random_variable, random_variable) (
6896 SFUNC = rv_stat2_sfunc,
6899 FINALFUNC = covar_samp_rv_ffunc
6902CREATE AGGREGATE corr(random_variable, random_variable) (
6903 SFUNC = rv_stat2_sfunc,
6906 FINALFUNC = corr_rv_ffunc
6909CREATE AGGREGATE stddev_pop(random_variable) (
6910 SFUNC = rv_stat1_sfunc,
6913 FINALFUNC = stddev_pop_rv_ffunc
6916CREATE AGGREGATE stddev_samp(random_variable) (
6917 SFUNC = rv_stat1_sfunc,
6920 FINALFUNC = stddev_samp_rv_ffunc
6926CREATE AGGREGATE rv_covar_pop_impl(
6927 random_variable, random_variable, random_variable) (
6928 SFUNC = rv_stat2_impl_sfunc,
6931 FINALFUNC = covar_pop_rv_ffunc
6934CREATE AGGREGATE rv_covar_samp_impl(
6935 random_variable, random_variable, random_variable) (
6936 SFUNC = rv_stat2_impl_sfunc,
6939 FINALFUNC = covar_samp_rv_ffunc
6942CREATE AGGREGATE rv_corr_impl(
6943 random_variable, random_variable, random_variable) (
6944 SFUNC = rv_stat2_impl_sfunc,
6947 FINALFUNC = corr_rv_ffunc
6950CREATE AGGREGATE rv_stddev_pop_impl(random_variable, random_variable) (
6951 SFUNC = rv_stat1_impl_sfunc,
6954 FINALFUNC = stddev_pop_rv_ffunc
6957CREATE AGGREGATE rv_stddev_samp_impl(random_variable, random_variable) (
6958 SFUNC = rv_stat1_impl_sfunc,
6961 FINALFUNC = stddev_samp_rv_ffunc
6976CREATE OR REPLACE
FUNCTION rv_percentile_make(fraction
double precision,
6978 RETURNS random_variable
AS
6983 IF fraction
IS NULL THEN
6986 IF fraction <
0 OR fraction >
1 THEN
6988 'percentile_cont: fraction must be between 0 and 1 (got %)', fraction;
6990 token := public.uuid_generate_v5(
6992 concat(
'arith',
'10', pairs::TEXT, fraction::TEXT));
6993 PERFORM create_gate(token,
'arith', pairs);
6994 PERFORM set_infos(token,
10);
6995 PERFORM set_extra(token, fraction::TEXT);
6996 RETURN random_variable_make(token);
6998$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE
6999 SET search_path=provsql,pg_temp,public SECURITY DEFINER;
7008CREATE OR REPLACE
FUNCTION percentile_cont_rv_sfunc(
7009 state UUID[], x random_variable)
7012 SELECT provsql.rv_stat1_sfunc(state, x);
7013$$
LANGUAGE sql IMMUTABLE PARALLEL SAFE;
7017CREATE OR REPLACE
FUNCTION percentile_cont_rv_ffunc(
7018 state UUID[], fraction
double precision)
7019 RETURNS random_variable
AS
7022 WHEN state
IS NULL OR array_length(state,
1)
IS NULL THEN NULL
7023 ELSE provsql.rv_percentile_make(fraction, state)
7025$$
LANGUAGE sql IMMUTABLE PARALLEL SAFE;
7027CREATE AGGREGATE percentile_cont(
double precision ORDER BY random_variable) (
7028 SFUNC = percentile_cont_rv_sfunc,
7031 FINALFUNC = percentile_cont_rv_ffunc
7036CREATE TYPE rv_percentile_state
AS (
7037 fraction
double precision,
7044CREATE OR REPLACE
FUNCTION rv_percentile_impl_sfunc(
7045 state rv_percentile_state, fraction
double precision,
7046 ind random_variable, x random_variable)
7047 RETURNS rv_percentile_state
AS
7050 coalesce((state).fraction, fraction),
7052 WHEN x
IS NULL THEN (state).tokens
7053 ELSE (state).tokens ||
7054 ARRAY[coalesce((ind)::UUID,
7055 (provsql.as_random(
1::
double precision))::UUID),
7057 END)::provsql.rv_percentile_state;
7058$$
LANGUAGE sql IMMUTABLE PARALLEL SAFE;
7061CREATE OR REPLACE
FUNCTION rv_percentile_impl_ffunc(state rv_percentile_state)
7062 RETURNS random_variable
AS
7065 WHEN state
IS NULL OR array_length((state).tokens,
1)
IS NULL THEN NULL
7066 ELSE provsql.rv_percentile_make((state).fraction, (state).tokens)
7068$$
LANGUAGE sql IMMUTABLE PARALLEL SAFE;
7070CREATE AGGREGATE rv_percentile_impl(
7071 double precision, random_variable, random_variable) (
7072 SFUNC = rv_percentile_impl_sfunc,
7073 STYPE = rv_percentile_state,
7074 INITCOND =
'(,"{}")',
7075 FINALFUNC = rv_percentile_impl_ffunc
7096CREATE OR REPLACE
FUNCTION provenance_delta
7105 IF token
IS NULL THEN
7109 IF token = gate_zero()
OR token = gate_one()
THEN
7113 delta_token:=uuid_generate_v5(uuid_ns_provsql(),concat(
'delta',token));
7115 PERFORM create_gate(delta_token,
'delta',
ARRAY[token::UUID]);
7119$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public SECURITY DEFINER PARALLEL SAFE IMMUTABLE;
7136CREATE OR REPLACE
FUNCTION provenance_aggregate(
7141 is_scalar
BOOLEAN DEFAULT false)
7142 RETURNS AGG_TOKEN
AS
7152 tokens := array_remove(tokens,
NULL);
7153 c:=COALESCE(array_length(tokens,
1),
0);
7155 agg_val =
CAST(val
as VARCHAR);
7158 agg_tok := gate_zero();
7171 agg_tok := uuid_generate_v5(
7173 concat(
'agg',aggfnoid,tokens,
CASE WHEN is_scalar
THEN 'S' ELSE '' END));
7174 PERFORM create_gate(agg_tok,
'agg', tokens);
7175 PERFORM set_infos(agg_tok, aggfnoid,
7176 CASE WHEN is_scalar
THEN aggtype | (-2147483648)
ELSE aggtype
END);
7177 PERFORM set_extra(agg_tok, agg_val);
7180 RETURN '( '||agg_tok||
' , '||agg_val||
' )';
7182$$
LANGUAGE plpgsql PARALLEL SAFE
SET search_path=provsql,pg_temp,public SECURITY DEFINER IMMUTABLE;
7193CREATE OR REPLACE
FUNCTION provenance_semimod(val ANYELEMENT, token UUID)
7208 SELECT uuid_generate_v5(uuid_ns_provsql(),concat(
'value',
CAST(val
AS VARCHAR)))
7210 SELECT uuid_generate_v5(uuid_ns_provsql(),concat(
'semimod',value_token,token))
7214 PERFORM create_gate(value_token,
'value');
7215 PERFORM set_extra(value_token,
CAST(val
AS VARCHAR));
7218 PERFORM create_gate(semimod_token,
'semimod',
ARRAY[token::UUID,value_token]);
7220 RETURN semimod_token;
7222$$
LANGUAGE plpgsql PARALLEL SAFE
SET search_path=provsql,pg_temp,public SECURITY DEFINER IMMUTABLE;
7248CREATE OR REPLACE
FUNCTION probability_evaluate(
7251 arguments TEXT =
NULL)
7252 RETURNS DOUBLE PRECISION AS
7253 'provsql',
'probability_evaluate' LANGUAGE C STABLE;
7268CREATE OR REPLACE
FUNCTION probability(
7271 arguments TEXT =
NULL)
7272 RETURNS DOUBLE PRECISION AS
7273 'provsql',
'probability_evaluate' LANGUAGE C STABLE;
7302CREATE OR REPLACE
FUNCTION probability(
7305 arguments TEXT =
NULL)
7306 RETURNS DOUBLE PRECISION AS
7308 SELECT predicate::
INTEGER::
double precision;
7309$$
LANGUAGE sql IMMUTABLE PARALLEL SAFE;
7318CREATE OR REPLACE
FUNCTION probability_bounds(
7320 OUT lower
DOUBLE PRECISION,
7321 OUT upper DOUBLE PRECISION)
AS
7322 'provsql',
'probability_bounds' LANGUAGE C STABLE;
7345CREATE OR REPLACE
FUNCTION expected(
7347 prov UUID = gate_one(),
7349 arguments TEXT =
NULL)
7350 RETURNS DOUBLE PRECISION AS $$
7351 SELECT moment(
input,
1, prov,
method, arguments);
7352$$
LANGUAGE sql PARALLEL SAFE STABLE
SET search_path=provsql SECURITY DEFINER;
7364CREATE OR REPLACE
FUNCTION rv_moment(
7365 token UUID, k
INTEGER, central
BOOLEAN,
7366 prov UUID
DEFAULT gate_one())
7367 RETURNS double precision
7368 AS 'provsql',
'rv_moment' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
7374CREATE OR REPLACE
FUNCTION agg_avg_moment_exact(token UUID, k
INTEGER)
7375 RETURNS double precision
7376 AS 'provsql',
'agg_avg_moment_exact' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
7384CREATE OR REPLACE
FUNCTION agg_collapsed_moment(token UUID, k
INTEGER)
7385 RETURNS double precision
7386 AS 'provsql',
'agg_collapsed_moment' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
7393CREATE OR REPLACE
FUNCTION agg_collapsed_moments(token UUID)
7394 RETURNS double precision[]
7395 AS 'provsql',
'agg_collapsed_moments' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
7413CREATE OR REPLACE
FUNCTION agg_defined_event(token UUID)
7416 gt PROVENANCE_GATE := get_gate_type(token);
7423 running_neg UUID := gate_one();
7424 parts UUID[] :=
'{}';
7427 SELECT proname
INTO fname
7428 FROM pg_proc
WHERE oid = (get_infos(token)).info1;
7429 IF fname
IN (
'sum',
'count')
THEN
7432 SELECT array_agg((get_children(c))[
1])
INTO toks
7433 FROM unnest(get_children(token))
AS c;
7434 IF toks
IS NULL THEN
7437 RETURN provenance_plus(toks);
7438 ELSIF gt =
'case' THEN
7439 wires := get_children(token);
7440 nw := array_length(wires,
1);
7443 parts := parts || provenance_times(
7444 running_neg, wires[
2 * i -
1],
7445 agg_defined_event(wires[
2 * i]));
7446 running_neg := provenance_times(running_neg,
7447 provenance_not(wires[
2 * i -
1]));
7449 parts := parts || provenance_times(running_neg,
7450 agg_defined_event(wires[nw]));
7451 RETURN provenance_plus(parts);
7456$$
LANGUAGE plpgsql STABLE STRICT PARALLEL SAFE
7457 SET search_path=provsql,pg_temp,public SECURITY DEFINER;
7489CREATE OR REPLACE
FUNCTION agg_raw_moment(
7492 prov UUID = gate_one(),
7494 arguments TEXT =
NULL)
7495 RETURNS DOUBLE PRECISION AS $$
7497 aggregation_function
VARCHAR;
7499 pair_children UUID[];
7506 total_probability float8;
7510 distinct_tok UUID[];
7515 IF token
IS NULL OR k
IS NULL THEN
7519 RAISE EXCEPTION
'agg_raw_moment(): k must be non-negative (got %)', k;
7541 IF get_gate_type(token) =
'case' THEN
7546 wires UUID[] := get_children(token);
7547 nw
INTEGER := array_length(get_children(token),
1);
7548 m
INTEGER := (array_length(get_children(token),
1) -
1) /
2;
7549 running_neg UUID := gate_one();
7554 def_mass float8 :=
0;
7559 prov_p := probability(prov);
7560 IF prov_p
IS NULL OR prov_p <=
0 THEN
7565 FOR ci
IN 1 .. m +
1 LOOP
7567 region_full := provenance_times(running_neg, wires[
2 * ci -
1], prov);
7568 vuid := wires[
2 * ci];
7570 provenance_times(running_neg, provenance_not(wires[
2 * ci -
1]));
7572 region_full := provenance_times(running_neg, prov);
7575 p := probability(provenance_times(region_full,
7576 agg_defined_event(vuid)));
7584 IF get_gate_type(vuid) =
'value' THEN
7585 bm := power(
CAST(get_extra(vuid)
AS float8), k);
7586 ELSIF get_gate_type(vuid)
IN (
'agg',
'case')
THEN
7587 bm := agg_raw_moment(agg_token_make(vuid,
0), k, region_full,
7590 bm := rv_moment(vuid, k,
false, region_full);
7592 total := total + p * bm;
7593 def_mass := def_mass + p;
7596 IF def_mass <= epsilon()
THEN
7599 RETURN total / def_mass;
7603 IF get_gate_type(token) <>
'agg' THEN
7604 IF get_gate_type(token)
IN (
'arith',
'conditioned')
THEN
7605 RAISE EXCEPTION
'expected / variance / moment over an arithmetic '
7606 'combination of aggregates (e.g. SUM(x) + SUM(y) or SUM(x) + 5), or a '
7607 'conditioning of one, is not yet supported: a moment can be taken only '
7608 'over a single aggregate (SUM / COUNT / MIN / MAX), optionally '
7609 'conditioned (SUM(x) | C)'
7610 USING HINT =
'Take the moment of each aggregate separately, or condition '
7611 'the bare aggregate.';
7613 RAISE EXCEPTION
USING MESSAGE=
'Wrong gate type for agg_raw_moment computation';
7620 SELECT pp.proname::
varchar FROM pg_proc pp
7621 WHERE oid=(get_infos(token)).info1
7622 INTO aggregation_function;
7624 child_pairs := get_children(token);
7625 n := COALESCE(array_length(child_pairs,
1),
0);
7627 IF aggregation_function =
'sum' OR aggregation_function =
'count' THEN
7646 IF prov = gate_one()
AND k <=
2 THEN
7647 total := agg_collapsed_moment((token)::UUID, k);
7648 IF total
IS NOT NULL THEN
7654 vals :=
ARRAY[]::float8[];
7655 toks :=
ARRAY[]::UUID[];
7657 pair_children := get_children(child_pairs[i]);
7658 toks := toks || pair_children[
1];
7659 vals := vals ||
CAST(get_extra(pair_children[
2])
AS float8);
7665 tup := array_fill(
1,
ARRAY[k]);
7669 prod_v := prod_v * vals[tup[j]];
7672 SELECT array_agg(
DISTINCT toks[idx])
INTO distinct_tok
7673 FROM unnest(tup)
AS idx;
7675 IF prov <> gate_one()
THEN
7676 distinct_tok := distinct_tok || prov;
7678 conj_token := provenance_times(VARIADIC distinct_tok);
7679 prob := probability_evaluate(conj_token,
method, arguments);
7681 total := total + prod_v * prob;
7684 WHILE d >=
1 AND tup[d] = n LOOP
7689 tup[d] := tup[d] +
1;
7691 ELSIF aggregation_function =
'min' OR aggregation_function =
'max' THEN
7699 WHEN aggregation_function =
'max'
7700 THEN power(-1::float8, k)
7716 SELECT (get_children(c))[
1]
AS tok,
7717 (
CASE WHEN aggregation_function=
'max' THEN -1
ELSE 1 END)
7718 *
CAST(get_extra((get_children(c))[
2])
AS DOUBLE PRECISION)
AS v
7719 FROM UNNEST(child_pairs)
AS c
7720 )
SELECT sign_max * COALESCE(SUM(p * power(v, k)),
0)
FROM (
7722 probability_evaluate(
7723 CASE WHEN prov = gate_one()
7724 THEN provenance_monus(provenance_plus(ARRAY_AGG(t1.tok)),
7725 provenance_plus(ARRAY_AGG(t2.tok)))
7726 ELSE provenance_times(prov,
7727 provenance_monus(provenance_plus(ARRAY_AGG(t1.tok)),
7728 provenance_plus(ARRAY_AGG(t2.tok))))
END,
7729 method, arguments)
AS p
7730 FROM tok_value t1
LEFT OUTER JOIN tok_value t2
ON t1.v > t2.v
7735 SELECT probability_evaluate(
7736 CASE WHEN prov = gate_one()
7737 THEN provenance_plus(ARRAY_AGG(tok))
7738 ELSE provenance_times(prov, provenance_plus(ARRAY_AGG(tok)))
END,
7740 FROM (
SELECT (get_children(c))[
1]
AS tok
FROM UNNEST(child_pairs)
AS c) s
7741 INTO total_probability;
7743 IF total_probability <= epsilon()
THEN
7746 RETURN total / total_probability;
7747 ELSIF aggregation_function =
'avg' THEN
7764 IF prov = gate_one()
THEN
7765 total := agg_avg_moment_exact((token)::UUID, k);
7766 IF total
IS NOT NULL THEN
7770 RETURN rv_moment((token)::UUID, k,
false, prov);
7772 RAISE EXCEPTION
USING MESSAGE=
7773 'Cannot compute moment for aggregation function ' || aggregation_function;
7777 IF prov <> gate_one()
7779 AND total <>
'Infinity'::float8
7780 AND total <>
'-Infinity'::float8
THEN
7781 total := total / probability_evaluate(prov,
method, arguments);
7786$$
LANGUAGE plpgsql PARALLEL SAFE
SET search_path=provsql SECURITY DEFINER;
7799CREATE OR REPLACE
FUNCTION variance(
7801 prov UUID = gate_one(),
7803 arguments TEXT =
NULL)
7804 RETURNS DOUBLE PRECISION AS $$
7809 IF pg_typeof(
input) =
'random_variable'::REGTYPE
THEN
7810 IF input IS NULL THEN
7820 RETURN provsql.rv_moment(
7821 rv_conditioned_target((
input::random_variable)::UUID),
2,
true,
7822 rv_conditioned_prov((
input::random_variable)::UUID, prov));
7825 IF pg_typeof(
input) =
'AGG_TOKEN'::REGTYPE
THEN
7826 IF input IS NULL THEN
7834 IF rv_conditioned_prov(
input::UUID, prov) = gate_one()
THEN
7835 DECLARE ms float8[];
7837 ms := agg_collapsed_moments(
7838 (agg_conditioned_target(
input::AGG_TOKEN))::UUID);
7839 IF ms
IS NOT NULL THEN
7840 RETURN ms[
2] - ms[
1] * ms[
1];
7844 m1 := agg_raw_moment(agg_conditioned_target(
input::AGG_TOKEN),
1,
7845 rv_conditioned_prov(
input::UUID, prov),
method, arguments);
7846 m2 := agg_raw_moment(agg_conditioned_target(
input::AGG_TOKEN),
2,
7847 rv_conditioned_prov(
input::UUID, prov),
method, arguments);
7848 IF m1
IS NULL OR m2
IS NULL THEN
7851 RETURN m2 - m1 * m1;
7855 IF pg_typeof(
input) =
'UUID'::REGTYPE
THEN
7856 IF input IS NULL THEN
7859 m1 := provsql.probability_evaluate(provsql.cond(
input::UUID, prov),
7861 RETURN m1 * (
1 - m1);
7864 RAISE EXCEPTION
'variance() is not yet supported for input type %', pg_typeof(
input);
7866$$
LANGUAGE plpgsql PARALLEL SAFE
SET search_path=provsql SECURITY DEFINER;
7879CREATE OR REPLACE
FUNCTION moment(
7882 prov UUID = gate_one(),
7884 arguments TEXT =
NULL)
7885 RETURNS DOUBLE PRECISION AS $$
7887 IF pg_typeof(
input) =
'random_variable'::REGTYPE
THEN
7888 IF input IS NULL OR k
IS NULL THEN
7893 RETURN provsql.rv_moment(
7894 rv_conditioned_target((
input::random_variable)::UUID), k,
false,
7895 rv_conditioned_prov((
input::random_variable)::UUID, prov));
7898 IF pg_typeof(
input) =
'AGG_TOKEN'::REGTYPE
THEN
7899 RETURN agg_raw_moment(agg_conditioned_target(
input::AGG_TOKEN), k,
7900 rv_conditioned_prov(
input::UUID, prov),
method, arguments);
7907 IF pg_typeof(
input) =
'UUID'::REGTYPE
THEN
7908 IF input IS NULL OR k
IS NULL THEN
7914 RETURN provsql.probability_evaluate(provsql.cond(
input::UUID, prov),
7918 RAISE EXCEPTION
'moment() is not yet supported for input type %', pg_typeof(
input);
7920$$
LANGUAGE plpgsql PARALLEL SAFE
SET search_path=provsql SECURITY DEFINER;
7935CREATE OR REPLACE
FUNCTION rv_quantile(
7936 token UUID, p
double precision,
7937 prov UUID
DEFAULT gate_one())
7938 RETURNS double precision
7939 AS 'provsql',
'rv_quantile' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
7955CREATE OR REPLACE
FUNCTION quantile(
7958 prov UUID = gate_one(),
7960 arguments TEXT =
NULL)
7961 RETURNS DOUBLE PRECISION AS $$
7966 IF p <> p
OR p <
0 OR p >
1 THEN
7967 RAISE EXCEPTION
'quantile: p must be in [0, 1] (got %)', p;
7970 IF pg_typeof(
input) =
'random_variable'::REGTYPE
THEN
7971 IF input IS NULL THEN
7976 RETURN provsql.rv_quantile(
7977 rv_conditioned_target((
input::random_variable)::UUID), p,
7978 rv_conditioned_prov((
input::random_variable)::UUID, prov));
7981 IF pg_typeof(
input)
IN (
'smallint'::REGTYPE,
'INTEGER'::REGTYPE,
7982 'bigint'::REGTYPE,
'NUMERIC'::REGTYPE,
7983 'real'::REGTYPE,
'double precision'::REGTYPE)
THEN
7985 RETURN input::
double precision;
7988 RAISE EXCEPTION
'quantile() is not yet supported for input type %', pg_typeof(
input);
7990$$
LANGUAGE plpgsql PARALLEL SAFE
SET search_path=provsql SECURITY DEFINER;
8001CREATE OR REPLACE
FUNCTION rv_support(
8002 token UUID, prov UUID
DEFAULT gate_one(),
8003 OUT lo float8,
OUT hi float8)
8004 AS 'provsql',
'rv_support' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
8046CREATE OR REPLACE
FUNCTION support(
8048 prov UUID = gate_one(),
8050 arguments TEXT =
NULL,
8055 aggregation_function
VARCHAR;
8057 values_arr float8[];
8058 total_probability float8;
8060 IF input IS NULL THEN
8061 lo :=
NULL; hi :=
NULL;
RETURN;
8067 IF pg_typeof(
input)
IN (
8068 'smallint'::REGTYPE,
'INTEGER'::REGTYPE,
'bigint'::REGTYPE,
8069 'NUMERIC'::REGTYPE,
'real'::REGTYPE,
'double precision'::REGTYPE)
THEN
8070 lo :=
input::
double precision;
8071 hi :=
input::
double precision;
8084 IF pg_typeof(
input)
IN (
'random_variable'::REGTYPE,
'UUID'::REGTYPE)
THEN
8089 SELECT r.lo, r.hi
INTO lo, hi
8090 FROM provsql.rv_support(
8091 rv_conditioned_target(
input::UUID),
8092 rv_conditioned_prov(
input::UUID, prov)) r;
8096 IF pg_typeof(
input) =
'AGG_TOKEN'::REGTYPE
THEN
8101 atok AGG_TOKEN := agg_conditioned_target(
input::AGG_TOKEN);
8103 IF get_gate_type(atok) <>
'agg' THEN
8104 RAISE EXCEPTION
USING MESSAGE=
'Wrong gate type for support computation';
8106 SELECT pp.proname::
varchar FROM pg_proc pp
8107 WHERE oid=(get_infos(atok)).info1
8108 INTO aggregation_function;
8109 child_pairs := get_children(atok);
8111 IF aggregation_function =
'sum' OR aggregation_function =
'count' THEN
8115 IF COALESCE(array_length(child_pairs,
1),
0) =
0 THEN
8116 lo :=
0; hi :=
0;
RETURN;
8118 SELECT sum(LEAST(v,
0::float8)), sum(GREATEST(v,
0::float8))
8120 FROM (
SELECT CAST(get_extra((get_children(c))[
2])
AS float8)
AS v
8121 FROM unnest(child_pairs)
AS c) sub;
8122 ELSIF aggregation_function =
'min' OR aggregation_function =
'max' THEN
8127 IF COALESCE(array_length(child_pairs,
1),
0) =
0 THEN
8128 lo :=
NULL; hi :=
NULL;
RETURN;
8131 SELECT min(v), max(v)
8133 FROM (
SELECT CAST(get_extra((get_children(c))[
2])
AS float8)
AS v
8134 FROM UNNEST(child_pairs)
AS c) sub;
8136 RAISE EXCEPTION
USING MESSAGE=
8137 'Cannot compute support for aggregation function ' || aggregation_function;
8143 RAISE EXCEPTION
'support() is not yet supported for input type %', pg_typeof(
input);
8145$$
LANGUAGE plpgsql PARALLEL SAFE
SET search_path=provsql SECURITY DEFINER;
8158CREATE OR REPLACE
FUNCTION central_moment(
8161 prov UUID = gate_one(),
8163 arguments TEXT =
NULL)
8164 RETURNS DOUBLE PRECISION AS $$
8174 IF pg_typeof(
input) =
'random_variable'::REGTYPE
THEN
8175 IF input IS NULL OR k
IS NULL THEN
8180 RETURN provsql.rv_moment(
8181 rv_conditioned_target((
input::random_variable)::UUID), k,
true,
8182 rv_conditioned_prov((
input::random_variable)::UUID, prov));
8185 IF pg_typeof(
input) =
'AGG_TOKEN'::REGTYPE
THEN
8186 IF input IS NULL OR k
IS NULL THEN
8190 RAISE EXCEPTION
'central_moment(): k must be non-negative (got %)', k;
8192 IF k =
0 THEN RETURN 1;
END IF;
8193 IF k =
1 THEN RETURN 0;
END IF;
8195 mu := agg_raw_moment(agg_conditioned_target(
input::AGG_TOKEN),
1,
8196 rv_conditioned_prov(
input::UUID, prov),
method, arguments);
8197 IF mu
IS NULL THEN RETURN NULL;
END IF;
8200 IF mu =
'Infinity'::float8
OR mu =
'-Infinity'::float8
THEN
8208 raw_i := agg_raw_moment(agg_conditioned_target(
input::AGG_TOKEN), i,
8209 rv_conditioned_prov(
input::UUID, prov),
method, arguments);
8210 IF raw_i
IS NULL THEN RETURN NULL;
END IF;
8211 total := total + binom * power(-mu, k - i) * raw_i;
8214 binom := binom * (k_double - i) / (i +
1);
8222 IF pg_typeof(
input) =
'UUID'::REGTYPE
THEN
8223 IF input IS NULL OR k
IS NULL THEN
8227 RAISE EXCEPTION
'central_moment(): k must be non-negative (got %)', k;
8229 IF k =
0 THEN RETURN 1;
END IF;
8230 IF k =
1 THEN RETURN 0;
END IF;
8231 mu := provsql.probability_evaluate(provsql.cond(
input::UUID, prov),
8233 RETURN (
1 - mu) * power(-mu, k) + mu * power(
1 - mu, k);
8236 RAISE EXCEPTION
'central_moment() is not yet supported for input type %', pg_typeof(
input);
8238$$
LANGUAGE plpgsql PARALLEL SAFE
SET search_path=provsql SECURITY DEFINER;
8241CREATE OR REPLACE
FUNCTION rv_covariance(x UUID, y UUID, prov UUID)
8242 RETURNS double precision
8243 AS 'provsql',
'rv_covariance' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
8268CREATE OR REPLACE
FUNCTION covariance(
8269 x random_variable, y random_variable, prov UUID
DEFAULT gate_one())
8270 RETURNS double precision AS $$
8271 SELECT provsql.rv_covariance((x)::UUID, (y)::UUID, prov);
8272$$
LANGUAGE sql PARALLEL SAFE STABLE
SET search_path=provsql SECURITY DEFINER;
8287CREATE OR REPLACE
FUNCTION stddev(
8288 x random_variable, prov UUID
DEFAULT gate_one())
8289 RETURNS double precision AS $$
8290 SELECT sqrt(provsql.variance(x, prov));
8291$$
LANGUAGE sql PARALLEL SAFE STABLE
SET search_path=provsql SECURITY DEFINER;
8294CREATE OR REPLACE
FUNCTION rv_correlation(x UUID, y UUID, prov UUID)
8295 RETURNS double precision
8296 AS 'provsql',
'rv_correlation' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
8313CREATE OR REPLACE
FUNCTION correlation(
8314 x random_variable, y random_variable, prov UUID
DEFAULT gate_one())
8315 RETURNS double precision AS $$
8316 SELECT provsql.rv_correlation((x)::UUID, (y)::UUID, prov);
8317$$
LANGUAGE sql PARALLEL SAFE STABLE
SET search_path=provsql SECURITY DEFINER;
8320CREATE OR REPLACE
FUNCTION rv_entropy(token UUID, prov UUID)
8321 RETURNS double precision
8322 AS 'provsql',
'rv_entropy' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
8340CREATE OR REPLACE
FUNCTION entropy(
8341 x random_variable, prov UUID
DEFAULT gate_one())
8342 RETURNS double precision AS $$
8343 SELECT provsql.rv_entropy((x)::UUID, prov);
8344$$
LANGUAGE sql PARALLEL SAFE STABLE
SET search_path=provsql SECURITY DEFINER;
8347CREATE OR REPLACE
FUNCTION rv_kl(p UUID, q UUID)
8348 RETURNS double precision
8349 AS 'provsql',
'rv_kl' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
8364CREATE OR REPLACE
FUNCTION kl(p random_variable, q random_variable)
8365 RETURNS double precision AS $$
8366 SELECT provsql.rv_kl((p)::UUID, (q)::UUID);
8367$$
LANGUAGE sql PARALLEL SAFE STABLE
SET search_path=provsql SECURITY DEFINER;
8371CREATE OR REPLACE
FUNCTION rv_mutual_information(x UUID, y UUID)
8372 RETURNS double precision
8373 AS 'provsql',
'rv_mutual_information' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
8387CREATE OR REPLACE
FUNCTION mutual_information(
8388 x random_variable, y random_variable)
8389 RETURNS double precision AS $$
8390 SELECT provsql.rv_mutual_information((x)::UUID, (y)::UUID);
8391$$
LANGUAGE sql PARALLEL SAFE STABLE
SET search_path=provsql SECURITY DEFINER;
8405CREATE OR REPLACE
FUNCTION shapley(
8409 arguments TEXT =
NULL,
8410 banzhaf
BOOLEAN =
'f')
8411 RETURNS DOUBLE PRECISION AS
8412 'provsql',
'shapley' LANGUAGE C STABLE;
8415CREATE OR REPLACE
FUNCTION shapley_all_vars(
8417 IN method TEXT =
NULL,
8418 IN arguments TEXT =
NULL,
8419 IN banzhaf
BOOLEAN =
'f',
8421 OUT value DOUBLE PRECISION)
8422 RETURNS SETOF RECORD
AS
8423 'provsql',
'shapley_all_vars'
8427CREATE OR REPLACE
FUNCTION banzhaf(
8431 arguments TEXT =
NULL)
8432 RETURNS DOUBLE PRECISION AS
8433 $$
SELECT provsql.shapley(token, variable,
method, arguments,
't') $$
8437CREATE OR REPLACE
FUNCTION banzhaf_all_vars(
8439 IN method TEXT =
NULL,
8440 IN arguments TEXT =
NULL,
8442 OUT value DOUBLE PRECISION)
8443 RETURNS SETOF RECORD
AS
8444 $$
SELECT *
FROM provsql.shapley_all_vars(token,
method, arguments,
't') $$
8479CREATE OR REPLACE
FUNCTION reachability_evaluate(
8483 probabilities
DOUBLE PRECISION[],
8487 RETURNS DOUBLE PRECISION AS
8488 'provsql',
'reachability_evaluate' LANGUAGE C IMMUTABLE PARALLEL SAFE;
8518CREATE OR REPLACE
FUNCTION reachability_compile_stats(
8520 IN destinations
INT[],
8522 IN probabilities
DOUBLE PRECISION[],
8525 IN directed
BOOLEAN,
8526 OUT probability
DOUBLE PRECISION,
8527 OUT data_treewidth
INT,
8529 OUT max_states
BIGINT,
8530 OUT nb_gates
BIGINT,
8531 OUT nb_variables
BIGINT)
8532 AS 'provsql',
'reachability_compile_stats'
8533 LANGUAGE C IMMUTABLE PARALLEL SAFE;
8569CREATE OR REPLACE
FUNCTION ucq_joint_compile_stats(
8570 IN disjunct_nvars
INT[],
8571 IN atom_disjunct
INT[],
8574 IN atom_arity
INT[],
8576 IN fact_elems
INT[],
8577 IN fact_arity
INT[],
8578 IN fact_tokens UUID[],
8579 IN fact_probs
DOUBLE PRECISION[],
8580 OUT probability
DOUBLE PRECISION,
8581 OUT joint_treewidth
INT,
8582 OUT data_treewidth_lb
INT,
8583 OUT circuit_treewidth_lb
INT,
8585 OUT max_states
BIGINT,
8587 OUT n_enumerating
INT)
8588 AS 'provsql',
'ucq_joint_compile_stats'
8589 LANGUAGE C IMMUTABLE PARALLEL SAFE;
8598CREATE OR REPLACE
FUNCTION ucq_joint_compile_stats(
8601 IN fact_elems
INT[],
8602 IN fact_arity
INT[],
8603 IN fact_tokens UUID[],
8604 IN fact_probs
DOUBLE PRECISION[],
8605 OUT probability
DOUBLE PRECISION,
8606 OUT joint_treewidth
INT,
8607 OUT data_treewidth_lb
INT,
8608 OUT circuit_treewidth_lb
INT,
8610 OUT max_states
BIGINT,
8612 OUT n_enumerating
INT)
8615 dnv
INT[] :=
'{}'; adisj
INT[] :=
'{}'; arel
INT[] :=
'{}';
8616 avars
INT[] :=
'{}'; aarity
INT[] :=
'{}';
8617 d JSONB; a JSONB; v TEXT; didx
INT :=
0;
8619 FOR d
IN SELECT *
FROM jsonb_array_elements(query->
'disjuncts') LOOP
8620 dnv := dnv || (d->>
'n_vars')::
INT;
8621 FOR a
IN SELECT *
FROM jsonb_array_elements(d->
'atoms') LOOP
8622 adisj := adisj || didx;
8623 arel := arel || (a->>
'rel')::
INT;
8624 aarity := aarity || jsonb_array_length(a->
'vars');
8625 FOR v
IN SELECT *
FROM jsonb_array_elements_text(a->
'vars') LOOP
8626 avars := avars || v::
INT;
8631 SELECT s.probability, s.joint_treewidth, s.data_treewidth_lb,
8632 s.circuit_treewidth_lb, s.n_bags, s.max_states, s.dd_size,
8634 INTO probability, joint_treewidth, data_treewidth_lb,
8635 circuit_treewidth_lb, n_bags, max_states, dd_size, n_enumerating
8636 FROM ucq_joint_compile_stats(dnv, adisj, arel, avars, aarity,
8637 fact_rel, fact_elems, fact_arity, fact_tokens, fact_probs) s;
8639$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE;
8660CREATE OR REPLACE
FUNCTION ucq_joint_compile_stats_tracked(
8661 IN disjunct_nvars
INT[],
8662 IN atom_disjunct
INT[],
8665 IN atom_arity
INT[],
8667 IN fact_elems
INT[],
8668 IN fact_arity
INT[],
8669 IN fact_tokens UUID[],
8670 OUT probability
DOUBLE PRECISION,
8671 OUT joint_treewidth
INT,
8672 OUT data_treewidth_lb
INT,
8673 OUT circuit_treewidth_lb
INT,
8675 OUT max_states
BIGINT,
8677 OUT n_enumerating
INT)
8678 AS 'provsql',
'ucq_joint_compile_stats_tracked'
8679 LANGUAGE C STABLE PARALLEL SAFE;
8685CREATE OR REPLACE
FUNCTION ucq_joint_compile_stats_tracked(
8688 IN fact_elems
INT[],
8689 IN fact_arity
INT[],
8690 IN fact_tokens UUID[],
8691 OUT probability
DOUBLE PRECISION,
8692 OUT joint_treewidth
INT,
8693 OUT data_treewidth_lb
INT,
8694 OUT circuit_treewidth_lb
INT,
8696 OUT max_states
BIGINT,
8698 OUT n_enumerating
INT)
8701 dnv
INT[] :=
'{}'; adisj
INT[] :=
'{}'; arel
INT[] :=
'{}';
8702 avars
INT[] :=
'{}'; aarity
INT[] :=
'{}';
8703 d JSONB; a JSONB; v TEXT; didx
INT :=
0;
8705 FOR d
IN SELECT *
FROM jsonb_array_elements(query->
'disjuncts') LOOP
8706 dnv := dnv || (d->>
'n_vars')::
INT;
8707 FOR a
IN SELECT *
FROM jsonb_array_elements(d->
'atoms') LOOP
8708 adisj := adisj || didx;
8709 arel := arel || (a->>
'rel')::
INT;
8710 aarity := aarity || jsonb_array_length(a->
'vars');
8711 FOR v
IN SELECT *
FROM jsonb_array_elements_text(a->
'vars') LOOP
8712 avars := avars || v::
INT;
8717 SELECT s.probability, s.joint_treewidth, s.data_treewidth_lb,
8718 s.circuit_treewidth_lb, s.n_bags, s.max_states, s.dd_size,
8720 INTO probability, joint_treewidth, data_treewidth_lb,
8721 circuit_treewidth_lb, n_bags, max_states, dd_size, n_enumerating
8722 FROM ucq_joint_compile_stats_tracked(dnv, adisj, arel, avars, aarity,
8723 fact_rel, fact_elems, fact_arity, fact_tokens) s;
8725$$
LANGUAGE plpgsql STABLE PARALLEL SAFE;
8740CREATE OR REPLACE
FUNCTION ucq_joint_materialize_tracked(
8741 disjunct_nvars
INT[],
8742 atom_disjunct
INT[],
8751 'provsql',
'ucq_joint_materialize_tracked' LANGUAGE C VOLATILE;
8761CREATE OR REPLACE
FUNCTION ucq_joint_materialize_tracked(
8769 dnv
INT[] :=
'{}'; adisj
INT[] :=
'{}'; arel
INT[] :=
'{}';
8770 avars
INT[] :=
'{}'; aarity
INT[] :=
'{}';
8771 d JSONB; a JSONB; v TEXT; didx
INT :=
0;
8773 FOR d
IN SELECT *
FROM jsonb_array_elements(query->
'disjuncts') LOOP
8774 dnv := dnv || (d->>
'n_vars')::
INT;
8775 FOR a
IN SELECT *
FROM jsonb_array_elements(d->
'atoms') LOOP
8776 adisj := adisj || didx;
8777 arel := arel || (a->>
'rel')::
INT;
8778 aarity := aarity || jsonb_array_length(a->
'vars');
8779 FOR v
IN SELECT *
FROM jsonb_array_elements_text(a->
'vars') LOOP
8780 avars := avars || v::
INT;
8785 RETURN ucq_joint_materialize_tracked(dnv, adisj, arel, avars, aarity,
8786 fact_rel, fact_elems, fact_arity, fact_tokens);
8788$$
LANGUAGE plpgsql VOLATILE;
8822CREATE OR REPLACE
FUNCTION ucq_joint_provenance(
8823 descriptor JSONB, fallback UUID
DEFAULT NULL)
8826 legs TEXT;
sql TEXT; saved TEXT;
8827 fact_rel
INT[]; fact_elems
INT[]; fact_arity
INT[]; fact_tokens UUID[];
8828 dnv
INT[]:=
'{}'; adisj
INT[]:=
'{}'; arel
INT[]:=
'{}';
8829 avars
INT[]:=
'{}'; aarity
INT[]:=
'{}';
8830 d jsonb; a jsonb; v TEXT; didx
INT:=
0;
8833 FOR d
IN SELECT *
FROM jsonb_array_elements(descriptor->
'disjuncts') LOOP
8834 dnv := dnv || (d->>
'n_vars')::
INT;
8835 FOR a
IN SELECT *
FROM jsonb_array_elements(d->
'atoms') LOOP
8836 adisj := adisj || didx; arel := arel || (a->>
'rel')::
INT;
8837 aarity := aarity || jsonb_array_length(a->
'vars');
8838 FOR v
IN SELECT *
FROM jsonb_array_elements_text(a->
'vars') LOOP
8839 avars := avars || v::
INT;
8849 format(
'SELECT %s, ARRAY[%s]::TEXT[], provsql FROM %s%s',
8851 (
SELECT string_agg(format(
'(%I)::TEXT', c),
',')
8852 FROM jsonb_array_elements_text(descriptor->
'elem_cols'->(rn-1)::
INT) c),
8856 CASE WHEN coalesce(descriptor->
'rel_where'->>(rn-1)::
INT,
'') <>
''
8857 THEN ' WHERE '||(descriptor->
'rel_where'->>(rn-1)::
INT)
8861 FROM jsonb_array_elements_text(descriptor->
'relations')
WITH ORDINALITY t(rel, rn);
8864 WITH facts(rel,elems,tok)
AS (%s),
8865 ord
AS (
SELECT row_number()
OVER ()
AS ord, rel, elems, tok
FROM facts),
8866 dict
AS (
SELECT val, (dense_rank()
OVER (
ORDER BY val))-1
AS id
8867 FROM (
SELECT DISTINCT unnest(elems)
AS val
FROM facts) u)
8868 SELECT (
SELECT array_agg(rel
ORDER BY ord)
FROM ord),
8869 (
SELECT array_agg(cardinality(elems)
ORDER BY ord)
FROM ord),
8870 (
SELECT array_agg(tok
ORDER BY ord)
FROM ord),
8871 (
SELECT array_agg(dd.id
ORDER BY o.ord, e.k)
8872 FROM ord o,
LATERAL unnest(o.elems)
WITH ORDINALITY e(val,k)
8873 JOIN dict dd
ON dd.val = e.val)
8878 saved := current_setting(
'provsql.active',
true);
8879 PERFORM set_config(
'provsql.active',
'off',
true);
8880 EXECUTE sql INTO fact_rel, fact_arity, fact_tokens, fact_elems;
8881 PERFORM set_config(
'provsql.active', saved,
true);
8883 RETURN ucq_joint_materialize_tracked(dnv,adisj,arel,avars,aarity,
8884 fact_rel,fact_elems,fact_arity,fact_tokens);
8885EXCEPTION
WHEN OTHERS
THEN
8891$$
LANGUAGE plpgsql VOLATILE;
8909CREATE OR REPLACE
FUNCTION ucq_mobius_materialize_tracked(
8910 disjunct_nvars
INT[],
8911 atom_disjunct
INT[],
8919 lineage UUID
DEFAULT NULL)
8921 'provsql',
'ucq_mobius_materialize_tracked' LANGUAGE C VOLATILE;
8930CREATE OR REPLACE
FUNCTION ucq_mobius_compile_stats(
8931 IN disjunct_nvars
INT[],
8932 IN atom_disjunct
INT[],
8935 IN atom_arity
INT[],
8937 IN fact_elems
INT[],
8938 IN fact_arity
INT[],
8939 IN fact_tokens UUID[],
8940 OUT probability
DOUBLE PRECISION,
8941 OUT n_components
INT,
8942 OUT n_cnf_conjuncts
INT,
8943 OUT lattice_size
INT,
8945 OUT n_cancelled
INT,
8946 OUT cancelled_hard
BOOLEAN,
8948 OUT memo_hits
BIGINT)
8949 AS 'provsql',
'ucq_mobius_compile_stats'
8950 LANGUAGE C VOLATILE;
8964CREATE OR REPLACE
FUNCTION mobius_or_null(tok UUID)
8966 SELECT CASE WHEN tok
IS NOT NULL AND provsql.get_gate_type(tok) =
'mobius'
8968$$
LANGUAGE sql STABLE;
8976CREATE OR REPLACE
FUNCTION ucq_mobius_provenance(
8977 descriptor JSONB, fallback UUID
DEFAULT NULL)
8980 legs TEXT;
sql TEXT; saved TEXT;
8981 fact_rel
INT[]; fact_elems
INT[]; fact_arity
INT[]; fact_tokens UUID[];
8982 dnv
INT[]:=
'{}'; adisj
INT[]:=
'{}'; arel
INT[]:=
'{}';
8983 avars
INT[]:=
'{}'; aarity
INT[]:=
'{}';
8984 d jsonb; a jsonb; v TEXT; didx
INT:=
0;
8986 FOR d
IN SELECT *
FROM jsonb_array_elements(descriptor->
'disjuncts') LOOP
8987 dnv := dnv || (d->>
'n_vars')::
INT;
8988 FOR a
IN SELECT *
FROM jsonb_array_elements(d->
'atoms') LOOP
8989 adisj := adisj || didx; arel := arel || (a->>
'rel')::
INT;
8990 aarity := aarity || jsonb_array_length(a->
'vars');
8991 FOR v
IN SELECT *
FROM jsonb_array_elements_text(a->
'vars') LOOP
8992 avars := avars || v::
INT;
8999 format(
'SELECT %s, ARRAY[%s]::TEXT[], provsql FROM %s%s',
9001 (
SELECT string_agg(format(
'(%I)::TEXT', c),
',')
9002 FROM jsonb_array_elements_text(descriptor->
'elem_cols'->(rn-1)::
INT) c),
9004 CASE WHEN coalesce(descriptor->
'rel_where'->>(rn-1)::
INT,
'') <>
''
9005 THEN ' WHERE '||(descriptor->
'rel_where'->>(rn-1)::
INT)
9009 FROM jsonb_array_elements_text(descriptor->
'relations')
WITH ORDINALITY t(rel, rn);
9012 WITH facts(rel,elems,tok)
AS (%s),
9013 ord
AS (
SELECT row_number()
OVER ()
AS ord, rel, elems, tok
FROM facts),
9014 dict
AS (
SELECT val, (dense_rank()
OVER (
ORDER BY val))-1
AS id
9015 FROM (
SELECT DISTINCT unnest(elems)
AS val
FROM facts) u)
9016 SELECT (
SELECT array_agg(rel
ORDER BY ord)
FROM ord),
9017 (
SELECT array_agg(cardinality(elems)
ORDER BY ord)
FROM ord),
9018 (
SELECT array_agg(tok
ORDER BY ord)
FROM ord),
9019 (
SELECT array_agg(dd.id
ORDER BY o.ord, e.k)
9020 FROM ord o,
LATERAL unnest(o.elems)
WITH ORDINALITY e(val,k)
9021 JOIN dict dd
ON dd.val = e.val)
9024 saved := current_setting(
'provsql.active',
true);
9025 PERFORM set_config(
'provsql.active',
'off',
true);
9026 EXECUTE sql INTO fact_rel, fact_arity, fact_tokens, fact_elems;
9027 PERFORM set_config(
'provsql.active', saved,
true);
9032 RETURN ucq_mobius_materialize_tracked(dnv,adisj,arel,avars,aarity,
9033 fact_rel,fact_elems,fact_arity,fact_tokens, fallback);
9034EXCEPTION
WHEN OTHERS
THEN
9037$$
LANGUAGE plpgsql VOLATILE;
9045CREATE OR REPLACE
FUNCTION mobius_compile_stats(
9046 IN descriptor JSONB,
9047 OUT probability
DOUBLE PRECISION,
9048 OUT n_components
INT,
9049 OUT n_cnf_conjuncts
INT,
9050 OUT lattice_size
INT,
9052 OUT n_cancelled
INT,
9053 OUT cancelled_hard
BOOLEAN,
9055 OUT memo_hits
BIGINT)
9058 legs TEXT;
sql TEXT; saved TEXT;
9059 fact_rel
INT[]; fact_elems
INT[]; fact_arity
INT[]; fact_tokens UUID[];
9060 dnv
INT[]:=
'{}'; adisj
INT[]:=
'{}'; arel
INT[]:=
'{}';
9061 avars
INT[]:=
'{}'; aarity
INT[]:=
'{}';
9062 d jsonb; a jsonb; v TEXT; didx
INT:=
0;
9064 FOR d
IN SELECT *
FROM jsonb_array_elements(descriptor->
'disjuncts') LOOP
9065 dnv := dnv || (d->>
'n_vars')::
INT;
9066 FOR a
IN SELECT *
FROM jsonb_array_elements(d->
'atoms') LOOP
9067 adisj := adisj || didx; arel := arel || (a->>
'rel')::
INT;
9068 aarity := aarity || jsonb_array_length(a->
'vars');
9069 FOR v
IN SELECT *
FROM jsonb_array_elements_text(a->
'vars') LOOP
9070 avars := avars || v::
INT;
9077 format(
'SELECT %s, ARRAY[%s]::TEXT[], provsql FROM %s%s',
9079 (
SELECT string_agg(format(
'(%I)::TEXT', c),
',')
9080 FROM jsonb_array_elements_text(descriptor->
'elem_cols'->(rn-1)::
INT) c),
9082 CASE WHEN coalesce(descriptor->
'rel_where'->>(rn-1)::
INT,
'') <>
''
9083 THEN ' WHERE '||(descriptor->
'rel_where'->>(rn-1)::
INT)
9087 FROM jsonb_array_elements_text(descriptor->
'relations')
WITH ORDINALITY t(rel, rn);
9090 WITH facts(rel,elems,tok)
AS (%s),
9091 ord
AS (
SELECT row_number()
OVER ()
AS ord, rel, elems, tok
FROM facts),
9092 dict
AS (
SELECT val, (dense_rank()
OVER (
ORDER BY val))-1
AS id
9093 FROM (
SELECT DISTINCT unnest(elems)
AS val
FROM facts) u)
9094 SELECT (
SELECT array_agg(rel
ORDER BY ord)
FROM ord),
9095 (
SELECT array_agg(cardinality(elems)
ORDER BY ord)
FROM ord),
9096 (
SELECT array_agg(tok
ORDER BY ord)
FROM ord),
9097 (
SELECT array_agg(dd.id
ORDER BY o.ord, e.k)
9098 FROM ord o,
LATERAL unnest(o.elems)
WITH ORDINALITY e(val,k)
9099 JOIN dict dd
ON dd.val = e.val)
9102 saved := current_setting(
'provsql.active',
true);
9103 PERFORM set_config(
'provsql.active',
'off',
true);
9104 EXECUTE sql INTO fact_rel, fact_arity, fact_tokens, fact_elems;
9105 PERFORM set_config(
'provsql.active', saved,
true);
9107 SELECT s.probability, s.n_components, s.n_cnf_conjuncts, s.lattice_size,
9108 s.n_nonzero, s.n_cancelled, s.cancelled_hard, s.dd_size, s.memo_hits
9109 INTO probability, n_components, n_cnf_conjuncts, lattice_size,
9110 n_nonzero, n_cancelled, cancelled_hard, dd_size, memo_hits
9111 FROM ucq_mobius_compile_stats(dnv,adisj,arel,avars,aarity,
9112 fact_rel,fact_elems,fact_arity,fact_tokens) s;
9114$$
LANGUAGE plpgsql VOLATILE;
9127CREATE OR REPLACE
FUNCTION ucq_joint_gather(
9129 OUT disjunct_nvars
INT[],
OUT atom_disjunct
INT[],
OUT atom_rel
INT[],
9130 OUT atom_vars
INT[],
OUT atom_arity
INT[],
9131 OUT fact_rel
INT[],
OUT fact_elems
INT[],
OUT fact_arity
INT[],
9132 OUT fact_tokens UUID[],
OUT val_by_id TEXT[])
9135 legs TEXT;
sql TEXT; saved TEXT; d jsonb; a jsonb; v TEXT; didx
INT :=
0;
9137 disjunct_nvars:=
'{}'; atom_disjunct:=
'{}'; atom_rel:=
'{}';
9138 atom_vars:=
'{}'; atom_arity:=
'{}';
9139 FOR d
IN SELECT *
FROM jsonb_array_elements(descriptor->
'disjuncts') LOOP
9140 disjunct_nvars := disjunct_nvars || (d->>
'n_vars')::
INT;
9141 FOR a
IN SELECT *
FROM jsonb_array_elements(d->
'atoms') LOOP
9142 atom_disjunct := atom_disjunct || didx;
9143 atom_rel := atom_rel || (a->>
'rel')::
INT;
9144 atom_arity := atom_arity || jsonb_array_length(a->
'vars');
9145 FOR v
IN SELECT *
FROM jsonb_array_elements_text(a->
'vars') LOOP
9146 atom_vars := atom_vars || v::
INT;
9153 format(
'SELECT %s, ARRAY[%s]::TEXT[], provsql FROM %s%s', rn -
1,
9154 (
SELECT string_agg(format(
'(%I)::TEXT', c),
',')
9155 FROM jsonb_array_elements_text(descriptor->
'elem_cols'->(rn-1)::
INT) c),
9157 CASE WHEN coalesce(descriptor->
'rel_where'->>(rn-1)::
INT,
'') <>
''
9158 THEN ' WHERE '||(descriptor->
'rel_where'->>(rn-1)::
INT)
9162 FROM jsonb_array_elements_text(descriptor->
'relations')
WITH ORDINALITY t(rel, rn);
9165 WITH facts(rel,elems,tok)
AS (%s),
9166 ord
AS (
SELECT row_number()
OVER ()
AS ord, rel, elems, tok
FROM facts),
9167 dict
AS (
SELECT val, (dense_rank()
OVER (
ORDER BY val))-1
AS id
9168 FROM (
SELECT DISTINCT unnest(elems)
AS val
FROM facts) u)
9169 SELECT (
SELECT array_agg(rel
ORDER BY ord)
FROM ord),
9170 (
SELECT array_agg(cardinality(elems)
ORDER BY ord)
FROM ord),
9171 (
SELECT array_agg(tok
ORDER BY ord)
FROM ord),
9172 (
SELECT array_agg(dd.id
ORDER BY o.ord, e.k)
9173 FROM ord o,
LATERAL unnest(o.elems)
WITH ORDINALITY e(val,k)
9174 JOIN dict dd
ON dd.val = e.val),
9175 (
SELECT array_agg(val
ORDER BY id)
FROM dict)
9178 saved := current_setting(
'provsql.active',
true);
9179 PERFORM set_config(
'provsql.active',
'off',
true);
9180 EXECUTE sql INTO fact_rel, fact_arity, fact_tokens, fact_elems, val_by_id;
9181 PERFORM set_config(
'provsql.active', saved,
true);
9183$$
LANGUAGE plpgsql VOLATILE;
9200CREATE OR REPLACE
FUNCTION ucq_joint_provenance_answer(
9201 descriptor JSONB, head_vars
INT[], head_vals TEXT[], fallback UUID
DEFAULT NULL)
9202RETURNS UUID
AS 'provsql',
'ucq_joint_provenance_answer'
9213CREATE OR REPLACE
FUNCTION ucq_mobius_provenance_answer(
9214 descriptor JSONB, head_vars
INT[], head_vals TEXT[], fallback UUID
DEFAULT NULL)
9215RETURNS UUID
AS 'provsql',
'ucq_mobius_provenance_answer'
9256CREATE OR REPLACE
FUNCTION reachability_materialize(
9258 IN destinations
INT[],
9260 IN probabilities
DOUBLE PRECISION[],
9261 IN block_keys UUID[],
9262 IN block_indices
INT[],
9263 IN source_vertices
INT[],
9264 IN source_tokens UUID[],
9265 IN source_probabilities
DOUBLE PRECISION[],
9266 IN directed
BOOLEAN,
9269 RETURNS SETOF RECORD
AS
9270 'provsql',
'reachability_materialize' LANGUAGE C VOLATILE;
9303CREATE OR REPLACE
FUNCTION reachability_materialize_hops(
9305 IN destinations
INT[],
9307 IN probabilities
DOUBLE PRECISION[],
9308 IN block_keys UUID[],
9309 IN block_indices
INT[],
9310 IN source_vertices
INT[],
9311 IN source_tokens UUID[],
9312 IN source_probabilities
DOUBLE PRECISION[],
9313 IN directed
BOOLEAN,
9319 RETURNS SETOF RECORD
AS
9320 'provsql',
'reachability_materialize_hops' LANGUAGE C VOLATILE;
9352CREATE OR REPLACE
FUNCTION reachability_materialize_any(
9354 IN destinations
INT[],
9356 IN probabilities
DOUBLE PRECISION[],
9357 IN block_keys UUID[],
9358 IN block_indices
INT[],
9359 IN source_vertices
INT[],
9360 IN source_tokens UUID[],
9361 IN source_probabilities
DOUBLE PRECISION[],
9362 IN directed
BOOLEAN,
9364 IN member_vertices
INT[],
9367 RETURNS SETOF RECORD
AS
9368 'provsql',
'reachability_materialize_any' LANGUAGE C VOLATILE;
9398CREATE OR REPLACE
FUNCTION reachability_materialize_cover(
9402 probabilities
DOUBLE PRECISION[],
9404 block_indices
INT[],
9405 source_vertices
INT[],
9406 source_tokens UUID[],
9407 source_probabilities
DOUBLE PRECISION[],
9409 member_vertices
INT[])
9411 'provsql',
'reachability_materialize_cover' LANGUAGE C VOLATILE;
9448CREATE OR REPLACE
FUNCTION plant_reach_any_groups(
9450 node_attribute TEXT,
9451 member_rel REGCLASS,
9452 member_attribute TEXT,
9453 group_attribute TEXT,
9455 source_attribute TEXT,
9456 destination_attribute TEXT,
9459 edge_quals TEXT
DEFAULT NULL,
9460 source_rel REGCLASS
DEFAULT NULL,
9461 source_rel_attribute TEXT
DEFAULT NULL,
9462 edge_sql TEXT
DEFAULT NULL,
9463 member_quals TEXT
DEFAULT NULL)
9472 sp
double precision[];
9473 gids
INT[] :=
ARRAY[]::
INT[];
9474 mids
INT[] :=
ARRAY[]::
INT[];
9477 verbosity
INT := coalesce(current_setting(
'provsql.verbose_level',
true)::
INT,
0);
9482 IF EXISTS (
SELECT 1 FROM pg_attribute
9483 WHERE attrelid = member_rel
AND attname =
'provsql'
9484 AND atttypid =
'UUID'::REGTYPE
AND NOT attisdropped)
THEN
9488 IF source_rel
IS NOT NULL THEN
9489 SELECT g.source_values, g.source_tokens, g.source_probabilities
9491 FROM provsql.gather_reachability_sources(source_rel,
9492 source_rel_attribute) g;
9494 sv :=
ARRAY[]::TEXT[];
9495 st :=
ARRAY[]::UUID[];
9496 sp :=
ARRAY[]::float8[];
9499 sv :=
ARRAY[source_value];
9500 st :=
ARRAY[
'00000000-0000-0000-0000-000000000000'::UUID];
9501 sp :=
ARRAY[
1.
0::float8];
9504 e := provsql.gather_reachability_edges(edge_rel, source_attribute,
9505 destination_attribute,
9506 sv, edge_quals, edge_sql);
9518 DROP TABLE IF EXISTS provsql_reach_any_flat_tmp;
9520 'CREATE TEMP TABLE provsql_reach_any_flat_tmp AS '
9521 ||
'SELECT w.%1$I::TEXT AS node_val, provsql.provenance() AS tok, '
9522 ||
' t.%5$I AS grp_key '
9523 ||
'FROM %2$I w JOIN %3$s t ON w.%1$I = t.%4$I'
9527 || coalesce(
' WHERE ' || member_quals,
''),
9528 node_attribute, work_name, member_rel::TEXT, member_attribute,
9530 PERFORM provsql.remove_provenance(
'provsql_reach_any_flat_tmp');
9531 DROP TABLE IF EXISTS provsql_reach_any_groups_tmp;
9532 CREATE TEMP
TABLE provsql_reach_any_groups_tmp
AS
9533 SELECT (row_number()
OVER ())::
INT AS gid, members, toks
FROM (
9534 SELECT array_agg(node_val)
AS members, array_agg(tok)
AS toks
9535 FROM provsql_reach_any_flat_tmp
9536 GROUP BY grp_key
HAVING count(*) >=
2) g;
9537 DROP TABLE provsql_reach_any_flat_tmp;
9539 FOR grp
IN SELECT gid, members
FROM provsql_reach_any_groups_tmp LOOP
9540 FOR m
IN SELECT DISTINCT unnest(grp.members)
AS val LOOP
9541 vid := array_position(e.vertices, m.val);
9542 IF vid
IS NOT NULL THEN
9543 gids := gids || grp.gid;
9544 mids := mids || vid;
9548 IF cardinality(gids) =
0 THEN
9549 DROP TABLE provsql_reach_any_groups_tmp;
9554 SELECT a.group_id, a.token
AS any_token, t.toks
9555 FROM provsql.reachability_materialize_any(
9556 e.sources, e.destinations, e.tokens, e.probabilities,
9557 e.block_keys, e.block_indices, e.extra_ids, st, sp,
9558 directed, gids, mids) a
9559 JOIN provsql_reach_any_groups_tmp t
ON t.gid = a.group_id
9561 canonical := public.uuid_generate_v5(
9562 provsql.uuid_ns_provsql(),
9563 concat(
'plus-canonical',
9564 (
SELECT array_agg(tok
ORDER BY tok)
9565 FROM unnest(grp.toks) tok)));
9566 PERFORM provsql.create_gate(canonical,
'plus',
ARRAY[grp.any_token]);
9567 PERFORM provsql.set_infos(canonical,
1);
9569 DROP TABLE provsql_reach_any_groups_tmp;
9570 IF verbosity >=
20 THEN
9573 PERFORM set_config(
'client_min_messages',
'notice',
true);
9574 RAISE NOTICE
'ProvSQL: certified any-member gates planted for the aggregation of "%" by %.%',
9575 work_name, member_rel, group_attribute;
9576 PERFORM set_config(
'client_min_messages',
'warning',
true);
9578 EXCEPTION
WHEN OTHERS
THEN
9579 IF verbosity >=
10 THEN
9580 PERFORM set_config(
'client_min_messages',
'notice',
true);
9581 RAISE NOTICE
'ProvSQL: any-member planting for "%" skipped (%)',
9583 PERFORM set_config(
'client_min_messages',
'warning',
true);
9589$$
LANGUAGE plpgsql
SET client_min_messages = warning;
9625CREATE OR REPLACE
FUNCTION plant_reach_cover(
9627 node_attribute TEXT,
9629 source_attribute TEXT,
9630 destination_attribute TEXT,
9634 edge_quals TEXT
DEFAULT NULL,
9635 source_rel REGCLASS
DEFAULT NULL,
9636 source_rel_attribute TEXT
DEFAULT NULL,
9637 edge_sql TEXT
DEFAULT NULL)
9644 sp
double precision[];
9647 vids
INT[] :=
ARRAY[]::
INT[];
9649 toks UUID[] :=
ARRAY[]::UUID[];
9652 verbosity
INT := coalesce(current_setting(
'provsql.verbose_level',
true)::
INT,
0);
9655 IF source_rel
IS NOT NULL THEN
9656 SELECT g.source_values, g.source_tokens, g.source_probabilities
9658 FROM provsql.gather_reachability_sources(source_rel,
9659 source_rel_attribute) g;
9661 sv :=
ARRAY[]::TEXT[];
9662 st :=
ARRAY[]::UUID[];
9663 sp :=
ARRAY[]::float8[];
9666 sv :=
ARRAY[source_value];
9667 st :=
ARRAY[
'00000000-0000-0000-0000-000000000000'::UUID];
9668 sp :=
ARRAY[
1.
0::float8];
9671 e := provsql.gather_reachability_edges(edge_rel, source_attribute,
9672 destination_attribute,
9673 sv, edge_quals, edge_sql);
9679 FOREACH val
IN ARRAY node_values LOOP
9680 vid := array_position(e.vertices, val);
9684 vids := vids || vid;
9685 EXECUTE format(
'SELECT provsql FROM %I WHERE %I::TEXT = $1',
9686 work_name, node_attribute)
9691 toks := toks || tok;
9694 cover_token := provsql.reachability_materialize_cover(
9695 e.sources, e.destinations, e.tokens, e.probabilities,
9696 e.block_keys, e.block_indices, e.extra_ids, st, sp,
9699 SELECT public.uuid_generate_v5(
9700 provsql.uuid_ns_provsql(),
9701 concat(
'times-canonical', array_agg(t
ORDER BY t)))
9704 PERFORM provsql.create_gate(canonical,
'times',
ARRAY[cover_token]);
9705 PERFORM provsql.set_infos(canonical,
1);
9706 IF verbosity >=
20 THEN
9709 PERFORM set_config(
'client_min_messages',
'notice',
true);
9710 RAISE NOTICE
'ProvSQL: certified all-members gate planted for the self-join of "%"',
9712 PERFORM set_config(
'client_min_messages',
'warning',
true);
9714 EXCEPTION
WHEN OTHERS
THEN
9715 IF verbosity >=
10 THEN
9716 PERFORM set_config(
'client_min_messages',
'notice',
true);
9717 RAISE NOTICE
'ProvSQL: all-members planting for "%" skipped (%)',
9719 PERFORM set_config(
'client_min_messages',
'warning',
true);
9725$$
LANGUAGE plpgsql
SET client_min_messages = warning;
9740CREATE OR REPLACE
FUNCTION token_conjunctive_leaves(token UUID)
9743WITH RECURSIVE walk(g)
AS (
9746 SELECT c
FROM walk w,
unnest(provsql.get_children(w.g))
AS c
9747 WHERE provsql.get_gate_type(w.g)
IN (
'times',
'project',
'eq',
'annotation')
9749SELECT CASE WHEN bool_and(provsql.get_gate_type(g)
9750 IN (
'times',
'project',
'eq',
'annotation',
'input'))
9751 THEN array_agg(
DISTINCT g)
9752 FILTER (
WHERE provsql.get_gate_type(g) =
'input')
9755$$
LANGUAGE sql STABLE;
9796CREATE OR REPLACE
FUNCTION gather_reachability_edges(
9798 IN source_attribute TEXT,
9799 IN destination_attribute TEXT,
9800 IN extra_vertices TEXT[],
9801 IN edge_quals TEXT
DEFAULT NULL,
9802 IN rel_sql TEXT
DEFAULT NULL,
9804 OUT destinations
INT[],
9806 OUT probabilities
DOUBLE PRECISION[],
9807 OUT block_keys UUID[],
9808 OUT block_indices
INT[],
9809 OUT extra_ids
INT[],
9810 OUT vertices TEXT[])
9819 verbosity
INT := coalesce(current_setting(
'provsql.verbose_level',
true)::
INT,
0);
9827 IF rel
IS NOT NULL AND rel_sql
IS NULL THEN
9828 tkind := (provsql.get_table_info(rel::oid)).kind;
9830 IF tkind
NOT IN (
'tid',
'bid')
THEN
9833 IF tkind =
'bid' THEN
9834 SELECT string_agg(quote_ident(a.attname) ||
'::TEXT',
' || '','' || '
9837 FROM unnest((provsql.get_table_info(rel::oid)).block_key)
9838 WITH ORDINALITY
AS k(attnum, ord)
9839 JOIN pg_attribute a
ON a.attrelid = rel
AND a.attnum = k.attnum;
9841 bkey_expr := coalesce(bkey_expr, quote_literal(
''));
9843 IF tkind
IS NOT NULL AND verbosity >=
20 THEN
9848 PERFORM set_config(
'client_min_messages',
'notice',
true);
9849 RAISE NOTICE
'ProvSQL: catalog characterises % as %', rel,
upper(tkind);
9850 PERFORM set_config(
'client_min_messages',
'warning',
true);
9859 DROP TABLE IF EXISTS provsql_reachability_edges_tmp;
9861 'CREATE TEMP TABLE provsql_reachability_edges_tmp AS '
9862 ||
'SELECT %1$I::TEXT AS u, %2$I::TEXT AS v, '
9863 ||
'provsql.strip_annotations(provsql.provenance()) AS token%5$s '
9864 ||
'FROM %3$s WHERE %1$I IS NOT NULL AND %2$I IS NOT NULL%4$s',
9865 source_attribute, destination_attribute,
9866 CASE WHEN rel_sql
IS NULL THEN rel::TEXT
9867 ELSE '(' || rel_sql ||
') AS provsql_edge_subquery' END,
9868 CASE WHEN edge_quals
IS NULL THEN ''
9869 ELSE ' AND (' || edge_quals ||
')' END,
9870 CASE WHEN tkind =
'bid'
9871 THEN ', public.uuid_generate_v5(provsql.uuid_ns_provsql(), '
9872 || quote_literal(
'bidblock' || rel::TEXT ||
':')
9873 ||
' || ' || bkey_expr ||
') AS bkey'
9874 ELSE ', NULL::UUID AS bkey' END);
9875 PERFORM provsql.remove_provenance(
'provsql_reachability_edges_tmp');
9877 DROP TABLE IF EXISTS provsql_reachability_support_tmp;
9878 IF tkind
IS NULL THEN
9881 IF EXISTS (
SELECT 1 FROM provsql_reachability_edges_tmp
9882 WHERE provsql.get_gate_type(token)
NOT IN (
'input',
'mulinput',
'times',
9883 'project',
'eq'))
THEN
9884 DROP TABLE provsql_reachability_edges_tmp;
9885 RAISE EXCEPTION
'reachability: the provenance of % must consist of base input, repair_key, or conjunctive join tokens', coalesce(rel::TEXT,
'the edge query');
9887 CREATE TEMP
TABLE provsql_reachability_support_tmp
AS
9888 SELECT t.token, l.leaf
9889 FROM (
SELECT DISTINCT token
FROM provsql_reachability_edges_tmp
9890 WHERE provsql.get_gate_type(token)
IN (
'times',
'project',
'eq')) t,
9891 LATERAL unnest(provsql.token_conjunctive_leaves(t.token))
AS l(leaf);
9893 FROM (
SELECT DISTINCT token
FROM provsql_reachability_edges_tmp) t
9894 WHERE provsql.get_gate_type(t.token)
IN (
'times',
'project',
'eq')
9895 AND provsql.token_conjunctive_leaves(t.token)
IS NULL)
THEN
9896 DROP TABLE provsql_reachability_support_tmp;
9897 DROP TABLE provsql_reachability_edges_tmp;
9898 RAISE EXCEPTION
'reachability: a join-defined edge token is not a pure conjunction of base tuples';
9900 IF EXISTS (
SELECT 1 FROM (
9901 SELECT leaf
FROM provsql_reachability_support_tmp
9903 SELECT DISTINCT token
FROM provsql_reachability_edges_tmp
9904 WHERE provsql.get_gate_type(token) =
'input'
9906 GROUP BY leaf
HAVING count(*) >
1)
THEN
9907 DROP TABLE provsql_reachability_support_tmp;
9908 DROP TABLE provsql_reachability_edges_tmp;
9909 RAISE EXCEPTION
'reachability: join-defined edges share base tuples (their supports overlap), so they are not independent';
9918 IF tkind =
'tid' THEN
9919 sel_probs :=
'coalesce(provsql.get_prob(e.token), 1.0)';
9920 sel_bkeys := $
sql$
'00000000-0000-0000-0000-000000000000'::UUID$
sql$;
9922 ELSIF tkind =
'bid' THEN
9923 sel_probs :=
'coalesce(provsql.get_prob(e.token), 1.0)';
9924 sel_bkeys := $
sql$
CASE WHEN provsql.get_gate_type(e.token) =
'mulinput'
9926 ELSE '00000000-0000-0000-0000-000000000000'::UUID
END$
sql$;
9927 sel_bidx :=
'e.bidx';
9929 sel_probs := $
sql$
CASE WHEN provsql.get_gate_type(e.token)
IN (
'times',
'project',
'eq')
9930 THEN (
SELECT CASE WHEN bool_or(coalesce(provsql.get_prob(s.leaf),
1.
0) =
0)
9932 ELSE exp(sum(ln(coalesce(provsql.get_prob(s.leaf),
1.
0))))
END
9933 FROM provsql_reachability_support_tmp s
9934 WHERE s.token = e.token)
9935 ELSE coalesce(provsql.get_prob(e.token),
1.
0)
END$
sql$;
9936 sel_bkeys := $
sql$
CASE WHEN provsql.get_gate_type(e.token) =
'mulinput'
9937 THEN (provsql.get_children(e.token))[
1]
9938 ELSE '00000000-0000-0000-0000-000000000000'::UUID
END$
sql$;
9939 sel_bidx := $
sql$
CASE WHEN provsql.get_gate_type(e.token) =
'mulinput'
9940 THEN (provsql.get_infos(e.token)).info1
ELSE 0 END$
sql$;
9946 SELECT u
AS x
FROM provsql_reachability_edges_tmp
9947 UNION SELECT v
FROM provsql_reachability_edges_tmp
9948 UNION SELECT unnest($
1)),
9950 SELECT x, (row_number()
OVER (
ORDER BY x))::
INT AS id
FROM verts)
9951 SELECT array_agg(iu.id), array_agg(iv.id),
9956 (
SELECT array_agg(i.id
ORDER BY ev.ord)
9957 FROM unnest($
1)
WITH ORDINALITY
AS ev(x, ord)
9958 JOIN ids i
ON i.x = ev.x),
9959 (
SELECT array_agg(x
ORDER BY id)
FROM ids)
9961 (row_number()
OVER (
PARTITION BY t.bkey))::
INT AS bidx
9962 FROM provsql_reachability_edges_tmp t) e
9963 JOIN ids iu
ON iu.x = e.u
9964 JOIN ids iv
ON iv.x = e.v
9965 $
sql$, sel_probs, sel_bkeys, sel_bidx)
9966 INTO sources, destinations, tokens, probabilities, block_keys,
9967 block_indices, extra_ids, vertices
9968 USING extra_vertices;
9970 DROP TABLE provsql_reachability_edges_tmp;
9971 DROP TABLE IF EXISTS provsql_reachability_support_tmp;
9976$$
LANGUAGE plpgsql
SET client_min_messages = warning;
9995CREATE OR REPLACE
FUNCTION gather_reachability_sources(
9997 IN source_attribute TEXT,
9998 OUT source_values TEXT[],
9999 OUT source_tokens UUID[],
10000 OUT source_probabilities
DOUBLE PRECISION[])
10008 SELECT 1 FROM pg_attribute
10009 WHERE attrelid = rel
AND attname =
'provsql'
10010 AND atttypid =
'UUID'::REGTYPE
AND NOT attisdropped)
10018 tkind := (get_table_info(rel::oid)).kind;
10019 IF tkind =
'bid' THEN
10020 RAISE EXCEPTION
'reachability: % is block-independent (repair_key); block-correlated source sets are not supported', rel;
10024 DROP TABLE IF EXISTS provsql_reachability_sources_tmp;
10027 'CREATE TEMP TABLE provsql_reachability_sources_tmp AS '
10028 ||
'SELECT %1$I::TEXT AS x, provenance() AS token '
10029 ||
'FROM %2$s WHERE %1$I IS NOT NULL',
10030 source_attribute, rel);
10031 PERFORM remove_provenance(
'provsql_reachability_sources_tmp');
10032 IF tkind
IS DISTINCT FROM 'tid'
10033 AND EXISTS (
SELECT 1 FROM provsql_reachability_sources_tmp
10034 WHERE get_gate_type(token) <>
'input')
THEN
10035 DROP TABLE provsql_reachability_sources_tmp;
10036 RAISE EXCEPTION
'reachability: the provenance of % must consist of base input tokens (independent tuples); views or query results are not supported', rel;
10038 SELECT array_agg(x), array_agg(token),
10039 array_agg(coalesce(get_prob(token),
1.
0))
10040 INTO source_values, source_tokens, source_probabilities
10041 FROM provsql_reachability_sources_tmp;
10042 DROP TABLE provsql_reachability_sources_tmp;
10045 'CREATE TEMP TABLE provsql_reachability_sources_tmp AS '
10046 ||
'SELECT DISTINCT %1$I::TEXT AS x FROM %2$s WHERE %1$I IS NOT NULL',
10047 source_attribute, rel);
10048 SELECT array_agg(x),
10049 array_agg(
'00000000-0000-0000-0000-000000000000'::UUID),
10050 array_agg(
1.
0::float8)
10051 INTO source_values, source_tokens, source_probabilities
10052 FROM provsql_reachability_sources_tmp;
10053 DROP TABLE provsql_reachability_sources_tmp;
10056$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public
SET client_min_messages = warning;
10100CREATE OR REPLACE
FUNCTION eval_reachability(
10102 source_attribute TEXT,
10103 destination_attribute TEXT,
10111 edge_quals TEXT
DEFAULT NULL,
10112 source_rel REGCLASS
DEFAULT NULL,
10113 source_rel_attribute TEXT
DEFAULT NULL,
10114 edge_sql TEXT
DEFAULT NULL,
10115 hop_bound
INT DEFAULT NULL,
10116 hop_seed
INT DEFAULT NULL,
10117 hops_position
INT DEFAULT NULL)
10124 sp
double precision[];
10125 verbosity
INT := coalesce(current_setting(
'provsql.verbose_level',
true)::
INT,
0);
10128 IF source_rel
IS NOT NULL THEN
10131 SELECT g.source_values, g.source_tokens, g.source_probabilities
10133 FROM provsql.gather_reachability_sources(source_rel,
10134 source_rel_attribute) g;
10136 sv :=
ARRAY[]::TEXT[];
10137 st :=
ARRAY[]::UUID[];
10138 sp :=
ARRAY[]::float8[];
10142 sv :=
ARRAY[source_value];
10143 st :=
ARRAY[
'00000000-0000-0000-0000-000000000000'::UUID];
10144 sp :=
ARRAY[
1.
0::float8];
10147 e := provsql.gather_reachability_edges(edge_rel, source_attribute,
10148 destination_attribute,
10149 sv, edge_quals, edge_sql);
10150 IF to_regclass(work_name)
IS NOT NULL THEN
10151 EXECUTE format(
'DROP TABLE %I', work_name);
10153 EXECUTE format(
'CREATE TEMP TABLE %I (%s, provsql UUID)', work_name, coldef);
10154 IF hop_bound
IS NULL THEN
10156 'INSERT INTO %I SELECT ($1::TEXT[])[m.vertex]::%s, m.token '
10157 ||
'FROM provsql.reachability_materialize($2, $3, $4, $5, $6, $7, $8, $9, $10, $11) m',
10158 work_name, coltype)
10159 USING e.vertices, e.sources, e.destinations, e.tokens, e.probabilities,
10160 e.block_keys, e.block_indices, e.extra_ids, st, sp, directed;
10165 'INSERT INTO %I SELECT %s, m.token '
10166 ||
'FROM provsql.reachability_materialize_hops($2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) m',
10168 CASE WHEN hops_position =
1
10169 THEN format(
'm.hops, ($1::TEXT[])[m.vertex]::%s', coltype)
10170 ELSE format(
'($1::TEXT[])[m.vertex]::%s, m.hops', coltype)
END)
10171 USING e.vertices, e.sources, e.destinations, e.tokens, e.probabilities,
10172 e.block_keys, e.block_indices, e.extra_ids, st, sp, directed,
10173 hop_bound, hop_seed;
10175 IF verbosity >=
20 THEN
10176 RAISE NOTICE
'ProvSQL: recursive CTE "%" compiled along a tree decomposition of %',
10177 work_name, coalesce(edge_rel::TEXT,
'the join-defined edge query');
10179 EXCEPTION
WHEN OTHERS
THEN
10180 IF verbosity >=
10 THEN
10181 RAISE NOTICE
'ProvSQL: reachability route for "%" fell back to the generic fixpoint (%)',
10182 work_name, SQLERRM;
10184 PERFORM provsql.eval_recursive(body_sql, work_name, colnames, coldef);
10187$$
LANGUAGE plpgsql;
10206CREATE OR REPLACE
FUNCTION view_circuit(
10208 token2desc REGCLASS,
10211 'provsql',
'view_circuit' LANGUAGE C;
10224CREATE OR REPLACE
FUNCTION compile_to_ddnnf_dot(
10226 compiler TEXT =
'')
10228 'provsql',
'compile_to_ddnnf_dot' LANGUAGE C;
10243CREATE OR REPLACE
FUNCTION compile_to_ddnnf(
10245 compiler TEXT =
'')
10247 'provsql',
'compile_to_ddnnf' LANGUAGE C;
10264CREATE OR REPLACE
FUNCTION ddnnf_stats(
10266 compiler TEXT =
'')
10268 'provsql',
'ddnnf_stats' LANGUAGE C;
10282CREATE OR REPLACE
FUNCTION tseytin_cnf(
10284 weighted
BOOLEAN =
TRUE,
10285 mapping
BOOLEAN =
TRUE)
10287 'provsql',
'tseytin_cnf' LANGUAGE C;
10301CREATE OR REPLACE
FUNCTION tseytin_cnf_mapping_json(token UUID)
10303 'provsql',
'tseytin_cnf_mapping_json' LANGUAGE C;
10305CREATE OR REPLACE
FUNCTION tseytin_cnf_mapping(token UUID)
10306 RETURNS TABLE(variable
INT, gate UUID, probability FLOAT8)
AS $$
10307 SELECT variable, gate, probability
10308 FROM jsonb_to_recordset(tseytin_cnf_mapping_json(token))
10309 AS x(variable
INT, gate UUID, probability FLOAT8)
10311$$
LANGUAGE SQL STABLE;
10323CREATE OR REPLACE
FUNCTION tree_decomposition_dot(
10326 'provsql',
'tree_decomposition_dot' LANGUAGE C;
10346CREATE OR REPLACE
FUNCTION tool_available(name TEXT)
10348 'provsql',
'tool_available' LANGUAGE C STRICT;
10378CREATE TABLE IF NOT EXISTS tool_overrides(
10379 name TEXT
PRIMARY KEY,
10380 removed
BOOLEAN NOT NULL DEFAULT false,
10384 input_formats TEXT[],
10385 output_format TEXT,
10389 dependencies TEXT[],
10391 argtpl_circuit TEXT,
10394SELECT pg_catalog.pg_extension_config_dump(
'tool_overrides',
'');
10406CREATE OR REPLACE
FUNCTION tool_registry_list()
10407 RETURNS TABLE(name TEXT, kind TEXT, executable TEXT, operations TEXT[],
10408 input_formats TEXT[], output_format TEXT, parser TEXT,
10409 preference
INT, enabled
BOOLEAN, argtpl TEXT,
10410 argtpl_circuit TEXT, endpoint TEXT, available
BOOLEAN)
AS
10411 'provsql',
'tool_registry_list' LANGUAGE C STABLE;
10416CREATE OR REPLACE VIEW tools
AS
10417 SELECT name, kind, executable, operations, input_formats, output_format,
10418 parser, preference, enabled, argtpl, argtpl_circuit, endpoint,
10420 FROM tool_registry_list();
10455CREATE OR REPLACE
FUNCTION register_tool(
10457 executable TEXT
DEFAULT NULL,
10458 kind TEXT
DEFAULT 'cli',
10459 operations TEXT[]
DEFAULT NULL,
10460 input_formats TEXT[]
DEFAULT NULL,
10461 output_format TEXT
DEFAULT NULL,
10462 parser TEXT
DEFAULT NULL,
10463 argtpl TEXT
DEFAULT NULL,
10464 argtpl_circuit TEXT
DEFAULT NULL,
10465 preference
INT DEFAULT 0,
10466 enabled
BOOLEAN DEFAULT true,
10467 endpoint TEXT
DEFAULT NULL)
10469 'provsql',
'tool_registry_register' LANGUAGE C;
10472CREATE OR REPLACE
FUNCTION unregister_tool(name TEXT)
10474 'provsql',
'tool_registry_unregister' LANGUAGE C STRICT;
10477CREATE OR REPLACE
FUNCTION set_tool_enabled(name TEXT, enabled
BOOLEAN)
10479 'provsql',
'tool_registry_set_enabled' LANGUAGE C STRICT;
10482CREATE OR REPLACE
FUNCTION set_tool_preference(name TEXT, preference
INT)
10484 'provsql',
'tool_registry_set_preference' LANGUAGE C STRICT;
10488REVOKE ALL ON FUNCTION register_tool(TEXT, TEXT, TEXT, TEXT[], TEXT[], TEXT, TEXT, TEXT, TEXT,
INT,
BOOLEAN, TEXT)
FROM PUBLIC;
10489REVOKE ALL ON FUNCTION unregister_tool(TEXT)
FROM PUBLIC;
10490REVOKE ALL ON FUNCTION set_tool_enabled(TEXT,
BOOLEAN)
FROM PUBLIC;
10491REVOKE ALL ON FUNCTION set_tool_preference(TEXT,
INT)
FROM PUBLIC;
10499CREATE OR REPLACE
FUNCTION to_provxml(
10501 token2desc REGCLASS =
NULL)
10503 'provsql',
'to_provxml' LANGUAGE C;
10506CREATE OR REPLACE
FUNCTION provenance()
RETURNS UUID
AS
10507 'provsql',
'provenance' LANGUAGE C;
10515CREATE OR REPLACE
FUNCTION where_provenance(token UUID)
10517 'provsql',
'where_provenance' LANGUAGE C;
10528CREATE OR REPLACE
FUNCTION reset_constants_cache()
10530 'provsql',
'reset_constants_cache' LANGUAGE C;
10532SELECT reset_constants_cache();
10534SELECT create_gate(gate_zero(),
'zero');
10535SELECT create_gate(gate_one(),
'one');
10540CREATE TYPE QUERY_TYPE_ENUM
AS ENUM (
10559CREATE FUNCTION sr_formula(token ANYELEMENT, token2value REGCLASS =
NULL)
10563 IF token
IS NULL THEN
10566 RETURN provsql.provenance_evaluate_compiled(
10573$$
LANGUAGE plpgsql PARALLEL SAFE STABLE;
10576CREATE FUNCTION sr_counting(token ANYELEMENT, token2value REGCLASS)
10580 RETURN provsql.provenance_evaluate_compiled(
10587$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
10590CREATE FUNCTION sr_why(token ANYELEMENT, token2value REGCLASS)
10594 RETURN provsql.provenance_evaluate_compiled(
10601$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
10604CREATE FUNCTION sr_how(token ANYELEMENT, token2value REGCLASS)
10608 RETURN provsql.provenance_evaluate_compiled(
10615$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
10618CREATE FUNCTION sr_which(token ANYELEMENT, token2value REGCLASS)
10622 RETURN provsql.provenance_evaluate_compiled(
10629$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
10637CREATE FUNCTION sr_boolexpr(token ANYELEMENT, token2value REGCLASS =
NULL)
10641 IF token
IS NULL THEN
10644 RETURN provsql.provenance_evaluate_compiled(
10651$$
LANGUAGE plpgsql PARALLEL SAFE STABLE;
10654CREATE FUNCTION sr_boolean(token ANYELEMENT, token2value REGCLASS)
10658 RETURN provsql.provenance_evaluate_compiled(
10665$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
10668CREATE FUNCTION true_nonzero(token UUID)
10670 'provsql',
'true_nonzero' LANGUAGE C PARALLEL SAFE STABLE;
10698CREATE FUNCTION nonzero(token UUID,
10699 semiring TEXT
DEFAULT NULL,
10700 mapping REGCLASS
DEFAULT NULL)
10704 IF token
IS NULL THEN
10707 IF semiring
IS NULL THEN
10708 RETURN provsql.true_nonzero(token);
10709 ELSIF semiring =
'BOOLEAN' THEN
10710 RETURN provsql.provenance_evaluate_compiled(token, mapping,
'BOOLEAN',
TRUE);
10711 ELSIF semiring =
'counting' THEN
10712 RETURN provsql.provenance_evaluate_compiled(token, mapping,
'counting',
1) <>
0;
10714 RAISE EXCEPTION
'nonzero: unsupported semiring "%" (supported: BOOLEAN, counting; NULL for the universal zero test)', semiring;
10717$$
LANGUAGE plpgsql PARALLEL SAFE STABLE;
10728CREATE FUNCTION present(token UUID)
10731 SELECT provsql.nonzero(token,
'BOOLEAN');
10732$$
LANGUAGE sql PARALLEL SAFE STABLE;
10746CREATE FUNCTION sr_tropical(token ANYELEMENT, token2value REGCLASS,
10747 nonnegative
BOOLEAN =
false)
10751 RETURN provsql.provenance_evaluate_compiled(
10754 CASE WHEN nonnegative
THEN 'tropical_nonneg' ELSE 'tropical' END,
10758$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
10765CREATE FUNCTION sr_viterbi(token ANYELEMENT, token2value REGCLASS)
10769 RETURN provsql.provenance_evaluate_compiled(
10776$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
10785CREATE FUNCTION sr_lukasiewicz(token ANYELEMENT, token2value REGCLASS)
10789 RETURN provsql.provenance_evaluate_compiled(
10796$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
10813CREATE FUNCTION sr_minmax(token UUID, token2value REGCLASS, element_one ANYENUM)
10817 RETURN provsql.provenance_evaluate_compiled(
10824$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
10838CREATE FUNCTION sr_maxmin(token UUID, token2value REGCLASS, element_one ANYENUM)
10842 RETURN provsql.provenance_evaluate_compiled(
10849$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
10860CREATE FUNCTION choose_function(state ANYELEMENT, data ANYELEMENT)
10861 RETURNS ANYELEMENT
AS
10864 IF state
IS NULL THEN
10870$$
LANGUAGE plpgsql PARALLEL SAFE IMMUTABLE;
10873CREATE AGGREGATE choose(ANYELEMENT) (
10874 SFUNC = choose_function,
10890CREATE OR REPLACE
FUNCTION explode_table(_tbl TEXT, AGG_TOKEN TEXT)
10898 SELECT n.nspname
INTO _nsp
10899 FROM pg_class c
JOIN pg_namespace n
ON n.oid = c.relnamespace
10900 WHERE c.oid = _tbl::REGCLASS;
10903 CREATE TABLE %1$I.temp_exploded AS
10906 provsql.get_extra(children[2]) AS new_t,
10907 provsql.provenance_times(children[1], provsql) AS new_provsql
10910 SELECT provsql.get_children(sm) AS children
10911 FROM UNNEST(provsql.get_children(%3$I)) AS sm
10912 ) AS sub', _nsp, _tbl, AGG_TOKEN);
10913 EXECUTE format(
'DROP TABLE %I.%I', _nsp, _tbl);
10914 EXECUTE format(
'ALTER TABLE %I.temp_exploded DROP COLUMN %I, DROP COLUMN provsql', _nsp, AGG_TOKEN);
10915 EXECUTE format(
'ALTER TABLE %I.temp_exploded RENAME COLUMN new_t TO %I', _nsp, AGG_TOKEN);
10916 EXECUTE format(
'ALTER TABLE %I.temp_exploded RENAME COLUMN new_provsql TO provsql', _nsp);
10917 EXECUTE format(
'ALTER TABLE %I.temp_exploded RENAME TO %I', _nsp, _tbl);
10919$$
LANGUAGE plpgsql;
10943CREATE OR REPLACE
FUNCTION setup_search_path()
10945 LANGUAGE plpgsql
AS $$
10947 db TEXT := current_database();
10953 SELECT s.setconfig
INTO cfg
10954 FROM pg_db_role_setting s
10955 JOIN pg_database d
ON d.oid = s.setdatabase
10956 WHERE d.datname = db
AND s.setrole =
0;
10958 IF cfg
IS NOT NULL THEN
10959 SELECT substr(e, length(
'search_path=') +
1)
INTO cur
10960 FROM unnest(cfg)
AS e
10961 WHERE e
LIKE 'search_path=%';
10964 IF cur
IS NULL THEN
10967 new_path :=
'"$user", public, provsql';
10968 EXECUTE format(
'ALTER DATABASE %I SET search_path = %s', db, new_path);
10969 RAISE NOTICE
'ProvSQL: set search_path = % for database "%" (no previous database-level setting). Only new sessions are affected.',
10976 SELECT 1 FROM unnest(string_to[](cur,
','))
AS p
10977 WHERE btrim(btrim(p),
'"') =
'provsql')
10979 RAISE NOTICE
'ProvSQL: search_path for database "%" already contains provsql (= %); no change.',
10984 new_path := cur ||
', provsql';
10985 EXECUTE format(
'ALTER DATABASE %I SET search_path = %s', db, new_path);
10986 RAISE NOTICE
'ProvSQL: appended provsql to search_path for database "%" (now: %). Only new sessions are affected.',
10992GRANT USAGE
ON SCHEMA provsql
TO PUBLIC;
10994SET search_path
TO public;
11009 has_provsql
BOOLEAN;
11011 SELECT reset_val
INTO rp
FROM pg_settings
WHERE name =
'search_path';
11012 SELECT bool_or(btrim(btrim(p),
'"') =
'provsql')
11014 FROM unnest(string_to[](coalesce(rp,
''),
','))
AS p;
11015 IF NOT coalesce(has_provsql,
false)
THEN
11016 SET LOCAL client_min_messages = notice;
11017 RAISE NOTICE
'ProvSQL: schema "provsql" is not in your default search_path (currently: %).', rp;
11018 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());
11032SELECT provsql.reset_constants_cache();
11033SET search_path
TO provsql;
11062CREATE TABLE update_provenance (
11065 query_type QUERY_TYPE_ENUM,
11067 ts
TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
11068 valid_time TSTZMULTIRANGE
DEFAULT TSTZMULTIRANGE(tstzrange(
CURRENT_TIMESTAMP,
NULL)),
11087CREATE OR REPLACE
FUNCTION transaction_token()
11096 tok := current_setting(
'provsql.transaction_token',
true);
11097 IF tok
IS NOT NULL AND tok <>
'' THEN
11101 new_tok := public.uuid_generate_v4();
11102 PERFORM create_gate(new_tok,
'update');
11103 PERFORM set_config(
'provsql.transaction_token', new_tok::TEXT,
true);
11108 query_text :=
NULL;
11115 INSERT INTO update_provenance(provsql, query, query_type, username, ts,
11117 VALUES (new_tok, query_text,
'TRANSACTION',
current_user,
11118 CURRENT_TIMESTAMP,
'{(,)}'::TSTZMULTIRANGE,
11119 pg_current_xact_id());
11136CREATE OR REPLACE
FUNCTION stamp_commit_time()
11140 now_ts TIMESTAMPTZ := clock_timestamp();
11142 UPDATE update_provenance
11144 valid_time =
CASE WHEN query_type =
'TRANSACTION' THEN valid_time
11145 ELSE TSTZMULTIRANGE(tstzrange(now_ts,
NULL))
END
11146 WHERE provsql =
NEW.provsql;
11149$$
LANGUAGE plpgsql;
11152 IF NOT EXISTS (
SELECT 1 FROM pg_trigger
11153 WHERE tgrelid =
'provsql.update_provenance'::REGCLASS
11154 AND tgname =
'stamp_commit_time')
THEN
11155 CREATE CONSTRAINT TRIGGER stamp_commit_time
11156 AFTER
INSERT ON provsql.update_provenance
11157 DEFERRABLE INITIALLY DEFERRED
11158 FOR EACH ROW EXECUTE PROCEDURE provsql.stamp_commit_time();
11165CREATE OR REPLACE
FUNCTION add_provenance(_tbl REGCLASS)
11173 SELECT 1 FROM pg_attribute
11174 WHERE attrelid = _tbl
AND attname =
'provsql' AND NOT attisdropped
11176 RAISE NOTICE
'table % already has provenance tracking', _tbl;
11182 EXECUTE format(
'ALTER TABLE %s ADD COLUMN provsql UUID', _tbl);
11184 'UPDATE %s SET provsql = public.uuid_generate_v4() WHERE provsql IS NULL',
11186 EXECUTE format(
'CREATE INDEX ON %s(provsql)', _tbl);
11188 'CREATE TRIGGER provenance_guard BEFORE INSERT OR UPDATE OF provsql '
11189 'ON %s FOR EACH ROW EXECUTE PROCEDURE provsql.provenance_guard()',
11192 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);
11193 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);
11194 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);
11196 PERFORM provsql.set_table_info(_tbl::oid,
'tid');
11197 PERFORM provsql.set_ancestors(_tbl::oid,
ARRAY[_tbl::oid]);
11199$$
LANGUAGE plpgsql SECURITY DEFINER;
11205CREATE OR REPLACE
FUNCTION delete_statement_trigger()
11215 enable_trigger BOOL;
11217 enable_trigger := current_setting(
'provsql.update_provenance',
true);
11218 IF enable_trigger =
'f' THEN
11221 delete_token := public.uuid_generate_v4();
11223 PERFORM create_gate(delete_token,
'update');
11227 FROM pg_stat_activity
11228 WHERE pid = pg_backend_pid();
11230 tx_token := transaction_token();
11232 INSERT INTO update_provenance (provsql, query, query_type, username, ts,
11233 valid_time, xid, tx_token)
11234 VALUES (delete_token, query_text,
'DELETE',
current_user,
CURRENT_TIMESTAMP,
11235 TSTZMULTIRANGE(tstzrange(
CURRENT_TIMESTAMP,
NULL)),
11236 pg_current_xact_id(), tx_token);
11240 delete_token := provenance_times(tx_token, delete_token);
11242 PERFORM set_config(
'provsql.update_provenance',
'off',
false);
11243 EXECUTE format(
'INSERT INTO %I.%I SELECT * FROM OLD_TABLE;', TG_TABLE_SCHEMA, TG_TABLE_NAME);
11244 PERFORM set_config(
'provsql.update_provenance',
'on',
false);
11246 FOR r
IN (
SELECT *
FROM OLD_TABLE) LOOP
11247 old_token := r.provsql;
11248 new_token := provenance_monus(old_token, delete_token);
11250 PERFORM set_config(
'provsql.update_provenance',
'off',
false);
11251 EXECUTE format(
'UPDATE %I.%I SET provsql = $1 WHERE provsql = $2;', TG_TABLE_SCHEMA, TG_TABLE_NAME)
11252 USING new_token, old_token;
11253 PERFORM set_config(
'provsql.update_provenance',
'on',
false);
11258$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp SECURITY DEFINER;
11267CREATE OR REPLACE
FUNCTION insert_statement_trigger()
11277 enable_trigger BOOL;
11279 enable_trigger := current_setting(
'provsql.update_provenance',
true);
11280 IF enable_trigger =
'f' THEN
11284 insert_token := public.uuid_generate_v4();
11286 PERFORM create_gate(insert_token,
'update');
11290 FROM pg_stat_activity
11291 WHERE pid = pg_backend_pid();
11293 tx_token := transaction_token();
11295 INSERT INTO update_provenance (provsql, query, query_type, username, ts,
11296 valid_time, xid, tx_token)
11297 VALUES (insert_token, query_text,
'INSERT',
current_user,
CURRENT_TIMESTAMP,
11298 TSTZMULTIRANGE(tstzrange(
CURRENT_TIMESTAMP,
NULL)),
11299 pg_current_xact_id(), tx_token);
11303 insert_token := provenance_times(tx_token, insert_token);
11305 FOR r
IN (
SELECT *
FROM NEW_TABLE) LOOP
11306 old_token := r.provsql;
11307 new_token := provenance_times(old_token, insert_token);
11308 PERFORM set_config(
'provsql.update_provenance',
'off',
false);
11309 EXECUTE format(
'UPDATE %I.%I SET provsql = $1 WHERE provsql = $2;', TG_TABLE_SCHEMA, TG_TABLE_NAME)
11310 USING new_token, old_token;
11311 PERFORM set_config(
'provsql.update_provenance',
'on',
false);
11316$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp SECURITY DEFINER;
11324CREATE OR REPLACE
FUNCTION update_statement_trigger()
11334 enable_trigger BOOL;
11336 enable_trigger := current_setting(
'provsql.update_provenance',
true);
11337 IF enable_trigger =
'f' THEN
11340 update_token := public.uuid_generate_v4();
11342 PERFORM create_gate(update_token,
'update');
11346 FROM pg_stat_activity
11347 WHERE pid = pg_backend_pid();
11349 tx_token := transaction_token();
11351 INSERT INTO update_provenance (provsql, query, query_type, username, ts,
11352 valid_time, xid, tx_token)
11353 VALUES (update_token, query_text,
'UPDATE',
current_user,
CURRENT_TIMESTAMP,
11354 TSTZMULTIRANGE(tstzrange(
CURRENT_TIMESTAMP,
NULL)),
11355 pg_current_xact_id(), tx_token);
11359 update_token := provenance_times(tx_token, update_token);
11361 FOR r
IN (
SELECT *
FROM NEW_TABLE) LOOP
11362 old_token := r.provsql;
11363 new_token := provenance_times(old_token, update_token);
11365 PERFORM set_config(
'provsql.update_provenance',
'off',
false);
11366 EXECUTE format(
'UPDATE %I.%I SET provsql = $1 WHERE provsql = $2;', TG_TABLE_SCHEMA, TG_TABLE_NAME)
11367 USING new_token, old_token;
11368 PERFORM set_config(
'provsql.update_provenance',
'on',
false);
11371 PERFORM set_config(
'provsql.update_provenance',
'off',
false);
11372 EXECUTE format(
'INSERT INTO %I.%I SELECT * FROM OLD_TABLE;', TG_TABLE_SCHEMA, TG_TABLE_NAME);
11373 PERFORM set_config(
'provsql.update_provenance',
'on',
false);
11375 FOR r
IN (
SELECT *
FROM OLD_TABLE) LOOP
11376 old_token := r.provsql;
11377 new_token := provenance_monus(old_token, update_token);
11379 PERFORM set_config(
'provsql.update_provenance',
'off',
false);
11380 EXECUTE format(
'UPDATE %I.%I SET provsql = $1 WHERE provsql = $2;', TG_TABLE_SCHEMA, TG_TABLE_NAME)
11381 USING new_token, old_token;
11382 PERFORM set_config(
'provsql.update_provenance',
'on',
false);
11387$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp SECURITY DEFINER;
11399SET search_path
TO provsql;
11413CREATE FUNCTION sr_temporal(token ANYELEMENT, token2value REGCLASS)
11414 RETURNS TSTZMULTIRANGE
AS
11417 RETURN provsql.provenance_evaluate_compiled(
11421 '{(,)}'::TSTZMULTIRANGE
11424$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
11440CREATE FUNCTION sr_interval_num(token ANYELEMENT, token2value REGCLASS)
11441 RETURNS nummultirange
AS
11444 RETURN provsql.provenance_evaluate_compiled(
11448 '{(,)}'::nummultirange
11451$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
11467CREATE FUNCTION sr_interval_int(token ANYELEMENT, token2value REGCLASS)
11468 RETURNS int4multirange
AS
11471 RETURN provsql.provenance_evaluate_compiled(
11475 '{(,)}'::int4multirange
11478$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
11489CREATE OR REPLACE
FUNCTION union_tstzintervals(
11491 token2value REGCLASS
11493RETURNS TSTZMULTIRANGE
AS
11495 SELECT sr_temporal(token, token2value)
11496$$
LANGUAGE SQL PARALLEL SAFE STABLE;
11506CREATE OR REPLACE
FUNCTION timetravel(
11508 at_time TIMESTAMPTZ
11510RETURNS SETOF RECORD
11515 RETURN QUERY
EXECUTE format(
11519 sr_temporal(provenance(), %2$L)
11523 sr_temporal(provenance(), %2$L) @> %3$L::TIMESTAMPTZ
11526 'provsql.time_validity_view',
11541CREATE OR REPLACE
FUNCTION timeslice(
11543 from_time TIMESTAMPTZ,
11544 to_time TIMESTAMPTZ
11546RETURNS SETOF RECORD
11551 RETURN QUERY
EXECUTE format(
11555 sr_temporal(provenance(), %2$L)
11559 sr_temporal(provenance(), %2$L)
11560 && tstzrange(%3$L::TIMESTAMPTZ, %4$L::TIMESTAMPTZ)
11563 'provsql.time_validity_view',
11580CREATE OR REPLACE
FUNCTION history(
11585RETURNS SETOF RECORD
11590 condition TEXT :=
'';
11593 IF array_length(col_names,
1)
IS NULL
11594 OR array_length(col_values,
1)
IS NULL
11595 OR array_length(col_names,
1) != array_length(col_values,
1)
11597 RAISE EXCEPTION
'col_names and col_values must have the same (non-null) length';
11600 FOR i
IN 1..array_length(col_names,
1)
11603 condition := condition ||
' AND ';
11605 condition := condition || format(
'%I = %L', col_names[i], col_values[i]);
11608 RETURN QUERY
EXECUTE format(
11612 sr_temporal(provenance(), %L)
11619 'provsql.time_validity_view',
11632CREATE OR REPLACE
FUNCTION get_valid_time(
11636RETURNS TSTZMULTIRANGE
11640 result TSTZMULTIRANGE;
11645 sr_temporal(provenance(), %L)
11651 'provsql.time_validity_view',
11670CREATE OR REPLACE
FUNCTION undo(
11688 SELECT query
INTO undone_query
11689 FROM update_provenance
11694 RAISE NOTICE
'Unable to find % in update_provenance', c;
11700 FROM pg_stat_activity
11701 WHERE pid = pg_backend_pid();
11703 undo_token := public.uuid_generate_v4();
11704 PERFORM create_gate(undo_token,
'update');
11705 INSERT INTO update_provenance(provsql, query, query_type, username, ts,
11706 valid_time, xid, tx_token)
11713 TSTZMULTIRANGE(tstzrange(
CURRENT_TIMESTAMP,
NULL)),
11714 pg_current_xact_id(),
11715 transaction_token()
11718 PERFORM set_config(
'provsql.update_provenance',
'off',
false);
11723 WHERE nspname
NOT IN (
'pg_catalog',
'information_schema',
'pg_toast',
'pg_temp_1',
'pg_toast_temp_1')
11726 EXECUTE format(
'SELECT tablename AS tname FROM pg_tables WHERE schemaname = %L', schema_rec.nspname)
11730 FROM information_schema.columns
11731 WHERE table_schema = schema_rec.nspname
11732 AND table_name = table_rec.tname
11733 AND table_name <>
'update_provenance'
11734 AND column_name =
'provsql'
11737 EXECUTE format(
'SELECT provsql AS x FROM %I.%I', schema_rec.nspname, table_rec.tname)
11739 new_x := replace_the_circuit(row_rec.x, c, undo_token);
11740 EXECUTE format(
'UPDATE %I.%I SET provsql = $1 WHERE provsql = $2',
11741 schema_rec.nspname, table_rec.tname)
11742 USING new_x, row_rec.x;
11748 PERFORM set_config(
'provsql.update_provenance',
'on',
false);
11764CREATE OR REPLACE
FUNCTION replace_the_circuit(
11776 ntype PROVENANCE_GATE;
11779 RETURN provenance_monus(c, u);
11781 ELSIF get_gate_type(x) =
'update' OR get_gate_type(x) =
'input' THEN
11785 FOREACH child
IN ARRAY get_children(x)
11787 nchildren := array_append(nchildren, replace_the_circuit(child, c, u));
11790 ntoken := public.uuid_generate_v4();
11791 ntype := get_gate_type(x);
11793 PERFORM create_gate(ntoken, ntype, nchildren);
11810CREATE OR REPLACE
FUNCTION substitute_gate(
11822 changed
BOOLEAN :=
false;
11824 ntype PROVENANCE_GATE;
11829 ntype := get_gate_type(x);
11831 IF ntype
IN (
'input',
'update',
'rv',
'value',
'zero',
'one')
THEN
11835 FOREACH child
IN ARRAY get_children(x)
11837 rewritten := substitute_gate(child,
old,
new);
11838 IF rewritten <> child
THEN
11841 nchildren := array_append(nchildren, rewritten);
11843 IF NOT changed
THEN
11846 ntoken := public.uuid_generate_v4();
11847 PERFORM create_gate(ntoken, ntype, nchildren);
11869CREATE OR REPLACE
FUNCTION replace_update(
11884 IF old IS NULL OR p
IS NULL THEN
11885 RAISE EXCEPTION
'replace_update: neither argument may be NULL';
11887 IF get_gate_type(
old) <>
'update' THEN
11888 RAISE EXCEPTION
'replace_update: % is not an update gate',
old
11889 USING HINT =
'Use provsql.replace_input() for a tuple''s own input gate.';
11892 SELECT *
INTO old_row
FROM update_provenance
WHERE provsql =
old LIMIT
1;
11893 IF old_row
IS NULL THEN
11894 RAISE EXCEPTION
'replace_update: % is not recorded in update_provenance',
old;
11897 new_token := public.uuid_generate_v4();
11898 PERFORM create_gate(new_token,
'update');
11899 PERFORM set_prob(new_token, p);
11901 INSERT INTO update_provenance(provsql, query, query_type, username, ts,
11902 valid_time, xid, tx_token)
11903 VALUES (new_token, old_row.query,
'REPLACE',
current_user,
11905 TSTZMULTIRANGE(tstzrange(
CURRENT_TIMESTAMP,
NULL)),
11906 pg_current_xact_id(), transaction_token());
11908 PERFORM set_config(
'provsql.update_provenance',
'off',
false);
11913 WHERE nspname
NOT IN (
'pg_catalog',
'information_schema',
'pg_toast',
'pg_temp_1',
'pg_toast_temp_1')
11916 EXECUTE format(
'SELECT tablename AS tname FROM pg_tables WHERE schemaname = %L', schema_rec.nspname)
11920 FROM information_schema.columns
11921 WHERE table_schema = schema_rec.nspname
11922 AND table_name = table_rec.tname
11923 AND table_name <>
'update_provenance'
11924 AND column_name =
'provsql'
11927 EXECUTE format(
'SELECT provsql AS x FROM %I.%I', schema_rec.nspname, table_rec.tname)
11929 new_x := substitute_gate(row_rec.x,
old, new_token);
11930 IF new_x <> row_rec.x
THEN
11931 EXECUTE format(
'UPDATE %I.%I SET provsql = $1 WHERE provsql = $2',
11932 schema_rec.nspname, table_rec.tname)
11933 USING new_x, row_rec.x;
11940 PERFORM set_config(
'provsql.update_provenance',
'on',
false);
11950CREATE VIEW provsql.time_validity_view
AS
11951 SELECT valid_time
AS value, provsql
AS provenance
FROM provsql.update_provenance;
11955SET search_path
TO public;
11962SELECT provsql.reset_constants_cache();