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;
149CREATE OR REPLACE
FUNCTION create_gate(
151 type PROVENANCE_GATE,
157 'provsql',
'create_gate' LANGUAGE C PARALLEL SAFE;
164CREATE OR REPLACE
FUNCTION get_gate_type(
166 RETURNS PROVENANCE_GATE
AS
167 'provsql',
'get_gate_type' LANGUAGE C IMMUTABLE PARALLEL SAFE;
169CREATE OR REPLACE
FUNCTION get_children(
172 'provsql',
'get_children' LANGUAGE C IMMUTABLE PARALLEL SAFE;
192CREATE OR REPLACE
FUNCTION set_prob(
193 token UUID, p
DOUBLE PRECISION)
195 'provsql',
'set_prob' LANGUAGE C PARALLEL RESTRICTED;
205CREATE OR REPLACE
FUNCTION probability_is_set(token UUID)
207 'provsql',
'probability_is_set' LANGUAGE C STABLE PARALLEL SAFE;
218CREATE OR REPLACE
FUNCTION note_fresh_leaf(token UUID)
220 'provsql',
'note_fresh_leaf' LANGUAGE C;
224CREATE OR REPLACE
FUNCTION is_fresh_leaf(token UUID)
226 'provsql',
'is_fresh_leaf' LANGUAGE C VOLATILE;
253CREATE OR REPLACE
FUNCTION replace_input(
old UUID, p
DOUBLE PRECISION)
258 tp provsql.PROVENANCE_GATE;
260 IF old IS NULL OR p
IS NULL THEN
261 RAISE EXCEPTION
'replace_input: neither argument may be NULL';
263 tp := provsql.get_gate_type(
old);
264 IF tp =
'mulinput' THEN
265 RAISE EXCEPTION
'replace_input: % belongs to a repair_key block',
old
266 USING HINT =
'A block''s values share one key gate and their masses '
267 'are meaningful together, so they are replaced together: '
268 'use provsql.replace_block().';
269 ELSIF tp =
'update' THEN
270 RAISE EXCEPTION
'replace_input: % is an update gate',
old
271 USING HINT =
'Use provsql.replace_update() to give a recorded data '
272 'modification a different probability.';
273 ELSIF tp <>
'input' THEN
274 RAISE EXCEPTION
'replace_input: % is a gate of type %, not an input',
old, tp
275 USING HINT =
'Only a leaf carries a probability of its own; a derived '
276 'gate''s is computed from its leaves.';
278 t := public.uuid_generate_v4();
279 PERFORM provsql.create_gate(t,
'input');
280 PERFORM provsql.set_prob(t, p);
281 PERFORM provsql.note_fresh_leaf(t);
298CREATE OR REPLACE
FUNCTION replace_input(
299 _tbl REGCLASS,
old UUID, p
DOUBLE PRECISION)
306 t := provsql.replace_input(
old, p);
307 EXECUTE format(
'UPDATE %s SET provsql = $1 WHERE provsql = $2', _tbl)
309 GET DIAGNOSTICS n = ROW_COUNT;
311 RAISE EXCEPTION
'replace_input: no row of % carries the token %', _tbl,
old;
335CREATE OR REPLACE
FUNCTION replace_block(
336 _tbl REGCLASS, old_key UUID, probs
DOUBLE PRECISION[]
DEFAULT NULL)
347 IF provsql.get_gate_type(old_key) <>
'input' THEN
348 RAISE EXCEPTION
'replace_block: % is not a block key gate', old_key;
355 was_active := coalesce(current_setting(
'provsql.active',
true),
'on');
356 PERFORM set_config(
'provsql.active',
'off',
true);
359 'CREATE TEMP TABLE provsql_replace_block_tmp ON COMMIT DROP AS
360 SELECT t.provsql AS old_token,
361 NULL::UUID AS new_token,
362 (provsql.get_infos(t.provsql)).info1 AS ord
364 WHERE provsql.get_gate_type(t.provsql) = ''mulinput''
365 AND (provsql.get_children(t.provsql))[1] = %L', _tbl, old_key);
367 SELECT count(*)
INTO n
FROM provsql_replace_block_tmp;
369 RAISE EXCEPTION
'replace_block: no row of % belongs to block %', _tbl, old_key;
371 IF probs
IS NOT NULL AND array_length(probs,
1) <> n
THEN
372 RAISE EXCEPTION
'replace_block: block % has % rows but % probabilities were given',
373 old_key, n, array_length(probs,
1);
376 new_key := public.uuid_generate_v4();
377 PERFORM provsql.create_gate(new_key,
'input');
379 FOR r
IN SELECT old_token, ord
FROM provsql_replace_block_tmp
ORDER BY ord LOOP
381 new_tok := public.uuid_generate_v4();
382 PERFORM provsql.create_gate(new_tok,
'mulinput',
ARRAY[new_key], r.ord, n,
NULL);
383 IF probs
IS NOT NULL THEN
384 PERFORM provsql.set_prob(new_tok, probs[i]);
386 PERFORM provsql.note_fresh_leaf(new_tok);
387 UPDATE provsql_replace_block_tmp
SET new_token = new_tok
388 WHERE old_token = r.old_token;
392 'UPDATE %s t SET provsql = b.new_token
393 FROM provsql_replace_block_tmp b WHERE t.provsql = b.old_token', _tbl);
395 DROP TABLE provsql_replace_block_tmp;
396 PERFORM set_config(
'provsql.active', was_active,
true);
400CREATE OR REPLACE
FUNCTION get_prob(
402 RETURNS DOUBLE PRECISION AS
403 'provsql',
'get_prob' LANGUAGE C STABLE PARALLEL SAFE;
407CREATE OR REPLACE
FUNCTION get_infos(
408 token UUID,
OUT info1
INT,
OUT info2
INT)
410 'provsql',
'get_infos' LANGUAGE C STABLE PARALLEL SAFE;
439CREATE OR REPLACE
FUNCTION provenance_assume(token UUID, assumption TEXT)
441 'provsql',
'provenance_assume' LANGUAGE C COST
100 PARALLEL SAFE;
458CREATE OR REPLACE
FUNCTION assume_boolean(token UUID)
RETURNS UUID
AS
459 'provsql',
'assume_boolean' LANGUAGE C COST
100 PARALLEL SAFE;
477CREATE OR REPLACE
FUNCTION annotate(token UUID, extra TEXT)
RETURNS UUID
AS
478 'provsql',
'annotate' LANGUAGE C COST
100 PARALLEL SAFE;
491CREATE OR REPLACE
FUNCTION strip_annotations(token UUID)
RETURNS UUID
AS
493WITH RECURSIVE peel(g)
AS (
496 SELECT (provsql.get_children(p.g))[
1]
FROM peel p
497 WHERE provsql.get_gate_type(p.g) =
'annotation'
499SELECT g
FROM peel
WHERE provsql.get_gate_type(g) <>
'annotation' LIMIT
1;
500$$
LANGUAGE sql STABLE PARALLEL SAFE;
529CREATE OR REPLACE
FUNCTION cond(target UUID, evidence UUID)
RETURNS UUID
AS
539 IF evidence
IS NULL OR evidence = gate_one()
THEN
544 tgt := coalesce(target, gate_one());
546 IF get_gate_type(tgt) =
'conditioned' THEN
550 ch := get_children(tgt);
552 ev := provenance_times(ch[
2], evidence);
553 jnt := provenance_times(ch[
3], evidence);
556 jnt := provenance_times(tgt, evidence);
559 result := public.uuid_generate_v5(uuid_ns_provsql(),
560 concat(
'conditioned', tgt, ev, jnt));
561 PERFORM create_gate(
result,
'conditioned',
ARRAY[tgt, ev, jnt]);
564$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public
565 SECURITY DEFINER PARALLEL SAFE;
574CREATE OPERATOR | (LEFTARG=UUID, RIGHTARG=UUID,
PROCEDURE=cond);
584CREATE OR REPLACE
FUNCTION cond_predicate(target UUID, predicate
BOOLEAN)
588 RAISE EXCEPTION
'UUID | (predicate) must be rewritten by the ProvSQL '
589 'planner hook: the right operand must be a Boolean combination of '
590 'random_variable / aggregate comparisons (is provsql.active off?)'
591 USING ERRCODE =
'feature_not_supported',
592 DETAIL =
'provsql-reason: operator-not-rewritten; scope: gap';
594$$
LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
596CREATE OPERATOR | (LEFTARG=UUID, RIGHTARG=
BOOLEAN,
PROCEDURE=cond_predicate);
612CREATE OR REPLACE
FUNCTION predicate_cond_predicate(target
BOOLEAN, evidence
BOOLEAN)
616 RAISE EXCEPTION
'(predicate) | (predicate) must be rewritten by the ProvSQL '
617 'planner hook: both operands must be Boolean combinations of '
618 'random_variable / aggregate comparisons (is provsql.active off?)'
619 USING ERRCODE =
'feature_not_supported',
620 DETAIL =
'provsql-reason: operator-not-rewritten; scope: gap';
622$$
LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
624CREATE OPERATOR | (LEFTARG=
BOOLEAN, RIGHTARG=
BOOLEAN,
PROCEDURE=predicate_cond_predicate);
638CREATE OR REPLACE
FUNCTION regular_indicator(cond
BOOLEAN)
RETURNS UUID
AS
640 SELECT CASE WHEN cond
THEN provsql.gate_one()
ELSE provsql.gate_zero()
END;
641$$
LANGUAGE sql IMMUTABLE PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
671CREATE OR REPLACE
FUNCTION given(evidence UUID)
RETURNS UUID
AS
674 RETURN provsql.evidence_as_observation(evidence);
676$$
LANGUAGE plpgsql VOLATILE PARALLEL SAFE
677 SET search_path=provsql,pg_temp,public SECURITY DEFINER;
687CREATE OPERATOR | (RIGHTARG=UUID,
PROCEDURE=given);
705CREATE OR REPLACE
FUNCTION given(predicate
BOOLEAN)
RETURNS UUID
AS
708 RAISE EXCEPTION
'given(predicate) / prefix | (predicate) must be rewritten '
709 'by the ProvSQL planner hook: the operand must be a Boolean combination '
710 'of random_variable / aggregate comparisons (is provsql.active off?)'
711 USING ERRCODE =
'feature_not_supported',
712 DETAIL =
'provsql-reason: operator-not-rewritten; scope: gap';
714$$
LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
716CREATE OPERATOR | (RIGHTARG=
BOOLEAN,
PROCEDURE=given);
748CREATE OR REPLACE
FUNCTION provenance_not(event UUID)
RETURNS UUID
AS
750 SELECT provsql.provenance_monus(provsql.gate_one(), event);
751$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
752 SET search_path=provsql,pg_temp,public;
761CREATE OPERATOR ! (RIGHTARG=UUID,
PROCEDURE=provenance_not);
778CREATE OR REPLACE
FUNCTION inversion_free_key(root TEXT, sec TEXT, factor
INT)
780 'provsql',
'inversion_free_key' LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
783CREATE OR REPLACE
FUNCTION get_extra(token UUID)
785 'provsql',
'get_extra' LANGUAGE C STABLE PARALLEL SAFE
RETURNS NULL ON NULL INPUT;
794CREATE OR REPLACE
FUNCTION get_nb_gates()
RETURNS BIGINT AS
795 'provsql',
'get_nb_gates' LANGUAGE C PARALLEL SAFE;
819CREATE OR REPLACE
FUNCTION check_store(
820 OUT unclean_shutdown
BOOLEAN,
822 OUT nb_tokens
BIGINT,
823 OUT next_index
BIGINT,
824 OUT dangling_indices
BIGINT,
825 OUT unreferenced
BIGINT,
826 OUT bad_wires
BIGINT,
827 OUT bad_extra
BIGINT)
829 'provsql',
'check_store' LANGUAGE C;
871CREATE OR REPLACE
FUNCTION circuit_cleanup(
872 dry_run
BOOLEAN DEFAULT false,
873 OUT gates_before
BIGINT,
874 OUT gates_after
BIGINT,
875 OUT wires_before
BIGINT,
876 OUT wires_after
BIGINT,
877 OUT extra_bytes_before
BIGINT,
878 OUT extra_bytes_after
BIGINT)
880 'provsql',
'circuit_cleanup' LANGUAGE C;
897CREATE OR REPLACE
FUNCTION delete_statement_trigger()
907 delete_token := public.uuid_generate_v4();
909 PERFORM create_gate(delete_token,
'input');
913 FROM pg_stat_activity
914 WHERE pid = pg_backend_pid();
916 INSERT INTO delete_provenance (delete_token, query, deleted_by, deleted_at)
917 VALUES (delete_token, query_text,
current_user,
CURRENT_TIMESTAMP);
919 EXECUTE format(
'INSERT INTO %I.%I SELECT * FROM OLD_TABLE;', TG_TABLE_SCHEMA, TG_TABLE_NAME);
921 FOR r
IN (
SELECT *
FROM OLD_TABLE) LOOP
922 old_token := r.provsql;
923 new_token := provenance_monus(old_token, delete_token);
925 EXECUTE format(
'UPDATE %I.%I SET provsql = $1 WHERE provsql = $2;', TG_TABLE_SCHEMA, TG_TABLE_NAME)
926 USING new_token, old_token;
931$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp SECURITY DEFINER;
953CREATE TABLE IF NOT EXISTS table_info(
954 relid REGCLASS
PRIMARY KEY,
956 block_key int2[]
NOT NULL DEFAULT ARRAY[]::int2[],
957 ancestors oid[]
NOT NULL DEFAULT ARRAY[]::oid[]
959SELECT pg_catalog.pg_extension_config_dump(
'table_info',
'');
971CREATE OR REPLACE
FUNCTION table_info_invalidate()
973 'provsql',
'provsql_table_info_invalidate' LANGUAGE C;
975DROP TRIGGER IF EXISTS table_info_invalidate
ON table_info;
976CREATE TRIGGER table_info_invalidate
977 AFTER
INSERT OR UPDATE OR DELETE ON table_info
978 FOR EACH ROW EXECUTE FUNCTION provsql.table_info_invalidate();
1002CREATE OR REPLACE
FUNCTION set_table_info(
1003 relid OID, kind TEXT, block_key INT2[]
DEFAULT ARRAY[]::INT2[])
1005 'provsql',
'set_table_info' LANGUAGE C SECURITY DEFINER;
1009CREATE OR REPLACE
FUNCTION remove_table_info(relid OID)
1011 'provsql',
'remove_table_info' LANGUAGE C SECURITY DEFINER;
1022CREATE OR REPLACE
FUNCTION get_table_info(
1023 relid OID,
OUT kind TEXT,
OUT block_key INT2[])
1025 'provsql',
'get_table_info' LANGUAGE C STABLE PARALLEL SAFE;
1044CREATE OR REPLACE
FUNCTION set_ancestors(
1045 relid OID, ancestors OID[]
DEFAULT ARRAY[]::OID[])
1047 'provsql',
'set_ancestors' LANGUAGE C SECURITY DEFINER;
1051CREATE OR REPLACE
FUNCTION remove_ancestors(relid OID)
1053 'provsql',
'remove_ancestors' LANGUAGE C SECURITY DEFINER;
1067CREATE OR REPLACE
FUNCTION migrate_table_info()
1069 'provsql',
'migrate_table_info' LANGUAGE C SECURITY DEFINER;
1078CREATE OR REPLACE
FUNCTION get_ancestors(relid OID)
1080 'provsql',
'get_ancestors' LANGUAGE C STABLE PARALLEL SAFE;
1104CREATE OR REPLACE
FUNCTION provenance_guard()
1105 RETURNS TRIGGER AS $$
1109 IF TG_OP =
'INSERT' THEN
1110 IF NEW.provsql
IS NULL THEN
1118 NEW.provsql := public.uuid_generate_v4();
1119 FOR _m
IN SELECT mapping, attribute
1120 FROM provsql.provenance_mapping_registry
1121 WHERE source = TG_RELID
AND maintained
1124 'INSERT INTO %s(value, provenance) SELECT ($1).%I, $2',
1125 _m.mapping::REGCLASS, _m.attribute)
1126 USING NEW,
NEW.provsql;
1129 PERFORM provsql.set_table_info(TG_RELID,
'opaque');
1131 ELSIF TG_OP =
'UPDATE' THEN
1132 IF NEW.provsql
IS DISTINCT FROM OLD.provsql
THEN
1133 IF provsql.is_fresh_leaf(
NEW.provsql)
THEN
1139 FOR _m
IN SELECT mapping, attribute
1140 FROM provsql.provenance_mapping_registry
WHERE source = TG_RELID
1143 'INSERT INTO %1$s(value, provenance) '
1144 'SELECT value, $2 FROM %1$s WHERE provenance = $1',
1145 _m.mapping::REGCLASS)
1146 USING OLD.provsql,
NEW.provsql;
1149 PERFORM provsql.set_table_info(TG_RELID,
'opaque');
1155$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public
1171CREATE OR REPLACE
FUNCTION add_provenance(_tbl REGCLASS)
1179 SELECT 1 FROM pg_attribute
1180 WHERE attrelid = _tbl
AND attname =
'provsql' AND NOT attisdropped
1182 RAISE NOTICE
'table % already has provenance tracking', _tbl;
1191 EXECUTE format(
'ALTER TABLE %s ADD COLUMN provsql UUID', _tbl);
1193 'UPDATE %s SET provsql = public.uuid_generate_v4() WHERE provsql IS NULL',
1195 EXECUTE format(
'CREATE INDEX ON %s(provsql)', _tbl);
1197 'CREATE TRIGGER provenance_guard BEFORE INSERT OR UPDATE OF provsql '
1198 'ON %s FOR EACH ROW EXECUTE FUNCTION provsql.provenance_guard()',
1200 PERFORM provsql.set_table_info(_tbl::oid,
'tid');
1205 PERFORM provsql.set_ancestors(_tbl::oid,
ARRAY[_tbl::oid]);
1215 SELECT string_agg(
DISTINCT v.rel::REGCLASS::TEXT,
', ')
INTO stale
1216 FROM (
SELECT r.ev_class
AS rel
1217 FROM pg_catalog.pg_depend d
1218 JOIN pg_catalog.pg_rewrite r
ON r.oid = d.objid
1219 WHERE d.classid =
'pg_catalog.pg_rewrite'::REGCLASS
1220 AND d.refclassid =
'pg_catalog.pg_class'::REGCLASS
1221 AND d.refobjid = _tbl
1222 AND r.ev_class <> _tbl)
AS v
1223 WHERE NOT EXISTS (
SELECT 1 FROM pg_catalog.pg_attribute a
1224 WHERE a.attrelid = v.rel
AND a.attname =
'provsql'
1225 AND NOT a.attisdropped);
1226 IF stale
IS NOT NULL THEN
1227 RAISE WARNING
'ProvSQL: % is read by views defined before it was '
1228 'tracked, which have no provenance column of their own, '
1229 'so a query over one of them is answered as plain SQL, '
1232 USING HINT =
'recreate the view (CREATE OR REPLACE VIEW ... or DROP and '
1233 'CREATE) so that its definition reads the tracked table',
1234 DETAIL =
'provsql-reason: view-defined-before-tracking; '
1239$$
LANGUAGE plpgsql SECURITY DEFINER;
1248CREATE OR REPLACE
FUNCTION remove_provenance(_tbl REGCLASS)
1253 PERFORM provsql.remove_table_info(_tbl::oid);
1259 SELECT 1 FROM pg_attribute
1260 WHERE attrelid = _tbl
AND attname =
'provsql' AND NOT attisdropped
1262 RAISE NOTICE
'table % does not have provenance tracking', _tbl;
1269 EXECUTE format(
'DROP TRIGGER provenance_guard on %s', _tbl);
1270 EXCEPTION
WHEN undefined_object
THEN
1272 EXECUTE format(
'ALTER TABLE %s DROP COLUMN provsql', _tbl);
1274 EXECUTE format(
'DROP TRIGGER add_gate on %s', _tbl);
1275 EXCEPTION
WHEN undefined_object
THEN
1278 EXECUTE format(
'DROP TRIGGER insert_statement on %s', _tbl);
1279 EXECUTE format(
'DROP TRIGGER update_statement on %s', _tbl);
1280 EXECUTE format(
'DROP TRIGGER delete_statement on %s', _tbl);
1281 EXCEPTION
WHEN undefined_object
THEN
1300CREATE OR REPLACE
FUNCTION repair_key(_tbl REGCLASS, key_att TEXT)
1306 block_key_cols INT2[];
1312 IF key_att =
'' THEN
1313 block_key_cols :=
ARRAY[]::INT2[];
1315 SELECT array_agg(a.attnum
ORDER BY t.ord)::INT2[]
1317 FROM unnest(string_to[](key_att,
','))
WITH ORDINALITY
AS t(name, ord)
1319 ON a.attrelid = _tbl
1320 AND a.attname = trim(t.name)
1322 AND NOT a.attisdropped;
1323 IF block_key_cols
IS NULL OR array_length(block_key_cols,
1)
IS NULL THEN
1324 RAISE EXCEPTION
'repair_key: could not resolve key columns from "%"', key_att
1325 USING ERRCODE =
'feature_not_supported',
1326 DETAIL =
'provsql-reason: repair-key-columns; scope: gap';
1328 IF array_length(block_key_cols,
1) >
16 THEN
1329 RAISE EXCEPTION
'repair_key: block key wider than 16 columns is not supported'
1330 USING ERRCODE =
'feature_not_supported',
1331 DETAIL =
'provsql-reason: repair-key-too-wide; scope: gap';
1341 EXECUTE format(
'ALTER TABLE %s ADD COLUMN provsql_temp UUID DEFAULT public.uuid_generate_v4()', _tbl);
1352 IF key_att =
'' THEN
1354 'CREATE TEMP TABLE provsql_repair_key_tmp ON COMMIT DROP AS
1355 SELECT public.uuid_generate_v4() AS provsql_key_token,
1356 COUNT(*) AS provsql_group_size
1358 rows_query := format(
1359 'SELECT t.provsql_temp,
1360 k.provsql_key_token AS key_token,
1361 ROW_NUMBER() OVER (ORDER BY t.ctid) AS within_group,
1362 k.provsql_group_size AS group_size
1363 FROM %s t CROSS JOIN provsql_repair_key_tmp k', _tbl);
1366 'CREATE TEMP TABLE provsql_repair_key_tmp ON COMMIT DROP AS
1368 public.uuid_generate_v4() AS provsql_key_token,
1369 COUNT(*) AS provsql_group_size
1371 GROUP BY %1$s', key_att, _tbl);
1372 rows_query := format(
1373 'SELECT t.provsql_temp,
1374 k.provsql_key_token AS key_token,
1375 ROW_NUMBER() OVER (PARTITION BY k.provsql_key_token
1376 ORDER BY t.ctid) AS within_group,
1377 k.provsql_group_size AS group_size
1379 JOIN provsql_repair_key_tmp k USING (%1$s)', key_att, _tbl);
1383 FOR r
IN SELECT provsql_key_token
FROM provsql_repair_key_tmp LOOP
1384 PERFORM provsql.create_gate(r.provsql_key_token,
'input');
1394 FOR r
IN EXECUTE rows_query LOOP
1395 PERFORM provsql.create_gate(r.provsql_temp,
'mulinput',
ARRAY[r.key_token],
1396 r.within_group::
INT, r.group_size::
INT,
NULL);
1399 DROP TABLE provsql_repair_key_tmp;
1401 EXECUTE format(
'ALTER TABLE %s ALTER COLUMN provsql_temp DROP DEFAULT', _tbl);
1402 EXECUTE format(
'ALTER TABLE %s RENAME COLUMN provsql_temp TO provsql', _tbl);
1403 EXECUTE format(
'CREATE INDEX ON %s(provsql)', _tbl);
1405 'CREATE TRIGGER provenance_guard BEFORE INSERT OR UPDATE OF provsql '
1406 'ON %s FOR EACH ROW EXECUTE FUNCTION provsql.provenance_guard()',
1408 PERFORM provsql.set_table_info(_tbl::oid,
'bid', block_key_cols);
1411 PERFORM provsql.set_ancestors(_tbl::oid,
ARRAY[_tbl::oid]);
1428CREATE OR REPLACE
FUNCTION cleanup_table_info()
1429 RETURNS event_trigger
AS
1435 SELECT objid
FROM pg_event_trigger_dropped_objects()
1436 WHERE object_type
IN (
'table',
'foreign table',
'materialized view')
1438 PERFORM provsql.remove_table_info(r.objid);
1440 DELETE FROM provsql.provenance_mapping_registry
1441 WHERE source = r.objid
OR mapping = r.objid;
1446DROP EVENT
TRIGGER IF EXISTS provsql_cleanup_table_info;
1449CREATE EVENT
TRIGGER provsql_cleanup_table_info
ON sql_drop
1450 EXECUTE FUNCTION provsql.cleanup_table_info();
1467CREATE TABLE IF NOT EXISTS provsql.provenance_mapping_registry(
1468 mapping oid
PRIMARY KEY,
1469 source oid
NOT NULL,
1470 attribute name
NOT NULL,
1471 maintained
BOOLEAN NOT NULL DEFAULT false
1473ALTER TABLE provsql.provenance_mapping_registry
1474 ADD COLUMN IF NOT EXISTS maintained
BOOLEAN NOT NULL DEFAULT false;
1475CREATE INDEX
IF NOT EXISTS provenance_mapping_registry_source_idx
1476 ON provsql.provenance_mapping_registry(source);
1499CREATE OR REPLACE
FUNCTION create_provenance_mapping(
1503 preserve_case BOOL
DEFAULT 'f',
1504 maintained BOOL
DEFAULT false
1512 IF (
CASE WHEN preserve_case
THEN to_regclass(format(
'%I', newtbl))
1513 ELSE to_regclass(newtbl)
END)
IS NOT NULL THEN
1514 RAISE NOTICE
'mapping table % already exists', newtbl;
1521 IF to_regclass(
'pg_temp.tmp_provsql')
IS NOT NULL THEN
1522 DROP TABLE tmp_provsql;
1524 EXECUTE format(
'CREATE TEMP TABLE tmp_provsql ON COMMIT DROP AS TABLE %s', oldtbl);
1525 ALTER TABLE tmp_provsql RENAME provsql
TO provenance;
1529 UPDATE tmp_provsql
SET provenance = provsql.strip_annotations(provenance)
1530 WHERE provsql.get_gate_type(provenance) =
'annotation';
1531 IF preserve_case
THEN
1532 EXECUTE format(
'CREATE TABLE %I AS SELECT %s AS value, provenance FROM tmp_provsql', newtbl, att);
1533 EXECUTE format(
'CREATE INDEX ON %I(provenance)', newtbl);
1535 EXECUTE format(
'CREATE TABLE %s AS SELECT %s AS value, provenance FROM tmp_provsql', newtbl, att);
1536 EXECUTE format(
'CREATE INDEX ON %s(provenance)', newtbl);
1544 INSERT INTO provsql.provenance_mapping_registry(mapping, source, attribute, maintained)
1546 (
CASE WHEN preserve_case
THEN to_regclass(format(
'%I', newtbl))
1547 ELSE to_regclass(newtbl)
END)::oid,
1548 oldtbl::oid, att, maintained)
1549 ON CONFLICT (mapping)
1550 DO
UPDATE SET source = EXCLUDED.source, attribute = EXCLUDED.attribute,
1551 maintained = EXCLUDED.maintained;
1564CREATE OR REPLACE
FUNCTION uuid_ns_provsql()
RETURNS UUID
AS
1567 SELECT '920d4f02-8718-5319-9532-d4ab83a64489'::UUID
1568$$
LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
1571CREATE OR REPLACE
FUNCTION gate_zero()
RETURNS UUID
AS
1573 SELECT public.uuid_generate_v5(provsql.uuid_ns_provsql(),
'zero');
1574$$
LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
1577CREATE OR REPLACE
FUNCTION gate_one()
RETURNS UUID
AS
1579 SELECT public.uuid_generate_v5(provsql.uuid_ns_provsql(),
'one');
1580$$
LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
1591CREATE OR REPLACE
FUNCTION gate_null()
RETURNS UUID
AS
1593 SELECT public.uuid_generate_v5(provsql.uuid_ns_provsql(),
'null');
1594$$
LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
1633CREATE OR REPLACE
FUNCTION provenance_times(VARIADIC tokens UUID[])
1635 'provsql',
'provenance_times' LANGUAGE C COST
100 PARALLEL SAFE IMMUTABLE;
1646CREATE OR REPLACE
FUNCTION provenance_monus(token1 UUID, token2 UUID)
1648 'provsql',
'provenance_monus' LANGUAGE C COST
100 PARALLEL SAFE IMMUTABLE;
1661CREATE OR REPLACE
FUNCTION provenance_project(token UUID, VARIADIC positions
INT[])
1663 'provsql',
'provenance_project' LANGUAGE C COST
100 PARALLEL SAFE IMMUTABLE;
1675CREATE OR REPLACE
FUNCTION provenance_eq(token UUID, pos1
INT, pos2
INT)
1677 'provsql',
'provenance_eq' LANGUAGE C COST
100 PARALLEL SAFE IMMUTABLE;
1693CREATE OR REPLACE
FUNCTION provenance_plus(tokens UUID[])
1695 'provsql',
'provenance_plus' LANGUAGE C COST
100 STRICT PARALLEL SAFE IMMUTABLE;
1707CREATE OR REPLACE
FUNCTION planted_scope(work_name TEXT)
1709 'provsql',
'planted_scope' LANGUAGE C STRICT;
1733CREATE OR REPLACE
FUNCTION plant_canonical(
1734 work_name TEXT, kind TEXT, tokens UUID[], target UUID,
1735 info1
INT, info2
INT DEFAULT 0)
1737 'provsql',
'plant_canonical' LANGUAGE C STRICT;
1784CREATE OR REPLACE
FUNCTION eval_recursive(
1789 max_iter
INT DEFAULT 1000)
1817 absorptive_mode
BOOLEAN :=
1818 coalesce(current_setting(
'provsql.provenance',
true),
'semiring')
1819 IN (
'absorptive',
'BOOLEAN');
1820 truncated
BOOLEAN :=
false;
1821 ntuples
INT :=
NULL;
1823 EXECUTE format(
'DROP TABLE IF EXISTS %I', work_name);
1824 DROP TABLE IF EXISTS provsql_rec_new;
1828 EXECUTE format(
'CREATE TEMP TABLE %I (%s, provsql UUID) ON COMMIT DROP',
1830 PERFORM provsql.planted_scope(work_name);
1831 EXECUTE format(
'CREATE TEMP TABLE provsql_rec_new (LIKE %I) ON COMMIT DROP',
1838 IF iters > max_iter
THEN
1843 RAISE EXCEPTION
'ProvSQL: the rounds of this recursion do not reach a '
1844 'fixpoint (after % of them): the rows it derives keep '
1845 'changing, so there is no fixpoint to annotate -- plain '
1846 'SQL does not terminate on such a recursion either',
1848 USING ERRCODE =
'feature_not_supported',
1849 DETAIL =
'provsql-reason: recursion-no-fixpoint; scope: deliberate';
1856 EXECUTE 'TRUNCATE provsql_rec_new';
1857 EXECUTE format(
'INSERT INTO provsql_rec_new(%s) %s', colnames, body_sql);
1858 GET DIAGNOSTICS new_count = ROW_COUNT;
1862 'SELECT EXISTS((TABLE provsql_rec_new EXCEPT TABLE %1$I) UNION ALL (TABLE %1$I EXCEPT TABLE provsql_rec_new))',
1863 work_name)
INTO changed;
1867 IF ntuples
IS NULL THEN
1869 'SELECT NOT EXISTS('
1870 ||
'(SELECT %2$s FROM provsql_rec_new EXCEPT SELECT %2$s FROM %1$I) UNION ALL '
1871 ||
'(SELECT %2$s FROM %1$I EXCEPT SELECT %2$s FROM provsql_rec_new))',
1872 work_name, colnames)
INTO set_stable;
1874 ntuples := new_count;
1879 EXECUTE format(
'TRUNCATE %I', work_name);
1880 EXECUTE format(
'INSERT INTO %1$I(%2$s) SELECT %2$s FROM provsql_rec_new', work_name, colnames);
1884 EXIT
WHEN NOT changed;
1891 IF ntuples
IS NOT NULL AND iters >= ntuples +
1 THEN
1892 IF absorptive_mode
THEN
1900 RAISE EXCEPTION
'ProvSQL: the rounds of this recursion do not reach a '
1901 'fixpoint (the rows settled after % of them, the '
1902 'derivations did not): a tuple is derived through '
1903 'itself, which cyclic data does, and so does a '
1904 'null-padded row that re-derives itself or a projection '
1905 'onto constants on acyclic data, so its annotation '
1906 'gains a term at every round. Only an absorptive '
1907 'provenance class has a value for it (set '
1908 'provsql.provenance to absorptive or to BOOLEAN)',
1910 USING ERRCODE =
'feature_not_supported',
1911 DETAIL =
'provsql-reason: recursion-no-fixpoint; scope: deliberate';
1919 'UPDATE %I SET provsql = provsql.provenance_assume(provsql, ''absorptive'')',
1923$$
LANGUAGE plpgsql
SET client_min_messages = warning;
1952CREATE OR REPLACE
FUNCTION eval_recursive_all(
1959 max_iter
INT DEFAULT 1000)
1966 EXECUTE format(
'DROP TABLE IF EXISTS %I', work_name);
1967 EXECUTE format(
'DROP TABLE IF EXISTS %I', all_name);
1968 DROP TABLE IF EXISTS provsql_rec_new;
1970 EXECUTE format(
'CREATE TEMP TABLE %I (%s, provsql UUID) ON COMMIT DROP',
1972 EXECUTE format(
'CREATE TEMP TABLE %I (LIKE %I) ON COMMIT DROP',
1973 all_name, work_name);
1974 EXECUTE format(
'CREATE TEMP TABLE provsql_rec_new (LIKE %I) ON COMMIT DROP',
1976 PERFORM provsql.planted_scope(all_name);
1979 EXECUTE format(
'INSERT INTO provsql_rec_new(%s) %s', colnames, q0_sql);
1980 GET DIAGNOSTICS new_count = ROW_COUNT;
1983 EXIT
WHEN new_count =
0;
1987 EXECUTE format(
'INSERT INTO %1$I(%2$s) SELECT %2$s FROM provsql_rec_new',
1988 all_name, colnames);
1991 EXECUTE format(
'TRUNCATE %I', work_name);
1992 EXECUTE format(
'INSERT INTO %1$I(%2$s) SELECT %2$s FROM provsql_rec_new',
1993 work_name, colnames);
1996 IF iters > max_iter
THEN
2001 RAISE EXCEPTION
'ProvSQL: the rounds of this UNION ALL recursion do not '
2002 'end (after % of them): its answer is the rows of every '
2003 'round, which SQL itself does not reach either on such '
2005 USING ERRCODE =
'feature_not_supported',
2006 DETAIL =
'provsql-reason: recursion-does-not-end; scope: deliberate';
2009 EXECUTE format(
'TRUNCATE provsql_rec_new');
2010 EXECUTE format(
'INSERT INTO provsql_rec_new(%s) %s', colnames, q1_sql);
2011 GET DIAGNOSTICS new_count = ROW_COUNT;
2014$$
LANGUAGE plpgsql
SET client_min_messages = warning;
2026CREATE OR REPLACE
FUNCTION provenance_cmp(
2032 'provsql',
'provenance_cmp' LANGUAGE C COST
100 PARALLEL SAFE IMMUTABLE;
2044CREATE FUNCTION cmp_surviving_factors(tokens UUID[], cmp UUID)
2046 'provsql',
'cmp_surviving_factors' LANGUAGE C PARALLEL SAFE STABLE;
2056CREATE OR REPLACE
FUNCTION provenance_cmp_times(cmp UUID, tokens UUID[])
2062 kept := provsql.cmp_surviving_factors(tokens, cmp);
2063 IF kept
IS NULL OR array_length(kept,
1)
IS NULL THEN
2066 RETURN provsql.provenance_times(VARIADIC kept || cmp);
2068$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE;
2089CREATE OR REPLACE
FUNCTION provenance_arith(
2094 'provsql',
'provenance_arith' LANGUAGE C COST
100 STRICT PARALLEL SAFE IMMUTABLE;
2112CREATE OR REPLACE
FUNCTION provenance_case(
2120 IF array_length(children,
1)
IS NULL OR array_length(children,
1) %
2 =
0 THEN
2121 RAISE EXCEPTION
'provenance_case expects an odd number of children '
2122 '(guard/value pairs followed by a default), got %',
2123 coalesce(array_length(children,
1),
0);
2125 case_token := public.uuid_generate_v5(
2127 concat(
'case', children::TEXT)
2129 PERFORM create_gate(case_token,
'case', children);
2133 SET search_path=provsql,pg_temp,public
2158CREATE OR REPLACE
FUNCTION provenance_evaluate_compiled(
2160 token2value REGCLASS,
2162 element_one ANYELEMENT)
2163RETURNS ANYELEMENT
AS
2164 'provsql',
'provenance_evaluate_compiled' LANGUAGE C PARALLEL SAFE STABLE;
2183CREATE OR REPLACE
FUNCTION provenance_evaluate(
2185 token2value REGCLASS,
2186 element_one ANYELEMENT,
2188 plus_function REGPROC,
2189 times_function REGPROC,
2190 monus_function REGPROC,
2191 delta_function REGPROC)
2192 RETURNS ANYELEMENT
AS
2195 gate_type PROVENANCE_GATE;
2196 result ALIAS
FOR $
0;
2202 SELECT get_gate_type(token)
INTO gate_type;
2204 IF gate_type
IS NULL THEN
2207 ELSIF gate_type =
'input' THEN
2208 EXECUTE format(
'SELECT value FROM %s WHERE provenance=%L', token2value, token)
2210 IF result IS NULL THEN
2211 result := element_one;
2213 ELSIF gate_type =
'mulinput' THEN
2214 SELECT concat(
'{',(get_children(token))[
1]::TEXT,
'=',(get_infos(token)).info1,
'}')
2216 ELSIF gate_type=
'update' THEN
2217 EXECUTE format(
'SELECT value FROM %s WHERE provenance=%L',token2value,token)
INTO result;
2218 IF result IS NULL THEN
2219 result:=element_one;
2221 ELSIF gate_type =
'plus' THEN
2222 EXECUTE format(
'SELECT %s(provsql.provenance_evaluate(t,%L,%L::%s,%L,%L,%L,%L,%L)) FROM unnest(get_children(%L)) AS t',
2223 plus_function, token2value, element_one, value_type, value_type, plus_function, times_function, monus_function, delta_function, token)
2226 ELSIF gate_type =
'times' THEN
2227 EXECUTE format(
'SELECT %s(provsql.provenance_evaluate(t,%L,%L::%s,%L,%L,%L,%L,%L)) FROM unnest(get_children(%L)) AS t',
2228 times_function, token2value, element_one, value_type, value_type, plus_function, times_function, monus_function, delta_function, token)
2231 ELSIF gate_type =
'monus' THEN
2232 IF monus_function
IS NULL THEN
2233 RAISE EXCEPTION
USING MESSAGE=
'Provenance with negation evaluated over a semiring without monus function',
2234 DETAIL =
'provsql-reason: semiring-no-monus; scope: deliberate';
2236 EXECUTE format(
'SELECT %s(a1,a2) FROM (SELECT provsql.provenance_evaluate(c[1],%L,%L::%s,%L,%L,%L,%L,%L) AS a1, ' ||
2237 'provsql.provenance_evaluate(c[2],%L,%L::%s,%L,%L,%L,%L,%L) AS a2 FROM get_children(%L) c) tmp',
2238 monus_function, token2value, element_one, value_type, value_type, plus_function, times_function, monus_function, delta_function,
2239 token2value, element_one, value_type, value_type, plus_function, times_function, monus_function, delta_function, token)
2243 ELSIF gate_type =
'eq' THEN
2244 EXECUTE format(
'SELECT provsql.provenance_evaluate((get_children(%L))[1],%L,%L::%s,%L,%L,%L,%L,%L)',
2245 token, token2value, element_one, value_type, value_type, plus_function, times_function, monus_function, delta_function)
2266 ELSIF gate_type =
'delta' THEN
2267 IF delta_function
IS NULL THEN
2268 RAISE EXCEPTION
USING MESSAGE=
'Provenance with aggregation evaluated over a semiring without delta function',
2269 DETAIL =
'provsql-reason: semiring-no-delta; scope: deliberate';
2271 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',
2272 delta_function, token, token2value, element_one, value_type, value_type, plus_function, times_function, monus_function, delta_function)
2276 ELSIF gate_type =
'zero' THEN
2277 EXECUTE format(
'SELECT %I(a) FROM (SELECT %L::%I AS a WHERE FALSE) temp', plus_function, element_one, value_type)
2280 ELSIF gate_type =
'one' THEN
2281 EXECUTE format(
'SELECT %L::%I', element_one, value_type)
2284 ELSIF gate_type =
'project' THEN
2285 EXECUTE format(
'SELECT provsql.provenance_evaluate((get_children(%L))[1],%L,%L::%s,%L,%L,%L,%L,%L)',
2286 token, token2value, element_one, value_type, value_type, plus_function, times_function, monus_function, delta_function)
2289 ELSIF gate_type =
'annotation' THEN
2293 EXECUTE format(
'SELECT provsql.provenance_evaluate((get_children(%L))[1],%L,%L::%s,%L,%L,%L,%L,%L)',
2294 token, token2value, element_one, value_type, value_type, plus_function, times_function, monus_function, delta_function)
2298 RAISE EXCEPTION
USING MESSAGE=
'provenance_evaluate cannot be called on formulas using ' || gate_type ||
' gates; use compiled semirings instead',
2299 DETAIL =
'provsql-reason: evaluate-gate-kind; scope: gap';
2304$$
LANGUAGE plpgsql PARALLEL SAFE STABLE;
2321CREATE OR REPLACE
FUNCTION provenance_evaluate(
2323 token2value REGCLASS,
2324 element_one ANYELEMENT,
2325 plus_function REGPROC,
2326 times_function REGPROC,
2327 monus_function REGPROC =
NULL,
2328 delta_function REGPROC =
NULL)
2329 RETURNS ANYELEMENT
AS
2330 'provsql',
'provenance_evaluate' LANGUAGE C STABLE;
2341CREATE TYPE GATE_WITH_DESC
AS (f UUID, t UUID, gate_type PROVENANCE_GATE, desc_str
CHARACTER VARYING, infos
INTEGER[], extra TEXT);
2353CREATE OR REPLACE
FUNCTION sub_circuit_with_desc(
2355 token2desc REGCLASS)
RETURNS SETOF GATE_WITH_DESC
AS
2358 RETURN QUERY
EXECUTE
2359 'WITH RECURSIVE transitive_closure(f,t,gate_type) AS (
2360 SELECT $1,t,provsql.get_gate_type($1) FROM unnest(provsql.get_children($1)) AS t
2362 SELECT p1.t,u,provsql.get_gate_type(p1.t) FROM transitive_closure p1, unnest(provsql.get_children(p1.t)) AS u)
2363 SELECT *, ARRAY[(get_infos(f)).info1, (get_infos(f)).info2], get_extra(f) FROM (
2364 SELECT f::UUID,t::UUID,gate_type,NULL FROM transitive_closure
2366 SELECT p2.provenance::UUID as f, NULL::UUID, ''input'', CAST (p2.value AS varchar) FROM transitive_closure p1 JOIN ' || token2desc ||
' AS p2
2369 SELECT provenance::UUID as f, NULL::UUID, ''input'', CAST (value AS varchar) FROM ' || token2desc ||
' WHERE provenance=$1
2374$$
LANGUAGE plpgsql PARALLEL SAFE;
2386CREATE OR REPLACE
FUNCTION identify_token(
2387 token UUID,
OUT table_name REGCLASS,
OUT nb_columns
INTEGER)
AS
2397 (
SELECT count(*)
FROM pg_attribute a2
WHERE a2.attrelid=a1.attrelid
AND attnum>
0 AND atttypid<>
0)-1 c
2398 FROM pg_attribute a1
JOIN pg_type
ON atttypid=pg_type.oid
2399 JOIN pg_class
ON attrelid=pg_class.oid
2400 JOIN pg_namespace
ON relnamespace=pg_namespace.oid
2401 WHERE typname=
'UUID' AND relkind=
'r'
2402 AND nspname<>
'provsql'
2403 AND attname=
'provsql'
2405 EXECUTE format(
'SELECT * FROM %I WHERE provsql=%L',t.relname,token)
INTO result;
2410 IF result.provsql
IS NOT NULL THEN
2411 table_name:=t.relname;
2417$$
LANGUAGE plpgsql STRICT;
2425CREATE OR REPLACE
FUNCTION sub_circuit_for_where(token UUID)
2426 RETURNS TABLE(f UUID, t UUID, gate_type PROVENANCE_GATE, table_name REGCLASS, nb_columns
INTEGER, infos
INTEGER[], extra TEXT)
AS
2428 WITH RECURSIVE transitive_closure(f,t,idx,gate_type)
AS (
2429 SELECT $
1,t,id,provsql.get_gate_type($
1)
FROM unnest(provsql.get_children($
1))
WITH ORDINALITY
AS a(t,id)
2431 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)
2432 )
SELECT f, t, gate_type, table_name, nb_columns,
ARRAY[(get_infos(f)).info1, (get_infos(f)).info2], get_extra(f)
FROM (
2442 SELECT DISTINCT f, t::UUID, idx, gate_type,
NULL::REGCLASS
AS table_name,
NULL::
INTEGER AS nb_columns
FROM transitive_closure
2444 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
2446 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
2481CREATE OR REPLACE
FUNCTION circuit_subgraph(root UUID, max_depth
INT DEFAULT 8)
2482 RETURNS TABLE(node UUID, parent UUID, child_pos
INT, gate_type TEXT, info1 TEXT, info2 TEXT, depth
INT)
AS
2484 WITH RECURSIVE bfs(node, parent, child_pos, depth)
AS (
2485 SELECT root,
NULL::UUID,
NULL::
INT,
0
2487 SELECT c.t, b.node, c.idx::
INT, b.depth +
1
2489 CROSS JOIN LATERAL unnest(provsql.get_children(b.node))
2490 WITH ORDINALITY
AS c(t, idx)
2491 WHERE b.depth < max_depth
2499 SELECT node, MAX(depth)
AS depth
FROM bfs
GROUP BY node
2505 SELECT DISTINCT parent, node
AS child, child_pos
2506 FROM bfs
WHERE parent
IS NOT NULL
2512 provsql.get_gate_type(d.node)::TEXT,
2517 LEFT JOIN edges e
ON e.child = d.node
2518 LEFT JOIN LATERAL provsql.get_infos(d.node) i
ON TRUE
2519 ORDER BY d.depth, d.node, e.parent;
2520$$
LANGUAGE sql STABLE PARALLEL SAFE;
2541CREATE OR REPLACE
FUNCTION simplified_circuit_subgraph(
2542 root UUID, max_depth
INT DEFAULT 8)
RETURNS jsonb
2543 AS 'provsql',
'simplified_circuit_subgraph'
2544 LANGUAGE C STABLE PARALLEL SAFE;
2568CREATE OR REPLACE
FUNCTION rv_histogram(
2569 token UUID, bins
INT DEFAULT 30, prov UUID
DEFAULT gate_one())
2571 AS 'provsql',
'rv_histogram'
2572 LANGUAGE C VOLATILE PARALLEL SAFE;
2599CREATE OR REPLACE
FUNCTION rv_analytical_curves(
2600 token UUID, samples
INT DEFAULT 100, prov UUID
DEFAULT gate_one())
2602 AS 'provsql',
'rv_analytical_curves'
2603 LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
2624CREATE OR REPLACE
FUNCTION rv_sample(
2625 token UUID, n
INTEGER, prov UUID
DEFAULT gate_one())
2626 RETURNS SETOF float8
2627 AS 'provsql',
'rv_sample'
2628 LANGUAGE C VOLATILE PARALLEL SAFE;
2646CREATE OR REPLACE
FUNCTION resolve_input(UUID UUID)
2647 RETURNS TABLE(relation REGCLASS, row_data JSONB)
AS
2659 SELECT c.oid::REGCLASS
AS regc
2661 JOIN pg_class c
ON a.attrelid = c.oid
2662 JOIN pg_namespace ns
ON c.relnamespace = ns.oid
2663 JOIN pg_type ty
ON a.atttypid = ty.oid
2664 WHERE a.attname =
'provsql'
2665 AND ty.typname =
'UUID'
2667 AND ns.nspname <>
'provsql'
2672 'SELECT %L::REGCLASS, to_jsonb(t) - ''provsql'', t.provsql FROM %s AS t WHERE provsql = $1',
2682$$
LANGUAGE plpgsql STABLE;
2705CREATE TYPE AGG_TOKEN;
2708CREATE OR REPLACE
FUNCTION agg_token_in(CSTRING)
2710 AS 'provsql',
'agg_token_in' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
2728CREATE OR REPLACE
FUNCTION agg_token_out(AGG_TOKEN)
2730 AS 'provsql',
'agg_token_out' LANGUAGE C STABLE STRICT PARALLEL SAFE;
2733CREATE OR REPLACE
FUNCTION agg_token_cast(AGG_TOKEN)
2735 AS 'provsql',
'agg_token_cast' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
2737CREATE TYPE AGG_TOKEN (
2738 internallength =
117,
2739 input = agg_token_in,
2740 output = agg_token_out,
2745CREATE OR REPLACE
FUNCTION agg_token_uuid(aggtok AGG_TOKEN)
2749 RETURN agg_token_cast(aggtok)::UUID;
2751$$
LANGUAGE plpgsql STRICT
SET search_path=provsql,pg_temp,public SECURITY DEFINER IMMUTABLE PARALLEL SAFE;
2754CREATE CAST (AGG_TOKEN
AS UUID)
WITH FUNCTION agg_token_uuid(AGG_TOKEN)
AS IMPLICIT;
2765CREATE OR REPLACE
FUNCTION agg_gate_value_missing(token UUID)
2769 gt provsql.PROVENANCE_GATE := provsql.get_gate_type(token);
2772 IF gt
IN (
'agg',
'arith',
'value')
THEN
2773 RETURN provsql.get_extra(token)
IS NULL;
2774 ELSIF gt =
'semimod' THEN
2775 ch := provsql.get_children(token);
2776 RETURN array_length(ch,
1) =
2
2777 AND provsql.get_extra(ch[
2])
IS NULL;
2778 ELSIF gt =
'conditioned' THEN
2779 ch := provsql.get_children(token);
2780 RETURN array_length(ch,
1) >=
1
2781 AND provsql.agg_gate_value_missing(ch[
1]);
2786$$
LANGUAGE plpgsql STABLE STRICT PARALLEL SAFE
2787 SET search_path=provsql,pg_temp,public;
2800CREATE OR REPLACE
FUNCTION agg_gate_value_text(token UUID)
2804 gt provsql.PROVENANCE_GATE := provsql.get_gate_type(token);
2806 IF gt
IN (
'agg',
'arith',
'value')
THEN
2807 RETURN provsql.get_extra(token);
2808 ELSIF gt =
'semimod' THEN
2809 RETURN provsql.agg_gate_value_text((provsql.get_children(token))[
2]);
2810 ELSIF gt =
'conditioned' THEN
2811 RETURN provsql.agg_gate_value_text((provsql.get_children(token))[
1]);
2815$$
LANGUAGE plpgsql STABLE STRICT PARALLEL SAFE
2816 SET search_path=provsql,pg_temp,public;
2830CREATE OR REPLACE
FUNCTION agg_guard_holds(token UUID)
2834 gt PROVENANCE_GATE := get_gate_type(token);
2847 ELSIF gt =
'zero' THEN
2849 ELSIF gt
IN (
'times',
'plus')
THEN
2850 SELECT bool_and(h), bool_or(h), bool_or(h
IS NULL)
2851 INTO all_true, any_true, any_null
2852 FROM (
SELECT provsql.agg_guard_holds(c)
AS h
2853 FROM unnest(get_children(token))
AS c)
AS s;
2854 IF gt =
'times' THEN
2857 RETURN CASE WHEN NOT all_true
THEN false
2858 WHEN any_null
THEN NULL
2862 RETURN CASE WHEN any_true
THEN true
2863 WHEN any_null
THEN NULL
2866 ELSIF gt =
'cmp' THEN
2867 ch := get_children(token);
2868 l := agg_gate_value(ch[
1]);
2869 r := agg_gate_value(ch[
2]);
2870 IF l
IS NULL OR r
IS NULL THEN
2877 IF agg_gate_value_missing(ch[
1])
OR agg_gate_value_missing(ch[
2])
THEN
2885 lt := lower(agg_gate_value_text(ch[
1]));
2886 rt := lower(agg_gate_value_text(ch[
2]));
2887 IF lt
IN (
'true',
'false',
't',
'f')
AND
2888 rt
IN (
'true',
'false',
't',
'f')
THEN
2889 SELECT oprname
INTO opname
2890 FROM pg_catalog.pg_operator
WHERE oid = (get_infos(token)).info1;
2891 IF opname =
'=' THEN
2892 RETURN lt::
BOOLEAN = rt::
BOOLEAN;
2893 ELSIF opname =
'<>' THEN
2894 RETURN lt::
BOOLEAN <> rt::
BOOLEAN;
2899 SELECT oprname
INTO opname
2900 FROM pg_catalog.pg_operator
WHERE oid = (get_infos(token)).info1;
2903 WHEN '<=' THEN l <= r
2905 WHEN '<>' THEN l <> r
2906 WHEN '>=' THEN l >= r
2909 ELSIF gt
IN (
'input',
'delta',
'monus',
'project',
'eq',
'mulinput',
2910 'assumed',
'annotation')
THEN
2916 RETURN provsql.plain_truth(token);
2920$$
LANGUAGE plpgsql STABLE STRICT PARALLEL SAFE
2921 SET search_path=provsql,pg_temp,public;
2937CREATE OR REPLACE
FUNCTION agg_gate_value(token UUID)
2941 gt PROVENANCE_GATE := get_gate_type(token);
2947 IF gt
IN (
'agg',
'arith',
'value')
THEN
2955 extra := get_extra(token);
2956 IF extra ~
'^\s*([-+]?([0-9]+\.?[0-9]*|\.[0-9]+)([eE][-+]?[0-9]+)?|[Nn][Aa][Nn])\s*$' THEN
2957 RETURN extra::
NUMERIC;
2960 ELSIF gt =
'semimod' THEN
2961 RETURN agg_gate_value((get_children(token))[
2]);
2962 ELSIF gt =
'conditioned' THEN
2963 RETURN agg_gate_value((get_children(token))[
1]);
2964 ELSIF gt =
'case' THEN
2965 ch := get_children(token);
2966 n := array_length(ch,
1);
2967 FOR i
IN 1 .. (n -
1) /
2 LOOP
2968 holds := agg_guard_holds(ch[
2 * i -
1]);
2969 IF holds
IS NULL THEN
2972 RETURN agg_gate_value(ch[
2 * i]);
2975 RETURN agg_gate_value(ch[n]);
2979$$
LANGUAGE plpgsql STABLE STRICT PARALLEL SAFE
2980 SET search_path=provsql,pg_temp,public;
3001CREATE OR REPLACE
FUNCTION agg_token_value_text(token UUID)
3007 WHEN provsql.get_gate_type(token) =
'agg'
3008 THEN provsql.get_extra(token) ||
' (*)'
3012 WHEN provsql.get_gate_type(token) =
'arith'
3013 THEN CASE provsql.agg_token_value_type(token)
3014 WHEN 'float8'::REGTYPE::oid
3015 THEN (provsql.get_extra(token)::
NUMERIC::float8)::TEXT ||
' (*)'
3016 WHEN 'float4'::REGTYPE::oid
3017 THEN (provsql.get_extra(token)::
NUMERIC::float4)::TEXT ||
' (*)'
3018 ELSE provsql.get_extra(token) ||
' (*)'
3022 WHEN provsql.get_gate_type(token)
IN (
'case',
'conditioned',
'semimod',
'value')
3023 THEN provsql.agg_gate_value(token)::TEXT ||
' (*)'
3026$$
LANGUAGE sql STABLE STRICT PARALLEL SAFE;
3029CREATE OR REPLACE
FUNCTION agg_token_to_numeric(AGG_TOKEN)
3031 AS 'provsql',
'agg_token_to_numeric' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
3034CREATE OR REPLACE
FUNCTION agg_token_to_float8(AGG_TOKEN)
3035 RETURNS double precision
3036 AS 'provsql',
'agg_token_to_float8' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
3039CREATE OR REPLACE
FUNCTION agg_token_to_int4(AGG_TOKEN)
3041 AS 'provsql',
'agg_token_to_int4' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
3044CREATE OR REPLACE
FUNCTION agg_token_to_int8(AGG_TOKEN)
3046 AS 'provsql',
'agg_token_to_int8' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
3049CREATE OR REPLACE
FUNCTION agg_token_to_bool(AGG_TOKEN)
3051 AS 'provsql',
'agg_token_to_bool' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
3054CREATE OR REPLACE
FUNCTION agg_token_to_text(AGG_TOKEN)
3056 AS 'provsql',
'agg_token_to_text' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
3065CREATE CAST (AGG_TOKEN
AS NUMERIC)
WITH FUNCTION agg_token_to_numeric(AGG_TOKEN)
AS ASSIGNMENT;
3082CREATE OR REPLACE
FUNCTION agg_token_value(AGG_TOKEN)
3084 AS 'provsql',
'agg_token_value' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
3089CREATE FUNCTION agg_token_plain_text(AGG_TOKEN)
3091 AS 'provsql',
'agg_token_plain_text' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
3098CREATE FUNCTION agg_token_explode_children(token UUID)
3102 IF provsql.get_gate_type(token) <>
'agg' THEN
3103 RAISE EXCEPTION
USING ERRCODE =
'feature_not_supported',
3104 MESSAGE =
'ProvSQL: only the result of an aggregate can be exploded '
3106 DETAIL =
'provsql-reason: explode-not-an-aggregate; scope: deliberate';
3108 IF (provsql.get_infos(token)).info1 <>
3109 'provsql.choose(ANYELEMENT)'::regprocedure::oid
THEN
3110 RAISE EXCEPTION
USING ERRCODE =
'feature_not_supported',
3111 MESSAGE = format(
'ProvSQL: the result of %s() cannot be exploded into '
3112 'rows, one per value it aggregates: only that of '
3113 'choose() is one of them; compare it in a HAVING '
3114 'clause, or mark it plain() to read its plain value',
3115 (
SELECT proname
FROM pg_catalog.pg_proc
3116 WHERE oid = (provsql.get_infos(token)).info1)),
3117 DETAIL =
'provsql-reason: explode-rows-aggregate-kind; scope: gap';
3119 RETURN provsql.get_children(token);
3121$$
LANGUAGE plpgsql STABLE PARALLEL SAFE;
3138CREATE FUNCTION agg_possible_values(
input ANYELEMENT,
3139 with_null
BOOLEAN DEFAULT false)
3143 max_values CONSTANT
INT :=
1000;
3157 IF pg_typeof(
input) <>
'provsql.AGG_TOKEN'::REGTYPE
THEN
3158 RAISE EXCEPTION
USING ERRCODE =
'feature_not_supported',
3159 MESSAGE =
'ProvSQL: only the result of an aggregate can be exploded '
3160 'into one row per value it takes over the possible worlds',
3161 DETAIL =
'provsql-reason: explode-not-an-aggregate; scope: deliberate';
3163 token :=
input::UUID;
3164 IF provsql.get_gate_type(token) <>
'agg' THEN
3165 RAISE EXCEPTION
USING ERRCODE =
'feature_not_supported',
3166 MESSAGE =
'ProvSQL: an arithmetic expression over aggregate results '
3167 'cannot be exploded into one row per value it takes over '
3168 'the possible worlds',
3169 DETAIL =
'provsql-reason: explode-arithmetic; scope: gap';
3171 SELECT p.proname, s.nspname
INTO fn, ns
3172 FROM pg_catalog.pg_proc p
3173 JOIN pg_catalog.pg_namespace s
ON s.oid = p.pronamespace
3174 WHERE p.oid = (provsql.get_infos(token)).info1;
3176 vals :=
ARRAY(
SELECT provsql.get_extra((provsql.get_children(sm))[
2])
3177 FROM unnest(provsql.get_children(token))
AS sm);
3178 n := coalesce(array_length(vals,
1),
0);
3185 scalar_agg := with_null;
3187 IF (ns, fn) = (
'pg_catalog',
'count')
THEN
3195 counted := (
SELECT count(*)
FROM unnest(vals)
AS v
3196 WHERE v
IS NOT NULL AND v <>
'0');
3197 first :=
CASE WHEN (provsql.get_infos(token)).info2 <
0 OR counted < n
3199 IF counted +
1 - first > max_values
THEN
3200 RAISE EXCEPTION
USING ERRCODE =
'feature_not_supported',
3201 MESSAGE = format(
'ProvSQL: the result of %s() aggregates %s rows, '
3202 'so it takes too many values over the possible '
3203 'worlds to explode it into one row per value',
3205 HINT =
'mark it plain() to read its plain value',
3206 DETAIL =
'provsql-reason: explode-too-many-values; scope: gap';
3208 RETURN ARRAY(
SELECT i::TEXT
3209 FROM generate_series(least(first, counted), counted)
AS i);
3212 IF (ns, fn)
NOT IN ((
'pg_catalog',
'min'), (
'pg_catalog',
'max'),
3213 (
'pg_catalog',
'sum'), (
'provsql',
'choose'))
THEN
3214 RAISE EXCEPTION
USING ERRCODE =
'feature_not_supported',
3215 MESSAGE = format(
'ProvSQL: the result of %s() cannot be exploded into '
3216 'one row per value it takes over the possible worlds: '
3217 'only count(), min(), max(), sum() and choose() have '
3218 'values that can be enumerated', fn),
3219 HINT =
'compare it in a HAVING clause, or mark it plain() to read its '
3221 DETAIL =
'provsql-reason: explode-aggregate-kind; scope: gap';
3224 IF EXISTS (
SELECT 1 FROM unnest(vals)
AS v
WHERE v
IS NULL)
THEN
3225 RAISE EXCEPTION
USING ERRCODE =
'feature_not_supported',
3226 MESSAGE = format(
'ProvSQL: the result of %s() aggregates a NULL value, '
3227 'so it cannot be exploded into one row per value it '
3228 'takes over the possible worlds: a comparison with '
3229 'NULL does not say that the result is NULL', fn),
3230 DETAIL =
'provsql-reason: explode-null-value; scope: gap';
3233 IF (ns, fn) = (
'pg_catalog',
'sum')
THEN
3241 sums :=
ARRAY[]::
NUMERIC[];
3242 FOREACH one
IN ARRAY ARRAY(
SELECT v::
NUMERIC FROM unnest(vals)
AS v) LOOP
3243 sums :=
ARRAY(
SELECT DISTINCT s
FROM
3244 (
SELECT unnest(sums)
AS s
3245 UNION ALL SELECT one
3246 UNION ALL SELECT unnest(sums) + one)
AS u);
3247 IF array_length(sums,
1) > max_values
THEN
3248 RAISE EXCEPTION
USING ERRCODE =
'feature_not_supported',
3249 MESSAGE = format(
'ProvSQL: the result of %s() takes more than %s '
3250 'values over the possible worlds, too many to '
3251 'explode it into one row per value', fn,
3253 HINT =
'mark it plain() to read its plain value',
3254 DETAIL =
'provsql-reason: explode-too-many-values; scope: gap';
3257 RETURN ARRAY(
SELECT s::TEXT
FROM unnest(sums)
AS s
ORDER BY s)
3258 ||
CASE WHEN scalar_agg
THEN ARRAY[
NULL::TEXT]
3259 ELSE ARRAY[]::TEXT[]
END;
3262 IF n > max_values
THEN
3263 RAISE EXCEPTION
USING ERRCODE =
'feature_not_supported',
3264 MESSAGE = format(
'ProvSQL: the result of %s() aggregates %s rows, so '
3265 'it takes too many values over the possible worlds to '
3266 'explode it into one row per value', fn, n),
3267 HINT =
'mark it plain() to read its plain value',
3268 DETAIL =
'provsql-reason: explode-too-many-values; scope: gap';
3273 RETURN ARRAY(
SELECT DISTINCT v
FROM unnest(vals)
AS v
ORDER BY v)
3274 ||
CASE WHEN scalar_agg
THEN ARRAY[
NULL::TEXT]
3275 ELSE ARRAY[]::TEXT[]
END;
3277$$
LANGUAGE plpgsql STABLE STRICT PARALLEL SAFE;
3284CREATE FUNCTION agg_token_frozen_value(AGG_TOKEN)
3286 AS 'provsql',
'agg_token_plain_text' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
3291CREATE OR REPLACE
FUNCTION agg_token_make(tok UUID, val
NUMERIC)
3292 RETURNS AGG_TOKEN
AS
3294 SELECT format(
'( %s , %s )', tok::TEXT, val::TEXT)::provsql.AGG_TOKEN;
3295$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
3296 SET search_path=provsql,pg_temp,public;
3301CREATE OR REPLACE
FUNCTION agg_value_gate(v
NUMERIC)
3305 token UUID := public.uuid_generate_v5(
3306 provsql.uuid_ns_provsql(), concat(
'value', v::TEXT));
3308 PERFORM provsql.create_gate(token,
'value',
NULL,
NULL,
NULL, v::TEXT);
3311$$
LANGUAGE plpgsql STRICT IMMUTABLE PARALLEL SAFE
3312 SET search_path=provsql,pg_temp,public SECURITY DEFINER;
3332CREATE OR REPLACE
FUNCTION agg_token_value_type(token UUID)
3335 SELECT CASE provsql.get_gate_type(token)
3336 WHEN 'agg' THEN (i.info2 &
2147483647)::oid
3337 WHEN 'arith' THEN CASE WHEN coalesce(i.info2,
0) =
0
3338 THEN 'NUMERIC'::REGTYPE::oid
ELSE i.info2::oid
END
3339 ELSE 'NUMERIC'::REGTYPE::oid
3341 FROM provsql.get_infos(token) i;
3342$$
LANGUAGE sql STABLE STRICT PARALLEL SAFE
3343 SET search_path=provsql,pg_temp,public;
3361CREATE OR REPLACE
FUNCTION agg_arith_result_type(op
INT, children UUID[])
3367 has_float8
BOOLEAN :=
false;
3368 has_float4
BOOLEAN :=
false;
3369 has_numeric
BOOLEAN :=
false;
3370 widest_int oid :=
NULL;
3372 IF children
IS NULL THEN
3373 RETURN 'NUMERIC'::REGTYPE::oid;
3375 FOREACH c
IN ARRAY children LOOP
3376 t := provsql.agg_token_value_type(c);
3377 IF t =
'float8'::REGTYPE::oid
THEN has_float8 :=
true;
3378 ELSIF t =
'float4'::REGTYPE::oid
THEN has_float4 :=
true;
3379 ELSIF t =
'NUMERIC'::REGTYPE::oid
THEN has_numeric :=
true;
3380 ELSIF t =
'int8'::REGTYPE::oid
THEN widest_int :=
'int8'::REGTYPE::oid;
3381 ELSIF t =
'int4'::REGTYPE::oid
THEN
3382 widest_int := coalesce(nullif(widest_int,
'int2'::REGTYPE::oid),
3383 'int4'::REGTYPE::oid);
3384 ELSIF t =
'int2'::REGTYPE::oid
THEN
3385 widest_int := coalesce(widest_int,
'int2'::REGTYPE::oid);
3389 RETURN 'float8'::REGTYPE::oid;
3392 RETURN 'float4'::REGTYPE::oid;
3395 RETURN coalesce(widest_int,
'int8'::REGTYPE::oid);
3397 IF op =
12 AND array_length(children,
1) =
2 THEN
3398 RETURN 'NUMERIC'::REGTYPE::oid;
3401 RETURN 'float8'::REGTYPE::oid;
3404 RETURN CASE WHEN has_numeric
THEN 'float8'::REGTYPE::oid
3405 ELSE 'float4'::REGTYPE::oid
END;
3408 RETURN 'NUMERIC'::REGTYPE::oid;
3410 RETURN coalesce(widest_int,
'NUMERIC'::REGTYPE::oid);
3412$$
LANGUAGE plpgsql STABLE STRICT PARALLEL SAFE
3413 SET search_path=provsql,pg_temp,public;
3415CREATE OR REPLACE
FUNCTION agg_arith_make(op
INT, children UUID[], val
NUMERIC)
3416 RETURNS AGG_TOKEN
AS
3419 token UUID := public.uuid_generate_v5(
3420 provsql.uuid_ns_provsql(), concat(
'arith', op::TEXT, children::TEXT));
3424 IF op
IS NULL OR children
IS NULL THEN
3430 restype := provsql.agg_arith_result_type(op, children);
3431 PERFORM provsql.create_gate(token,
'arith', children, op, restype::
INT,
3436 WHEN val
IS NULL THEN 'NULL'
3437 WHEN restype =
'float8'::REGTYPE::oid
THEN (val::float8)::TEXT
3438 WHEN restype =
'float4'::REGTYPE::oid
THEN (val::float4)::TEXT
3441 RETURN format(
'( %s , %s )', token::TEXT, shown)::provsql.AGG_TOKEN;
3443$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE
3444 SET search_path=provsql,pg_temp,public SECURITY DEFINER;
3448CREATE OR REPLACE
FUNCTION agg_token_plus(a AGG_TOKEN, b AGG_TOKEN)
3449 RETURNS AGG_TOKEN
AS
3450$$
SELECT provsql.agg_arith_make(
0,
ARRAY[(a)::UUID, (b)::UUID],
3451 provsql.agg_token_value(a) + provsql.agg_token_value(b)); $$
3452 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3455CREATE OR REPLACE
FUNCTION agg_token_minus(a AGG_TOKEN, b AGG_TOKEN)
3456 RETURNS AGG_TOKEN
AS
3457$$
SELECT provsql.agg_arith_make(
2,
ARRAY[(a)::UUID, (b)::UUID],
3458 provsql.agg_token_value(a) - provsql.agg_token_value(b)); $$
3459 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3462CREATE OR REPLACE
FUNCTION agg_token_times(a AGG_TOKEN, b AGG_TOKEN)
3463 RETURNS AGG_TOKEN
AS
3464$$
SELECT provsql.agg_arith_make(
1,
ARRAY[(a)::UUID, (b)::UUID],
3465 provsql.agg_token_value(a) * provsql.agg_token_value(b)); $$
3466 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3469CREATE OR REPLACE
FUNCTION agg_token_div(a AGG_TOKEN, b AGG_TOKEN)
3470 RETURNS AGG_TOKEN
AS
3471$$
SELECT provsql.agg_arith_make(
3,
ARRAY[(a)::UUID, (b)::UUID],
3472 provsql.agg_token_value(a) / NULLIF(provsql.agg_token_value(b),
0)); $$
3473 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3476CREATE OR REPLACE
FUNCTION agg_token_neg(a AGG_TOKEN)
3477 RETURNS AGG_TOKEN
AS
3478$$
SELECT provsql.agg_arith_make(
4,
ARRAY[(a)::UUID],
3479 - provsql.agg_token_value(a)); $$
3480 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3490CREATE OR REPLACE
FUNCTION provsql_round(a AGG_TOKEN)
3491 RETURNS AGG_TOKEN
AS
3492$$
SELECT provsql.agg_arith_make(
12,
ARRAY[(a)::UUID],
3493 pg_catalog.round(provsql.agg_token_value(a))); $$
3494 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3497CREATE OR REPLACE
FUNCTION provsql_round(a AGG_TOKEN, d
INTEGER)
3498 RETURNS AGG_TOKEN
AS
3499$$
SELECT provsql.agg_arith_make(
12,
3500 ARRAY[(a)::UUID, provsql.agg_value_gate(d::
NUMERIC)],
3501 pg_catalog.round(provsql.agg_token_value(a), d)); $$
3502 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3518CREATE OR REPLACE
FUNCTION provsql_numeric(a AGG_TOKEN)
3519 RETURNS AGG_TOKEN
AS $$
SELECT a $$
3520 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3532CREATE OR REPLACE
FUNCTION provsql_float8(a AGG_TOKEN)
3533 RETURNS AGG_TOKEN
AS
3535 WHEN provsql.agg_token_value_type((a)::UUID) =
'float8'::REGTYPE::oid
3537 ELSE provsql.agg_arith_make(
16,
ARRAY[(a)::UUID],
3538 (provsql.agg_token_value(a)::float8)::
NUMERIC)
3540 LANGUAGE sql STABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3543CREATE OR REPLACE
FUNCTION provsql_float4(a AGG_TOKEN)
3544 RETURNS AGG_TOKEN
AS
3546 WHEN provsql.agg_token_value_type((a)::UUID) =
'float4'::REGTYPE::oid
3548 ELSE provsql.agg_arith_make(
17,
ARRAY[(a)::UUID],
3549 (provsql.agg_token_value(a)::float4)::
NUMERIC)
3551 LANGUAGE sql STABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3554CREATE OR REPLACE
FUNCTION provsql_int8(a AGG_TOKEN)
3555 RETURNS AGG_TOKEN
AS $$
SELECT provsql.provsql_round(a) $$
3556 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3559CREATE OR REPLACE
FUNCTION provsql_int4(a AGG_TOKEN)
3560 RETURNS AGG_TOKEN
AS $$
SELECT provsql.provsql_round(a) $$
3561 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3564CREATE OR REPLACE
FUNCTION provsql_int2(a AGG_TOKEN)
3565 RETURNS AGG_TOKEN
AS $$
SELECT provsql.provsql_round(a) $$
3566 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3570CREATE OR REPLACE
FUNCTION provsql_floor(a AGG_TOKEN)
3571 RETURNS AGG_TOKEN
AS
3572$$
SELECT provsql.agg_arith_make(
13,
ARRAY[(a)::UUID],
3573 pg_catalog.floor(provsql.agg_token_value(a))); $$
3574 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3577CREATE OR REPLACE
FUNCTION provsql_ceil(a AGG_TOKEN)
3578 RETURNS AGG_TOKEN
AS
3579$$
SELECT provsql.agg_arith_make(
14,
ARRAY[(a)::UUID],
3580 pg_catalog.ceil(provsql.agg_token_value(a))); $$
3581 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3584CREATE OR REPLACE
FUNCTION provsql_ceiling(a AGG_TOKEN)
3585 RETURNS AGG_TOKEN
AS
3586$$
SELECT provsql.agg_arith_make(
14,
ARRAY[(a)::UUID],
3587 pg_catalog.ceil(provsql.agg_token_value(a))); $$
3588 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3591CREATE OR REPLACE
FUNCTION provsql_abs(a AGG_TOKEN)
3592 RETURNS AGG_TOKEN
AS
3593$$
SELECT provsql.agg_arith_make(
15,
ARRAY[(a)::UUID],
3594 pg_catalog.abs(provsql.agg_token_value(a))); $$
3595 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3599CREATE OR REPLACE
FUNCTION agg_token_plus_numeric(a AGG_TOKEN, b
NUMERIC)
3600 RETURNS AGG_TOKEN
AS
3601$$
SELECT provsql.agg_arith_make(
0,
ARRAY[(a)::UUID, provsql.agg_value_gate(b)],
3602 provsql.agg_token_value(a) + b); $$
3603 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3606CREATE OR REPLACE
FUNCTION agg_token_minus_numeric(a AGG_TOKEN, b
NUMERIC)
3607 RETURNS AGG_TOKEN
AS
3608$$
SELECT provsql.agg_arith_make(
2,
ARRAY[(a)::UUID, provsql.agg_value_gate(b)],
3609 provsql.agg_token_value(a) - b); $$
3610 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3613CREATE OR REPLACE
FUNCTION agg_token_times_numeric(a AGG_TOKEN, b
NUMERIC)
3614 RETURNS AGG_TOKEN
AS
3615$$
SELECT provsql.agg_arith_make(
1,
ARRAY[(a)::UUID, provsql.agg_value_gate(b)],
3616 provsql.agg_token_value(a) * b); $$
3617 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3620CREATE OR REPLACE
FUNCTION agg_token_div_numeric(a AGG_TOKEN, b
NUMERIC)
3621 RETURNS AGG_TOKEN
AS
3622$$
SELECT provsql.agg_arith_make(
3,
ARRAY[(a)::UUID, provsql.agg_value_gate(b)],
3623 provsql.agg_token_value(a) / NULLIF(b,
0)); $$
3624 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3628CREATE OR REPLACE
FUNCTION numeric_plus_agg_token(a
NUMERIC, b AGG_TOKEN)
3629 RETURNS AGG_TOKEN
AS
3630$$
SELECT provsql.agg_arith_make(
0,
ARRAY[provsql.agg_value_gate(a), (b)::UUID],
3631 a + provsql.agg_token_value(b)); $$
3632 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3635CREATE OR REPLACE
FUNCTION numeric_minus_agg_token(a
NUMERIC, b AGG_TOKEN)
3636 RETURNS AGG_TOKEN
AS
3637$$
SELECT provsql.agg_arith_make(
2,
ARRAY[provsql.agg_value_gate(a), (b)::UUID],
3638 a - provsql.agg_token_value(b)); $$
3639 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3642CREATE OR REPLACE
FUNCTION numeric_times_agg_token(a
NUMERIC, b AGG_TOKEN)
3643 RETURNS AGG_TOKEN
AS
3644$$
SELECT provsql.agg_arith_make(
1,
ARRAY[provsql.agg_value_gate(a), (b)::UUID],
3645 a * provsql.agg_token_value(b)); $$
3646 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3649CREATE OR REPLACE
FUNCTION numeric_div_agg_token(a
NUMERIC, b AGG_TOKEN)
3650 RETURNS AGG_TOKEN
AS
3651$$
SELECT provsql.agg_arith_make(
3,
ARRAY[provsql.agg_value_gate(a), (b)::UUID],
3652 a / NULLIF(provsql.agg_token_value(b),
0)); $$
3653 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3664CREATE OR REPLACE
FUNCTION agg_token_intdiv(a AGG_TOKEN, b AGG_TOKEN)
3665 RETURNS AGG_TOKEN
AS
3666$$
SELECT provsql.agg_arith_make(
11,
ARRAY[(a)::UUID, (b)::UUID],
3667 trunc(provsql.agg_token_value(a) / NULLIF(provsql.agg_token_value(b),
0))); $$
3668 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3671CREATE OR REPLACE
FUNCTION agg_token_intdiv_numeric(a AGG_TOKEN, b
NUMERIC)
3672 RETURNS AGG_TOKEN
AS
3673$$
SELECT provsql.agg_arith_make(
11,
ARRAY[(a)::UUID, provsql.agg_value_gate(b)],
3674 trunc(provsql.agg_token_value(a) / NULLIF(b,
0))); $$
3675 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3678CREATE OR REPLACE
FUNCTION numeric_intdiv_agg_token(a
NUMERIC, b AGG_TOKEN)
3679 RETURNS AGG_TOKEN
AS
3680$$
SELECT provsql.agg_arith_make(
11,
ARRAY[provsql.agg_value_gate(a), (b)::UUID],
3681 trunc(a / NULLIF(provsql.agg_token_value(b),
0))); $$
3682 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3685CREATE OPERATOR + (LEFTARG=AGG_TOKEN, RIGHTARG=AGG_TOKEN,
PROCEDURE=agg_token_plus, COMMUTATOR = +);
3686CREATE OPERATOR - (LEFTARG=AGG_TOKEN, RIGHTARG=AGG_TOKEN,
PROCEDURE=agg_token_minus);
3687CREATE OPERATOR * (LEFTARG=AGG_TOKEN, RIGHTARG=AGG_TOKEN,
PROCEDURE=agg_token_times, COMMUTATOR = *);
3688CREATE OPERATOR / (LEFTARG=AGG_TOKEN, RIGHTARG=AGG_TOKEN,
PROCEDURE=agg_token_div);
3689CREATE OPERATOR - (RIGHTARG=AGG_TOKEN,
PROCEDURE=agg_token_neg);
3694CREATE OPERATOR @ (RIGHTARG=AGG_TOKEN,
PROCEDURE=provsql_abs);
3711CREATE OR REPLACE
FUNCTION agg_transcendental(fn TEXT, a AGG_TOKEN)
3715 WHEN provsql.agg_token_value_type((a)::UUID)
3716 IN (
'float8'::REGTYPE::oid,
'float4'::REGTYPE::oid)
3718 WHEN 'sqrt' THEN sqrt(provsql.agg_token_value(a)::float8)
3719 WHEN 'ln' THEN ln(provsql.agg_token_value(a)::float8)
3720 WHEN 'exp' THEN exp(provsql.agg_token_value(a)::float8)
3725 WHEN 'sqrt' THEN sqrt(provsql.agg_token_value(a))
3726 WHEN 'ln' THEN ln(provsql.agg_token_value(a))
3727 WHEN 'exp' THEN exp(provsql.agg_token_value(a))
3730$$
LANGUAGE sql STABLE STRICT PARALLEL SAFE
3731 SET search_path=provsql,pg_temp,public;
3733CREATE OR REPLACE
FUNCTION provsql_ln(a AGG_TOKEN)
3734 RETURNS AGG_TOKEN
AS
3735$$
SELECT provsql.agg_arith_make(
8,
ARRAY[(a)::UUID],
3736 provsql.agg_transcendental(
'ln', a)); $$
3737 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3740CREATE OR REPLACE
FUNCTION provsql_exp(a AGG_TOKEN)
3741 RETURNS AGG_TOKEN
AS
3742$$
SELECT provsql.agg_arith_make(
9,
ARRAY[(a)::UUID],
3743 provsql.agg_transcendental(
'exp', a)); $$
3744 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3748CREATE OR REPLACE
FUNCTION provsql_sqrt(a AGG_TOKEN)
3749 RETURNS AGG_TOKEN
AS
3750$$
SELECT provsql.agg_arith_make(
7,
3751 ARRAY[(a)::UUID, provsql.agg_value_gate(
0.
5)],
3752 provsql.agg_transcendental(
'sqrt', a)); $$
3753 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3757CREATE OR REPLACE
FUNCTION agg_token_pow_numeric(a AGG_TOKEN, b
NUMERIC)
3758 RETURNS AGG_TOKEN
AS
3759$$
SELECT provsql.agg_arith_make(
7,
3760 ARRAY[(a)::UUID, provsql.agg_value_gate(b)],
3761 provsql.agg_token_value(a) ^ b); $$
3762 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3764CREATE OPERATOR ^ (LEFTARG=AGG_TOKEN, RIGHTARG=
NUMERIC,
3765 PROCEDURE=agg_token_pow_numeric);
3770CREATE OR REPLACE
FUNCTION provsql_power(a AGG_TOKEN, b
NUMERIC)
3771 RETURNS AGG_TOKEN
AS
3772$$
SELECT provsql.agg_arith_make(
7,
3773 ARRAY[(a)::UUID, provsql.agg_value_gate(b)],
3774 power(provsql.agg_token_value(a), b)); $$
3775 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3780CREATE OR REPLACE
FUNCTION provsql_power(a AGG_TOKEN, b
double precision)
3781 RETURNS AGG_TOKEN
AS
3782$$
SELECT provsql.agg_arith_make(
7,
3783 ARRAY[(a)::UUID, provsql.agg_value_gate(b::text::
NUMERIC)],
3784 power(provsql.agg_token_value(a)::float8, b)::text::
NUMERIC); $$
3785 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3788CREATE OR REPLACE
FUNCTION provsql_pow(a AGG_TOKEN, b
NUMERIC)
3789 RETURNS AGG_TOKEN
AS
3790$$
SELECT provsql.provsql_power(a, b); $$
3791 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3794CREATE OR REPLACE
FUNCTION provsql_pow(a AGG_TOKEN, b
double precision)
3795 RETURNS AGG_TOKEN
AS
3796$$
SELECT provsql.provsql_power(a, b); $$
3797 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3799CREATE OPERATOR + (LEFTARG=AGG_TOKEN, RIGHTARG=
NUMERIC,
PROCEDURE=agg_token_plus_numeric, COMMUTATOR = +);
3800CREATE OPERATOR - (LEFTARG=AGG_TOKEN, RIGHTARG=
NUMERIC,
PROCEDURE=agg_token_minus_numeric);
3801CREATE OPERATOR * (LEFTARG=AGG_TOKEN, RIGHTARG=
NUMERIC,
PROCEDURE=agg_token_times_numeric, COMMUTATOR = *);
3802CREATE OPERATOR / (LEFTARG=AGG_TOKEN, RIGHTARG=
NUMERIC,
PROCEDURE=agg_token_div_numeric);
3804CREATE OPERATOR + (LEFTARG=
NUMERIC, RIGHTARG=AGG_TOKEN,
PROCEDURE=numeric_plus_agg_token, COMMUTATOR = +);
3805CREATE OPERATOR - (LEFTARG=
NUMERIC, RIGHTARG=AGG_TOKEN,
PROCEDURE=numeric_minus_agg_token);
3806CREATE OPERATOR * (LEFTARG=
NUMERIC, RIGHTARG=AGG_TOKEN,
PROCEDURE=numeric_times_agg_token, COMMUTATOR = *);
3807CREATE OPERATOR / (LEFTARG=
NUMERIC, RIGHTARG=AGG_TOKEN,
PROCEDURE=numeric_div_agg_token);
3810CREATE CAST (AGG_TOKEN
AS double precision)
WITH FUNCTION agg_token_to_float8(AGG_TOKEN)
AS ASSIGNMENT;
3812CREATE CAST (AGG_TOKEN
AS INTEGER)
WITH FUNCTION agg_token_to_int4(AGG_TOKEN)
AS ASSIGNMENT;
3814CREATE CAST (AGG_TOKEN
AS bigint)
WITH FUNCTION agg_token_to_int8(AGG_TOKEN)
AS ASSIGNMENT;
3816CREATE CAST (AGG_TOKEN
AS TEXT)
WITH FUNCTION agg_token_to_text(AGG_TOKEN)
AS ASSIGNMENT;
3818CREATE CAST (AGG_TOKEN
AS BOOLEAN)
WITH FUNCTION agg_token_to_bool(AGG_TOKEN)
AS ASSIGNMENT;
3833CREATE OR REPLACE
FUNCTION agg_token_cond(a AGG_TOKEN, cond UUID)
3834 RETURNS AGG_TOKEN
AS
3842 IF cond
IS NULL OR cond = gate_one()
THEN
3847 IF get_gate_type(tok) =
'conditioned'
3848 AND array_length(get_children(tok),
1) =
2 THEN
3849 ch := get_children(tok);
3851 ev := provenance_times(ch[
2], cond);
3856 result := public.uuid_generate_v5(uuid_ns_provsql(),
3857 concat(
'conditioned', tok, ev));
3858 PERFORM create_gate(
result,
'conditioned',
ARRAY[tok, ev]);
3859 RETURN agg_token_make(
result, agg_token_value(a));
3861$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public
3862 SECURITY DEFINER PARALLEL SAFE;
3865 LEFTARG = AGG_TOKEN,
3867 PROCEDURE = agg_token_cond
3878CREATE OR REPLACE
FUNCTION agg_token_cond_predicate(
3879 a AGG_TOKEN, predicate
BOOLEAN)
RETURNS AGG_TOKEN
AS
3882 RAISE EXCEPTION
'AGG_TOKEN | (predicate) must be rewritten by the ProvSQL '
3883 'planner hook: the right operand must be a Boolean combination of '
3884 'aggregate / random_variable comparisons (is provsql.active off?)'
3885 USING ERRCODE =
'feature_not_supported',
3886 DETAIL =
'provsql-reason: operator-not-rewritten; scope: gap';
3888$$
LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
3891 LEFTARG = AGG_TOKEN,
3893 PROCEDURE = agg_token_cond_predicate
3905CREATE OR REPLACE
FUNCTION agg_conditioned_target(a AGG_TOKEN)
3906 RETURNS AGG_TOKEN
AS
3909 WHEN provsql.get_gate_type((a)::UUID) =
'conditioned'
3910 AND array_length(provsql.get_children((a)::UUID),
1) =
2
3911 THEN provsql.agg_token_make(
3912 (provsql.get_children((a)::UUID))[
1], provsql.agg_token_value(a))
3915$$
LANGUAGE sql STABLE PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
3924CREATE OR REPLACE
FUNCTION agg_token_comp_numeric(a AGG_TOKEN, b
NUMERIC)
3927IMMUTABLE STRICT PARALLEL SAFE
3930 RAISE EXCEPTION
'Comparison AGG_TOKEN-NUMERIC not implemented, should be replaced by ProvSQL behavior'
3931 USING ERRCODE =
'feature_not_supported',
3932 DETAIL =
'provsql-reason: agg-comparison-not-rewritten; scope: gap';
3942CREATE OR REPLACE
FUNCTION numeric_comp_agg_token(a
NUMERIC, b AGG_TOKEN)
3945IMMUTABLE STRICT PARALLEL SAFE
3948 RAISE EXCEPTION
'Comparison NUMERIC-AGG_TOKEN not implemented, should be replaced by ProvSQL behavior'
3949 USING ERRCODE =
'feature_not_supported',
3950 DETAIL =
'provsql-reason: agg-comparison-not-rewritten; scope: gap';
3956 LEFTARG = AGG_TOKEN,
3958 PROCEDURE = agg_token_comp_numeric,
3965 RIGHTARG = AGG_TOKEN,
3966 PROCEDURE = numeric_comp_agg_token,
3973 LEFTARG = AGG_TOKEN,
3975 PROCEDURE = agg_token_comp_numeric,
3982 RIGHTARG = AGG_TOKEN,
3983 PROCEDURE = numeric_comp_agg_token,
3990 LEFTARG = AGG_TOKEN,
3992 PROCEDURE = agg_token_comp_numeric,
3999 RIGHTARG = AGG_TOKEN,
4000 PROCEDURE = numeric_comp_agg_token,
4007 LEFTARG = AGG_TOKEN,
4009 PROCEDURE = agg_token_comp_numeric,
4016 RIGHTARG = AGG_TOKEN,
4017 PROCEDURE = numeric_comp_agg_token,
4024 LEFTARG = AGG_TOKEN,
4026 PROCEDURE = agg_token_comp_numeric,
4033 RIGHTARG = AGG_TOKEN,
4034 PROCEDURE = numeric_comp_agg_token,
4041 LEFTARG = AGG_TOKEN,
4043 PROCEDURE = agg_token_comp_numeric,
4050 RIGHTARG = AGG_TOKEN,
4051 PROCEDURE = numeric_comp_agg_token,
4065CREATE OR REPLACE
FUNCTION agg_token_comp_agg_token(a AGG_TOKEN, b AGG_TOKEN)
4068IMMUTABLE STRICT PARALLEL SAFE
4071 RAISE EXCEPTION
'Comparison AGG_TOKEN-AGG_TOKEN not implemented, should be replaced by ProvSQL behavior'
4072 USING ERRCODE =
'feature_not_supported',
4073 DETAIL =
'provsql-reason: agg-comparison-not-rewritten; scope: gap';
4079 LEFTARG=AGG_TOKEN, RIGHTARG=AGG_TOKEN,
PROCEDURE=agg_token_comp_agg_token,
4080 COMMUTATOR = >, NEGATOR = >=
4084 LEFTARG=AGG_TOKEN, RIGHTARG=AGG_TOKEN,
PROCEDURE=agg_token_comp_agg_token,
4085 COMMUTATOR = >=, NEGATOR = >
4089 LEFTARG=AGG_TOKEN, RIGHTARG=AGG_TOKEN,
PROCEDURE=agg_token_comp_agg_token,
4090 COMMUTATOR = <, NEGATOR = <=
4094 LEFTARG=AGG_TOKEN, RIGHTARG=AGG_TOKEN,
PROCEDURE=agg_token_comp_agg_token,
4095 COMMUTATOR = <=, NEGATOR = <
4099 LEFTARG=AGG_TOKEN, RIGHTARG=AGG_TOKEN,
PROCEDURE=agg_token_comp_agg_token,
4100 COMMUTATOR = =, NEGATOR = <>
4104 LEFTARG=AGG_TOKEN, RIGHTARG=AGG_TOKEN,
PROCEDURE=agg_token_comp_agg_token,
4105 COMMUTATOR = <>, NEGATOR = =
4115CREATE OR REPLACE
FUNCTION agg_token_comp_text(a AGG_TOKEN, b TEXT)
4118IMMUTABLE STRICT PARALLEL SAFE
4121 RAISE EXCEPTION
'Comparison AGG_TOKEN-TEXT not implemented, should be replaced by ProvSQL behavior'
4122 USING ERRCODE =
'feature_not_supported',
4123 DETAIL =
'provsql-reason: agg-comparison-not-rewritten; scope: gap';
4133CREATE OR REPLACE
FUNCTION text_comp_agg_token(a TEXT, b AGG_TOKEN)
4136IMMUTABLE STRICT PARALLEL SAFE
4139 RAISE EXCEPTION
'Comparison TEXT-AGG_TOKEN not implemented, should be replaced by ProvSQL behavior'
4140 USING ERRCODE =
'feature_not_supported',
4141 DETAIL =
'provsql-reason: agg-comparison-not-rewritten; scope: gap';
4147 LEFTARG = AGG_TOKEN,
4149 PROCEDURE = agg_token_comp_text,
4156 RIGHTARG = AGG_TOKEN,
4157 PROCEDURE = text_comp_agg_token,
4164 LEFTARG = AGG_TOKEN,
4166 PROCEDURE = agg_token_comp_text,
4173 RIGHTARG = AGG_TOKEN,
4174 PROCEDURE = text_comp_agg_token,
4212CREATE TYPE random_variable;
4215CREATE OR REPLACE
FUNCTION random_variable_in(CSTRING)
4216 RETURNS random_variable
4217 AS 'provsql',
'random_variable_in' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
4220CREATE OR REPLACE
FUNCTION random_variable_out(random_variable)
4222 AS 'provsql',
'random_variable_out' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
4224CREATE TYPE random_variable (
4225 internallength =
16,
4226 input = random_variable_in,
4227 output = random_variable_out,
4232CREATE OR REPLACE
FUNCTION random_variable_make(tok UUID)
4233 RETURNS random_variable
4234 AS 'provsql',
'random_variable_make' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
4247CREATE CAST (random_variable
AS UUID)
WITHOUT FUNCTION AS ASSIGNMENT;
4248CREATE CAST (UUID
AS random_variable)
WITHOUT FUNCTION;
4263CREATE OR REPLACE
FUNCTION agg_token_to_random_variable(a AGG_TOKEN)
4264 RETURNS random_variable
AS
4265$$
SELECT provsql.random_variable_make(provsql.agg_token_uuid($
1)); $$
4266 LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
4267CREATE CAST (AGG_TOKEN
AS random_variable)
4268 WITH FUNCTION agg_token_to_random_variable(AGG_TOKEN)
AS IMPLICIT;
4278CREATE OR REPLACE
FUNCTION is_finite_float8(x
double precision)
4281 SELECT $
1 <>
'NaN'::float8
AND $
1 <>
'Infinity'::float8
AND $
1 <>
'-Infinity'::float8;
4282$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
4310CREATE OR REPLACE
FUNCTION rv_parametric2(
4312 p1_tok UUID, p1_lit
double precision,
4313 p2_tok UUID, p2_lit
double precision)
4314 RETURNS random_variable
AS
4318 wires UUID[] :=
ARRAY[]::UUID[];
4322 IF p1_tok
IS NOT NULL THEN
4323 wires := wires || p1_tok;
4324 s1 :=
'$' || (array_length(wires,
1) -
1);
4326 IF NOT provsql.is_finite_float8(p1_lit)
THEN
4327 RAISE EXCEPTION
'provsql.%: literal parameter must be finite (got %)',
4332 IF p2_tok
IS NOT NULL THEN
4333 wires := wires || p2_tok;
4334 s2 :=
'$' || (array_length(wires,
1) -
1);
4336 IF NOT provsql.is_finite_float8(p2_lit)
THEN
4337 RAISE EXCEPTION
'provsql.%: literal parameter must be finite (got %)',
4342 token := public.uuid_generate_v4();
4343 PERFORM provsql.create_gate(token,
'rv', wires,
NULL,
NULL,
4344 family ||
':' || s1 ||
',' || s2);
4345 RETURN provsql.random_variable_make(token);
4347$$
LANGUAGE plpgsql VOLATILE PARALLEL SAFE;
4352CREATE OR REPLACE
FUNCTION rv_parametric1(family TEXT, p_tok UUID)
4353 RETURNS random_variable
AS
4358 token := public.uuid_generate_v4();
4359 PERFORM provsql.create_gate(token,
'rv',
ARRAY[p_tok],
NULL,
NULL, family ||
':$0');
4360 RETURN provsql.random_variable_make(token);
4362$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
4375CREATE OR REPLACE
FUNCTION normal(mu random_variable, sigma
double precision)
4376 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'normal', ($
1)::UUID,
NULL,
NULL, $
2); $$
4377 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
4378CREATE OR REPLACE
FUNCTION normal(mu
double precision, sigma random_variable)
4379 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'normal',
NULL, $
1, ($
2)::UUID,
NULL); $$
4380 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
4381CREATE OR REPLACE
FUNCTION normal(mu random_variable, sigma random_variable)
4382 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'normal', ($
1)::UUID,
NULL, ($
2)::UUID,
NULL); $$
4383 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
4386CREATE OR REPLACE
FUNCTION logistic(mu random_variable, s
double precision)
4387 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'logistic', ($
1)::UUID,
NULL,
NULL, $
2); $$
4388 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
4389CREATE OR REPLACE
FUNCTION logistic(mu
double precision, s random_variable)
4390 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'logistic',
NULL, $
1, ($
2)::UUID,
NULL); $$
4391 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
4392CREATE OR REPLACE
FUNCTION logistic(mu random_variable, s random_variable)
4393 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'logistic', ($
1)::UUID,
NULL, ($
2)::UUID,
NULL); $$
4394 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
4397CREATE OR REPLACE
FUNCTION uniform(a random_variable, b
double precision)
4398 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'uniform', ($
1)::UUID,
NULL,
NULL, $
2); $$
4399 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
4400CREATE OR REPLACE
FUNCTION uniform(a
double precision, b random_variable)
4401 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'uniform',
NULL, $
1, ($
2)::UUID,
NULL); $$
4402 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
4403CREATE OR REPLACE
FUNCTION uniform(a random_variable, b random_variable)
4404 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'uniform', ($
1)::UUID,
NULL, ($
2)::UUID,
NULL); $$
4405 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
4408CREATE OR REPLACE
FUNCTION exponential(lambda random_variable)
4409 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric1(
'exponential', ($
1)::UUID); $$
4410 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
4413CREATE OR REPLACE
FUNCTION gamma(k random_variable, lambda
double precision)
4414 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'gamma', ($
1)::UUID,
NULL,
NULL, $
2); $$
4415 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
4416CREATE OR REPLACE
FUNCTION gamma(k
double precision, lambda random_variable)
4417 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'gamma',
NULL, $
1, ($
2)::UUID,
NULL); $$
4418 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
4419CREATE OR REPLACE
FUNCTION gamma(k random_variable, lambda random_variable)
4420 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'gamma', ($
1)::UUID,
NULL, ($
2)::UUID,
NULL); $$
4421 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
4424CREATE OR REPLACE
FUNCTION lognormal(mu random_variable, sigma
double precision)
4425 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'lognormal', ($
1)::UUID,
NULL,
NULL, $
2); $$
4426 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
4427CREATE OR REPLACE
FUNCTION lognormal(mu
double precision, sigma random_variable)
4428 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'lognormal',
NULL, $
1, ($
2)::UUID,
NULL); $$
4429 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
4430CREATE OR REPLACE
FUNCTION lognormal(mu random_variable, sigma random_variable)
4431 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'lognormal', ($
1)::UUID,
NULL, ($
2)::UUID,
NULL); $$
4432 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
4435CREATE OR REPLACE
FUNCTION weibull(k random_variable, lambda
double precision)
4436 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'weibull', ($
1)::UUID,
NULL,
NULL, $
2); $$
4437 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
4438CREATE OR REPLACE
FUNCTION weibull(k
double precision, lambda random_variable)
4439 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'weibull',
NULL, $
1, ($
2)::UUID,
NULL); $$
4440 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
4441CREATE OR REPLACE
FUNCTION weibull(k random_variable, lambda random_variable)
4442 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'weibull', ($
1)::UUID,
NULL, ($
2)::UUID,
NULL); $$
4443 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
4446CREATE OR REPLACE
FUNCTION pareto(xm random_variable, alpha
double precision)
4447 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'pareto', ($
1)::UUID,
NULL,
NULL, $
2); $$
4448 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
4449CREATE OR REPLACE
FUNCTION pareto(xm
double precision, alpha random_variable)
4450 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'pareto',
NULL, $
1, ($
2)::UUID,
NULL); $$
4451 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
4452CREATE OR REPLACE
FUNCTION pareto(xm random_variable, alpha random_variable)
4453 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'pareto', ($
1)::UUID,
NULL, ($
2)::UUID,
NULL); $$
4454 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
4457CREATE OR REPLACE
FUNCTION beta(alpha random_variable, beta
double precision)
4458 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'beta', ($
1)::UUID,
NULL,
NULL, $
2); $$
4459 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
4460CREATE OR REPLACE
FUNCTION beta(alpha
double precision, beta random_variable)
4461 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'beta',
NULL, $
1, ($
2)::UUID,
NULL); $$
4462 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
4463CREATE OR REPLACE
FUNCTION beta(alpha random_variable, beta random_variable)
4464 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'beta', ($
1)::UUID,
NULL, ($
2)::UUID,
NULL); $$
4465 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
4468CREATE OR REPLACE
FUNCTION inverse_gamma(alpha random_variable, beta
double precision)
4469 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'inverse_gamma', ($
1)::UUID,
NULL,
NULL, $
2); $$
4470 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
4471CREATE OR REPLACE
FUNCTION inverse_gamma(alpha
double precision, beta random_variable)
4472 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'inverse_gamma',
NULL, $
1, ($
2)::UUID,
NULL); $$
4473 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
4474CREATE OR REPLACE
FUNCTION inverse_gamma(alpha random_variable, beta random_variable)
4475 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'inverse_gamma', ($
1)::UUID,
NULL, ($
2)::UUID,
NULL); $$
4476 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
4479CREATE OR REPLACE
FUNCTION inverse_gaussian(mu random_variable, lambda
double precision)
4480 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'inverse_gaussian', ($
1)::UUID,
NULL,
NULL, $
2); $$
4481 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
4482CREATE OR REPLACE
FUNCTION inverse_gaussian(mu
double precision, lambda random_variable)
4483 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'inverse_gaussian',
NULL, $
1, ($
2)::UUID,
NULL); $$
4484 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
4485CREATE OR REPLACE
FUNCTION inverse_gaussian(mu random_variable, lambda random_variable)
4486 RETURNS random_variable
AS $$
SELECT provsql.rv_parametric2(
'inverse_gaussian', ($
1)::UUID,
NULL, ($
2)::UUID,
NULL); $$
4487 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
4517CREATE OR REPLACE
FUNCTION normal(mu
double precision, sigma
double precision)
4518 RETURNS random_variable
AS
4523 IF NOT provsql.is_finite_float8(mu)
OR NOT provsql.is_finite_float8(sigma)
THEN
4524 RAISE EXCEPTION
'provsql.normal: parameters must be finite (got mu=%, sigma=%)', mu, sigma;
4527 RAISE EXCEPTION
'provsql.normal: sigma must be non-negative (got %)', sigma;
4530 RETURN provsql.as_random(mu);
4532 token := public.uuid_generate_v4();
4533 PERFORM provsql.create_gate(token,
'rv',
NULL,
NULL,
NULL,
'normal:' || mu ||
',' || sigma);
4534 RETURN provsql.random_variable_make(token);
4536$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
4557CREATE OR REPLACE
FUNCTION logistic(mu
double precision, s
double precision)
4558 RETURNS random_variable
AS
4563 IF NOT provsql.is_finite_float8(mu)
OR NOT provsql.is_finite_float8(s)
THEN
4564 RAISE EXCEPTION
'provsql.logistic: parameters must be finite (got mu=%, s=%)', mu, s;
4567 RAISE EXCEPTION
'provsql.logistic: scale s must be non-negative (got %)', s;
4570 RETURN provsql.as_random(mu);
4572 token := public.uuid_generate_v4();
4573 PERFORM provsql.create_gate(token,
'rv',
NULL,
NULL,
NULL,
'logistic:' || mu ||
',' || s);
4574 RETURN provsql.random_variable_make(token);
4576$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
4593CREATE OR REPLACE
FUNCTION uniform(a
double precision, b
double precision)
4594 RETURNS random_variable
AS
4599 IF NOT provsql.is_finite_float8(a)
OR NOT provsql.is_finite_float8(b)
THEN
4600 RAISE EXCEPTION
'provsql.uniform: bounds must be finite (got a=%, b=%)', a, b;
4603 RAISE EXCEPTION
'provsql.uniform: a must be <= b (got a=%, b=%)', a, b;
4606 RETURN provsql.as_random(a);
4608 token := public.uuid_generate_v4();
4609 PERFORM provsql.create_gate(token,
'rv',
NULL,
NULL,
NULL,
'uniform:' || a ||
',' || b);
4610 RETURN provsql.random_variable_make(token);
4612$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
4627CREATE OR REPLACE
FUNCTION exponential(lambda
double precision)
4628 RETURNS random_variable
AS
4633 IF NOT provsql.is_finite_float8(lambda)
THEN
4634 RAISE EXCEPTION
'provsql.exponential: lambda must be finite (got %)', lambda;
4637 RAISE EXCEPTION
'provsql.exponential: lambda must be strictly positive (got %)', lambda;
4639 token := public.uuid_generate_v4();
4640 PERFORM provsql.create_gate(token,
'rv',
NULL,
NULL,
NULL,
'exponential:' || lambda);
4641 RETURN provsql.random_variable_make(token);
4643$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
4668CREATE OR REPLACE
FUNCTION erlang(k
INTEGER, lambda
double precision)
4669 RETURNS random_variable
AS
4675 RAISE EXCEPTION
'provsql.erlang: k must be >= 1 (got %)', k;
4677 IF NOT provsql.is_finite_float8(lambda)
THEN
4678 RAISE EXCEPTION
'provsql.erlang: lambda must be finite (got %)', lambda;
4681 RAISE EXCEPTION
'provsql.erlang: lambda must be strictly positive (got %)', lambda;
4684 RETURN provsql.exponential(lambda);
4686 token := public.uuid_generate_v4();
4687 PERFORM provsql.create_gate(token,
'rv',
NULL,
NULL,
NULL,
'erlang:' || k ||
',' || lambda);
4688 RETURN provsql.random_variable_make(token);
4690$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
4713CREATE OR REPLACE
FUNCTION gamma(k
double precision, lambda
double precision)
4714 RETURNS random_variable
AS
4719 IF NOT provsql.is_finite_float8(k)
THEN
4720 RAISE EXCEPTION
'provsql.gamma: k must be finite (got %)', k;
4723 RAISE EXCEPTION
'provsql.gamma: k must be strictly positive (got %)', k;
4725 IF NOT provsql.is_finite_float8(lambda)
THEN
4726 RAISE EXCEPTION
'provsql.gamma: lambda must be finite (got %)', lambda;
4729 RAISE EXCEPTION
'provsql.gamma: lambda must be strictly positive (got %)', lambda;
4731 IF k = floor(k)
AND k <=
2147483647 THEN
4732 RETURN provsql.erlang(k::
INTEGER, lambda);
4734 token := public.uuid_generate_v4();
4735 PERFORM provsql.create_gate(token,
'rv',
NULL,
NULL,
NULL,
'gamma:' || k ||
',' || lambda);
4736 RETURN provsql.random_variable_make(token);
4738$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
4753CREATE OR REPLACE
FUNCTION chi_squared(k
double precision)
4754 RETURNS random_variable
AS
4757 IF NOT provsql.is_finite_float8(k)
THEN
4758 RAISE EXCEPTION
'provsql.chi_squared: k must be finite (got %)', k;
4761 RAISE EXCEPTION
'provsql.chi_squared: k must be strictly positive (got %)', k;
4763 RETURN provsql.gamma(k /
2,
0.
5);
4765$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
4787CREATE OR REPLACE
FUNCTION lognormal(mu
double precision, sigma
double precision)
4788 RETURNS random_variable
AS
4793 IF NOT provsql.is_finite_float8(mu)
OR NOT provsql.is_finite_float8(sigma)
THEN
4794 RAISE EXCEPTION
'provsql.lognormal: parameters must be finite (got mu=%, sigma=%)', mu, sigma;
4797 RAISE EXCEPTION
'provsql.lognormal: sigma must be non-negative (got %)', sigma;
4800 RETURN provsql.as_random(exp(mu));
4802 token := public.uuid_generate_v4();
4803 PERFORM provsql.create_gate(token,
'rv',
NULL,
NULL,
NULL,
'lognormal:' || mu ||
',' || sigma);
4804 RETURN provsql.random_variable_make(token);
4806$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
4827CREATE OR REPLACE
FUNCTION weibull(k
double precision, lambda
double precision)
4828 RETURNS random_variable
AS
4833 IF NOT provsql.is_finite_float8(k)
OR NOT provsql.is_finite_float8(lambda)
THEN
4834 RAISE EXCEPTION
'provsql.weibull: parameters must be finite (got k=%, lambda=%)', k, lambda;
4836 IF k <=
0 OR lambda <=
0 THEN
4837 RAISE EXCEPTION
'provsql.weibull: parameters must be strictly positive (got k=%, lambda=%)', k, lambda;
4840 RETURN provsql.exponential(
1 / lambda);
4842 token := public.uuid_generate_v4();
4843 PERFORM provsql.create_gate(token,
'rv',
NULL,
NULL,
NULL,
'weibull:' || k ||
',' || lambda);
4844 RETURN provsql.random_variable_make(token);
4846$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
4866CREATE OR REPLACE
FUNCTION pareto(xm
double precision, alpha
double precision)
4867 RETURNS random_variable
AS
4872 IF NOT provsql.is_finite_float8(xm)
OR NOT provsql.is_finite_float8(alpha)
THEN
4873 RAISE EXCEPTION
'provsql.pareto: parameters must be finite (got xm=%, alpha=%)', xm, alpha;
4875 IF xm <=
0 OR alpha <=
0 THEN
4876 RAISE EXCEPTION
'provsql.pareto: parameters must be strictly positive (got xm=%, alpha=%)', xm, alpha;
4878 token := public.uuid_generate_v4();
4879 PERFORM provsql.create_gate(token,
'rv',
NULL,
NULL,
NULL,
'pareto:' || xm ||
',' || alpha);
4880 RETURN provsql.random_variable_make(token);
4882$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
4903CREATE OR REPLACE
FUNCTION inverse_gamma(alpha
double precision, beta
double precision)
4904 RETURNS random_variable
AS
4909 IF NOT provsql.is_finite_float8(alpha)
OR NOT provsql.is_finite_float8(beta)
THEN
4910 RAISE EXCEPTION
'provsql.inverse_gamma: parameters must be finite (got alpha=%, beta=%)', alpha, beta;
4912 IF alpha <=
0 OR beta <=
0 THEN
4913 RAISE EXCEPTION
'provsql.inverse_gamma: parameters must be strictly positive (got alpha=%, beta=%)', alpha, beta;
4915 token := public.uuid_generate_v4();
4916 PERFORM provsql.create_gate(token,
'rv',
NULL,
NULL,
NULL,
'inverse_gamma:' || alpha ||
',' || beta);
4917 RETURN provsql.random_variable_make(token);
4919$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
4940CREATE OR REPLACE
FUNCTION inverse_gaussian(mu
double precision, lambda
double precision)
4941 RETURNS random_variable
AS
4946 IF NOT provsql.is_finite_float8(mu)
OR NOT provsql.is_finite_float8(lambda)
THEN
4947 RAISE EXCEPTION
'provsql.inverse_gaussian: parameters must be finite (got mu=%, lambda=%)', mu, lambda;
4949 IF mu <=
0 OR lambda <=
0 THEN
4950 RAISE EXCEPTION
'provsql.inverse_gaussian: parameters must be strictly positive (got mu=%, lambda=%)', mu, lambda;
4952 token := public.uuid_generate_v4();
4953 PERFORM provsql.create_gate(token,
'rv',
NULL,
NULL,
NULL,
'inverse_gaussian:' || mu ||
',' || lambda);
4954 RETURN provsql.random_variable_make(token);
4956$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
4963CREATE OR REPLACE
FUNCTION wald(mu
double precision, lambda
double precision)
4964 RETURNS random_variable
AS
4966 SELECT provsql.inverse_gaussian(mu, lambda);
4967$$
LANGUAGE sql VOLATILE PARALLEL SAFE;
4987CREATE OR REPLACE
FUNCTION categorical_from_log_pmf(
4988 outcomes
double precision[], log_pmf
double precision[])
4989 RETURNS random_variable
AS
4992 n
INT := array_length(outcomes,
1);
4993 max_lp
double precision :=
'-Infinity';
4994 kept_o
double precision[] :=
'{}';
4995 kept_p
double precision[] :=
'{}';
4996 total
double precision :=
0;
5000 IF n
IS NULL OR n =
0 OR n <> coalesce(array_length(log_pmf,
1),
0)
THEN
5001 RAISE EXCEPTION
'provsql.categorical_from_log_pmf: outcomes and log_pmf must be non-empty arrays of the same length';
5004 IF log_pmf[i] > max_lp
THEN max_lp := log_pmf[i];
END IF;
5006 IF max_lp =
'-Infinity' THEN
5007 RAISE EXCEPTION
'provsql.categorical_from_log_pmf: all masses are zero';
5010 v := exp(log_pmf[i] - max_lp);
5012 kept_o := array_append(kept_o, outcomes[i]);
5013 kept_p := array_append(kept_p, v);
5017 FOR i
IN 1..array_length(kept_p,
1) LOOP
5018 kept_p[i] := kept_p[i] / total;
5020 RETURN provsql.categorical(kept_p, kept_o);
5022$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
5039CREATE OR REPLACE
FUNCTION poisson(lambda
double precision)
5040 RETURNS random_variable
AS
5045 outcomes
double precision[] :=
'{}';
5046 lps
double precision[] :=
'{}';
5047 lp
double precision :=
0;
5050 IF NOT provsql.is_finite_float8(lambda)
OR lambda <
0 THEN
5051 RAISE EXCEPTION
'provsql.poisson: lambda must be finite and non-negative (got %)', lambda;
5054 RETURN provsql.as_random(
0);
5056 lo := greatest(
0, floor(lambda -
12 * sqrt(lambda)))::
INT;
5057 hi := ceil(lambda +
12 * sqrt(lambda))::
INT +
30;
5058 IF hi - lo +
1 >
10000 THEN
5059 RAISE EXCEPTION
'provsql.poisson: support window of % outcomes exceeds 10000; approximate with normal(%, sqrt(%))', hi - lo +
1, lambda, lambda;
5064 lp := lp + ln(lambda) - ln(k::
double precision);
5066 outcomes := array_append(outcomes, k::
double precision);
5067 lps := array_append(lps, lp);
5071 outcomes := array_prepend(
0::
double precision, outcomes);
5072 lps := array_prepend(-lambda, lps);
5074 RETURN provsql.categorical_from_log_pmf(outcomes, lps);
5076$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
5089CREATE OR REPLACE
FUNCTION poisson(lambda random_variable)
5090 RETURNS random_variable
AS
5091$$
SELECT provsql.rv_parametric1(
'poisson', ($
1)::UUID); $$
5092 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
5111CREATE OR REPLACE
FUNCTION beta(alpha
double precision, beta
double precision)
5112 RETURNS random_variable
AS
5117 IF NOT provsql.is_finite_float8(alpha)
OR NOT provsql.is_finite_float8(beta)
THEN
5118 RAISE EXCEPTION
'provsql.beta: parameters must be finite (got alpha=%, beta=%)', alpha, beta;
5120 IF alpha <=
0 OR beta <=
0 THEN
5121 RAISE EXCEPTION
'provsql.beta: parameters must be strictly positive (got alpha=%, beta=%)', alpha, beta;
5123 IF alpha =
1 AND beta =
1 THEN
5124 RETURN provsql.uniform(
0,
1);
5126 token := public.uuid_generate_v4();
5127 PERFORM provsql.create_gate(token,
'rv',
NULL,
NULL,
NULL,
'beta:' || alpha ||
',' || beta);
5128 RETURN provsql.random_variable_make(token);
5130$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
5143CREATE OR REPLACE
FUNCTION binomial(n
INTEGER, p
double precision)
5144 RETURNS random_variable
AS
5147 outcomes
double precision[] :=
'{}';
5148 lps
double precision[] :=
'{}';
5149 lp
double precision;
5152 IF n
IS NULL OR n <
0 THEN
5153 RAISE EXCEPTION
'provsql.binomial: n must be non-negative (got %)', n;
5155 IF NOT provsql.is_finite_float8(p)
OR p <
0 OR p >
1 THEN
5156 RAISE EXCEPTION
'provsql.binomial: p must be in [0, 1] (got %)', p;
5159 RAISE EXCEPTION
'provsql.binomial: n = % exceeds 10000; approximate with normal(n*p, sqrt(n*p*(1-p)))', n;
5161 IF n =
0 OR p =
0 THEN
5162 RETURN provsql.as_random(
0);
5165 RETURN provsql.as_random(n);
5167 lp := n * ln(
1 - p);
5168 outcomes := array_append(outcomes,
0::
double precision);
5169 lps := array_append(lps, lp);
5170 FOR k
IN 0..(n -
1) LOOP
5171 lp := lp + ln((n - k)::
double precision / (k +
1)) + ln(p / (
1 - p));
5172 outcomes := array_append(outcomes, (k +
1)::
double precision);
5173 lps := array_append(lps, lp);
5175 RETURN provsql.categorical_from_log_pmf(outcomes, lps);
5177$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
5190CREATE OR REPLACE
FUNCTION binomial(n
INTEGER, p random_variable)
5191 RETURNS random_variable
AS
5192$$
SELECT provsql.rv_parametric2(
'binomial',
NULL, $
1::
double precision,
5193 ($
2)::UUID,
NULL); $$
5194 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
5206CREATE OR REPLACE
FUNCTION geometric(p
double precision)
5207 RETURNS random_variable
AS
5211 outcomes
double precision[] :=
'{}';
5212 lps
double precision[] :=
'{}';
5215 IF NOT provsql.is_finite_float8(p)
OR p <=
0 OR p >
1 THEN
5216 RAISE EXCEPTION
'provsql.geometric: p must be in (0, 1] (got %)', p;
5219 RETURN provsql.as_random(
1);
5221 k_max :=
1 + ceil(ln(1e-15) / ln(
1 - p))::
INT;
5222 IF k_max >
10000 THEN
5223 RAISE EXCEPTION
'provsql.geometric: support window of % outcomes exceeds 10000 (p = % is too small); approximate with exponential(%)', k_max, p, p;
5225 FOR k
IN 1..k_max LOOP
5226 outcomes := array_append(outcomes, k::
double precision);
5227 lps := array_append(lps, (k -
1) * ln(
1 - p) + ln(p));
5229 RETURN provsql.categorical_from_log_pmf(outcomes, lps);
5231$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
5241CREATE OR REPLACE
FUNCTION geometric(p random_variable)
5242 RETURNS random_variable
AS
5243$$
SELECT provsql.rv_parametric1(
'geometric', ($
1)::UUID); $$
5244 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
5260CREATE OR REPLACE
FUNCTION hypergeometric(pop_n
INTEGER, k_marked
INTEGER, n
INTEGER)
5261 RETURNS random_variable
AS
5266 outcomes
double precision[] :=
'{}';
5267 lps
double precision[] :=
'{}';
5268 lp
double precision :=
0;
5271 IF pop_n
IS NULL OR k_marked
IS NULL OR n
IS NULL
5272 OR pop_n <
0 OR k_marked <
0 OR n <
0
5273 OR k_marked > pop_n
OR n > pop_n
THEN
5274 RAISE EXCEPTION
'provsql.hypergeometric: need 0 <= k_marked, n <= pop_n (got pop_n=%, k_marked=%, n=%)', pop_n, k_marked, n;
5276 lo := greatest(
0, n - (pop_n - k_marked));
5277 hi := least(n, k_marked);
5278 IF hi - lo +
1 >
10000 THEN
5279 RAISE EXCEPTION
'provsql.hypergeometric: support window of % outcomes exceeds 10000', hi - lo +
1;
5281 outcomes := array_append(outcomes, lo::
double precision);
5282 lps := array_append(lps, lp);
5283 FOR k
IN lo..(hi -
1) LOOP
5285 lp := lp + ln((k_marked - k)::
double precision * (n - k))
5286 - ln((k +
1)::
double precision * (pop_n - k_marked - n + k +
1));
5287 outcomes := array_append(outcomes, (k +
1)::
double precision);
5288 lps := array_append(lps, lp);
5290 RETURN provsql.categorical_from_log_pmf(outcomes, lps);
5292$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
5307CREATE OR REPLACE
FUNCTION negative_binomial(r
double precision, p
double precision)
5308 RETURNS random_variable
AS
5311 outcomes
double precision[] :=
'{}';
5312 lps
double precision[] :=
'{}';
5313 lp
double precision;
5314 max_lp
double precision;
5315 mean
double precision;
5318 IF NOT provsql.is_finite_float8(r)
OR r <=
0 THEN
5319 RAISE EXCEPTION
'provsql.negative_binomial: r must be finite and strictly positive (got %)', r;
5321 IF NOT provsql.is_finite_float8(p)
OR p <=
0 OR p >
1 THEN
5322 RAISE EXCEPTION
'provsql.negative_binomial: p must be in (0, 1] (got %)', p;
5325 RETURN provsql.as_random(
0);
5327 mean := r * (
1 - p) / p;
5330 outcomes := array_append(outcomes,
0::
double precision);
5331 lps := array_append(lps, lp);
5333 lp := lp + ln((k + r) / (k +
1)) + ln(
1 - p);
5335 IF lp > max_lp
THEN max_lp := lp;
END IF;
5336 outcomes := array_append(outcomes, k::
double precision);
5337 lps := array_append(lps, lp);
5338 EXIT
WHEN k > mean
AND lp < max_lp + ln(1e-15);
5340 RAISE EXCEPTION
'provsql.negative_binomial: support window exceeds 10000 outcomes (r=%, p=%)', r, p;
5343 RETURN provsql.categorical_from_log_pmf(outcomes, lps);
5345$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
5354CREATE OR REPLACE
FUNCTION negative_binomial(r
double precision, p random_variable)
5355 RETURNS random_variable
AS
5356$$
SELECT provsql.rv_parametric2(
'negative_binomial',
NULL, $
1, ($
2)::UUID,
NULL); $$
5357 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
5358CREATE OR REPLACE
FUNCTION negative_binomial(r random_variable, p
double precision)
5359 RETURNS random_variable
AS
5360$$
SELECT provsql.rv_parametric2(
'negative_binomial', ($
1)::UUID,
NULL,
NULL, $
2); $$
5361 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
5362CREATE OR REPLACE
FUNCTION negative_binomial(r random_variable, p random_variable)
5363 RETURNS random_variable
AS
5364$$
SELECT provsql.rv_parametric2(
'negative_binomial', ($
1)::UUID,
NULL, ($
2)::UUID,
NULL); $$
5365 LANGUAGE sql STRICT VOLATILE PARALLEL SAFE;
5379CREATE OR REPLACE
FUNCTION rv_families()
5380 RETURNS TABLE(name TEXT, nparams
INT, param_names TEXT[], label TEXT)
AS
5381 'provsql',
'rv_families' LANGUAGE C STABLE PARALLEL SAFE;
5423CREATE OR REPLACE
FUNCTION mixture(
5424 p UUID, x random_variable, y random_variable)
5425 RETURNS random_variable
AS
5429 p_kind provsql.PROVENANCE_GATE;
5432 x_kind provsql.PROVENANCE_GATE;
5433 y_kind provsql.PROVENANCE_GATE;
5435 p_kind := provsql.get_gate_type(p);
5436 IF p_kind
NOT IN (
'input',
'mulinput',
'update',
5437 'plus',
'times',
'monus',
5438 'project',
'eq',
'cmp',
5440 RAISE EXCEPTION
'provsql.mixture: p must be a Boolean gate '
5441 '(input/mulinput/update/plus/times/monus/project/eq/cmp/zero/one), got %', p_kind
5442 USING ERRCODE =
'feature_not_supported',
5443 DETAIL =
'provsql-reason: mixture-argument-kind; scope: out-of-scope';
5446 x_uuid := (x)::UUID;
5447 y_uuid := (y)::UUID;
5448 x_kind := provsql.get_gate_type(x_uuid);
5449 y_kind := provsql.get_gate_type(y_uuid);
5450 IF x_kind
NOT IN (
'rv',
'value',
'arith',
'mixture')
THEN
5451 RAISE EXCEPTION
'provsql.mixture: x must be a scalar RV root (rv / value / arith / mixture), got %', x_kind
5452 USING ERRCODE =
'feature_not_supported',
5453 DETAIL =
'provsql-reason: mixture-argument-kind; scope: out-of-scope';
5455 IF y_kind
NOT IN (
'rv',
'value',
'arith',
'mixture')
THEN
5456 RAISE EXCEPTION
'provsql.mixture: y must be a scalar RV root (rv / value / arith / mixture), got %', y_kind
5457 USING ERRCODE =
'feature_not_supported',
5458 DETAIL =
'provsql-reason: mixture-argument-kind; scope: out-of-scope';
5461 token := public.uuid_generate_v5(
5462 provsql.uuid_ns_provsql(),
5463 concat(
'mixture', p, x_uuid, y_uuid));
5464 PERFORM provsql.create_gate(token,
'mixture',
ARRAY[p, x_uuid, y_uuid]);
5465 RETURN provsql.random_variable_make(token);
5467$$
LANGUAGE plpgsql STRICT IMMUTABLE PARALLEL SAFE;
5494CREATE OR REPLACE
FUNCTION mixture(
5495 p_value
double precision,
5498 RETURNS random_variable
AS
5503 IF p_value
IS NULL OR p_value <> p_value
OR p_value <
0 OR p_value >
1 THEN
5504 RAISE EXCEPTION
'provsql.mixture: probability must be in [0,1] (got %)', p_value;
5506 p_token := public.uuid_generate_v4();
5507 PERFORM provsql.create_gate(p_token,
'input');
5508 PERFORM provsql.set_prob(p_token, p_value);
5509 RETURN provsql.mixture(p_token, x, y);
5511$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
5545CREATE OR REPLACE
FUNCTION categorical(
5546 probs
double precision[],
5547 outcomes
double precision[])
5548 RETURNS random_variable
AS
5552 p_sum
double precision :=
0.
0;
5557 mul_tokens UUID[] :=
ARRAY[]::UUID[];
5559 pi_i
double precision;
5560 vi_i
double precision;
5562 IF probs
IS NULL OR outcomes
IS NULL THEN
5563 RAISE EXCEPTION
'provsql.categorical: probs and outcomes must be non-null';
5565 n := array_length(probs,
1);
5566 IF n
IS NULL OR n <
1 THEN
5567 RAISE EXCEPTION
'provsql.categorical: probs must be non-empty';
5569 IF array_length(outcomes,
1) <> n
THEN
5570 RAISE EXCEPTION
'provsql.categorical: probs and outcomes must have the same length (got % and %)',
5571 n, array_length(outcomes,
1);
5576 vi_i := outcomes[i];
5581 IF pi_i
IS NULL OR pi_i =
'NaN'::float8
OR pi_i <
0 OR pi_i >
1 THEN
5582 RAISE EXCEPTION
'provsql.categorical: probs[%] must be in [0,1] (got %)', i, pi_i;
5584 IF vi_i
IS NULL OR vi_i =
'NaN'::float8
5585 OR vi_i =
'Infinity'::float8
OR vi_i =
'-Infinity'::float8
THEN
5586 RAISE EXCEPTION
'provsql.categorical: outcomes[%] must be finite (got %)', i, vi_i;
5588 p_sum := p_sum + pi_i;
5590 IF abs(p_sum -
1.
0) > 1e-9
THEN
5591 RAISE EXCEPTION
'provsql.categorical: probs must sum to 1 within 1e-9 (got %)', p_sum;
5603 nb_positive
INTEGER :=
0;
5604 only_idx
INTEGER :=
0;
5607 IF probs[i] >
0.
0 THEN
5608 nb_positive := nb_positive +
1;
5612 IF nb_positive =
1 THEN
5613 RETURN provsql.as_random(outcomes[only_idx]);
5620 key_token := public.uuid_generate_v4();
5621 PERFORM provsql.create_gate(key_token,
'input');
5622 PERFORM provsql.set_prob(key_token,
1.
0);
5629 IF pi_i <=
0.
0 THEN CONTINUE;
END IF;
5630 mul_token := public.uuid_generate_v4();
5631 PERFORM provsql.create_gate(mul_token,
'mulinput',
ARRAY[key_token],
5632 i -
1,
NULL, outcomes[i]::TEXT);
5633 PERFORM provsql.set_prob(mul_token, pi_i);
5634 mul_tokens := mul_tokens || mul_token;
5637 mix_wires :=
ARRAY[key_token] || mul_tokens;
5638 mix_token := public.uuid_generate_v4();
5639 PERFORM provsql.create_gate(mix_token,
'mixture', mix_wires);
5640 RETURN provsql.random_variable_make(mix_token);
5642$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
5675CREATE OR REPLACE
FUNCTION gmm(
5676 weights
double precision[],
5677 means
double precision[],
5678 stddevs
double precision[])
5679 RETURNS random_variable
AS
5683 w_sum
double precision :=
0.
0;
5685 acc random_variable :=
NULL;
5686 remaining
double precision :=
0.
0;
5688 IF weights
IS NULL OR means
IS NULL OR stddevs
IS NULL THEN
5689 RAISE EXCEPTION
'provsql.gmm: weights, means, and stddevs must be non-null';
5691 n := array_length(weights,
1);
5692 IF n
IS NULL OR n <
1 THEN
5693 RAISE EXCEPTION
'provsql.gmm: weights must be non-empty';
5695 IF array_length(means,
1) <> n
OR array_length(stddevs,
1) <> n
THEN
5696 RAISE EXCEPTION
'provsql.gmm: weights, means, and stddevs must have the same length (got %, %, %)',
5697 n, array_length(means,
1), array_length(stddevs,
1);
5700 IF weights[i]
IS NULL OR weights[i] =
'NaN'::float8
5701 OR weights[i] <
0 OR weights[i] >
1 THEN
5702 RAISE EXCEPTION
'provsql.gmm: weights[%] must be in [0,1] (got %)',
5705 w_sum := w_sum + weights[i];
5707 IF abs(w_sum -
1.
0) > 1e-9
THEN
5708 RAISE EXCEPTION
'provsql.gmm: weights must sum to 1 within 1e-9 (got %)', w_sum;
5714 FOR i
IN REVERSE n..
1 LOOP
5715 IF weights[i] <=
0.
0 THEN
5719 acc := provsql.normal(means[i], stddevs[i]);
5720 remaining := weights[i];
5722 remaining := remaining + weights[i];
5723 acc := provsql.mixture(least(
1.
0, weights[i] / remaining),
5724 provsql.normal(means[i], stddevs[i]), acc);
5729$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
5756CREATE OR REPLACE
FUNCTION empirical_samples(samples
double precision[])
5757 RETURNS random_variable
AS
5761 sorted
double precision[];
5762 outcomes
double precision[] :=
'{}';
5763 probs
double precision[] :=
'{}';
5765 prev
double precision;
5767 started
BOOLEAN :=
false;
5769 n := array_length(samples,
1);
5770 IF n
IS NULL OR n <
1 THEN
5771 RAISE EXCEPTION
'provsql.empirical_samples: samples must be non-empty';
5773 sorted :=
ARRAY(
SELECT s
FROM unnest(samples)
AS s
ORDER BY 1);
5774 FOREACH v
IN ARRAY sorted LOOP
5775 IF v
IS NULL OR v =
'NaN'::float8
5776 OR v =
'Infinity'::float8
OR v =
'-Infinity'::float8
THEN
5778 'provsql.empirical_samples: samples must be finite (got %)', v;
5780 IF started
AND v = prev
THEN
5784 outcomes := outcomes || prev;
5785 probs := probs || (run::
double precision / n);
5792 outcomes := outcomes || prev;
5793 probs := probs || (run::
double precision / n);
5794 IF array_length(outcomes,
1) >
10000 THEN
5796 'provsql.empirical_samples: at most 10000 distinct values are '
5797 'supported (got %); thin the chain or bin the samples (e.g. with '
5798 'width_bucket)', array_length(outcomes,
1);
5800 RETURN provsql.categorical(probs, outcomes);
5802$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
5832CREATE OR REPLACE
FUNCTION empirical_cdf(grid
double precision[],
5833 cdf
double precision[])
5834 RETURNS random_variable
AS
5839 acc random_variable :=
NULL;
5840 remaining
double precision :=
0.
0;
5842 comp random_variable;
5844 n := array_length(grid,
1);
5845 IF n
IS NULL OR n <
2 THEN
5846 RAISE EXCEPTION
'provsql.empirical_cdf: grid must have at least two entries';
5848 IF array_length(cdf,
1) <> n
THEN
5849 RAISE EXCEPTION
'provsql.empirical_cdf: grid and cdf must have the same length (got % and %)',
5850 n, array_length(cdf,
1);
5853 RAISE EXCEPTION
'provsql.empirical_cdf: at most 10000 grid points are supported (got %)', n;
5856 IF grid[i]
IS NULL OR grid[i] =
'NaN'::float8
5857 OR grid[i] =
'Infinity'::float8
OR grid[i] =
'-Infinity'::float8
THEN
5858 RAISE EXCEPTION
'provsql.empirical_cdf: grid[%] must be finite (got %)', i, grid[i];
5860 IF i >
1 AND NOT grid[i] > grid[i-1]
THEN
5861 RAISE EXCEPTION
'provsql.empirical_cdf: grid must be strictly increasing (grid[%] = %, grid[%] = %)',
5862 i-1, grid[i-1], i, grid[i];
5864 IF cdf[i]
IS NULL OR cdf[i] =
'NaN'::float8
OR cdf[i] <
0 OR cdf[i] >
1 THEN
5865 RAISE EXCEPTION
'provsql.empirical_cdf: cdf[%] must be in [0,1] (got %)', i, cdf[i];
5867 IF i >
1 AND cdf[i] < cdf[i-1]
THEN
5868 RAISE EXCEPTION
'provsql.empirical_cdf: cdf must be non-decreasing (cdf[%] = %, cdf[%] = %)',
5869 i-1, cdf[i-1], i, cdf[i];
5872 IF abs(cdf[n] -
1.
0) > 1e-9
THEN
5873 RAISE EXCEPTION
'provsql.empirical_cdf: cdf must end at 1 within 1e-9 (got %)', cdf[n];
5879 FOR i
IN REVERSE n..
1 LOOP
5880 w :=
CASE WHEN i =
1 THEN cdf[
1]
ELSE cdf[i] - cdf[i-1]
END;
5884 comp :=
CASE WHEN i =
1 THEN provsql.as_random(grid[
1])
5885 ELSE provsql.uniform(grid[i-1], grid[i])
END;
5890 remaining := remaining + w;
5891 acc := provsql.mixture(least(
1.
0, w / remaining), comp, acc);
5896$$
LANGUAGE plpgsql STRICT VOLATILE PARALLEL SAFE;
5917CREATE OR REPLACE
FUNCTION as_random(c
double precision)
5918 RETURNS random_variable
AS
5926 c_canon
double precision := c +
0.
0;
5927 c_text
varchar :=
CAST(c_canon
AS VARCHAR);
5928 token UUID := public.uuid_generate_v5(
5929 provsql.uuid_ns_provsql(), concat(
'value', c_text));
5931 PERFORM provsql.create_gate(token,
'value',
NULL,
NULL,
NULL, c_text);
5932 RETURN provsql.random_variable_make(token);
5934$$
LANGUAGE plpgsql STRICT IMMUTABLE PARALLEL SAFE;
5949CREATE CAST (
double precision AS random_variable)
5950 WITH FUNCTION as_random(
double precision)
AS IMPLICIT;
5953CREATE OR REPLACE
FUNCTION as_random(c
INTEGER)
5954 RETURNS random_variable
AS
5955$$
SELECT provsql.as_random(c::
double precision); $$
5956LANGUAGE sql STRICT IMMUTABLE PARALLEL SAFE;
5959CREATE OR REPLACE
FUNCTION as_random(c
NUMERIC)
5960 RETURNS random_variable
AS
5961$$
SELECT provsql.as_random(c::
double precision); $$
5962LANGUAGE sql STRICT IMMUTABLE PARALLEL SAFE;
5965CREATE CAST (
INTEGER AS random_variable)
5966 WITH FUNCTION as_random(
INTEGER)
AS IMPLICIT;
5969CREATE CAST (
NUMERIC AS random_variable)
5970 WITH FUNCTION as_random(
NUMERIC)
AS IMPLICIT;
6002CREATE OR REPLACE
FUNCTION random_variable_plus(
6003 a random_variable, b random_variable)
6004 RETURNS random_variable
AS
6006 SELECT provsql.random_variable_make(
6007 provsql.provenance_arith(
6011$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
6014CREATE OR REPLACE
FUNCTION random_variable_minus(
6015 a random_variable, b random_variable)
6016 RETURNS random_variable
AS
6018 SELECT provsql.random_variable_make(
6019 provsql.provenance_arith(
6023$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
6026CREATE OR REPLACE
FUNCTION random_variable_times(
6027 a random_variable, b random_variable)
6028 RETURNS random_variable
AS
6030 SELECT provsql.random_variable_make(
6031 provsql.provenance_arith(
6035$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
6038CREATE OR REPLACE
FUNCTION random_variable_div(
6039 a random_variable, b random_variable)
6040 RETURNS random_variable
AS
6042 SELECT provsql.random_variable_make(
6043 provsql.provenance_arith(
6047$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
6050CREATE OR REPLACE
FUNCTION random_variable_neg(a random_variable)
6051 RETURNS random_variable
AS
6053 SELECT provsql.random_variable_make(
6054 provsql.provenance_arith(
6057$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
6066CREATE OR REPLACE
FUNCTION random_variable_pow(
6067 a random_variable, b random_variable)
6068 RETURNS random_variable
AS
6070 SELECT provsql.random_variable_make(
6071 provsql.provenance_arith(
6075$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
6084CREATE OR REPLACE
FUNCTION ln(a random_variable)
6085 RETURNS random_variable
AS
6087 SELECT provsql.random_variable_make(
6088 provsql.provenance_arith(
6091$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
6094CREATE OR REPLACE
FUNCTION exp(a random_variable)
6095 RETURNS random_variable
AS
6097 SELECT provsql.random_variable_make(
6098 provsql.provenance_arith(
6101$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
6109CREATE OR REPLACE
FUNCTION pow(a random_variable, b random_variable)
6110 RETURNS random_variable
AS
6112 SELECT provsql.random_variable_pow(a, b);
6113$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
6115CREATE OR REPLACE
FUNCTION power(a random_variable, b random_variable)
6116 RETURNS random_variable
AS
6118 SELECT provsql.random_variable_pow(a, b);
6119$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
6126CREATE OR REPLACE
FUNCTION sqrt(a random_variable)
6127 RETURNS random_variable
AS
6129 SELECT provsql.random_variable_pow(a, provsql.as_random(
0.
5));
6130$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
6140CREATE OR REPLACE
FUNCTION random_variable_cmp_oid(sym TEXT)
6143 SELECT (sym ||
'(double precision,double precision)')::regoperator::oid;
6144$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
6160CREATE OR REPLACE
FUNCTION random_variable_cmp_placeholder(
6161 a random_variable, b random_variable)
6165 RAISE EXCEPTION
'random_variable comparison must be rewritten by the '
6166 'ProvSQL planner hook (is provsql.active off?)'
6167 USING ERRCODE =
'feature_not_supported',
6168 DETAIL =
'provsql-reason: rv-operator-not-rewritten; scope: out-of-scope';
6170$$
LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
6172CREATE OR REPLACE
FUNCTION random_variable_lt(
6173 a random_variable, b random_variable)
RETURNS BOOLEAN AS
6174$$
SELECT provsql.random_variable_cmp_placeholder(a, b); $$
6175LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
6177CREATE OR REPLACE
FUNCTION random_variable_le(
6178 a random_variable, b random_variable)
RETURNS BOOLEAN AS
6179$$
SELECT provsql.random_variable_cmp_placeholder(a, b); $$
6180LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
6182CREATE OR REPLACE
FUNCTION random_variable_eq(
6183 a random_variable, b random_variable)
RETURNS BOOLEAN AS
6184$$
SELECT provsql.random_variable_cmp_placeholder(a, b); $$
6185LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
6187CREATE OR REPLACE
FUNCTION random_variable_ne(
6188 a random_variable, b random_variable)
RETURNS BOOLEAN AS
6189$$
SELECT provsql.random_variable_cmp_placeholder(a, b); $$
6190LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
6192CREATE OR REPLACE
FUNCTION random_variable_ge(
6193 a random_variable, b random_variable)
RETURNS BOOLEAN AS
6194$$
SELECT provsql.random_variable_cmp_placeholder(a, b); $$
6195LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
6197CREATE OR REPLACE
FUNCTION random_variable_gt(
6198 a random_variable, b random_variable)
RETURNS BOOLEAN AS
6199$$
SELECT provsql.random_variable_cmp_placeholder(a, b); $$
6200LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
6208CREATE OR REPLACE
FUNCTION rv_cmp_lt(
6209 a random_variable, b random_variable)
RETURNS UUID
AS
6211 SELECT provsql.provenance_cmp(
6213 provsql.random_variable_cmp_oid(
'<'),
6215$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
6218CREATE OR REPLACE
FUNCTION rv_cmp_le(
6219 a random_variable, b random_variable)
RETURNS UUID
AS
6221 SELECT provsql.provenance_cmp(
6223 provsql.random_variable_cmp_oid(
'<='),
6225$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
6228CREATE OR REPLACE
FUNCTION rv_cmp_eq(
6229 a random_variable, b random_variable)
RETURNS UUID
AS
6231 SELECT provsql.provenance_cmp(
6233 provsql.random_variable_cmp_oid(
'='),
6235$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
6238CREATE OR REPLACE
FUNCTION rv_cmp_ne(
6239 a random_variable, b random_variable)
RETURNS UUID
AS
6241 SELECT provsql.provenance_cmp(
6243 provsql.random_variable_cmp_oid(
'<>'),
6245$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
6248CREATE OR REPLACE
FUNCTION rv_cmp_ge(
6249 a random_variable, b random_variable)
RETURNS UUID
AS
6251 SELECT provsql.provenance_cmp(
6253 provsql.random_variable_cmp_oid(
'>='),
6255$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
6258CREATE OR REPLACE
FUNCTION rv_cmp_gt(
6259 a random_variable, b random_variable)
RETURNS UUID
AS
6261 SELECT provsql.provenance_cmp(
6263 provsql.random_variable_cmp_oid(
'>'),
6265$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
6268 LEFTARG = random_variable,
6269 RIGHTARG = random_variable,
6270 PROCEDURE = random_variable_plus,
6275 LEFTARG = random_variable,
6276 RIGHTARG = random_variable,
6277 PROCEDURE = random_variable_minus
6281 LEFTARG = random_variable,
6282 RIGHTARG = random_variable,
6283 PROCEDURE = random_variable_times,
6288 LEFTARG = random_variable,
6289 RIGHTARG = random_variable,
6290 PROCEDURE = random_variable_div
6295 RIGHTARG = random_variable,
6296 PROCEDURE = random_variable_neg
6300 LEFTARG = random_variable,
6301 RIGHTARG = random_variable,
6302 PROCEDURE = random_variable_pow
6306 LEFTARG = random_variable,
6307 RIGHTARG = random_variable,
6308 PROCEDURE = random_variable_lt,
6314 LEFTARG = random_variable,
6315 RIGHTARG = random_variable,
6316 PROCEDURE = random_variable_le,
6322 LEFTARG = random_variable,
6323 RIGHTARG = random_variable,
6324 PROCEDURE = random_variable_eq,
6330 LEFTARG = random_variable,
6331 RIGHTARG = random_variable,
6332 PROCEDURE = random_variable_ne,
6338 LEFTARG = random_variable,
6339 RIGHTARG = random_variable,
6340 PROCEDURE = random_variable_ge,
6354CREATE OR REPLACE
FUNCTION agg_token_btree_cmp(a AGG_TOKEN, b AGG_TOKEN)
6355 RETURNS INTEGER AS 'MODULE_PATHNAME',
'agg_token_btree_cmp'
6356 LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
6358CREATE OPERATOR CLASS agg_token_ops
6359 DEFAULT FOR TYPE AGG_TOKEN
USING btree
AS
6365 FUNCTION 1 agg_token_btree_cmp(AGG_TOKEN, AGG_TOKEN);
6369 LEFTARG = random_variable,
6370 RIGHTARG = random_variable,
6371 PROCEDURE = random_variable_gt,
6390CREATE OR REPLACE
FUNCTION random_variable_btree_cmp(
6391 a random_variable, b random_variable)
RETURNS INTEGER AS
6394 RAISE EXCEPTION
'comparison or ordering of random_variable values is '
6395 'meaningless: a random_variable is a distribution, not a scalar'
6397 'Compare them as a probabilistic event -- in a WHERE / JOIN clause or '
6398 'with probability(x > y); take order statistics with provsql.greatest / '
6399 'provsql.least (or the min / max aggregates); summarise numerically with '
6400 'expected / variance / support.',
6401 DETAIL =
'provsql-reason: rv-comparison; scope: out-of-scope';
6403$$
LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
6410CREATE OPERATOR CLASS random_variable_ops
6411 DEFAULT FOR TYPE random_variable
USING btree
AS
6417 FUNCTION 1 random_variable_btree_cmp(random_variable, random_variable);
6435CREATE OR REPLACE
FUNCTION random_variable_cond(rv random_variable, cond UUID)
6436 RETURNS random_variable
AS
6444 IF cond
IS NULL OR cond = gate_one()
THEN
6454 cond := provsql.evidence_as_observation(cond);
6457 IF get_gate_type(tgt) =
'conditioned'
6458 AND array_length(get_children(tgt),
1) =
2 THEN
6461 ch := get_children(tgt);
6463 ev := provenance_times(ch[
2], cond);
6468 result := public.uuid_generate_v5(uuid_ns_provsql(),
6469 concat(
'conditioned', tgt, ev));
6470 PERFORM create_gate(
result,
'conditioned',
ARRAY[tgt, ev]);
6471 RETURN (
result)::random_variable;
6473$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public
6474 SECURITY DEFINER PARALLEL SAFE;
6477 LEFTARG = random_variable,
6479 PROCEDURE = random_variable_cond
6493CREATE OR REPLACE
FUNCTION random_variable_cond_predicate(
6494 rv random_variable, predicate
BOOLEAN)
RETURNS random_variable
AS
6497 RAISE EXCEPTION
'random_variable | (predicate) must be rewritten by the '
6498 'ProvSQL planner hook: the right operand must be a Boolean combination '
6499 'of random_variable comparisons (is provsql.active off?)'
6500 USING ERRCODE =
'feature_not_supported',
6501 DETAIL =
'provsql-reason: rv-operator-not-rewritten; scope: out-of-scope';
6503$$
LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
6506 LEFTARG = random_variable,
6508 PROCEDURE = random_variable_cond_predicate
6519CREATE OR REPLACE
FUNCTION rv_conditioned_target(token UUID)
RETURNS UUID
AS
6522 WHEN provsql.get_gate_type(token) =
'conditioned'
6523 AND array_length(provsql.get_children(token),
1) =
2
6524 THEN (provsql.get_children(token))[
1]
6527$$
LANGUAGE sql STABLE PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
6537CREATE OR REPLACE
FUNCTION rv_conditioned_prov(token UUID, prov UUID)
6541 WHEN provsql.get_gate_type(token) =
'conditioned'
6542 AND array_length(provsql.get_children(token),
1) =
2
6543 THEN provsql.provenance_times((provsql.get_children(token))[
2], prov)
6546$$
LANGUAGE sql STABLE PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
6578CREATE OR REPLACE
FUNCTION evidence_as_observation(ev UUID)
RETURNS UUID
AS
6586 IF ev
IS NULL OR provsql.get_gate_type(ev) <>
'cmp' THEN
6589 ch := provsql.get_children(ev);
6590 IF array_length(ch,
1) <>
2 THEN
6596 SELECT info1
INTO i1
FROM provsql.get_infos(ev);
6597 IF (
SELECT oprname
FROM pg_catalog.pg_operator
WHERE oid = i1)
IS DISTINCT FROM '=' THEN
6600 IF provsql.get_gate_type(ch[
1]) =
'rv'
6601 AND provsql.get_gate_type(ch[
2]) =
'value' THEN
6602 leaf := ch[
1]; datum_gate := ch[
2];
6603 ELSIF provsql.get_gate_type(ch[
2]) =
'rv'
6604 AND provsql.get_gate_type(ch[
1]) =
'value' THEN
6605 leaf := ch[
2]; datum_gate := ch[
1];
6609 RETURN provsql.observe((leaf)::random_variable,
6610 provsql.get_extra(datum_gate)::
double precision);
6612$$
LANGUAGE plpgsql VOLATILE
6613 SET search_path=provsql,pg_temp,public SECURITY DEFINER PARALLEL SAFE;
6636CREATE OR REPLACE
FUNCTION observe(x random_variable, datum
double precision)
6640 leaf UUID := (x)::UUID;
6643 IF provsql.get_gate_type(leaf) <>
'rv' THEN
6644 RAISE EXCEPTION
'provsql.observe: the argument must be a bare '
6645 'random-variable leaf (a gate_rv), got a % gate', provsql.get_gate_type(leaf)
6646 USING HINT =
'observe binds a datum to a single distribution leaf; '
6647 'observing a derived quantity (a sum, product, or comparison) needs '
6648 'a change-of-variables density and is out of scope.',
6649 DETAIL =
'provsql-reason: observe-argument-kind; scope: out-of-scope';
6651 IF NOT provsql.is_finite_float8(datum)
THEN
6652 RAISE EXCEPTION
'provsql.observe: datum must be finite (got %)', datum;
6654 result := public.uuid_generate_v4();
6655 PERFORM provsql.create_gate(
result,
'observe',
ARRAY[leaf],
NULL,
NULL, datum::TEXT);
6658$$
LANGUAGE plpgsql VOLATILE
6659 SET search_path=provsql,pg_temp,public SECURITY DEFINER PARALLEL SAFE;
6668CREATE OR REPLACE
FUNCTION and_agg_sfunc(state UUID, ev UUID)
6671 SELECT provsql.provenance_times(state, ev);
6672$$
LANGUAGE sql PARALLEL SAFE;
6682CREATE AGGREGATE and_agg(UUID) (
6683 SFUNC = and_agg_sfunc,
6695CREATE OR REPLACE
FUNCTION evidence(evidence UUID)
6696 RETURNS double precision
6697 AS 'provsql',
'rv_evidence' LANGUAGE C STRICT PARALLEL SAFE;
6708CREATE OR REPLACE
FUNCTION observe_atoms(evidence UUID)
6711 WITH RECURSIVE walk(tok)
AS (
6715 FROM walk,
LATERAL unnest(provsql.get_children(walk.tok))
AS c
6716 WHERE provsql.get_gate_type(walk.tok) =
'times'
6718 SELECT array_agg(tok
ORDER BY tok)
6720 WHERE provsql.get_gate_type(tok) =
'observe';
6721$$
LANGUAGE sql STABLE PARALLEL SAFE
SET search_path=provsql,pg_temp,public;
6745CREATE OR REPLACE
FUNCTION shapley_observe(
6746 target UUID, evidence UUID, payoff TEXT
DEFAULT 'expected')
6747 RETURNS TABLE(observation UUID,
value double precision)
AS
6753 pv
double precision[];
6755 fact
double precision[];
6762 sh
double precision;
6766 IF payoff
NOT IN (
'expected',
'variance')
THEN
6767 RAISE EXCEPTION
'provsql.shapley_observe: payoff must be ''expected'' or '
6768 '''variance'' (got %)', payoff;
6770 atoms := provsql.observe_atoms(evidence);
6771 n := coalesce(array_length(atoms,
1),
0);
6773 RAISE EXCEPTION
'provsql.shapley_observe: evidence contains no observe() '
6774 'atoms (got a % gate)', provsql.get_gate_type(evidence)
6775 USING ERRCODE =
'feature_not_supported',
6776 DETAIL =
'provsql-reason: shapley-observe-no-evidence; scope: out-of-scope';
6779 RAISE EXCEPTION
'provsql.shapley_observe: exact attribution over % '
6780 'observations is exponential; capped at 12 (sampling-based '
6781 'attribution is future work)', n
6782 USING ERRCODE =
'feature_not_supported',
6783 DETAIL =
'provsql-reason: shapley-observe-too-many; scope: out-of-scope';
6787 fact :=
ARRAY[
1::
double precision];
6788 FOR i
IN 1..n LOOP fact := fact || (fact[i] * i);
END LOOP;
6791 pv := array_fill(
NULL::
double precision,
ARRAY[nmasks]);
6792 popc := array_fill(
0,
ARRAY[nmasks]);
6795 FOR mask
IN 0 .. nmasks -
1 LOOP
6796 subset :=
ARRAY[]::UUID[];
6798 FOR i
IN 0 .. n -
1 LOOP
6799 IF (mask >> i) &
1 =
1 THEN
6800 subset := subset || atoms[i +
1];
6804 popc[mask +
1] := cnt;
6806 ev_s := provsql.gate_one();
6808 ev_s := provsql.provenance_times(VARIADIC subset);
6810 IF payoff =
'expected' THEN
6811 pv[mask +
1] := provsql.rv_moment(target,
1,
false, ev_s);
6813 pv[mask +
1] := provsql.rv_moment(target,
2,
true, ev_s);
6818 FOR i
IN 0 .. n -
1 LOOP
6821 FOR mask
IN 0 .. nmasks -
1 LOOP
6822 IF (mask >> i) &
1 =
0 THEN
6823 s_size := popc[mask +
1];
6825 sh := sh + (fact[s_size +
1] * fact[n - s_size] / fact[n +
1])
6826 * (pv[(mask | bit) +
1] - pv[mask +
1]);
6829 observation := atoms[i +
1];
6834$$
LANGUAGE plpgsql VOLATILE
6835 SET search_path=provsql,pg_temp,public SECURITY DEFINER;
6865CREATE OR REPLACE
FUNCTION "greatest"(VARIADIC args random_variable[])
6866 RETURNS random_variable
AS
6871 IF args
IS NULL THEN
6874 SELECT array_agg(
DISTINCT (a)::UUID)
INTO children
6875 FROM unnest(args) a
WHERE a
IS NOT NULL;
6876 IF children
IS NULL OR array_length(children,
1)
IS NULL THEN
6879 IF array_length(children,
1) =
1 THEN
6880 RETURN provsql.random_variable_make(children[
1]);
6882 RETURN provsql.random_variable_make(
6883 provsql.provenance_arith(
5, children));
6885$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE;
6887CREATE OR REPLACE
FUNCTION "least"(VARIADIC args random_variable[])
6888 RETURNS random_variable
AS
6893 IF args
IS NULL THEN
6896 SELECT array_agg(
DISTINCT (a)::UUID)
INTO children
6897 FROM unnest(args) a
WHERE a
IS NOT NULL;
6898 IF children
IS NULL OR array_length(children,
1)
IS NULL THEN
6901 IF array_length(children,
1) =
1 THEN
6902 RETURN provsql.random_variable_make(children[
1]);
6904 RETURN provsql.random_variable_make(
6905 provsql.provenance_arith(
6, children));
6907$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE;
6918CREATE OR REPLACE
FUNCTION rv_case(
6921RETURNS random_variable
AS
6923 SELECT provsql.random_variable_make(provsql.provenance_case(children));
6924$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
6940CREATE OR REPLACE
FUNCTION agg_case(
6945 SELECT format(
'( %s , %s )', t::TEXT,
6946 coalesce(provsql.agg_gate_value(t)::TEXT,
''))::provsql.AGG_TOKEN
6947 FROM (
SELECT provsql.provenance_case(children)
AS t)
AS s;
6948$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
6993CREATE OR REPLACE
FUNCTION rv_aggregate_semimod(
6994 prov UUID, rv random_variable)
6995 RETURNS random_variable
AS
6997 SELECT provsql.mixture(prov, rv, provsql.as_random(
0::
double precision));
6998$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
7012CREATE OR REPLACE
FUNCTION rv_aggregate_semimod(
7013 prov UUID, rv random_variable,
identity double precision)
7014 RETURNS random_variable
AS
7016 SELECT provsql.mixture(prov, rv, provsql.as_random(
identity));
7017$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
7031CREATE OR REPLACE
FUNCTION rv_aggregate_indicator(prov UUID)
7032 RETURNS random_variable
AS
7034 SELECT provsql.rv_aggregate_semimod(prov, provsql.as_random(
1::
double precision));
7035$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
7048CREATE OR REPLACE
FUNCTION rv_aggregate_indicator(prov UUID, rv random_variable)
7049 RETURNS random_variable
AS
7051 SELECT CASE WHEN rv
IS NULL THEN NULL
7052 ELSE provsql.rv_aggregate_indicator(prov)
END;
7053$$
LANGUAGE sql IMMUTABLE PARALLEL SAFE;
7064CREATE OR REPLACE
FUNCTION sum_rv_sfunc(
7065 state UUID[], rv random_variable)
7069 WHEN rv
IS NULL THEN state
7070 ELSE array_append(state, (rv)::UUID)
7072$$
LANGUAGE sql IMMUTABLE PARALLEL SAFE;
7087CREATE OR REPLACE
FUNCTION sum_rv_ffunc(state UUID[])
7088 RETURNS random_variable
AS
7093 IF state
IS NULL OR array_length(state,
1)
IS NULL THEN
7096 IF array_length(state,
1) =
1 THEN
7097 RETURN provsql.random_variable_make(state[
1]);
7099 arith_token := provsql.provenance_arith(
0, state);
7100 RETURN provsql.random_variable_make(arith_token);
7102$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE;
7104CREATE AGGREGATE sum(random_variable) (
7105 SFUNC = sum_rv_sfunc,
7108 FINALFUNC = sum_rv_ffunc
7124CREATE OR REPLACE
FUNCTION rv_sum_or_null_ffunc(state UUID[])
7125 RETURNS random_variable
AS
7128 IF state
IS NULL OR array_length(state,
1)
IS NULL THEN
7131 IF array_length(state,
1) =
1 THEN
7132 RETURN provsql.random_variable_make(state[
1]);
7134 RETURN provsql.random_variable_make(
7135 provsql.provenance_arith(
0, state));
7137$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE;
7139CREATE AGGREGATE rv_sum_or_null(random_variable) (
7140 SFUNC = sum_rv_sfunc,
7143 FINALFUNC = rv_sum_or_null_ffunc
7170CREATE OR REPLACE
FUNCTION avg_rv_ffunc(state UUID[])
7171 RETURNS random_variable
AS
7178 denom_state UUID[] :=
'{}';
7181 IF state
IS NULL THEN
7184 n := array_length(state,
1);
7189 one_uuid := (provsql.as_random(
1::
double precision))::UUID;
7191 denom_state := array_append(denom_state, one_uuid);
7195 num_token := state[
1];
7196 denom_token := denom_state[
1];
7198 num_token := provsql.provenance_arith(
0, state);
7199 denom_token := provsql.provenance_arith(
0, denom_state);
7202 RETURN provsql.random_variable_make(
7203 provsql.provenance_arith(
7205 ARRAY[num_token, denom_token]));
7207$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE;
7209CREATE AGGREGATE avg(random_variable) (
7210 SFUNC = sum_rv_sfunc,
7213 FINALFUNC = avg_rv_ffunc
7241CREATE OR REPLACE
FUNCTION product_rv_ffunc(state UUID[])
7242 RETURNS random_variable
AS
7245 IF state
IS NULL OR array_length(state,
1)
IS NULL THEN
7248 IF array_length(state,
1) =
1 THEN
7249 RETURN provsql.random_variable_make(state[
1]);
7251 RETURN provsql.random_variable_make(
7252 provsql.provenance_arith(
1, state));
7254$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE;
7256CREATE AGGREGATE product(random_variable) (
7257 SFUNC = sum_rv_sfunc,
7260 FINALFUNC = product_rv_ffunc
7288CREATE OR REPLACE
FUNCTION extremum_rv_ffunc(
7289 state UUID[], op
INTEGER,
identity double precision)
7290 RETURNS random_variable
AS
7293 IF state
IS NULL OR array_length(state,
1)
IS NULL THEN
7296 IF array_length(state,
1) =
1 THEN
7297 RETURN provsql.random_variable_make(state[
1]);
7299 RETURN provsql.random_variable_make(
7300 provsql.provenance_arith(op, state));
7302$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE;
7304CREATE OR REPLACE
FUNCTION max_rv_ffunc(state UUID[])
7305 RETURNS random_variable
AS
7308 SELECT provsql.extremum_rv_ffunc(state,
5,
'-Infinity'::
double precision);
7309$$
LANGUAGE sql IMMUTABLE PARALLEL SAFE;
7311CREATE OR REPLACE
FUNCTION min_rv_ffunc(state UUID[])
7312 RETURNS random_variable
AS
7315 SELECT provsql.extremum_rv_ffunc(state,
6,
'Infinity'::
double precision);
7316$$
LANGUAGE sql IMMUTABLE PARALLEL SAFE;
7318CREATE AGGREGATE max(random_variable) (
7319 SFUNC = sum_rv_sfunc,
7322 FINALFUNC = max_rv_ffunc
7325CREATE AGGREGATE min(random_variable) (
7326 SFUNC = sum_rv_sfunc,
7329 FINALFUNC = min_rv_ffunc
7357CREATE OR REPLACE
FUNCTION rv_stat1_sfunc(state UUID[], x random_variable)
7361 WHEN x
IS NULL THEN state
7362 ELSE state ||
ARRAY[(provsql.as_random(
1::
double precision))::UUID,
7365$$
LANGUAGE sql IMMUTABLE PARALLEL SAFE;
7371CREATE OR REPLACE
FUNCTION rv_stat2_sfunc(
7372 state UUID[], x random_variable, y random_variable)
7376 WHEN x
IS NULL OR y
IS NULL THEN state
7377 ELSE state ||
ARRAY[(provsql.as_random(
1::
double precision))::UUID,
7378 (x)::UUID, (y)::UUID]
7380$$
LANGUAGE sql IMMUTABLE PARALLEL SAFE;
7385CREATE OR REPLACE
FUNCTION rv_stat1_impl_sfunc(
7386 state UUID[], ind random_variable, x random_variable)
7390 WHEN x
IS NULL THEN state
7391 ELSE state ||
ARRAY[coalesce((ind)::UUID,
7392 (provsql.as_random(
1::
double precision))::UUID),
7395$$
LANGUAGE sql IMMUTABLE PARALLEL SAFE;
7399CREATE OR REPLACE
FUNCTION rv_stat2_impl_sfunc(
7400 state UUID[], ind random_variable, x random_variable, y random_variable)
7404 WHEN x
IS NULL OR y
IS NULL THEN state
7405 ELSE state ||
ARRAY[coalesce((ind)::UUID,
7406 (provsql.as_random(
1::
double precision))::UUID),
7407 (x)::UUID, (y)::UUID]
7409$$
LANGUAGE sql IMMUTABLE PARALLEL SAFE;
7426CREATE OR REPLACE
FUNCTION rv_stat_sum_tokens(
7427 state UUID[], stride
INTEGER,
7428 OUT n_tok UUID,
OUT sx_tok UUID,
OUT sxx_tok UUID,
7429 OUT sy_tok UUID,
OUT sxy_tok UUID,
OUT syy_tok UUID)
7433 nrows
INTEGER := coalesce(array_length(state,
1),
0) / stride;
7434 inds UUID[] :=
'{}';
7444 FOR i
IN 1..nrows LOOP
7445 ind := state[(i-1) * stride +
1];
7446 x := state[(i-1) * stride +
2];
7447 inds := array_append(inds, ind);
7448 xs := array_append(xs, provenance_arith(
1,
ARRAY[ind, x]));
7449 xxs := array_append(xxs, provenance_arith(
1,
ARRAY[ind, x, x]));
7451 y := state[(i-1) * stride +
3];
7452 ys := array_append(ys, provenance_arith(
1,
ARRAY[ind, y]));
7453 xys := array_append(xys, provenance_arith(
1,
ARRAY[ind, x, y]));
7454 yys := array_append(yys, provenance_arith(
1,
ARRAY[ind, y, y]));
7457 n_tok := provenance_arith(
0, inds);
7458 sx_tok := provenance_arith(
0, xs);
7459 sxx_tok := provenance_arith(
0, xxs);
7461 sy_tok := provenance_arith(
0, ys);
7462 sxy_tok := provenance_arith(
0, xys);
7463 syy_tok := provenance_arith(
0, yys);
7466$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE
7467 SET search_path=provsql,pg_temp,public SECURITY DEFINER;
7471CREATE OR REPLACE
FUNCTION rv_stat_var_pop_token(
7472 n_tok UUID, s_tok UUID, ss_tok UUID)
7475 SELECT provsql.provenance_arith(
2,
ARRAY[
7476 provsql.provenance_arith(
3,
ARRAY[ss_tok, n_tok]),
7477 provsql.provenance_arith(
1,
ARRAY[
7478 provsql.provenance_arith(
3,
ARRAY[s_tok, n_tok]),
7479 provsql.provenance_arith(
3,
ARRAY[s_tok, n_tok])])]);
7480$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
7485CREATE OR REPLACE
FUNCTION rv_stat_var_samp_token(
7486 n_tok UUID, s_tok UUID, ss_tok UUID)
7489 SELECT provsql.provenance_arith(
3,
ARRAY[
7490 provsql.provenance_arith(
2,
ARRAY[
7492 provsql.provenance_arith(
3,
ARRAY[
7493 provsql.provenance_arith(
1,
ARRAY[s_tok, s_tok]), n_tok])]),
7494 provsql.provenance_arith(
2,
ARRAY[
7495 n_tok, (provsql.as_random(
1::
double precision))::UUID])]);
7496$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
7501CREATE OR REPLACE
FUNCTION rv_stat_sqrt_token(v_tok UUID)
7504 SELECT provsql.provenance_arith(
7,
ARRAY[
7505 provsql.provenance_arith(
5,
ARRAY[
7506 v_tok, (provsql.as_random(
0::
double precision))::UUID]),
7507 (provsql.as_random(
0.
5::
double precision))::UUID]);
7508$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
7512CREATE OR REPLACE
FUNCTION rv_stat_covar_pop_token(
7513 n_tok UUID, sx_tok UUID, sy_tok UUID, sxy_tok UUID)
7516 SELECT provsql.provenance_arith(
2,
ARRAY[
7517 provsql.provenance_arith(
3,
ARRAY[sxy_tok, n_tok]),
7518 provsql.provenance_arith(
1,
ARRAY[
7519 provsql.provenance_arith(
3,
ARRAY[sx_tok, n_tok]),
7520 provsql.provenance_arith(
3,
ARRAY[sy_tok, n_tok])])]);
7521$$
LANGUAGE sql IMMUTABLE STRICT PARALLEL SAFE;
7524CREATE OR REPLACE
FUNCTION covar_pop_rv_ffunc(state UUID[])
7525 RETURNS random_variable
AS
7530 IF state
IS NULL OR array_length(state,
1)
IS NULL THEN
7533 SELECT *
INTO t
FROM rv_stat_sum_tokens(state,
3);
7534 RETURN random_variable_make(
7535 rv_stat_covar_pop_token(t.n_tok, t.sx_tok, t.sy_tok, t.sxy_tok));
7537$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE
7538 SET search_path=provsql,pg_temp,public SECURITY DEFINER;
7542CREATE OR REPLACE
FUNCTION covar_samp_rv_ffunc(state UUID[])
7543 RETURNS random_variable
AS
7548 IF state
IS NULL OR array_length(state,
1)
IS NULL THEN
7551 SELECT *
INTO t
FROM rv_stat_sum_tokens(state,
3);
7552 RETURN random_variable_make(
7553 provenance_arith(
3,
ARRAY[
7554 provenance_arith(
2,
ARRAY[
7556 provenance_arith(
3,
ARRAY[
7557 provenance_arith(
1,
ARRAY[t.sx_tok, t.sy_tok]), t.n_tok])]),
7558 provenance_arith(
2,
ARRAY[
7559 t.n_tok, (as_random(
1::
double precision))::UUID])]));
7561$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE
7562 SET search_path=provsql,pg_temp,public SECURITY DEFINER;
7568CREATE OR REPLACE
FUNCTION corr_rv_ffunc(state UUID[])
7569 RETURNS random_variable
AS
7576 IF state
IS NULL OR array_length(state,
1)
IS NULL THEN
7579 SELECT *
INTO t
FROM rv_stat_sum_tokens(state,
3);
7580 vx := rv_stat_var_pop_token(t.n_tok, t.sx_tok, t.sxx_tok);
7581 vy := rv_stat_var_pop_token(t.n_tok, t.sy_tok, t.syy_tok);
7582 RETURN random_variable_make(
7583 provenance_arith(
3,
ARRAY[
7584 rv_stat_covar_pop_token(t.n_tok, t.sx_tok, t.sy_tok, t.sxy_tok),
7585 rv_stat_sqrt_token(provenance_arith(
1,
ARRAY[vx, vy]))]));
7587$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE
7588 SET search_path=provsql,pg_temp,public SECURITY DEFINER;
7591CREATE OR REPLACE
FUNCTION stddev_pop_rv_ffunc(state UUID[])
7592 RETURNS random_variable
AS
7597 IF state
IS NULL OR array_length(state,
1)
IS NULL THEN
7600 SELECT *
INTO t
FROM rv_stat_sum_tokens(state,
2);
7601 RETURN random_variable_make(
7603 rv_stat_var_pop_token(t.n_tok, t.sx_tok, t.sxx_tok)));
7605$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE
7606 SET search_path=provsql,pg_temp,public SECURITY DEFINER;
7609CREATE OR REPLACE
FUNCTION stddev_samp_rv_ffunc(state UUID[])
7610 RETURNS random_variable
AS
7615 IF state
IS NULL OR array_length(state,
1)
IS NULL THEN
7618 SELECT *
INTO t
FROM rv_stat_sum_tokens(state,
2);
7619 RETURN random_variable_make(
7621 rv_stat_var_samp_token(t.n_tok, t.sx_tok, t.sxx_tok)));
7623$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE
7624 SET search_path=provsql,pg_temp,public SECURITY DEFINER;
7626CREATE AGGREGATE covar_pop(random_variable, random_variable) (
7627 SFUNC = rv_stat2_sfunc,
7630 FINALFUNC = covar_pop_rv_ffunc
7633CREATE AGGREGATE covar_samp(random_variable, random_variable) (
7634 SFUNC = rv_stat2_sfunc,
7637 FINALFUNC = covar_samp_rv_ffunc
7640CREATE AGGREGATE corr(random_variable, random_variable) (
7641 SFUNC = rv_stat2_sfunc,
7644 FINALFUNC = corr_rv_ffunc
7647CREATE AGGREGATE stddev_pop(random_variable) (
7648 SFUNC = rv_stat1_sfunc,
7651 FINALFUNC = stddev_pop_rv_ffunc
7654CREATE AGGREGATE stddev_samp(random_variable) (
7655 SFUNC = rv_stat1_sfunc,
7658 FINALFUNC = stddev_samp_rv_ffunc
7664CREATE AGGREGATE rv_covar_pop_impl(
7665 random_variable, random_variable, random_variable) (
7666 SFUNC = rv_stat2_impl_sfunc,
7669 FINALFUNC = covar_pop_rv_ffunc
7672CREATE AGGREGATE rv_covar_samp_impl(
7673 random_variable, random_variable, random_variable) (
7674 SFUNC = rv_stat2_impl_sfunc,
7677 FINALFUNC = covar_samp_rv_ffunc
7680CREATE AGGREGATE rv_corr_impl(
7681 random_variable, random_variable, random_variable) (
7682 SFUNC = rv_stat2_impl_sfunc,
7685 FINALFUNC = corr_rv_ffunc
7688CREATE AGGREGATE rv_stddev_pop_impl(random_variable, random_variable) (
7689 SFUNC = rv_stat1_impl_sfunc,
7692 FINALFUNC = stddev_pop_rv_ffunc
7695CREATE AGGREGATE rv_stddev_samp_impl(random_variable, random_variable) (
7696 SFUNC = rv_stat1_impl_sfunc,
7699 FINALFUNC = stddev_samp_rv_ffunc
7714CREATE OR REPLACE
FUNCTION rv_percentile_make(fraction
double precision,
7716 RETURNS random_variable
AS
7721 IF fraction
IS NULL THEN
7724 IF fraction <
0 OR fraction >
1 THEN
7726 'percentile_cont: fraction must be between 0 and 1 (got %)', fraction;
7728 token := public.uuid_generate_v5(
7730 concat(
'arith',
'10', pairs::TEXT, fraction::TEXT));
7732 PERFORM create_gate(token,
'arith', pairs,
10,
NULL, fraction::TEXT);
7733 RETURN random_variable_make(token);
7735$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE
7736 SET search_path=provsql,pg_temp,public SECURITY DEFINER;
7745CREATE OR REPLACE
FUNCTION percentile_cont_rv_sfunc(
7746 state UUID[], x random_variable)
7749 SELECT provsql.rv_stat1_sfunc(state, x);
7750$$
LANGUAGE sql IMMUTABLE PARALLEL SAFE;
7754CREATE OR REPLACE
FUNCTION percentile_cont_rv_ffunc(
7755 state UUID[], fraction
double precision)
7756 RETURNS random_variable
AS
7759 WHEN state
IS NULL OR array_length(state,
1)
IS NULL THEN NULL
7760 ELSE provsql.rv_percentile_make(fraction, state)
7762$$
LANGUAGE sql IMMUTABLE PARALLEL SAFE;
7764CREATE AGGREGATE percentile_cont(
double precision ORDER BY random_variable) (
7765 SFUNC = percentile_cont_rv_sfunc,
7768 FINALFUNC = percentile_cont_rv_ffunc
7773CREATE TYPE rv_percentile_state
AS (
7774 fraction
double precision,
7781CREATE OR REPLACE
FUNCTION rv_percentile_impl_sfunc(
7782 state rv_percentile_state, fraction
double precision,
7783 ind random_variable, x random_variable)
7784 RETURNS rv_percentile_state
AS
7787 coalesce((state).fraction, fraction),
7789 WHEN x
IS NULL THEN (state).tokens
7790 ELSE (state).tokens ||
7791 ARRAY[coalesce((ind)::UUID,
7792 (provsql.as_random(
1::
double precision))::UUID),
7794 END)::provsql.rv_percentile_state;
7795$$
LANGUAGE sql IMMUTABLE PARALLEL SAFE;
7798CREATE OR REPLACE
FUNCTION rv_percentile_impl_ffunc(state rv_percentile_state)
7799 RETURNS random_variable
AS
7802 WHEN state
IS NULL OR array_length((state).tokens,
1)
IS NULL THEN NULL
7803 ELSE provsql.rv_percentile_make((state).fraction, (state).tokens)
7805$$
LANGUAGE sql IMMUTABLE PARALLEL SAFE;
7807CREATE AGGREGATE rv_percentile_impl(
7808 double precision, random_variable, random_variable) (
7809 SFUNC = rv_percentile_impl_sfunc,
7810 STYPE = rv_percentile_state,
7811 INITCOND =
'(,"{}")',
7812 FINALFUNC = rv_percentile_impl_ffunc
7836CREATE OR REPLACE
FUNCTION provenance_delta
7839 'provsql',
'provenance_delta' LANGUAGE C COST
100 PARALLEL SAFE IMMUTABLE;
7863CREATE OR REPLACE
FUNCTION provenance_aggregate(
7868 is_scalar
BOOLEAN DEFAULT false)
7869 RETURNS AGG_TOKEN
AS
7870 'provsql',
'provenance_aggregate' LANGUAGE C COST
100 PARALLEL SAFE IMMUTABLE;
7884CREATE OR REPLACE
FUNCTION provenance_semimod(val ANYELEMENT, token UUID)
7886 'provsql',
'provenance_semimod' LANGUAGE C COST
100 PARALLEL SAFE IMMUTABLE;
7900CREATE FUNCTION provenance_semimod_nested(val AGG_TOKEN, token UUID)
7902 'provsql',
'provenance_semimod_nested' LANGUAGE C PARALLEL SAFE IMMUTABLE;
7916CREATE FUNCTION provenance_semimod_flat(val AGG_TOKEN, token UUID)
7918 'provsql',
'provenance_semimod_flat' LANGUAGE C PARALLEL SAFE IMMUTABLE;
7922CREATE AGGREGATE provenance_contributions_cat(UUID[]) (
7942CREATE OR REPLACE
FUNCTION provenance_semimod_nullable(val ANYELEMENT, token UUID)
7944 'provsql',
'provenance_semimod_nullable' LANGUAGE C COST
100 PARALLEL SAFE IMMUTABLE;
7958CREATE OR REPLACE
FUNCTION row_number_as_rank(rank AGG_TOKEN, row_number
bigint)
7960 AS 'provsql',
'row_number_as_rank' LANGUAGE C VOLATILE STRICT PARALLEL SAFE;
7976CREATE OR REPLACE
FUNCTION window_distinct_tokens(vals anyarray, tokens UUID[])
7979 SELECT array_agg(s
ORDER BY s)
7980 FROM (
SELECT provsql.provenance_semimod(
1, provsql.provenance_plus(array_agg(tokens[i])))
AS s
7981 FROM generate_subscripts(vals,
1)
AS i
GROUP BY vals[i]) g
7982$$
LANGUAGE sql IMMUTABLE PARALLEL SAFE;
7997CREATE OR REPLACE
FUNCTION plain(
value ANYELEMENT)
7998 RETURNS ANYELEMENT
AS
7999$$
SELECT value $$
LANGUAGE sql IMMUTABLE PARALLEL SAFE;
8025CREATE OR REPLACE
FUNCTION probability_evaluate(
8028 arguments TEXT =
NULL)
8029 RETURNS DOUBLE PRECISION AS
8030 'provsql',
'probability_evaluate' LANGUAGE C STABLE;
8045CREATE OR REPLACE
FUNCTION probability(
8048 arguments TEXT =
NULL)
8049 RETURNS DOUBLE PRECISION AS
8050 'provsql',
'probability_evaluate' LANGUAGE C STABLE;
8079CREATE OR REPLACE
FUNCTION probability(
8082 arguments TEXT =
NULL)
8083 RETURNS DOUBLE PRECISION AS
8085 SELECT predicate::
INTEGER::
double precision;
8086$$
LANGUAGE sql IMMUTABLE PARALLEL SAFE;
8095CREATE OR REPLACE
FUNCTION probability_bounds(
8097 OUT lower
DOUBLE PRECISION,
8098 OUT upper DOUBLE PRECISION)
AS
8099 'provsql',
'probability_bounds' LANGUAGE C STABLE;
8122CREATE OR REPLACE
FUNCTION expected(
8124 prov UUID = gate_one(),
8126 arguments TEXT =
NULL)
8127 RETURNS DOUBLE PRECISION AS $$
8128 SELECT moment(
input,
1, prov,
method, arguments);
8129$$
LANGUAGE sql PARALLEL SAFE STABLE
SET search_path=provsql SECURITY DEFINER;
8141CREATE OR REPLACE
FUNCTION rv_moment(
8142 token UUID, k
INTEGER, central
BOOLEAN,
8143 prov UUID
DEFAULT gate_one())
8144 RETURNS double precision
8145 AS 'provsql',
'rv_moment' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
8151CREATE OR REPLACE
FUNCTION agg_avg_moment_exact(token UUID, k
INTEGER)
8152 RETURNS double precision
8153 AS 'provsql',
'agg_avg_moment_exact' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
8161CREATE OR REPLACE
FUNCTION agg_collapsed_moment(token UUID, k
INTEGER)
8162 RETURNS double precision
8163 AS 'provsql',
'agg_collapsed_moment' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
8170CREATE OR REPLACE
FUNCTION agg_collapsed_moments(token UUID)
8171 RETURNS double precision[]
8172 AS 'provsql',
'agg_collapsed_moments' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
8190CREATE OR REPLACE
FUNCTION agg_defined_event(token UUID)
8193 gt PROVENANCE_GATE := get_gate_type(token);
8200 running_neg UUID := gate_one();
8201 parts UUID[] :=
'{}';
8203 IF token = gate_null()
THEN
8207 SELECT proname
INTO fname
8208 FROM pg_proc
WHERE oid = (get_infos(token)).info1;
8212 IF fname =
'count' AND (get_infos(token)).info2 <
0 THEN
8215 SELECT array_agg((get_children(c))[
1])
INTO toks
8216 FROM unnest(get_children(token))
AS c;
8217 IF toks
IS NULL THEN
8220 RETURN provenance_plus(toks);
8221 ELSIF gt =
'case' THEN
8222 wires := get_children(token);
8223 nw := array_length(wires,
1);
8226 parts := parts || provenance_times(
8227 running_neg, wires[
2 * i -
1],
8228 agg_defined_event(wires[
2 * i]));
8229 running_neg := provenance_times(running_neg,
8230 provenance_not(wires[
2 * i -
1]));
8232 parts := parts || provenance_times(running_neg,
8233 agg_defined_event(wires[nw]));
8234 RETURN provenance_plus(parts);
8235 ELSIF gt =
'arith' THEN
8244 SELECT array_agg(agg_defined_event(c))
INTO parts
8245 FROM unnest(get_children(token))
AS c;
8246 IF parts
IS NULL OR array_length(parts,
1)
IS NULL THEN
8249 RETURN provenance_times(VARIADIC parts);
8255$$
LANGUAGE plpgsql STABLE STRICT PARALLEL SAFE
8256 SET search_path=provsql,pg_temp,public SECURITY DEFINER;
8288CREATE OR REPLACE
FUNCTION agg_raw_moment(
8291 prov UUID = gate_one(),
8293 arguments TEXT =
NULL)
8294 RETURNS DOUBLE PRECISION AS $$
8296 aggregation_function
VARCHAR;
8298 pair_children UUID[];
8305 total_probability float8;
8309 distinct_tok UUID[];
8316 IF token
IS NULL OR k
IS NULL THEN
8320 RAISE EXCEPTION
'agg_raw_moment(): k must be non-negative (got %)', k;
8342 IF get_gate_type(token) =
'case' THEN
8347 wires UUID[] := get_children(token);
8348 nw
INTEGER := array_length(get_children(token),
1);
8349 m
INTEGER := (array_length(get_children(token),
1) -
1) /
2;
8350 running_neg UUID := gate_one();
8355 def_mass float8 :=
0;
8360 prov_p := probability(prov);
8361 IF prov_p
IS NULL OR prov_p <=
0 THEN
8366 FOR ci
IN 1 .. m +
1 LOOP
8368 region_full := provenance_times(running_neg, wires[
2 * ci -
1], prov);
8369 vuid := wires[
2 * ci];
8371 provenance_times(running_neg, provenance_not(wires[
2 * ci -
1]));
8373 region_full := provenance_times(running_neg, prov);
8376 p := probability(provenance_times(region_full,
8377 agg_defined_event(vuid)));
8385 IF get_gate_type(vuid) =
'value' THEN
8386 bm := power(
CAST(get_extra(vuid)
AS float8), k);
8387 ELSIF get_gate_type(vuid)
IN (
'agg',
'case')
THEN
8388 bm := agg_raw_moment(agg_token_make(vuid,
0), k, region_full,
8391 bm := rv_moment(vuid, k,
false, region_full);
8393 total := total + p * bm;
8394 def_mass := def_mass + p;
8397 IF def_mass <=
0 THEN
8400 RETURN total / def_mass;
8404 IF get_gate_type(token) <>
'agg' THEN
8405 IF get_gate_type(token)
IN (
'arith',
'conditioned')
THEN
8409 RETURN rv_moment((token)::UUID, k,
false, prov);
8411 RAISE EXCEPTION
USING MESSAGE=
'Wrong gate type for agg_raw_moment computation',
8412 DETAIL =
'provsql-reason: moment-not-an-aggregate; scope: deliberate';
8419 SELECT pp.proname::
varchar FROM pg_proc pp
8420 WHERE oid=(get_infos(token)).info1
8421 INTO aggregation_function;
8423 child_pairs := get_children(token);
8424 n := COALESCE(array_length(child_pairs,
1),
0);
8431 IF EXISTS (
SELECT 1 FROM unnest(child_pairs)
AS c
8432 WHERE get_gate_type((get_children(c))[
2]) <>
'value')
THEN
8433 RETURN rv_moment((token)::UUID, k,
false, prov);
8436 IF aggregation_function =
'sum' OR aggregation_function =
'count' THEN
8447 is_scalar := (get_infos(token)).info2 <
0;
8450 vals :=
ARRAY[]::float8[];
8451 toks :=
ARRAY[]::UUID[];
8453 pair_children := get_children(child_pairs[i]);
8454 toks := toks || pair_children[
1];
8455 vals := vals ||
CAST(get_extra(pair_children[
2])
AS float8);
8458 WHEN aggregation_function =
'count' AND is_scalar
THEN gate_one()
8459 WHEN n =
0 THEN gate_zero()
8460 ELSE provenance_plus(toks)
END;
8465 RETURN CASE WHEN defined_tok = gate_one()
THEN 0 ELSE NULL END;
8477 IF prov = gate_one()
AND k <=
2 THEN
8478 total := agg_collapsed_moment((token)::UUID, k);
8479 IF total
IS NOT NULL THEN
8480 IF defined_tok = gate_one()
THEN
8483 prob := probability_evaluate(defined_tok,
method, arguments);
8484 IF prob
IS NULL OR prob <=
0 THEN
8487 RETURN total / prob;
8494 tup := array_fill(
1,
ARRAY[k]);
8498 prod_v := prod_v * vals[tup[j]];
8501 SELECT array_agg(
DISTINCT toks[idx])
INTO distinct_tok
8502 FROM unnest(tup)
AS idx;
8504 IF prov <> gate_one()
THEN
8505 distinct_tok := distinct_tok || prov;
8507 conj_token := provenance_times(VARIADIC distinct_tok);
8508 prob := probability_evaluate(conj_token,
method, arguments);
8510 total := total + prod_v * prob;
8513 WHILE d >=
1 AND tup[d] = n LOOP
8518 tup[d] := tup[d] +
1;
8524 IF defined_tok <> gate_one()
THEN
8525 IF prov <> gate_one()
THEN
8526 defined_tok := provenance_times(prov, defined_tok);
8528 prob := probability_evaluate(defined_tok,
method, arguments);
8529 IF prob
IS NULL OR prob <=
0 THEN
8532 RETURN total / prob;
8534 ELSIF aggregation_function =
'min' OR aggregation_function =
'max' THEN
8542 WHEN aggregation_function =
'max'
8543 THEN power(-1::float8, k)
8559 SELECT (get_children(c))[
1]
AS tok,
8560 (
CASE WHEN aggregation_function=
'max' THEN -1
ELSE 1 END)
8561 *
CAST(get_extra((get_children(c))[
2])
AS DOUBLE PRECISION)
AS v
8562 FROM UNNEST(child_pairs)
AS c
8563 )
SELECT sign_max * COALESCE(SUM(p * power(v, k)),
0)
FROM (
8565 probability_evaluate(
8566 CASE WHEN prov = gate_one()
8567 THEN provenance_monus(provenance_plus(ARRAY_AGG(t1.tok)),
8568 provenance_plus(ARRAY_AGG(t2.tok)))
8569 ELSE provenance_times(prov,
8570 provenance_monus(provenance_plus(ARRAY_AGG(t1.tok)),
8571 provenance_plus(ARRAY_AGG(t2.tok))))
END,
8572 method, arguments)
AS p
8573 FROM tok_value t1
LEFT OUTER JOIN tok_value t2
ON t1.v > t2.v
8578 SELECT probability_evaluate(
8579 CASE WHEN prov = gate_one()
8580 THEN provenance_plus(ARRAY_AGG(tok))
8581 ELSE provenance_times(prov, provenance_plus(ARRAY_AGG(tok)))
END,
8583 FROM (
SELECT (get_children(c))[
1]
AS tok
FROM UNNEST(child_pairs)
AS c) s
8584 INTO total_probability;
8586 IF total_probability <=
0 THEN
8589 RETURN total / total_probability;
8590 ELSIF aggregation_function =
'avg' THEN
8611 IF prov <> gate_one()
THEN
8613 inner_prov UUID := prov;
8617 IF get_gate_type(inner_prov) =
'delta' THEN
8618 inner_prov := (get_children(inner_prov))[
1];
8620 IF get_gate_type(inner_prov) =
'plus' THEN
8621 prov_toks := get_children(inner_prov);
8623 prov_toks :=
ARRAY[inner_prov];
8625 SELECT array_agg((get_children(c))[
1])
INTO agg_toks
8626 FROM unnest(child_pairs)
AS c;
8627 IF agg_toks <@ prov_toks
THEN
8632 IF prov = gate_one()
THEN
8633 total := agg_avg_moment_exact((token)::UUID, k);
8634 IF total
IS NOT NULL THEN
8638 RETURN rv_moment((token)::UUID, k,
false, prov);
8640 RAISE EXCEPTION
USING MESSAGE=
8641 'Cannot compute moment for aggregation function ' || aggregation_function,
8642 DETAIL =
'provsql-reason: moment-aggregate-kind; scope: gap';
8646 IF prov <> gate_one()
8648 AND total <>
'Infinity'::float8
8649 AND total <>
'-Infinity'::float8
THEN
8650 total := total / probability_evaluate(prov,
method, arguments);
8655$$
LANGUAGE plpgsql PARALLEL SAFE
SET search_path=provsql SECURITY DEFINER;
8668CREATE OR REPLACE
FUNCTION variance(
8670 prov UUID = gate_one(),
8672 arguments TEXT =
NULL)
8673 RETURNS DOUBLE PRECISION AS $$
8678 IF pg_typeof(
input) =
'random_variable'::REGTYPE
THEN
8679 IF input IS NULL THEN
8689 RETURN provsql.rv_moment(
8690 rv_conditioned_target((
input::random_variable)::UUID),
2,
true,
8691 rv_conditioned_prov((
input::random_variable)::UUID, prov));
8694 IF pg_typeof(
input) =
'AGG_TOKEN'::REGTYPE
THEN
8695 IF input IS NULL THEN
8703 IF rv_conditioned_prov(
input::UUID, prov) = gate_one()
THEN
8704 DECLARE ms float8[];
8706 ms := agg_collapsed_moments(
8707 (agg_conditioned_target(
input::AGG_TOKEN))::UUID);
8708 IF ms
IS NOT NULL THEN
8709 RETURN ms[
2] - ms[
1] * ms[
1];
8713 m1 := agg_raw_moment(agg_conditioned_target(
input::AGG_TOKEN),
1,
8714 rv_conditioned_prov(
input::UUID, prov),
method, arguments);
8715 m2 := agg_raw_moment(agg_conditioned_target(
input::AGG_TOKEN),
2,
8716 rv_conditioned_prov(
input::UUID, prov),
method, arguments);
8717 IF m1
IS NULL OR m2
IS NULL THEN
8720 RETURN m2 - m1 * m1;
8724 IF pg_typeof(
input) =
'UUID'::REGTYPE
THEN
8725 IF input IS NULL THEN
8728 m1 := provsql.probability_evaluate(provsql.cond(
input::UUID, prov),
8730 RETURN m1 * (
1 - m1);
8733 RAISE EXCEPTION
'variance() is not yet supported for input type %', pg_typeof(
input)
8734 USING ERRCODE =
'feature_not_supported',
8735 DETAIL =
'provsql-reason: moment-input-type; scope: gap';
8737$$
LANGUAGE plpgsql PARALLEL SAFE
SET search_path=provsql SECURITY DEFINER;
8750CREATE OR REPLACE
FUNCTION moment(
8753 prov UUID = gate_one(),
8755 arguments TEXT =
NULL)
8756 RETURNS DOUBLE PRECISION AS $$
8758 IF pg_typeof(
input) =
'random_variable'::REGTYPE
THEN
8759 IF input IS NULL OR k
IS NULL THEN
8764 RETURN provsql.rv_moment(
8765 rv_conditioned_target((
input::random_variable)::UUID), k,
false,
8766 rv_conditioned_prov((
input::random_variable)::UUID, prov));
8769 IF pg_typeof(
input) =
'AGG_TOKEN'::REGTYPE
THEN
8770 RETURN agg_raw_moment(agg_conditioned_target(
input::AGG_TOKEN), k,
8771 rv_conditioned_prov(
input::UUID, prov),
method, arguments);
8778 IF pg_typeof(
input) =
'UUID'::REGTYPE
THEN
8779 IF input IS NULL OR k
IS NULL THEN
8785 RETURN provsql.probability_evaluate(provsql.cond(
input::UUID, prov),
8789 RAISE EXCEPTION
'moment() is not yet supported for input type %', pg_typeof(
input)
8790 USING ERRCODE =
'feature_not_supported',
8791 DETAIL =
'provsql-reason: moment-input-type; scope: gap';
8793$$
LANGUAGE plpgsql PARALLEL SAFE
SET search_path=provsql SECURITY DEFINER;
8808CREATE OR REPLACE
FUNCTION rv_quantile(
8809 token UUID, p
double precision,
8810 prov UUID
DEFAULT gate_one())
8811 RETURNS double precision
8812 AS 'provsql',
'rv_quantile' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
8828CREATE OR REPLACE
FUNCTION quantile(
8831 prov UUID = gate_one(),
8833 arguments TEXT =
NULL)
8834 RETURNS DOUBLE PRECISION AS $$
8839 IF p <> p
OR p <
0 OR p >
1 THEN
8840 RAISE EXCEPTION
'quantile: p must be in [0, 1] (got %)', p;
8843 IF pg_typeof(
input) =
'random_variable'::REGTYPE
THEN
8844 IF input IS NULL THEN
8849 RETURN provsql.rv_quantile(
8850 rv_conditioned_target((
input::random_variable)::UUID), p,
8851 rv_conditioned_prov((
input::random_variable)::UUID, prov));
8854 IF pg_typeof(
input)
IN (
'smallint'::REGTYPE,
'INTEGER'::REGTYPE,
8855 'bigint'::REGTYPE,
'NUMERIC'::REGTYPE,
8856 'real'::REGTYPE,
'double precision'::REGTYPE)
THEN
8858 RETURN input::
double precision;
8861 RAISE EXCEPTION
'quantile() is not yet supported for input type %', pg_typeof(
input)
8862 USING ERRCODE =
'feature_not_supported',
8863 DETAIL =
'provsql-reason: quantile-input-type; scope: gap';
8865$$
LANGUAGE plpgsql PARALLEL SAFE
SET search_path=provsql SECURITY DEFINER;
8876CREATE OR REPLACE
FUNCTION rv_support(
8877 token UUID, prov UUID
DEFAULT gate_one(),
8878 OUT lo float8,
OUT hi float8)
8879 AS 'provsql',
'rv_support' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
8921CREATE OR REPLACE
FUNCTION support(
8923 prov UUID = gate_one(),
8925 arguments TEXT =
NULL,
8930 aggregation_function
VARCHAR;
8932 values_arr float8[];
8933 total_probability float8;
8935 IF input IS NULL THEN
8936 lo :=
NULL; hi :=
NULL;
RETURN;
8942 IF pg_typeof(
input)
IN (
8943 'smallint'::REGTYPE,
'INTEGER'::REGTYPE,
'bigint'::REGTYPE,
8944 'NUMERIC'::REGTYPE,
'real'::REGTYPE,
'double precision'::REGTYPE)
THEN
8945 lo :=
input::
double precision;
8946 hi :=
input::
double precision;
8959 IF pg_typeof(
input)
IN (
'random_variable'::REGTYPE,
'UUID'::REGTYPE)
THEN
8964 SELECT r.lo, r.hi
INTO lo, hi
8965 FROM provsql.rv_support(
8966 rv_conditioned_target(
input::UUID),
8967 rv_conditioned_prov(
input::UUID, prov)) r;
8971 IF pg_typeof(
input) =
'AGG_TOKEN'::REGTYPE
THEN
8976 atok AGG_TOKEN := agg_conditioned_target(
input::AGG_TOKEN);
8978 IF get_gate_type(atok) <>
'agg' THEN
8979 RAISE EXCEPTION
USING MESSAGE=
'Wrong gate type for support computation',
8980 DETAIL =
'provsql-reason: support-not-an-aggregate; scope: deliberate';
8982 SELECT pp.proname::
varchar FROM pg_proc pp
8983 WHERE oid=(get_infos(atok)).info1
8984 INTO aggregation_function;
8985 child_pairs := get_children(atok);
8987 IF aggregation_function =
'sum' OR aggregation_function =
'count' THEN
8991 IF COALESCE(array_length(child_pairs,
1),
0) =
0 THEN
8992 lo :=
0; hi :=
0;
RETURN;
8994 SELECT sum(LEAST(v,
0::float8)), sum(GREATEST(v,
0::float8))
8996 FROM (
SELECT CAST(get_extra((get_children(c))[
2])
AS float8)
AS v
8997 FROM unnest(child_pairs)
AS c) sub;
8998 ELSIF aggregation_function =
'min' OR aggregation_function =
'max' THEN
9003 IF COALESCE(array_length(child_pairs,
1),
0) =
0 THEN
9004 lo :=
NULL; hi :=
NULL;
RETURN;
9007 SELECT min(v), max(v)
9009 FROM (
SELECT CAST(get_extra((get_children(c))[
2])
AS float8)
AS v
9010 FROM UNNEST(child_pairs)
AS c) sub;
9012 RAISE EXCEPTION
USING MESSAGE=
9013 'Cannot compute support for aggregation function ' || aggregation_function,
9014 DETAIL =
'provsql-reason: support-aggregate-kind; scope: gap';
9020 RAISE EXCEPTION
'support() is not yet supported for input type %', pg_typeof(
input)
9021 USING ERRCODE =
'feature_not_supported',
9022 DETAIL =
'provsql-reason: support-input-type; scope: gap';
9024$$
LANGUAGE plpgsql PARALLEL SAFE
SET search_path=provsql SECURITY DEFINER;
9037CREATE OR REPLACE
FUNCTION central_moment(
9040 prov UUID = gate_one(),
9042 arguments TEXT =
NULL)
9043 RETURNS DOUBLE PRECISION AS $$
9053 IF pg_typeof(
input) =
'random_variable'::REGTYPE
THEN
9054 IF input IS NULL OR k
IS NULL THEN
9059 RETURN provsql.rv_moment(
9060 rv_conditioned_target((
input::random_variable)::UUID), k,
true,
9061 rv_conditioned_prov((
input::random_variable)::UUID, prov));
9064 IF pg_typeof(
input) =
'AGG_TOKEN'::REGTYPE
THEN
9065 IF input IS NULL OR k
IS NULL THEN
9069 RAISE EXCEPTION
'central_moment(): k must be non-negative (got %)', k;
9071 IF k =
0 THEN RETURN 1;
END IF;
9072 IF k =
1 THEN RETURN 0;
END IF;
9074 mu := agg_raw_moment(agg_conditioned_target(
input::AGG_TOKEN),
1,
9075 rv_conditioned_prov(
input::UUID, prov),
method, arguments);
9076 IF mu
IS NULL THEN RETURN NULL;
END IF;
9079 IF mu =
'Infinity'::float8
OR mu =
'-Infinity'::float8
THEN
9087 raw_i := agg_raw_moment(agg_conditioned_target(
input::AGG_TOKEN), i,
9088 rv_conditioned_prov(
input::UUID, prov),
method, arguments);
9089 IF raw_i
IS NULL THEN RETURN NULL;
END IF;
9090 total := total + binom * power(-mu, k - i) * raw_i;
9093 binom := binom * (k_double - i) / (i +
1);
9101 IF pg_typeof(
input) =
'UUID'::REGTYPE
THEN
9102 IF input IS NULL OR k
IS NULL THEN
9106 RAISE EXCEPTION
'central_moment(): k must be non-negative (got %)', k;
9108 IF k =
0 THEN RETURN 1;
END IF;
9109 IF k =
1 THEN RETURN 0;
END IF;
9110 mu := provsql.probability_evaluate(provsql.cond(
input::UUID, prov),
9112 RETURN (
1 - mu) * power(-mu, k) + mu * power(
1 - mu, k);
9115 RAISE EXCEPTION
'central_moment() is not yet supported for input type %', pg_typeof(
input)
9116 USING ERRCODE =
'feature_not_supported',
9117 DETAIL =
'provsql-reason: moment-input-type; scope: gap';
9119$$
LANGUAGE plpgsql PARALLEL SAFE
SET search_path=provsql SECURITY DEFINER;
9122CREATE OR REPLACE
FUNCTION rv_covariance(x UUID, y UUID, prov UUID)
9123 RETURNS double precision
9124 AS 'provsql',
'rv_covariance' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
9149CREATE OR REPLACE
FUNCTION covariance(
9150 x random_variable, y random_variable, prov UUID
DEFAULT gate_one())
9151 RETURNS double precision AS $$
9152 SELECT provsql.rv_covariance((x)::UUID, (y)::UUID, prov);
9153$$
LANGUAGE sql PARALLEL SAFE STABLE
SET search_path=provsql SECURITY DEFINER;
9168CREATE OR REPLACE
FUNCTION stddev(
9169 x random_variable, prov UUID
DEFAULT gate_one())
9170 RETURNS double precision AS $$
9171 SELECT sqrt(provsql.variance(x, prov));
9172$$
LANGUAGE sql PARALLEL SAFE STABLE
SET search_path=provsql SECURITY DEFINER;
9175CREATE OR REPLACE
FUNCTION rv_correlation(x UUID, y UUID, prov UUID)
9176 RETURNS double precision
9177 AS 'provsql',
'rv_correlation' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
9194CREATE OR REPLACE
FUNCTION correlation(
9195 x random_variable, y random_variable, prov UUID
DEFAULT gate_one())
9196 RETURNS double precision AS $$
9197 SELECT provsql.rv_correlation((x)::UUID, (y)::UUID, prov);
9198$$
LANGUAGE sql PARALLEL SAFE STABLE
SET search_path=provsql SECURITY DEFINER;
9201CREATE OR REPLACE
FUNCTION rv_entropy(token UUID, prov UUID)
9202 RETURNS double precision
9203 AS 'provsql',
'rv_entropy' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
9221CREATE OR REPLACE
FUNCTION entropy(
9222 x random_variable, prov UUID
DEFAULT gate_one())
9223 RETURNS double precision AS $$
9224 SELECT provsql.rv_entropy((x)::UUID, prov);
9225$$
LANGUAGE sql PARALLEL SAFE STABLE
SET search_path=provsql SECURITY DEFINER;
9228CREATE OR REPLACE
FUNCTION rv_kl(p UUID, q UUID)
9229 RETURNS double precision
9230 AS 'provsql',
'rv_kl' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
9245CREATE OR REPLACE
FUNCTION kl(p random_variable, q random_variable)
9246 RETURNS double precision AS $$
9247 SELECT provsql.rv_kl((p)::UUID, (q)::UUID);
9248$$
LANGUAGE sql PARALLEL SAFE STABLE
SET search_path=provsql SECURITY DEFINER;
9252CREATE OR REPLACE
FUNCTION rv_mutual_information(x UUID, y UUID)
9253 RETURNS double precision
9254 AS 'provsql',
'rv_mutual_information' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
9268CREATE OR REPLACE
FUNCTION mutual_information(
9269 x random_variable, y random_variable)
9270 RETURNS double precision AS $$
9271 SELECT provsql.rv_mutual_information((x)::UUID, (y)::UUID);
9272$$
LANGUAGE sql PARALLEL SAFE STABLE
SET search_path=provsql SECURITY DEFINER;
9286CREATE OR REPLACE
FUNCTION shapley(
9290 arguments TEXT =
NULL,
9291 banzhaf
BOOLEAN =
'f')
9292 RETURNS DOUBLE PRECISION AS
9293 'provsql',
'shapley' LANGUAGE C STABLE;
9296CREATE OR REPLACE
FUNCTION shapley_all_vars(
9298 IN method TEXT =
NULL,
9299 IN arguments TEXT =
NULL,
9300 IN banzhaf
BOOLEAN =
'f',
9302 OUT value DOUBLE PRECISION)
9303 RETURNS SETOF RECORD
AS
9304 'provsql',
'shapley_all_vars'
9308CREATE OR REPLACE
FUNCTION banzhaf(
9312 arguments TEXT =
NULL)
9313 RETURNS DOUBLE PRECISION AS
9314 $$
SELECT provsql.shapley(token, variable,
method, arguments,
't') $$
9318CREATE OR REPLACE
FUNCTION banzhaf_all_vars(
9320 IN method TEXT =
NULL,
9321 IN arguments TEXT =
NULL,
9323 OUT value DOUBLE PRECISION)
9324 RETURNS SETOF RECORD
AS
9325 $$
SELECT *
FROM provsql.shapley_all_vars(token,
method, arguments,
't') $$
9360CREATE OR REPLACE
FUNCTION reachability_evaluate(
9364 probabilities
DOUBLE PRECISION[],
9368 RETURNS DOUBLE PRECISION AS
9369 'provsql',
'reachability_evaluate' LANGUAGE C IMMUTABLE PARALLEL SAFE;
9399CREATE OR REPLACE
FUNCTION reachability_compile_stats(
9401 IN destinations
INT[],
9403 IN probabilities
DOUBLE PRECISION[],
9406 IN directed
BOOLEAN,
9407 OUT probability
DOUBLE PRECISION,
9408 OUT data_treewidth
INT,
9410 OUT max_states
BIGINT,
9411 OUT nb_gates
BIGINT,
9412 OUT nb_variables
BIGINT)
9413 AS 'provsql',
'reachability_compile_stats'
9414 LANGUAGE C IMMUTABLE PARALLEL SAFE;
9450CREATE OR REPLACE
FUNCTION ucq_joint_compile_stats(
9451 IN disjunct_nvars
INT[],
9452 IN atom_disjunct
INT[],
9455 IN atom_arity
INT[],
9457 IN fact_elems
INT[],
9458 IN fact_arity
INT[],
9459 IN fact_tokens UUID[],
9460 IN fact_probs
DOUBLE PRECISION[],
9461 OUT probability
DOUBLE PRECISION,
9462 OUT joint_treewidth
INT,
9463 OUT data_treewidth_lb
INT,
9464 OUT circuit_treewidth_lb
INT,
9466 OUT max_states
BIGINT,
9468 OUT n_enumerating
INT)
9469 AS 'provsql',
'ucq_joint_compile_stats'
9470 LANGUAGE C IMMUTABLE PARALLEL SAFE;
9479CREATE OR REPLACE
FUNCTION ucq_joint_compile_stats(
9482 IN fact_elems
INT[],
9483 IN fact_arity
INT[],
9484 IN fact_tokens UUID[],
9485 IN fact_probs
DOUBLE PRECISION[],
9486 OUT probability
DOUBLE PRECISION,
9487 OUT joint_treewidth
INT,
9488 OUT data_treewidth_lb
INT,
9489 OUT circuit_treewidth_lb
INT,
9491 OUT max_states
BIGINT,
9493 OUT n_enumerating
INT)
9496 dnv
INT[] :=
'{}'; adisj
INT[] :=
'{}'; arel
INT[] :=
'{}';
9497 avars
INT[] :=
'{}'; aarity
INT[] :=
'{}';
9498 d JSONB; a JSONB; v TEXT; didx
INT :=
0;
9500 FOR d
IN SELECT *
FROM jsonb_array_elements(query->
'disjuncts') LOOP
9501 dnv := dnv || (d->>
'n_vars')::
INT;
9502 FOR a
IN SELECT *
FROM jsonb_array_elements(d->
'atoms') LOOP
9503 adisj := adisj || didx;
9504 arel := arel || (a->>
'rel')::
INT;
9505 aarity := aarity || jsonb_array_length(a->
'vars');
9506 FOR v
IN SELECT *
FROM jsonb_array_elements_text(a->
'vars') LOOP
9507 avars := avars || v::
INT;
9512 SELECT s.probability, s.joint_treewidth, s.data_treewidth_lb,
9513 s.circuit_treewidth_lb, s.n_bags, s.max_states, s.dd_size,
9515 INTO probability, joint_treewidth, data_treewidth_lb,
9516 circuit_treewidth_lb, n_bags, max_states, dd_size, n_enumerating
9517 FROM ucq_joint_compile_stats(dnv, adisj, arel, avars, aarity,
9518 fact_rel, fact_elems, fact_arity, fact_tokens, fact_probs) s;
9520$$
LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE;
9541CREATE OR REPLACE
FUNCTION ucq_joint_compile_stats_tracked(
9542 IN disjunct_nvars
INT[],
9543 IN atom_disjunct
INT[],
9546 IN atom_arity
INT[],
9548 IN fact_elems
INT[],
9549 IN fact_arity
INT[],
9550 IN fact_tokens UUID[],
9551 OUT probability
DOUBLE PRECISION,
9552 OUT joint_treewidth
INT,
9553 OUT data_treewidth_lb
INT,
9554 OUT circuit_treewidth_lb
INT,
9556 OUT max_states
BIGINT,
9558 OUT n_enumerating
INT)
9559 AS 'provsql',
'ucq_joint_compile_stats_tracked'
9560 LANGUAGE C STABLE PARALLEL SAFE;
9566CREATE OR REPLACE
FUNCTION ucq_joint_compile_stats_tracked(
9569 IN fact_elems
INT[],
9570 IN fact_arity
INT[],
9571 IN fact_tokens UUID[],
9572 OUT probability
DOUBLE PRECISION,
9573 OUT joint_treewidth
INT,
9574 OUT data_treewidth_lb
INT,
9575 OUT circuit_treewidth_lb
INT,
9577 OUT max_states
BIGINT,
9579 OUT n_enumerating
INT)
9582 dnv
INT[] :=
'{}'; adisj
INT[] :=
'{}'; arel
INT[] :=
'{}';
9583 avars
INT[] :=
'{}'; aarity
INT[] :=
'{}';
9584 d JSONB; a JSONB; v TEXT; didx
INT :=
0;
9586 FOR d
IN SELECT *
FROM jsonb_array_elements(query->
'disjuncts') LOOP
9587 dnv := dnv || (d->>
'n_vars')::
INT;
9588 FOR a
IN SELECT *
FROM jsonb_array_elements(d->
'atoms') LOOP
9589 adisj := adisj || didx;
9590 arel := arel || (a->>
'rel')::
INT;
9591 aarity := aarity || jsonb_array_length(a->
'vars');
9592 FOR v
IN SELECT *
FROM jsonb_array_elements_text(a->
'vars') LOOP
9593 avars := avars || v::
INT;
9598 SELECT s.probability, s.joint_treewidth, s.data_treewidth_lb,
9599 s.circuit_treewidth_lb, s.n_bags, s.max_states, s.dd_size,
9601 INTO probability, joint_treewidth, data_treewidth_lb,
9602 circuit_treewidth_lb, n_bags, max_states, dd_size, n_enumerating
9603 FROM ucq_joint_compile_stats_tracked(dnv, adisj, arel, avars, aarity,
9604 fact_rel, fact_elems, fact_arity, fact_tokens) s;
9606$$
LANGUAGE plpgsql STABLE PARALLEL SAFE;
9621CREATE OR REPLACE
FUNCTION ucq_joint_materialize_tracked(
9622 disjunct_nvars
INT[],
9623 atom_disjunct
INT[],
9632 'provsql',
'ucq_joint_materialize_tracked' LANGUAGE C VOLATILE;
9642CREATE OR REPLACE
FUNCTION ucq_joint_materialize_tracked(
9650 dnv
INT[] :=
'{}'; adisj
INT[] :=
'{}'; arel
INT[] :=
'{}';
9651 avars
INT[] :=
'{}'; aarity
INT[] :=
'{}';
9652 d JSONB; a JSONB; v TEXT; didx
INT :=
0;
9654 FOR d
IN SELECT *
FROM jsonb_array_elements(query->
'disjuncts') LOOP
9655 dnv := dnv || (d->>
'n_vars')::
INT;
9656 FOR a
IN SELECT *
FROM jsonb_array_elements(d->
'atoms') LOOP
9657 adisj := adisj || didx;
9658 arel := arel || (a->>
'rel')::
INT;
9659 aarity := aarity || jsonb_array_length(a->
'vars');
9660 FOR v
IN SELECT *
FROM jsonb_array_elements_text(a->
'vars') LOOP
9661 avars := avars || v::
INT;
9666 RETURN ucq_joint_materialize_tracked(dnv, adisj, arel, avars, aarity,
9667 fact_rel, fact_elems, fact_arity, fact_tokens);
9669$$
LANGUAGE plpgsql VOLATILE;
9703CREATE OR REPLACE
FUNCTION ucq_joint_provenance(
9704 descriptor JSONB, fallback UUID
DEFAULT NULL)
9707 legs TEXT;
sql TEXT; saved TEXT;
9708 fact_rel
INT[]; fact_elems
INT[]; fact_arity
INT[]; fact_tokens UUID[];
9709 dnv
INT[]:=
'{}'; adisj
INT[]:=
'{}'; arel
INT[]:=
'{}';
9710 avars
INT[]:=
'{}'; aarity
INT[]:=
'{}';
9711 d jsonb; a jsonb; v TEXT; didx
INT:=
0;
9714 FOR d
IN SELECT *
FROM jsonb_array_elements(descriptor->
'disjuncts') LOOP
9715 dnv := dnv || (d->>
'n_vars')::
INT;
9716 FOR a
IN SELECT *
FROM jsonb_array_elements(d->
'atoms') LOOP
9717 adisj := adisj || didx; arel := arel || (a->>
'rel')::
INT;
9718 aarity := aarity || jsonb_array_length(a->
'vars');
9719 FOR v
IN SELECT *
FROM jsonb_array_elements_text(a->
'vars') LOOP
9720 avars := avars || v::
INT;
9730 format(
'SELECT %s, ARRAY[%s]::TEXT[], provsql FROM %s%s',
9732 (
SELECT string_agg(format(
'(%I)::TEXT', c),
',')
9733 FROM jsonb_array_elements_text(descriptor->
'elem_cols'->(rn-1)::
INT) c),
9737 CASE WHEN coalesce(descriptor->
'rel_where'->>(rn-1)::
INT,
'') <>
''
9738 THEN ' WHERE '||(descriptor->
'rel_where'->>(rn-1)::
INT)
9742 FROM jsonb_array_elements_text(descriptor->
'relations')
WITH ORDINALITY t(rel, rn);
9745 WITH facts(rel,elems,tok)
AS (%s),
9746 ord
AS (
SELECT row_number()
OVER ()
AS ord, rel, elems, tok
FROM facts),
9747 dict
AS (
SELECT val, (dense_rank()
OVER (
ORDER BY val))-1
AS id
9748 FROM (
SELECT DISTINCT unnest(elems)
AS val
FROM facts) u)
9749 SELECT (
SELECT array_agg(rel
ORDER BY ord)
FROM ord),
9750 (
SELECT array_agg(cardinality(elems)
ORDER BY ord)
FROM ord),
9751 (
SELECT array_agg(tok
ORDER BY ord)
FROM ord),
9752 (
SELECT array_agg(dd.id
ORDER BY o.ord, e.k)
9753 FROM ord o,
LATERAL unnest(o.elems)
WITH ORDINALITY e(val,k)
9754 JOIN dict dd
ON dd.val = e.val)
9759 saved := current_setting(
'provsql.active',
true);
9760 PERFORM set_config(
'provsql.active',
'off',
true);
9761 EXECUTE sql INTO fact_rel, fact_arity, fact_tokens, fact_elems;
9762 PERFORM set_config(
'provsql.active', saved,
true);
9764 RETURN ucq_joint_materialize_tracked(dnv,adisj,arel,avars,aarity,
9765 fact_rel,fact_elems,fact_arity,fact_tokens);
9766EXCEPTION
WHEN OTHERS
THEN
9772$$
LANGUAGE plpgsql VOLATILE;
9790CREATE OR REPLACE
FUNCTION ucq_mobius_materialize_tracked(
9791 disjunct_nvars
INT[],
9792 atom_disjunct
INT[],
9800 lineage UUID
DEFAULT NULL)
9802 'provsql',
'ucq_mobius_materialize_tracked' LANGUAGE C VOLATILE;
9811CREATE OR REPLACE
FUNCTION ucq_mobius_compile_stats(
9812 IN disjunct_nvars
INT[],
9813 IN atom_disjunct
INT[],
9816 IN atom_arity
INT[],
9818 IN fact_elems
INT[],
9819 IN fact_arity
INT[],
9820 IN fact_tokens UUID[],
9821 OUT probability
DOUBLE PRECISION,
9822 OUT n_components
INT,
9823 OUT n_cnf_conjuncts
INT,
9824 OUT lattice_size
INT,
9826 OUT n_cancelled
INT,
9827 OUT cancelled_hard
BOOLEAN,
9829 OUT memo_hits
BIGINT)
9830 AS 'provsql',
'ucq_mobius_compile_stats'
9831 LANGUAGE C VOLATILE;
9845CREATE OR REPLACE
FUNCTION mobius_or_null(tok UUID)
9847 SELECT CASE WHEN tok
IS NOT NULL AND provsql.get_gate_type(tok) =
'mobius'
9849$$
LANGUAGE sql STABLE;
9857CREATE OR REPLACE
FUNCTION ucq_mobius_provenance(
9858 descriptor JSONB, fallback UUID
DEFAULT NULL)
9861 legs TEXT;
sql TEXT; saved TEXT;
9862 fact_rel
INT[]; fact_elems
INT[]; fact_arity
INT[]; fact_tokens UUID[];
9863 dnv
INT[]:=
'{}'; adisj
INT[]:=
'{}'; arel
INT[]:=
'{}';
9864 avars
INT[]:=
'{}'; aarity
INT[]:=
'{}';
9865 d jsonb; a jsonb; v TEXT; didx
INT:=
0;
9867 FOR d
IN SELECT *
FROM jsonb_array_elements(descriptor->
'disjuncts') LOOP
9868 dnv := dnv || (d->>
'n_vars')::
INT;
9869 FOR a
IN SELECT *
FROM jsonb_array_elements(d->
'atoms') LOOP
9870 adisj := adisj || didx; arel := arel || (a->>
'rel')::
INT;
9871 aarity := aarity || jsonb_array_length(a->
'vars');
9872 FOR v
IN SELECT *
FROM jsonb_array_elements_text(a->
'vars') LOOP
9873 avars := avars || v::
INT;
9880 format(
'SELECT %s, ARRAY[%s]::TEXT[], provsql FROM %s%s',
9882 (
SELECT string_agg(format(
'(%I)::TEXT', c),
',')
9883 FROM jsonb_array_elements_text(descriptor->
'elem_cols'->(rn-1)::
INT) c),
9885 CASE WHEN coalesce(descriptor->
'rel_where'->>(rn-1)::
INT,
'') <>
''
9886 THEN ' WHERE '||(descriptor->
'rel_where'->>(rn-1)::
INT)
9890 FROM jsonb_array_elements_text(descriptor->
'relations')
WITH ORDINALITY t(rel, rn);
9893 WITH facts(rel,elems,tok)
AS (%s),
9894 ord
AS (
SELECT row_number()
OVER ()
AS ord, rel, elems, tok
FROM facts),
9895 dict
AS (
SELECT val, (dense_rank()
OVER (
ORDER BY val))-1
AS id
9896 FROM (
SELECT DISTINCT unnest(elems)
AS val
FROM facts) u)
9897 SELECT (
SELECT array_agg(rel
ORDER BY ord)
FROM ord),
9898 (
SELECT array_agg(cardinality(elems)
ORDER BY ord)
FROM ord),
9899 (
SELECT array_agg(tok
ORDER BY ord)
FROM ord),
9900 (
SELECT array_agg(dd.id
ORDER BY o.ord, e.k)
9901 FROM ord o,
LATERAL unnest(o.elems)
WITH ORDINALITY e(val,k)
9902 JOIN dict dd
ON dd.val = e.val)
9905 saved := current_setting(
'provsql.active',
true);
9906 PERFORM set_config(
'provsql.active',
'off',
true);
9907 EXECUTE sql INTO fact_rel, fact_arity, fact_tokens, fact_elems;
9908 PERFORM set_config(
'provsql.active', saved,
true);
9913 RETURN ucq_mobius_materialize_tracked(dnv,adisj,arel,avars,aarity,
9914 fact_rel,fact_elems,fact_arity,fact_tokens, fallback);
9915EXCEPTION
WHEN OTHERS
THEN
9918$$
LANGUAGE plpgsql VOLATILE;
9926CREATE OR REPLACE
FUNCTION mobius_compile_stats(
9927 IN descriptor JSONB,
9928 OUT probability
DOUBLE PRECISION,
9929 OUT n_components
INT,
9930 OUT n_cnf_conjuncts
INT,
9931 OUT lattice_size
INT,
9933 OUT n_cancelled
INT,
9934 OUT cancelled_hard
BOOLEAN,
9936 OUT memo_hits
BIGINT)
9939 legs TEXT;
sql TEXT; saved TEXT;
9940 fact_rel
INT[]; fact_elems
INT[]; fact_arity
INT[]; fact_tokens UUID[];
9941 dnv
INT[]:=
'{}'; adisj
INT[]:=
'{}'; arel
INT[]:=
'{}';
9942 avars
INT[]:=
'{}'; aarity
INT[]:=
'{}';
9943 d jsonb; a jsonb; v TEXT; didx
INT:=
0;
9945 FOR d
IN SELECT *
FROM jsonb_array_elements(descriptor->
'disjuncts') LOOP
9946 dnv := dnv || (d->>
'n_vars')::
INT;
9947 FOR a
IN SELECT *
FROM jsonb_array_elements(d->
'atoms') LOOP
9948 adisj := adisj || didx; arel := arel || (a->>
'rel')::
INT;
9949 aarity := aarity || jsonb_array_length(a->
'vars');
9950 FOR v
IN SELECT *
FROM jsonb_array_elements_text(a->
'vars') LOOP
9951 avars := avars || v::
INT;
9958 format(
'SELECT %s, ARRAY[%s]::TEXT[], provsql FROM %s%s',
9960 (
SELECT string_agg(format(
'(%I)::TEXT', c),
',')
9961 FROM jsonb_array_elements_text(descriptor->
'elem_cols'->(rn-1)::
INT) c),
9963 CASE WHEN coalesce(descriptor->
'rel_where'->>(rn-1)::
INT,
'') <>
''
9964 THEN ' WHERE '||(descriptor->
'rel_where'->>(rn-1)::
INT)
9968 FROM jsonb_array_elements_text(descriptor->
'relations')
WITH ORDINALITY t(rel, rn);
9971 WITH facts(rel,elems,tok)
AS (%s),
9972 ord
AS (
SELECT row_number()
OVER ()
AS ord, rel, elems, tok
FROM facts),
9973 dict
AS (
SELECT val, (dense_rank()
OVER (
ORDER BY val))-1
AS id
9974 FROM (
SELECT DISTINCT unnest(elems)
AS val
FROM facts) u)
9975 SELECT (
SELECT array_agg(rel
ORDER BY ord)
FROM ord),
9976 (
SELECT array_agg(cardinality(elems)
ORDER BY ord)
FROM ord),
9977 (
SELECT array_agg(tok
ORDER BY ord)
FROM ord),
9978 (
SELECT array_agg(dd.id
ORDER BY o.ord, e.k)
9979 FROM ord o,
LATERAL unnest(o.elems)
WITH ORDINALITY e(val,k)
9980 JOIN dict dd
ON dd.val = e.val)
9983 saved := current_setting(
'provsql.active',
true);
9984 PERFORM set_config(
'provsql.active',
'off',
true);
9985 EXECUTE sql INTO fact_rel, fact_arity, fact_tokens, fact_elems;
9986 PERFORM set_config(
'provsql.active', saved,
true);
9988 SELECT s.probability, s.n_components, s.n_cnf_conjuncts, s.lattice_size,
9989 s.n_nonzero, s.n_cancelled, s.cancelled_hard, s.dd_size, s.memo_hits
9990 INTO probability, n_components, n_cnf_conjuncts, lattice_size,
9991 n_nonzero, n_cancelled, cancelled_hard, dd_size, memo_hits
9992 FROM ucq_mobius_compile_stats(dnv,adisj,arel,avars,aarity,
9993 fact_rel,fact_elems,fact_arity,fact_tokens) s;
9995$$
LANGUAGE plpgsql VOLATILE;
10008CREATE OR REPLACE
FUNCTION ucq_joint_gather(
10010 OUT disjunct_nvars
INT[],
OUT atom_disjunct
INT[],
OUT atom_rel
INT[],
10011 OUT atom_vars
INT[],
OUT atom_arity
INT[],
10012 OUT fact_rel
INT[],
OUT fact_elems
INT[],
OUT fact_arity
INT[],
10013 OUT fact_tokens UUID[],
OUT val_by_id TEXT[])
10016 legs TEXT;
sql TEXT; saved TEXT; d jsonb; a jsonb; v TEXT; didx
INT :=
0;
10018 disjunct_nvars:=
'{}'; atom_disjunct:=
'{}'; atom_rel:=
'{}';
10019 atom_vars:=
'{}'; atom_arity:=
'{}';
10020 FOR d
IN SELECT *
FROM jsonb_array_elements(descriptor->
'disjuncts') LOOP
10021 disjunct_nvars := disjunct_nvars || (d->>
'n_vars')::
INT;
10022 FOR a
IN SELECT *
FROM jsonb_array_elements(d->
'atoms') LOOP
10023 atom_disjunct := atom_disjunct || didx;
10024 atom_rel := atom_rel || (a->>
'rel')::
INT;
10025 atom_arity := atom_arity || jsonb_array_length(a->
'vars');
10026 FOR v
IN SELECT *
FROM jsonb_array_elements_text(a->
'vars') LOOP
10027 atom_vars := atom_vars || v::
INT;
10034 format(
'SELECT %s, ARRAY[%s]::TEXT[], provsql FROM %s%s', rn -
1,
10035 (
SELECT string_agg(format(
'(%I)::TEXT', c),
',')
10036 FROM jsonb_array_elements_text(descriptor->
'elem_cols'->(rn-1)::
INT) c),
10038 CASE WHEN coalesce(descriptor->
'rel_where'->>(rn-1)::
INT,
'') <>
''
10039 THEN ' WHERE '||(descriptor->
'rel_where'->>(rn-1)::
INT)
10043 FROM jsonb_array_elements_text(descriptor->
'relations')
WITH ORDINALITY t(rel, rn);
10046 WITH facts(rel,elems,tok)
AS (%s),
10047 ord
AS (
SELECT row_number()
OVER ()
AS ord, rel, elems, tok
FROM facts),
10048 dict
AS (
SELECT val, (dense_rank()
OVER (
ORDER BY val))-1
AS id
10049 FROM (
SELECT DISTINCT unnest(elems)
AS val
FROM facts) u)
10050 SELECT (
SELECT array_agg(rel
ORDER BY ord)
FROM ord),
10051 (
SELECT array_agg(cardinality(elems)
ORDER BY ord)
FROM ord),
10052 (
SELECT array_agg(tok
ORDER BY ord)
FROM ord),
10053 (
SELECT array_agg(dd.id
ORDER BY o.ord, e.k)
10054 FROM ord o,
LATERAL unnest(o.elems)
WITH ORDINALITY e(val,k)
10055 JOIN dict dd
ON dd.val = e.val),
10056 (
SELECT array_agg(val
ORDER BY id)
FROM dict)
10059 saved := current_setting(
'provsql.active',
true);
10060 PERFORM set_config(
'provsql.active',
'off',
true);
10061 EXECUTE sql INTO fact_rel, fact_arity, fact_tokens, fact_elems, val_by_id;
10062 PERFORM set_config(
'provsql.active', saved,
true);
10064$$
LANGUAGE plpgsql VOLATILE;
10081CREATE OR REPLACE
FUNCTION ucq_joint_provenance_answer(
10082 descriptor JSONB, head_vars
INT[], head_vals TEXT[], fallback UUID
DEFAULT NULL)
10083RETURNS UUID
AS 'provsql',
'ucq_joint_provenance_answer'
10094CREATE OR REPLACE
FUNCTION ucq_mobius_provenance_answer(
10095 descriptor JSONB, head_vars
INT[], head_vals TEXT[], fallback UUID
DEFAULT NULL)
10096RETURNS UUID
AS 'provsql',
'ucq_mobius_provenance_answer'
10137CREATE OR REPLACE
FUNCTION reachability_materialize(
10139 IN destinations
INT[],
10141 IN probabilities
DOUBLE PRECISION[],
10142 IN block_keys UUID[],
10143 IN block_indices
INT[],
10144 IN source_vertices
INT[],
10145 IN source_tokens UUID[],
10146 IN source_probabilities
DOUBLE PRECISION[],
10147 IN directed
BOOLEAN,
10150 RETURNS SETOF RECORD
AS
10151 'provsql',
'reachability_materialize' LANGUAGE C VOLATILE;
10184CREATE OR REPLACE
FUNCTION reachability_materialize_hops(
10186 IN destinations
INT[],
10188 IN probabilities
DOUBLE PRECISION[],
10189 IN block_keys UUID[],
10190 IN block_indices
INT[],
10191 IN source_vertices
INT[],
10192 IN source_tokens UUID[],
10193 IN source_probabilities
DOUBLE PRECISION[],
10194 IN directed
BOOLEAN,
10200 RETURNS SETOF RECORD
AS
10201 'provsql',
'reachability_materialize_hops' LANGUAGE C VOLATILE;
10233CREATE OR REPLACE
FUNCTION reachability_materialize_any(
10235 IN destinations
INT[],
10237 IN probabilities
DOUBLE PRECISION[],
10238 IN block_keys UUID[],
10239 IN block_indices
INT[],
10240 IN source_vertices
INT[],
10241 IN source_tokens UUID[],
10242 IN source_probabilities
DOUBLE PRECISION[],
10243 IN directed
BOOLEAN,
10244 IN group_ids
INT[],
10245 IN member_vertices
INT[],
10248 RETURNS SETOF RECORD
AS
10249 'provsql',
'reachability_materialize_any' LANGUAGE C VOLATILE;
10279CREATE OR REPLACE
FUNCTION reachability_materialize_cover(
10281 destinations
INT[],
10283 probabilities
DOUBLE PRECISION[],
10285 block_indices
INT[],
10286 source_vertices
INT[],
10287 source_tokens UUID[],
10288 source_probabilities
DOUBLE PRECISION[],
10290 member_vertices
INT[])
10292 'provsql',
'reachability_materialize_cover' LANGUAGE C VOLATILE;
10329CREATE OR REPLACE
FUNCTION plant_reach_any_groups(
10331 node_attribute TEXT,
10332 member_rel REGCLASS,
10333 member_attribute TEXT,
10334 group_attribute TEXT,
10336 source_attribute TEXT,
10337 destination_attribute TEXT,
10340 edge_quals TEXT
DEFAULT NULL,
10341 source_rel REGCLASS
DEFAULT NULL,
10342 source_rel_attribute TEXT
DEFAULT NULL,
10343 edge_sql TEXT
DEFAULT NULL,
10344 member_quals TEXT
DEFAULT NULL)
10353 sp
double precision[];
10354 gids
INT[] :=
ARRAY[]::
INT[];
10355 mids
INT[] :=
ARRAY[]::
INT[];
10357 verbosity
INT := coalesce(current_setting(
'provsql.verbose_level',
true)::
INT,
0);
10362 IF EXISTS (
SELECT 1 FROM pg_attribute
10363 WHERE attrelid = member_rel
AND attname =
'provsql'
10364 AND atttypid =
'UUID'::REGTYPE
AND NOT attisdropped)
THEN
10368 IF source_rel
IS NOT NULL THEN
10369 SELECT g.source_values, g.source_tokens, g.source_probabilities
10371 FROM provsql.gather_reachability_sources(source_rel,
10372 source_rel_attribute) g;
10374 sv :=
ARRAY[]::TEXT[];
10375 st :=
ARRAY[]::UUID[];
10376 sp :=
ARRAY[]::float8[];
10379 sv :=
ARRAY[source_value];
10380 st :=
ARRAY[
'00000000-0000-0000-0000-000000000000'::UUID];
10381 sp :=
ARRAY[
1.
0::float8];
10384 e := provsql.gather_reachability_edges(edge_rel, source_attribute,
10385 destination_attribute,
10386 sv, edge_quals, edge_sql);
10398 DROP TABLE IF EXISTS provsql_reach_any_flat_tmp;
10400 'CREATE TEMP TABLE provsql_reach_any_flat_tmp AS '
10401 ||
'SELECT w.%1$I::TEXT AS node_val, provsql.provenance() AS tok, '
10402 ||
' t.%5$I AS grp_key '
10403 ||
'FROM %2$I w JOIN %3$s t ON w.%1$I = t.%4$I'
10407 || coalesce(
' WHERE ' || member_quals,
''),
10408 node_attribute, work_name, member_rel::TEXT, member_attribute,
10410 PERFORM provsql.remove_provenance(
'provsql_reach_any_flat_tmp');
10411 DROP TABLE IF EXISTS provsql_reach_any_groups_tmp;
10412 CREATE TEMP
TABLE provsql_reach_any_groups_tmp
AS
10413 SELECT (row_number()
OVER ())::
INT AS gid, members, toks
FROM (
10414 SELECT array_agg(node_val)
AS members, array_agg(tok)
AS toks
10415 FROM provsql_reach_any_flat_tmp
10416 GROUP BY grp_key
HAVING count(*) >=
2) g;
10417 DROP TABLE provsql_reach_any_flat_tmp;
10419 FOR grp
IN SELECT gid, members
FROM provsql_reach_any_groups_tmp LOOP
10420 FOR m
IN SELECT DISTINCT unnest(grp.members)
AS val LOOP
10421 vid := array_position(e.vertices, m.val);
10422 IF vid
IS NOT NULL THEN
10423 gids := gids || grp.gid;
10424 mids := mids || vid;
10428 IF cardinality(gids) =
0 THEN
10429 DROP TABLE provsql_reach_any_groups_tmp;
10434 SELECT a.group_id, a.token
AS any_token, t.toks
10435 FROM provsql.reachability_materialize_any(
10436 e.sources, e.destinations, e.tokens, e.probabilities,
10437 e.block_keys, e.block_indices, e.extra_ids, st, sp,
10438 directed, gids, mids) a
10439 JOIN provsql_reach_any_groups_tmp t
ON t.gid = a.group_id
10441 PERFORM provsql.plant_canonical(work_name,
'plus', grp.toks,
10444 DROP TABLE provsql_reach_any_groups_tmp;
10445 IF verbosity >=
20 THEN
10448 PERFORM set_config(
'client_min_messages',
'notice',
true);
10449 RAISE NOTICE
'ProvSQL: certified any-member gates planted for the aggregation of "%" by %.%',
10450 work_name, member_rel, group_attribute;
10451 PERFORM set_config(
'client_min_messages',
'warning',
true);
10453 EXCEPTION
WHEN OTHERS
THEN
10454 IF verbosity >=
10 THEN
10455 PERFORM set_config(
'client_min_messages',
'notice',
true);
10456 RAISE NOTICE
'ProvSQL: any-member planting for "%" skipped (%)',
10457 work_name, SQLERRM;
10458 PERFORM set_config(
'client_min_messages',
'warning',
true);
10464$$
LANGUAGE plpgsql
SET client_min_messages = warning;
10500CREATE OR REPLACE
FUNCTION plant_reach_cover(
10502 node_attribute TEXT,
10504 source_attribute TEXT,
10505 destination_attribute TEXT,
10508 node_values TEXT[],
10509 edge_quals TEXT
DEFAULT NULL,
10510 source_rel REGCLASS
DEFAULT NULL,
10511 source_rel_attribute TEXT
DEFAULT NULL,
10512 edge_sql TEXT
DEFAULT NULL)
10519 sp
double precision[];
10522 vids
INT[] :=
ARRAY[]::
INT[];
10524 toks UUID[] :=
ARRAY[]::UUID[];
10526 verbosity
INT := coalesce(current_setting(
'provsql.verbose_level',
true)::
INT,
0);
10529 IF source_rel
IS NOT NULL THEN
10530 SELECT g.source_values, g.source_tokens, g.source_probabilities
10532 FROM provsql.gather_reachability_sources(source_rel,
10533 source_rel_attribute) g;
10535 sv :=
ARRAY[]::TEXT[];
10536 st :=
ARRAY[]::UUID[];
10537 sp :=
ARRAY[]::float8[];
10540 sv :=
ARRAY[source_value];
10541 st :=
ARRAY[
'00000000-0000-0000-0000-000000000000'::UUID];
10542 sp :=
ARRAY[
1.
0::float8];
10545 e := provsql.gather_reachability_edges(edge_rel, source_attribute,
10546 destination_attribute,
10547 sv, edge_quals, edge_sql);
10553 FOREACH val
IN ARRAY node_values LOOP
10554 vid := array_position(e.vertices, val);
10555 IF vid
IS NULL THEN
10558 vids := vids || vid;
10559 EXECUTE format(
'SELECT provsql FROM %I WHERE %I::TEXT = $1',
10560 work_name, node_attribute)
10561 INTO tok
USING val;
10562 IF tok
IS NULL THEN
10565 toks := toks || tok;
10568 cover_token := provsql.reachability_materialize_cover(
10569 e.sources, e.destinations, e.tokens, e.probabilities,
10570 e.block_keys, e.block_indices, e.extra_ids, st, sp,
10573 PERFORM provsql.plant_canonical(work_name,
'times', toks, cover_token,
1);
10574 IF verbosity >=
20 THEN
10577 PERFORM set_config(
'client_min_messages',
'notice',
true);
10578 RAISE NOTICE
'ProvSQL: certified all-members gate planted for the self-join of "%"',
10580 PERFORM set_config(
'client_min_messages',
'warning',
true);
10582 EXCEPTION
WHEN OTHERS
THEN
10583 IF verbosity >=
10 THEN
10584 PERFORM set_config(
'client_min_messages',
'notice',
true);
10585 RAISE NOTICE
'ProvSQL: all-members planting for "%" skipped (%)',
10586 work_name, SQLERRM;
10587 PERFORM set_config(
'client_min_messages',
'warning',
true);
10593$$
LANGUAGE plpgsql
SET client_min_messages = warning;
10608CREATE OR REPLACE
FUNCTION token_conjunctive_leaves(token UUID)
10611WITH RECURSIVE walk(g)
AS (
10614 SELECT c
FROM walk w,
unnest(provsql.get_children(w.g))
AS c
10615 WHERE provsql.get_gate_type(w.g)
IN (
'times',
'project',
'eq',
'annotation')
10617SELECT CASE WHEN bool_and(provsql.get_gate_type(g)
10618 IN (
'times',
'project',
'eq',
'annotation',
'input'))
10619 THEN array_agg(
DISTINCT g)
10620 FILTER (
WHERE provsql.get_gate_type(g) =
'input')
10623$$
LANGUAGE sql STABLE;
10664CREATE OR REPLACE
FUNCTION gather_reachability_edges(
10666 IN source_attribute TEXT,
10667 IN destination_attribute TEXT,
10668 IN extra_vertices TEXT[],
10669 IN edge_quals TEXT
DEFAULT NULL,
10670 IN rel_sql TEXT
DEFAULT NULL,
10672 OUT destinations
INT[],
10674 OUT probabilities
DOUBLE PRECISION[],
10675 OUT block_keys UUID[],
10676 OUT block_indices
INT[],
10677 OUT extra_ids
INT[],
10678 OUT vertices TEXT[])
10687 verbosity
INT := coalesce(current_setting(
'provsql.verbose_level',
true)::
INT,
0);
10695 IF rel
IS NOT NULL AND rel_sql
IS NULL THEN
10696 tkind := (provsql.get_table_info(rel::oid)).kind;
10698 IF tkind
NOT IN (
'tid',
'bid')
THEN
10701 IF tkind =
'bid' THEN
10702 SELECT string_agg(quote_ident(a.attname) ||
'::TEXT',
' || '','' || '
10705 FROM unnest((provsql.get_table_info(rel::oid)).block_key)
10706 WITH ORDINALITY
AS k(attnum, ord)
10707 JOIN pg_attribute a
ON a.attrelid = rel
AND a.attnum = k.attnum;
10709 bkey_expr := coalesce(bkey_expr, quote_literal(
''));
10711 IF tkind
IS NOT NULL AND verbosity >=
20 THEN
10716 PERFORM set_config(
'client_min_messages',
'notice',
true);
10717 RAISE NOTICE
'ProvSQL: catalog characterises % as %', rel,
upper(tkind);
10718 PERFORM set_config(
'client_min_messages',
'warning',
true);
10727 DROP TABLE IF EXISTS provsql_reachability_edges_tmp;
10729 'CREATE TEMP TABLE provsql_reachability_edges_tmp AS '
10730 ||
'SELECT %1$I::TEXT AS u, %2$I::TEXT AS v, '
10731 ||
'provsql.strip_annotations(provsql.provenance()) AS token%5$s '
10732 ||
'FROM %3$s WHERE %1$I IS NOT NULL AND %2$I IS NOT NULL%4$s',
10733 source_attribute, destination_attribute,
10734 CASE WHEN rel_sql
IS NULL THEN rel::TEXT
10735 ELSE '(' || rel_sql ||
') AS provsql_edge_subquery' END,
10736 CASE WHEN edge_quals
IS NULL THEN ''
10737 ELSE ' AND (' || edge_quals ||
')' END,
10738 CASE WHEN tkind =
'bid'
10739 THEN ', public.uuid_generate_v5(provsql.uuid_ns_provsql(), '
10740 || quote_literal(
'bidblock' || rel::TEXT ||
':')
10741 ||
' || ' || bkey_expr ||
') AS bkey'
10742 ELSE ', NULL::UUID AS bkey' END);
10743 PERFORM provsql.remove_provenance(
'provsql_reachability_edges_tmp');
10745 DROP TABLE IF EXISTS provsql_reachability_support_tmp;
10746 IF tkind
IS NULL THEN
10749 IF EXISTS (
SELECT 1 FROM provsql_reachability_edges_tmp
10750 WHERE provsql.get_gate_type(token)
NOT IN (
'input',
'mulinput',
'times',
10751 'project',
'eq'))
THEN
10752 DROP TABLE provsql_reachability_edges_tmp;
10753 RAISE EXCEPTION
'reachability: the provenance of % must consist of base input, repair_key, or conjunctive join tokens', coalesce(rel::TEXT,
'the edge query')
10754 USING ERRCODE =
'feature_not_supported',
10755 DETAIL =
'provsql-reason: reachability-provenance-shape; scope: gap';
10757 CREATE TEMP
TABLE provsql_reachability_support_tmp
AS
10758 SELECT t.token, l.leaf
10759 FROM (
SELECT DISTINCT token
FROM provsql_reachability_edges_tmp
10760 WHERE provsql.get_gate_type(token)
IN (
'times',
'project',
'eq')) t,
10761 LATERAL unnest(provsql.token_conjunctive_leaves(t.token))
AS l(leaf);
10762 IF EXISTS (
SELECT 1
10763 FROM (
SELECT DISTINCT token
FROM provsql_reachability_edges_tmp) t
10764 WHERE provsql.get_gate_type(t.token)
IN (
'times',
'project',
'eq')
10765 AND provsql.token_conjunctive_leaves(t.token)
IS NULL)
THEN
10766 DROP TABLE provsql_reachability_support_tmp;
10767 DROP TABLE provsql_reachability_edges_tmp;
10768 RAISE EXCEPTION
'reachability: a join-defined edge token is not a pure conjunction of base tuples'
10769 USING ERRCODE =
'feature_not_supported',
10770 DETAIL =
'provsql-reason: reachability-edge-not-conjunction; scope: gap';
10772 IF EXISTS (
SELECT 1 FROM (
10773 SELECT leaf
FROM provsql_reachability_support_tmp
10775 SELECT DISTINCT token
FROM provsql_reachability_edges_tmp
10776 WHERE provsql.get_gate_type(token) =
'input'
10778 GROUP BY leaf
HAVING count(*) >
1)
THEN
10779 DROP TABLE provsql_reachability_support_tmp;
10780 DROP TABLE provsql_reachability_edges_tmp;
10781 RAISE EXCEPTION
'reachability: join-defined edges share base tuples (their supports overlap), so they are not independent'
10782 USING ERRCODE =
'feature_not_supported',
10783 DETAIL =
'provsql-reason: reachability-edges-share-tuples; scope: gap';
10792 IF tkind =
'tid' THEN
10793 sel_probs :=
'coalesce(provsql.get_prob(e.token), 1.0)';
10794 sel_bkeys := $
sql$
'00000000-0000-0000-0000-000000000000'::UUID$
sql$;
10796 ELSIF tkind =
'bid' THEN
10797 sel_probs :=
'coalesce(provsql.get_prob(e.token), 1.0)';
10798 sel_bkeys := $
sql$
CASE WHEN provsql.get_gate_type(e.token) =
'mulinput'
10800 ELSE '00000000-0000-0000-0000-000000000000'::UUID
END$
sql$;
10801 sel_bidx :=
'e.bidx';
10803 sel_probs := $
sql$
CASE WHEN provsql.get_gate_type(e.token)
IN (
'times',
'project',
'eq')
10804 THEN (
SELECT CASE WHEN bool_or(coalesce(provsql.get_prob(s.leaf),
1.
0) =
0)
10806 ELSE exp(sum(ln(coalesce(provsql.get_prob(s.leaf),
1.
0))))
END
10807 FROM provsql_reachability_support_tmp s
10808 WHERE s.token = e.token)
10809 ELSE coalesce(provsql.get_prob(e.token),
1.
0)
END$
sql$;
10810 sel_bkeys := $
sql$
CASE WHEN provsql.get_gate_type(e.token) =
'mulinput'
10811 THEN (provsql.get_children(e.token))[
1]
10812 ELSE '00000000-0000-0000-0000-000000000000'::UUID
END$
sql$;
10813 sel_bidx := $
sql$
CASE WHEN provsql.get_gate_type(e.token) =
'mulinput'
10814 THEN (provsql.get_infos(e.token)).info1
ELSE 0 END$
sql$;
10820 SELECT u
AS x
FROM provsql_reachability_edges_tmp
10821 UNION SELECT v
FROM provsql_reachability_edges_tmp
10822 UNION SELECT unnest($
1)),
10824 SELECT x, (row_number()
OVER (
ORDER BY x))::
INT AS id
FROM verts)
10825 SELECT array_agg(iu.id), array_agg(iv.id),
10826 array_agg(e.token),
10830 (
SELECT array_agg(i.id
ORDER BY ev.ord)
10831 FROM unnest($
1)
WITH ORDINALITY
AS ev(x, ord)
10832 JOIN ids i
ON i.x = ev.x),
10833 (
SELECT array_agg(x
ORDER BY id)
FROM ids)
10835 (row_number()
OVER (
PARTITION BY t.bkey))::
INT AS bidx
10836 FROM provsql_reachability_edges_tmp t) e
10837 JOIN ids iu
ON iu.x = e.u
10838 JOIN ids iv
ON iv.x = e.v
10839 $
sql$, sel_probs, sel_bkeys, sel_bidx)
10840 INTO sources, destinations, tokens, probabilities, block_keys,
10841 block_indices, extra_ids, vertices
10842 USING extra_vertices;
10844 DROP TABLE provsql_reachability_edges_tmp;
10845 DROP TABLE IF EXISTS provsql_reachability_support_tmp;
10850$$
LANGUAGE plpgsql
SET client_min_messages = warning;
10869CREATE OR REPLACE
FUNCTION gather_reachability_sources(
10871 IN source_attribute TEXT,
10872 OUT source_values TEXT[],
10873 OUT source_tokens UUID[],
10874 OUT source_probabilities
DOUBLE PRECISION[])
10882 SELECT 1 FROM pg_attribute
10883 WHERE attrelid = rel
AND attname =
'provsql'
10884 AND atttypid =
'UUID'::REGTYPE
AND NOT attisdropped)
10892 tkind := (get_table_info(rel::oid)).kind;
10893 IF tkind =
'bid' THEN
10894 RAISE EXCEPTION
'reachability: % is block-independent (repair_key); block-correlated source sets are not supported', rel
10895 USING ERRCODE =
'feature_not_supported',
10896 DETAIL =
'provsql-reason: reachability-block-correlated; scope: gap';
10900 DROP TABLE IF EXISTS provsql_reachability_sources_tmp;
10903 'CREATE TEMP TABLE provsql_reachability_sources_tmp AS '
10904 ||
'SELECT %1$I::TEXT AS x, provenance() AS token '
10905 ||
'FROM %2$s WHERE %1$I IS NOT NULL',
10906 source_attribute, rel);
10907 PERFORM remove_provenance(
'provsql_reachability_sources_tmp');
10908 IF tkind
IS DISTINCT FROM 'tid'
10909 AND EXISTS (
SELECT 1 FROM provsql_reachability_sources_tmp
10910 WHERE get_gate_type(token) <>
'input')
THEN
10911 DROP TABLE provsql_reachability_sources_tmp;
10912 RAISE EXCEPTION
'reachability: the provenance of % must consist of base input tokens (independent tuples); views or query results are not supported', rel
10913 USING ERRCODE =
'feature_not_supported',
10914 DETAIL =
'provsql-reason: reachability-not-base-inputs; scope: gap';
10916 SELECT array_agg(x), array_agg(token),
10917 array_agg(coalesce(get_prob(token),
1.
0))
10918 INTO source_values, source_tokens, source_probabilities
10919 FROM provsql_reachability_sources_tmp;
10920 DROP TABLE provsql_reachability_sources_tmp;
10923 'CREATE TEMP TABLE provsql_reachability_sources_tmp AS '
10924 ||
'SELECT DISTINCT %1$I::TEXT AS x FROM %2$s WHERE %1$I IS NOT NULL',
10925 source_attribute, rel);
10926 SELECT array_agg(x),
10927 array_agg(
'00000000-0000-0000-0000-000000000000'::UUID),
10928 array_agg(
1.
0::float8)
10929 INTO source_values, source_tokens, source_probabilities
10930 FROM provsql_reachability_sources_tmp;
10931 DROP TABLE provsql_reachability_sources_tmp;
10934$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public
SET client_min_messages = warning;
10978CREATE OR REPLACE
FUNCTION eval_reachability(
10980 source_attribute TEXT,
10981 destination_attribute TEXT,
10989 edge_quals TEXT
DEFAULT NULL,
10990 source_rel REGCLASS
DEFAULT NULL,
10991 source_rel_attribute TEXT
DEFAULT NULL,
10992 edge_sql TEXT
DEFAULT NULL,
10993 hop_bound
INT DEFAULT NULL,
10994 hop_seed
INT DEFAULT NULL,
10995 hops_position
INT DEFAULT NULL)
11002 sp
double precision[];
11003 verbosity
INT := coalesce(current_setting(
'provsql.verbose_level',
true)::
INT,
0);
11006 IF source_rel
IS NOT NULL THEN
11009 SELECT g.source_values, g.source_tokens, g.source_probabilities
11011 FROM provsql.gather_reachability_sources(source_rel,
11012 source_rel_attribute) g;
11014 sv :=
ARRAY[]::TEXT[];
11015 st :=
ARRAY[]::UUID[];
11016 sp :=
ARRAY[]::float8[];
11020 sv :=
ARRAY[source_value];
11021 st :=
ARRAY[
'00000000-0000-0000-0000-000000000000'::UUID];
11022 sp :=
ARRAY[
1.
0::float8];
11025 e := provsql.gather_reachability_edges(edge_rel, source_attribute,
11026 destination_attribute,
11027 sv, edge_quals, edge_sql);
11028 IF to_regclass(work_name)
IS NOT NULL THEN
11029 EXECUTE format(
'DROP TABLE %I', work_name);
11032 EXECUTE format(
'CREATE TEMP TABLE %I (%s, provsql UUID) ON COMMIT DROP',
11033 work_name, coldef);
11034 PERFORM provsql.planted_scope(work_name);
11035 IF hop_bound
IS NULL THEN
11037 'INSERT INTO %I SELECT ($1::TEXT[])[m.vertex]::%s, m.token '
11038 ||
'FROM provsql.reachability_materialize($2, $3, $4, $5, $6, $7, $8, $9, $10, $11) m',
11039 work_name, coltype)
11040 USING e.vertices, e.sources, e.destinations, e.tokens, e.probabilities,
11041 e.block_keys, e.block_indices, e.extra_ids, st, sp, directed;
11046 'INSERT INTO %I SELECT %s, m.token '
11047 ||
'FROM provsql.reachability_materialize_hops($2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) m',
11049 CASE WHEN hops_position =
1
11050 THEN format(
'm.hops, ($1::TEXT[])[m.vertex]::%s', coltype)
11051 ELSE format(
'($1::TEXT[])[m.vertex]::%s, m.hops', coltype)
END)
11052 USING e.vertices, e.sources, e.destinations, e.tokens, e.probabilities,
11053 e.block_keys, e.block_indices, e.extra_ids, st, sp, directed,
11054 hop_bound, hop_seed;
11056 IF verbosity >=
20 THEN
11057 RAISE NOTICE
'ProvSQL: recursive CTE "%" compiled along a tree decomposition of %',
11058 regexp_replace(work_name,
'^provsql_rec_[0-9]+a?_',
''),
11059 coalesce(edge_rel::TEXT,
'the join-defined edge query');
11061 EXCEPTION
WHEN OTHERS
THEN
11062 IF verbosity >=
10 THEN
11065 RAISE NOTICE
'ProvSQL: reachability route for "%" fell back to the generic fixpoint (%)',
11066 regexp_replace(work_name,
'^provsql_rec_[0-9]+a?_',
''), SQLERRM;
11068 PERFORM provsql.eval_recursive(body_sql, work_name, colnames, coldef);
11071$$
LANGUAGE plpgsql;
11090CREATE OR REPLACE
FUNCTION view_circuit(
11092 token2desc REGCLASS,
11095 'provsql',
'view_circuit' LANGUAGE C;
11108CREATE OR REPLACE
FUNCTION compile_to_ddnnf_dot(
11110 compiler TEXT =
'')
11112 'provsql',
'compile_to_ddnnf_dot' LANGUAGE C;
11127CREATE OR REPLACE
FUNCTION compile_to_ddnnf(
11129 compiler TEXT =
'')
11131 'provsql',
'compile_to_ddnnf' LANGUAGE C;
11148CREATE OR REPLACE
FUNCTION ddnnf_stats(
11150 compiler TEXT =
'')
11152 'provsql',
'ddnnf_stats' LANGUAGE C;
11166CREATE OR REPLACE
FUNCTION tseytin_cnf(
11168 weighted
BOOLEAN =
TRUE,
11169 mapping
BOOLEAN =
TRUE)
11171 'provsql',
'tseytin_cnf' LANGUAGE C;
11185CREATE OR REPLACE
FUNCTION tseytin_cnf_mapping_json(token UUID)
11187 'provsql',
'tseytin_cnf_mapping_json' LANGUAGE C;
11189CREATE OR REPLACE
FUNCTION tseytin_cnf_mapping(token UUID)
11190 RETURNS TABLE(variable
INT, gate UUID, probability FLOAT8)
AS $$
11191 SELECT variable, gate, probability
11192 FROM jsonb_to_recordset(tseytin_cnf_mapping_json(token))
11193 AS x(variable
INT, gate UUID, probability FLOAT8)
11195$$
LANGUAGE SQL STABLE;
11207CREATE OR REPLACE
FUNCTION tree_decomposition_dot(
11210 'provsql',
'tree_decomposition_dot' LANGUAGE C;
11230CREATE OR REPLACE
FUNCTION tool_available(name TEXT)
11232 'provsql',
'tool_available' LANGUAGE C STRICT;
11262CREATE TABLE IF NOT EXISTS tool_overrides(
11263 name TEXT
PRIMARY KEY,
11264 removed
BOOLEAN NOT NULL DEFAULT false,
11268 input_formats TEXT[],
11269 output_format TEXT,
11273 dependencies TEXT[],
11275 argtpl_circuit TEXT,
11278SELECT pg_catalog.pg_extension_config_dump(
'tool_overrides',
'');
11290CREATE OR REPLACE
FUNCTION tool_registry_list()
11291 RETURNS TABLE(name TEXT, kind TEXT, executable TEXT, operations TEXT[],
11292 input_formats TEXT[], output_format TEXT, parser TEXT,
11293 preference
INT, enabled
BOOLEAN, argtpl TEXT,
11294 argtpl_circuit TEXT, endpoint TEXT, available
BOOLEAN)
AS
11295 'provsql',
'tool_registry_list' LANGUAGE C STABLE;
11300CREATE OR REPLACE VIEW tools
AS
11301 SELECT name, kind, executable, operations, input_formats, output_format,
11302 parser, preference, enabled, argtpl, argtpl_circuit, endpoint,
11304 FROM tool_registry_list();
11339CREATE OR REPLACE
FUNCTION register_tool(
11341 executable TEXT
DEFAULT NULL,
11342 kind TEXT
DEFAULT 'cli',
11343 operations TEXT[]
DEFAULT NULL,
11344 input_formats TEXT[]
DEFAULT NULL,
11345 output_format TEXT
DEFAULT NULL,
11346 parser TEXT
DEFAULT NULL,
11347 argtpl TEXT
DEFAULT NULL,
11348 argtpl_circuit TEXT
DEFAULT NULL,
11349 preference
INT DEFAULT 0,
11350 enabled
BOOLEAN DEFAULT true,
11351 endpoint TEXT
DEFAULT NULL)
11353 'provsql',
'tool_registry_register' LANGUAGE C;
11356CREATE OR REPLACE
FUNCTION unregister_tool(name TEXT)
11358 'provsql',
'tool_registry_unregister' LANGUAGE C STRICT;
11361CREATE OR REPLACE
FUNCTION set_tool_enabled(name TEXT, enabled
BOOLEAN)
11363 'provsql',
'tool_registry_set_enabled' LANGUAGE C STRICT;
11366CREATE OR REPLACE
FUNCTION set_tool_preference(name TEXT, preference
INT)
11368 'provsql',
'tool_registry_set_preference' LANGUAGE C STRICT;
11372REVOKE ALL ON FUNCTION register_tool(TEXT, TEXT, TEXT, TEXT[], TEXT[], TEXT, TEXT, TEXT, TEXT,
INT,
BOOLEAN, TEXT)
FROM PUBLIC;
11373REVOKE ALL ON FUNCTION unregister_tool(TEXT)
FROM PUBLIC;
11374REVOKE ALL ON FUNCTION set_tool_enabled(TEXT,
BOOLEAN)
FROM PUBLIC;
11375REVOKE ALL ON FUNCTION set_tool_preference(TEXT,
INT)
FROM PUBLIC;
11383CREATE OR REPLACE
FUNCTION to_provxml(
11385 token2desc REGCLASS =
NULL)
11387 'provsql',
'to_provxml' LANGUAGE C;
11390CREATE OR REPLACE
FUNCTION provenance()
RETURNS UUID
AS
11391 'provsql',
'provenance' LANGUAGE C;
11399CREATE OR REPLACE
FUNCTION where_provenance(token UUID)
11401 'provsql',
'where_provenance' LANGUAGE C;
11412CREATE OR REPLACE
FUNCTION reset_constants_cache()
11414 'provsql',
'reset_constants_cache' LANGUAGE C;
11416SELECT reset_constants_cache();
11418SELECT create_gate(gate_zero(),
'zero');
11419SELECT create_gate(gate_one(),
'one');
11420SELECT create_gate(gate_null(),
'value',
NULL,
NULL,
NULL,
'NULL');
11425CREATE TYPE QUERY_TYPE_ENUM
AS ENUM (
11444CREATE FUNCTION sr_formula(token ANYELEMENT, token2value REGCLASS =
NULL)
11448 IF token
IS NULL THEN
11451 RETURN provsql.provenance_evaluate_compiled(
11458$$
LANGUAGE plpgsql PARALLEL SAFE STABLE;
11461CREATE FUNCTION sr_counting(token ANYELEMENT, token2value REGCLASS)
11465 RETURN provsql.provenance_evaluate_compiled(
11472$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
11475CREATE FUNCTION sr_why(token ANYELEMENT, token2value REGCLASS)
11479 RETURN provsql.provenance_evaluate_compiled(
11486$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
11489CREATE FUNCTION sr_how(token ANYELEMENT, token2value REGCLASS)
11493 RETURN provsql.provenance_evaluate_compiled(
11500$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
11503CREATE FUNCTION sr_which(token ANYELEMENT, token2value REGCLASS)
11507 RETURN provsql.provenance_evaluate_compiled(
11514$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
11522CREATE FUNCTION sr_boolexpr(token ANYELEMENT, token2value REGCLASS =
NULL)
11526 IF token
IS NULL THEN
11529 RETURN provsql.provenance_evaluate_compiled(
11536$$
LANGUAGE plpgsql PARALLEL SAFE STABLE;
11545CREATE FUNCTION sr_boolean(token ANYELEMENT, token2value REGCLASS =
NULL)
11549 IF token
IS NULL THEN
11552 RETURN provsql.provenance_evaluate_compiled(
11559$$
LANGUAGE plpgsql PARALLEL SAFE STABLE;
11568CREATE FUNCTION plain_truth(token UUID)
11570 'provsql',
'plain_truth' LANGUAGE C PARALLEL SAFE STABLE;
11573CREATE FUNCTION true_nonzero(token UUID)
11575 'provsql',
'true_nonzero' LANGUAGE C PARALLEL SAFE STABLE;
11603CREATE FUNCTION nonzero(token UUID,
11604 semiring TEXT
DEFAULT NULL,
11605 mapping REGCLASS
DEFAULT NULL)
11609 IF token
IS NULL THEN
11612 IF semiring
IS NULL THEN
11613 RETURN provsql.true_nonzero(token);
11614 ELSIF semiring =
'BOOLEAN' THEN
11615 IF mapping
IS NULL THEN
11621 RETURN provsql.plain_truth(token);
11623 RETURN provsql.provenance_evaluate_compiled(token, mapping,
'BOOLEAN',
TRUE);
11624 ELSIF semiring =
'counting' THEN
11625 RETURN provsql.provenance_evaluate_compiled(token, mapping,
'counting',
1) <>
0;
11627 RAISE EXCEPTION
'nonzero: unsupported semiring "%" (supported: BOOLEAN, counting; NULL for the universal zero test)', semiring
11628 USING ERRCODE =
'feature_not_supported',
11629 DETAIL =
'provsql-reason: nonzero-semiring; scope: gap';
11632$$
LANGUAGE plpgsql PARALLEL SAFE STABLE;
11645CREATE FUNCTION present(token UUID)
11648 SELECT provsql.nonzero(token,
'BOOLEAN');
11649$$
LANGUAGE sql PARALLEL SAFE STABLE;
11663CREATE FUNCTION sr_tropical(token ANYELEMENT, token2value REGCLASS,
11664 nonnegative
BOOLEAN =
false)
11668 RETURN provsql.provenance_evaluate_compiled(
11671 CASE WHEN nonnegative
THEN 'tropical_nonneg' ELSE 'tropical' END,
11675$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
11682CREATE FUNCTION sr_viterbi(token ANYELEMENT, token2value REGCLASS)
11686 RETURN provsql.provenance_evaluate_compiled(
11693$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
11702CREATE FUNCTION sr_lukasiewicz(token ANYELEMENT, token2value REGCLASS)
11706 RETURN provsql.provenance_evaluate_compiled(
11713$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
11730CREATE FUNCTION sr_minmax(token UUID, token2value REGCLASS, element_one ANYENUM)
11734 RETURN provsql.provenance_evaluate_compiled(
11741$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
11755CREATE FUNCTION sr_maxmin(token UUID, token2value REGCLASS, element_one ANYENUM)
11759 RETURN provsql.provenance_evaluate_compiled(
11766$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
11777CREATE FUNCTION choose_function(state ANYELEMENT, data ANYELEMENT)
11778 RETURNS ANYELEMENT
AS
11781 IF state
IS NULL THEN
11787$$
LANGUAGE plpgsql PARALLEL SAFE IMMUTABLE;
11790CREATE AGGREGATE choose(ANYELEMENT) (
11791 SFUNC = choose_function,
11796CREATE FUNCTION array_collect_step(state ANYARRAY, data ANYNONARRAY)
11797 RETURNS ANYARRAY
AS
11798$$
SELECT array_append(state, data) $$
11799LANGUAGE sql PARALLEL SAFE IMMUTABLE;
11805CREATE AGGREGATE array_collect(ANYNONARRAY) (
11806 SFUNC = array_collect_step,
11823CREATE OR REPLACE
FUNCTION explode_table(_tbl TEXT, AGG_TOKEN TEXT)
11831 SELECT n.nspname
INTO _nsp
11832 FROM pg_class c
JOIN pg_namespace n
ON n.oid = c.relnamespace
11833 WHERE c.oid = _tbl::REGCLASS;
11836 CREATE TABLE %1$I.temp_exploded AS
11839 provsql.get_extra(children[2]) AS new_t,
11840 provsql.provenance_times(children[1], provsql) AS new_provsql
11843 SELECT provsql.get_children(sm) AS children
11844 FROM UNNEST(provsql.agg_token_explode_children(%3$I)) AS sm
11845 ) AS sub', _nsp, _tbl, AGG_TOKEN);
11846 EXECUTE format(
'DROP TABLE %I.%I', _nsp, _tbl);
11847 EXECUTE format(
'ALTER TABLE %I.temp_exploded DROP COLUMN %I, DROP COLUMN provsql', _nsp, AGG_TOKEN);
11848 EXECUTE format(
'ALTER TABLE %I.temp_exploded RENAME COLUMN new_t TO %I', _nsp, AGG_TOKEN);
11849 EXECUTE format(
'ALTER TABLE %I.temp_exploded RENAME COLUMN new_provsql TO provsql', _nsp);
11850 EXECUTE format(
'ALTER TABLE %I.temp_exploded RENAME TO %I', _nsp, _tbl);
11852$$
LANGUAGE plpgsql;
11876CREATE OR REPLACE
FUNCTION setup_search_path()
11878 LANGUAGE plpgsql
AS $$
11880 db TEXT := current_database();
11886 SELECT s.setconfig
INTO cfg
11887 FROM pg_db_role_setting s
11888 JOIN pg_database d
ON d.oid = s.setdatabase
11889 WHERE d.datname = db
AND s.setrole =
0;
11891 IF cfg
IS NOT NULL THEN
11892 SELECT substr(e, length(
'search_path=') +
1)
INTO cur
11893 FROM unnest(cfg)
AS e
11894 WHERE e
LIKE 'search_path=%';
11897 IF cur
IS NULL THEN
11900 new_path :=
'"$user", public, provsql';
11901 EXECUTE format(
'ALTER DATABASE %I SET search_path = %s', db, new_path);
11902 RAISE NOTICE
'ProvSQL: set search_path = % for database "%" (no previous database-level setting). Only new sessions are affected.',
11909 SELECT 1 FROM unnest(string_to[](cur,
','))
AS p
11910 WHERE btrim(btrim(p),
'"') =
'provsql')
11912 RAISE NOTICE
'ProvSQL: search_path for database "%" already contains provsql (= %); no change.',
11917 new_path := cur ||
', provsql';
11918 EXECUTE format(
'ALTER DATABASE %I SET search_path = %s', db, new_path);
11919 RAISE NOTICE
'ProvSQL: appended provsql to search_path for database "%" (now: %). Only new sessions are affected.',
11925GRANT USAGE
ON SCHEMA provsql
TO PUBLIC;
11927SET search_path
TO public;
11942 has_provsql
BOOLEAN;
11944 SELECT reset_val
INTO rp
FROM pg_settings
WHERE name =
'search_path';
11945 SELECT bool_or(btrim(btrim(p),
'"') =
'provsql')
11947 FROM unnest(string_to[](coalesce(rp,
''),
','))
AS p;
11948 IF NOT coalesce(has_provsql,
false)
THEN
11949 SET LOCAL client_min_messages = notice;
11950 RAISE NOTICE
'ProvSQL: schema "provsql" is not in your default search_path (currently: %).', rp;
11951 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());
11965SELECT provsql.reset_constants_cache();
11966SET search_path
TO provsql;
11995CREATE TABLE update_provenance (
11998 query_type QUERY_TYPE_ENUM,
12000 ts
TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
12001 valid_time TSTZMULTIRANGE
DEFAULT TSTZMULTIRANGE(tstzrange(
CURRENT_TIMESTAMP,
NULL)),
12020CREATE OR REPLACE
FUNCTION transaction_token()
12029 tok := current_setting(
'provsql.transaction_token',
true);
12030 IF tok
IS NOT NULL AND tok <>
'' THEN
12034 new_tok := public.uuid_generate_v4();
12035 PERFORM create_gate(new_tok,
'update');
12036 PERFORM set_config(
'provsql.transaction_token', new_tok::TEXT,
true);
12041 query_text :=
NULL;
12048 INSERT INTO update_provenance(provsql, query, query_type, username, ts,
12050 VALUES (new_tok, query_text,
'TRANSACTION',
current_user,
12051 CURRENT_TIMESTAMP,
'{(,)}'::TSTZMULTIRANGE,
12052 pg_current_xact_id());
12069CREATE OR REPLACE
FUNCTION stamp_commit_time()
12073 now_ts TIMESTAMPTZ := clock_timestamp();
12075 UPDATE update_provenance
12077 valid_time =
CASE WHEN query_type =
'TRANSACTION' THEN valid_time
12078 ELSE TSTZMULTIRANGE(tstzrange(now_ts,
NULL))
END
12079 WHERE provsql =
NEW.provsql;
12082$$
LANGUAGE plpgsql;
12085 IF NOT EXISTS (
SELECT 1 FROM pg_trigger
12086 WHERE tgrelid =
'provsql.update_provenance'::REGCLASS
12087 AND tgname =
'stamp_commit_time')
THEN
12088 CREATE CONSTRAINT TRIGGER stamp_commit_time
12089 AFTER
INSERT ON provsql.update_provenance
12090 DEFERRABLE INITIALLY DEFERRED
12091 FOR EACH ROW EXECUTE FUNCTION provsql.stamp_commit_time();
12098CREATE OR REPLACE
FUNCTION add_provenance(_tbl REGCLASS)
12106 SELECT 1 FROM pg_attribute
12107 WHERE attrelid = _tbl
AND attname =
'provsql' AND NOT attisdropped
12109 RAISE NOTICE
'table % already has provenance tracking', _tbl;
12115 EXECUTE format(
'ALTER TABLE %s ADD COLUMN provsql UUID', _tbl);
12117 'UPDATE %s SET provsql = public.uuid_generate_v4() WHERE provsql IS NULL',
12119 EXECUTE format(
'CREATE INDEX ON %s(provsql)', _tbl);
12121 'CREATE TRIGGER provenance_guard BEFORE INSERT OR UPDATE OF provsql '
12122 'ON %s FOR EACH ROW EXECUTE FUNCTION provsql.provenance_guard()',
12125 EXECUTE format(
'CREATE TRIGGER insert_statement AFTER INSERT ON %s REFERENCING NEW TABLE AS NEW_TABLE FOR EACH STATEMENT EXECUTE FUNCTION provsql.insert_statement_trigger()', _tbl);
12126 EXECUTE format(
'CREATE TRIGGER delete_statement AFTER DELETE ON %s REFERENCING OLD TABLE AS OLD_TABLE FOR EACH STATEMENT EXECUTE FUNCTION provsql.delete_statement_trigger()', _tbl);
12127 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 FUNCTION provsql.update_statement_trigger()', _tbl);
12129 PERFORM provsql.set_table_info(_tbl::oid,
'tid');
12130 PERFORM provsql.set_ancestors(_tbl::oid,
ARRAY[_tbl::oid]);
12140 SELECT string_agg(
DISTINCT v.rel::REGCLASS::TEXT,
', ')
INTO stale
12141 FROM (
SELECT r.ev_class
AS rel
12142 FROM pg_catalog.pg_depend d
12143 JOIN pg_catalog.pg_rewrite r
ON r.oid = d.objid
12144 WHERE d.classid =
'pg_catalog.pg_rewrite'::REGCLASS
12145 AND d.refclassid =
'pg_catalog.pg_class'::REGCLASS
12146 AND d.refobjid = _tbl
12147 AND r.ev_class <> _tbl)
AS v
12148 WHERE NOT EXISTS (
SELECT 1 FROM pg_catalog.pg_attribute a
12149 WHERE a.attrelid = v.rel
AND a.attname =
'provsql'
12150 AND NOT a.attisdropped);
12151 IF stale
IS NOT NULL THEN
12152 RAISE WARNING
'ProvSQL: % is read by views defined before it was '
12153 'tracked, which have no provenance column of their own, '
12154 'so a query over one of them is answered as plain SQL, '
12157 USING HINT =
'recreate the view (CREATE OR REPLACE VIEW ... or DROP and '
12158 'CREATE) so that its definition reads the tracked table',
12159 DETAIL =
'provsql-reason: view-defined-before-tracking; '
12164$$
LANGUAGE plpgsql SECURITY DEFINER;
12170CREATE OR REPLACE
FUNCTION delete_statement_trigger()
12180 enable_trigger BOOL;
12182 enable_trigger := current_setting(
'provsql.update_provenance',
true);
12183 IF enable_trigger =
'f' THEN
12186 delete_token := public.uuid_generate_v4();
12188 PERFORM create_gate(delete_token,
'update');
12192 FROM pg_stat_activity
12193 WHERE pid = pg_backend_pid();
12195 tx_token := transaction_token();
12197 INSERT INTO update_provenance (provsql, query, query_type, username, ts,
12198 valid_time, xid, tx_token)
12199 VALUES (delete_token, query_text,
'DELETE',
current_user,
CURRENT_TIMESTAMP,
12200 TSTZMULTIRANGE(tstzrange(
CURRENT_TIMESTAMP,
NULL)),
12201 pg_current_xact_id(), tx_token);
12205 delete_token := provenance_times(tx_token, delete_token);
12207 PERFORM set_config(
'provsql.update_provenance',
'off',
false);
12208 EXECUTE format(
'INSERT INTO %I.%I SELECT * FROM OLD_TABLE;', TG_TABLE_SCHEMA, TG_TABLE_NAME);
12209 PERFORM set_config(
'provsql.update_provenance',
'on',
false);
12211 FOR r
IN (
SELECT *
FROM OLD_TABLE) LOOP
12212 old_token := r.provsql;
12213 new_token := provenance_monus(old_token, delete_token);
12215 PERFORM set_config(
'provsql.update_provenance',
'off',
false);
12216 EXECUTE format(
'UPDATE %I.%I SET provsql = $1 WHERE provsql = $2;', TG_TABLE_SCHEMA, TG_TABLE_NAME)
12217 USING new_token, old_token;
12218 PERFORM set_config(
'provsql.update_provenance',
'on',
false);
12223$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp SECURITY DEFINER;
12232CREATE OR REPLACE
FUNCTION insert_statement_trigger()
12242 enable_trigger BOOL;
12244 enable_trigger := current_setting(
'provsql.update_provenance',
true);
12245 IF enable_trigger =
'f' THEN
12249 insert_token := public.uuid_generate_v4();
12251 PERFORM create_gate(insert_token,
'update');
12255 FROM pg_stat_activity
12256 WHERE pid = pg_backend_pid();
12258 tx_token := transaction_token();
12260 INSERT INTO update_provenance (provsql, query, query_type, username, ts,
12261 valid_time, xid, tx_token)
12262 VALUES (insert_token, query_text,
'INSERT',
current_user,
CURRENT_TIMESTAMP,
12263 TSTZMULTIRANGE(tstzrange(
CURRENT_TIMESTAMP,
NULL)),
12264 pg_current_xact_id(), tx_token);
12268 insert_token := provenance_times(tx_token, insert_token);
12270 FOR r
IN (
SELECT *
FROM NEW_TABLE) LOOP
12271 old_token := r.provsql;
12272 new_token := provenance_times(old_token, insert_token);
12273 PERFORM set_config(
'provsql.update_provenance',
'off',
false);
12274 EXECUTE format(
'UPDATE %I.%I SET provsql = $1 WHERE provsql = $2;', TG_TABLE_SCHEMA, TG_TABLE_NAME)
12275 USING new_token, old_token;
12276 PERFORM set_config(
'provsql.update_provenance',
'on',
false);
12281$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp SECURITY DEFINER;
12289CREATE OR REPLACE
FUNCTION update_statement_trigger()
12299 enable_trigger BOOL;
12301 enable_trigger := current_setting(
'provsql.update_provenance',
true);
12302 IF enable_trigger =
'f' THEN
12305 update_token := public.uuid_generate_v4();
12307 PERFORM create_gate(update_token,
'update');
12311 FROM pg_stat_activity
12312 WHERE pid = pg_backend_pid();
12314 tx_token := transaction_token();
12316 INSERT INTO update_provenance (provsql, query, query_type, username, ts,
12317 valid_time, xid, tx_token)
12318 VALUES (update_token, query_text,
'UPDATE',
current_user,
CURRENT_TIMESTAMP,
12319 TSTZMULTIRANGE(tstzrange(
CURRENT_TIMESTAMP,
NULL)),
12320 pg_current_xact_id(), tx_token);
12324 update_token := provenance_times(tx_token, update_token);
12326 FOR r
IN (
SELECT *
FROM NEW_TABLE) LOOP
12327 old_token := r.provsql;
12328 new_token := provenance_times(old_token, update_token);
12330 PERFORM set_config(
'provsql.update_provenance',
'off',
false);
12331 EXECUTE format(
'UPDATE %I.%I SET provsql = $1 WHERE provsql = $2;', TG_TABLE_SCHEMA, TG_TABLE_NAME)
12332 USING new_token, old_token;
12333 PERFORM set_config(
'provsql.update_provenance',
'on',
false);
12336 PERFORM set_config(
'provsql.update_provenance',
'off',
false);
12337 EXECUTE format(
'INSERT INTO %I.%I SELECT * FROM OLD_TABLE;', TG_TABLE_SCHEMA, TG_TABLE_NAME);
12338 PERFORM set_config(
'provsql.update_provenance',
'on',
false);
12340 FOR r
IN (
SELECT *
FROM OLD_TABLE) LOOP
12341 old_token := r.provsql;
12342 new_token := provenance_monus(old_token, update_token);
12344 PERFORM set_config(
'provsql.update_provenance',
'off',
false);
12345 EXECUTE format(
'UPDATE %I.%I SET provsql = $1 WHERE provsql = $2;', TG_TABLE_SCHEMA, TG_TABLE_NAME)
12346 USING new_token, old_token;
12347 PERFORM set_config(
'provsql.update_provenance',
'on',
false);
12352$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp SECURITY DEFINER;
12364SET search_path
TO provsql;
12378CREATE FUNCTION sr_temporal(token ANYELEMENT, token2value REGCLASS)
12379 RETURNS TSTZMULTIRANGE
AS
12382 RETURN provsql.provenance_evaluate_compiled(
12386 '{(,)}'::TSTZMULTIRANGE
12389$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
12405CREATE FUNCTION sr_interval_num(token ANYELEMENT, token2value REGCLASS)
12406 RETURNS nummultirange
AS
12409 RETURN provsql.provenance_evaluate_compiled(
12413 '{(,)}'::nummultirange
12416$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
12432CREATE FUNCTION sr_interval_int(token ANYELEMENT, token2value REGCLASS)
12433 RETURNS int4multirange
AS
12436 RETURN provsql.provenance_evaluate_compiled(
12440 '{(,)}'::int4multirange
12443$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
12454CREATE OR REPLACE
FUNCTION union_tstzintervals(
12456 token2value REGCLASS
12458RETURNS TSTZMULTIRANGE
AS
12460 SELECT sr_temporal(token, token2value)
12461$$
LANGUAGE SQL PARALLEL SAFE STABLE;
12471CREATE OR REPLACE
FUNCTION timetravel(
12473 at_time TIMESTAMPTZ
12475RETURNS SETOF RECORD
12480 RETURN QUERY
EXECUTE format(
12484 sr_temporal(provenance(), %2$L)
12488 sr_temporal(provenance(), %2$L) @> %3$L::TIMESTAMPTZ
12491 'provsql.time_validity_view',
12506CREATE OR REPLACE
FUNCTION timeslice(
12508 from_time TIMESTAMPTZ,
12509 to_time TIMESTAMPTZ
12511RETURNS SETOF RECORD
12516 RETURN QUERY
EXECUTE format(
12520 sr_temporal(provenance(), %2$L)
12524 sr_temporal(provenance(), %2$L)
12525 && tstzrange(%3$L::TIMESTAMPTZ, %4$L::TIMESTAMPTZ)
12528 'provsql.time_validity_view',
12545CREATE OR REPLACE
FUNCTION history(
12550RETURNS SETOF RECORD
12555 condition TEXT :=
'';
12558 IF array_length(col_names,
1)
IS NULL
12559 OR array_length(col_values,
1)
IS NULL
12560 OR array_length(col_names,
1) != array_length(col_values,
1)
12562 RAISE EXCEPTION
'col_names and col_values must have the same (non-null) length';
12565 FOR i
IN 1..array_length(col_names,
1)
12568 condition := condition ||
' AND ';
12570 condition := condition || format(
'%I = %L', col_names[i], col_values[i]);
12573 RETURN QUERY
EXECUTE format(
12577 sr_temporal(provenance(), %L)
12584 'provsql.time_validity_view',
12597CREATE OR REPLACE
FUNCTION get_valid_time(
12601RETURNS TSTZMULTIRANGE
12605 result TSTZMULTIRANGE;
12610 sr_temporal(provenance(), %L)
12616 'provsql.time_validity_view',
12635CREATE OR REPLACE
FUNCTION undo(
12653 SELECT query
INTO undone_query
12654 FROM update_provenance
12659 RAISE NOTICE
'Unable to find % in update_provenance', c;
12665 FROM pg_stat_activity
12666 WHERE pid = pg_backend_pid();
12668 undo_token := public.uuid_generate_v4();
12669 PERFORM create_gate(undo_token,
'update');
12670 INSERT INTO update_provenance(provsql, query, query_type, username, ts,
12671 valid_time, xid, tx_token)
12678 TSTZMULTIRANGE(tstzrange(
CURRENT_TIMESTAMP,
NULL)),
12679 pg_current_xact_id(),
12680 transaction_token()
12683 PERFORM set_config(
'provsql.update_provenance',
'off',
false);
12688 WHERE nspname
NOT IN (
'pg_catalog',
'information_schema',
'pg_toast',
'pg_temp_1',
'pg_toast_temp_1')
12691 EXECUTE format(
'SELECT tablename AS tname FROM pg_tables WHERE schemaname = %L', schema_rec.nspname)
12695 FROM information_schema.columns
12696 WHERE table_schema = schema_rec.nspname
12697 AND table_name = table_rec.tname
12698 AND table_name <>
'update_provenance'
12699 AND column_name =
'provsql'
12702 EXECUTE format(
'SELECT provsql AS x FROM %I.%I', schema_rec.nspname, table_rec.tname)
12704 new_x := replace_the_circuit(row_rec.x, c, undo_token);
12705 EXECUTE format(
'UPDATE %I.%I SET provsql = $1 WHERE provsql = $2',
12706 schema_rec.nspname, table_rec.tname)
12707 USING new_x, row_rec.x;
12713 PERFORM set_config(
'provsql.update_provenance',
'on',
false);
12729CREATE OR REPLACE
FUNCTION replace_the_circuit(
12741 ntype PROVENANCE_GATE;
12744 RETURN provenance_monus(c, u);
12746 ELSIF get_gate_type(x) =
'update' OR get_gate_type(x) =
'input' THEN
12750 FOREACH child
IN ARRAY get_children(x)
12752 nchildren := array_append(nchildren, replace_the_circuit(child, c, u));
12755 ntoken := public.uuid_generate_v4();
12756 ntype := get_gate_type(x);
12758 PERFORM create_gate(ntoken, ntype, nchildren);
12775CREATE OR REPLACE
FUNCTION substitute_gate(
12787 changed
BOOLEAN :=
false;
12789 ntype PROVENANCE_GATE;
12794 ntype := get_gate_type(x);
12796 IF ntype
IN (
'input',
'update',
'rv',
'value',
'zero',
'one')
THEN
12800 FOREACH child
IN ARRAY get_children(x)
12802 rewritten := substitute_gate(child,
old,
new);
12803 IF rewritten <> child
THEN
12806 nchildren := array_append(nchildren, rewritten);
12808 IF NOT changed
THEN
12811 ntoken := public.uuid_generate_v4();
12812 PERFORM create_gate(ntoken, ntype, nchildren);
12834CREATE OR REPLACE
FUNCTION replace_update(
12849 IF old IS NULL OR p
IS NULL THEN
12850 RAISE EXCEPTION
'replace_update: neither argument may be NULL';
12852 IF get_gate_type(
old) <>
'update' THEN
12853 RAISE EXCEPTION
'replace_update: % is not an update gate',
old
12854 USING HINT =
'Use provsql.replace_input() for a tuple''s own input gate.';
12857 SELECT *
INTO old_row
FROM update_provenance
WHERE provsql =
old LIMIT
1;
12858 IF old_row
IS NULL THEN
12859 RAISE EXCEPTION
'replace_update: % is not recorded in update_provenance',
old;
12862 new_token := public.uuid_generate_v4();
12863 PERFORM create_gate(new_token,
'update');
12864 PERFORM set_prob(new_token, p);
12866 INSERT INTO update_provenance(provsql, query, query_type, username, ts,
12867 valid_time, xid, tx_token)
12868 VALUES (new_token, old_row.query,
'REPLACE',
current_user,
12870 TSTZMULTIRANGE(tstzrange(
CURRENT_TIMESTAMP,
NULL)),
12871 pg_current_xact_id(), transaction_token());
12873 PERFORM set_config(
'provsql.update_provenance',
'off',
false);
12878 WHERE nspname
NOT IN (
'pg_catalog',
'information_schema',
'pg_toast',
'pg_temp_1',
'pg_toast_temp_1')
12881 EXECUTE format(
'SELECT tablename AS tname FROM pg_tables WHERE schemaname = %L', schema_rec.nspname)
12885 FROM information_schema.columns
12886 WHERE table_schema = schema_rec.nspname
12887 AND table_name = table_rec.tname
12888 AND table_name <>
'update_provenance'
12889 AND column_name =
'provsql'
12892 EXECUTE format(
'SELECT provsql AS x FROM %I.%I', schema_rec.nspname, table_rec.tname)
12894 new_x := substitute_gate(row_rec.x,
old, new_token);
12895 IF new_x <> row_rec.x
THEN
12896 EXECUTE format(
'UPDATE %I.%I SET provsql = $1 WHERE provsql = $2',
12897 schema_rec.nspname, table_rec.tname)
12898 USING new_x, row_rec.x;
12905 PERFORM set_config(
'provsql.update_provenance',
'on',
false);
12915CREATE VIEW provsql.time_validity_view
AS
12916 SELECT valid_time
AS value, provsql
AS provenance
FROM provsql.update_provenance;
12920SET search_path
TO public;
12927SELECT provsql.reset_constants_cache();