19SET search_path
TO provsql;
27CREATE TYPE PROVENANCE_GATE
AS
58CREATE OR REPLACE
FUNCTION create_gate(
61 children UUID[]
DEFAULT NULL)
63 'provsql',
'create_gate' LANGUAGE C PARALLEL SAFE;
65CREATE OR REPLACE
FUNCTION get_gate_type(
67 RETURNS PROVENANCE_GATE
AS
68 'provsql',
'get_gate_type' LANGUAGE C IMMUTABLE PARALLEL SAFE;
70CREATE OR REPLACE
FUNCTION get_children(
73 'provsql',
'get_children' LANGUAGE C IMMUTABLE PARALLEL SAFE;
80CREATE OR REPLACE
FUNCTION set_prob(
81 token UUID, p
DOUBLE PRECISION)
83 'provsql',
'set_prob' LANGUAGE C PARALLEL SAFE;
85CREATE OR REPLACE
FUNCTION get_prob(
87 RETURNS DOUBLE PRECISION AS
88 'provsql',
'get_prob' LANGUAGE C STABLE PARALLEL SAFE;
106CREATE OR REPLACE
FUNCTION set_infos(
107 token UUID, info1
INT, info2
INT DEFAULT NULL)
109 'provsql',
'set_infos' LANGUAGE C PARALLEL SAFE;
112CREATE OR REPLACE
FUNCTION get_infos(
113 token UUID,
OUT info1
INT,
OUT info2
INT)
115 'provsql',
'get_infos' LANGUAGE C STABLE PARALLEL SAFE;
131CREATE OR REPLACE
FUNCTION set_extra(
132 token UUID, data TEXT)
134 'provsql',
'set_extra' LANGUAGE C PARALLEL SAFE STRICT;
136CREATE OR REPLACE
FUNCTION get_extra(token UUID)
138 'provsql',
'get_extra' LANGUAGE C STABLE PARALLEL SAFE
RETURNS NULL ON NULL INPUT;
141CREATE OR REPLACE
FUNCTION get_nb_gates()
RETURNS BIGINT AS
142 'provsql',
'get_nb_gates' LANGUAGE C PARALLEL SAFE;
153CREATE OR REPLACE
FUNCTION add_gate_trigger()
159 PERFORM create_gate(
NEW.provsql,
'input');
162$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp SECURITY DEFINER;
170CREATE OR REPLACE
FUNCTION delete_statement_trigger()
180 delete_token := public.uuid_generate_v4();
182 PERFORM create_gate(delete_token,
'input');
186 FROM pg_stat_activity
187 WHERE pid = pg_backend_pid();
189 INSERT INTO delete_provenance (delete_token, query, deleted_by, deleted_at)
190 VALUES (delete_token, query_text,
current_user,
CURRENT_TIMESTAMP);
192 EXECUTE format(
'INSERT INTO %I.%I SELECT * FROM OLD_TABLE;', TG_TABLE_SCHEMA, TG_TABLE_NAME);
194 FOR r
IN (
SELECT *
FROM OLD_TABLE) LOOP
195 old_token := r.provsql;
196 new_token := provenance_monus(old_token, delete_token);
198 EXECUTE format(
'UPDATE %I.%I SET provsql = $1 WHERE provsql = $2;', TG_TABLE_SCHEMA, TG_TABLE_NAME)
199 USING new_token, old_token;
204$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp SECURITY DEFINER;
215CREATE OR REPLACE
FUNCTION add_provenance(_tbl REGCLASS)
219 EXECUTE format(
'ALTER TABLE %s ADD COLUMN provsql UUID UNIQUE DEFAULT public.uuid_generate_v4()', _tbl);
220 EXECUTE format(
'SELECT provsql.create_gate(provsql, ''input'') FROM %s', _tbl);
221 EXECUTE format(
'CREATE TRIGGER add_gate BEFORE INSERT ON %s FOR EACH ROW EXECUTE PROCEDURE provsql.add_gate_trigger()',_tbl);
223$$
LANGUAGE plpgsql SECURITY DEFINER;
232CREATE OR REPLACE
FUNCTION remove_provenance(_tbl REGCLASS)
237 EXECUTE format(
'ALTER TABLE %s DROP COLUMN provsql', _tbl);
239 EXECUTE format(
'DROP TRIGGER add_gate on %s', _tbl);
240 EXCEPTION
WHEN undefined_object
THEN
243 EXECUTE format(
'DROP TRIGGER insert_statement on %s', _tbl);
244 EXECUTE format(
'DROP TRIGGER update_statement on %s', _tbl);
245 EXECUTE format(
'DROP TRIGGER delete_statement on %s', _tbl);
246 EXCEPTION
WHEN undefined_object
THEN
262CREATE OR REPLACE
FUNCTION repair_key(_tbl REGCLASS, key_att TEXT)
273 where_condition TEXT;
277 select_key_att :=
'1';
279 select_key_att := key_att;
282 EXECUTE format(
'ALTER TABLE %s ADD COLUMN provsql_temp UUID UNIQUE DEFAULT public.uuid_generate_v4()', _tbl);
285 EXECUTE format(
'SELECT %s AS key FROM %s GROUP BY %s', select_key_att, _tbl, key_att)
287 IF key_att =
'()' THEN
288 where_condition :=
'';
290 where_condition := format(
'WHERE %s = %L', key_att, key.key);
293 EXECUTE format(
'SELECT COUNT(*) FROM %s %s', _tbl, where_condition)
INTO nb_rows;
295 key_token := public.uuid_generate_v4();
296 PERFORM provsql.create_gate(key_token,
'input');
299 EXECUTE format(
'SELECT provsql_temp FROM %s %s', _tbl, where_condition)
301 token:=RECORD.provsql_temp;
302 PERFORM provsql.create_gate(token,
'mulinput',
ARRAY[key_token]);
303 PERFORM provsql.set_prob(token,
1./nb_rows);
304 PERFORM provsql.set_infos(token, ind);
308 EXECUTE format(
'ALTER TABLE %s RENAME COLUMN provsql_temp TO provsql', _tbl);
309 EXECUTE format(
'CREATE TRIGGER add_gate BEFORE INSERT ON %s FOR EACH ROW EXECUTE PROCEDURE provsql.add_gate_trigger()',_tbl);
324CREATE OR REPLACE
FUNCTION create_provenance_mapping(
328 preserve_case BOOL
DEFAULT 'f'
333 EXECUTE format(
'CREATE TEMP TABLE tmp_provsql ON COMMIT DROP AS TABLE %s', oldtbl);
334 ALTER TABLE tmp_provsql RENAME provsql
TO provenance;
335 IF preserve_case
THEN
336 EXECUTE format(
'CREATE TABLE %I AS SELECT %s AS value, provenance FROM tmp_provsql', newtbl, att);
337 EXECUTE format(
'CREATE INDEX ON %I(provenance)', newtbl);
339 EXECUTE format(
'CREATE TABLE %s AS SELECT %s AS value, provenance FROM tmp_provsql', newtbl, att);
340 EXECUTE format(
'CREATE INDEX ON %s(provenance)', newtbl);
354CREATE OR REPLACE
FUNCTION uuid_ns_provsql()
RETURNS UUID
AS
357 SELECT '920d4f02-8718-5319-9532-d4ab83a64489'::UUID
358$$
LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
361CREATE OR REPLACE
FUNCTION gate_zero()
RETURNS UUID
AS
363 SELECT public.uuid_generate_v5(provsql.uuid_ns_provsql(),
'zero');
364$$
LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
367CREATE OR REPLACE
FUNCTION gate_one()
RETURNS UUID
AS
369 SELECT public.uuid_generate_v5(provsql.uuid_ns_provsql(),
'one');
370$$
LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
373CREATE OR REPLACE
FUNCTION epsilon()
RETURNS DOUBLE PRECISION AS
375 SELECT CAST(
0.
001 AS DOUBLE PRECISION)
376$$
LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
392CREATE OR REPLACE
FUNCTION provenance_times(VARIADIC tokens UUID[])
397 filtered_tokens UUID[];
399 SELECT array_agg(t)
FROM unnest(tokens) t
WHERE t
IS NOT NULL AND t <> gate_one()
INTO filtered_tokens;
401 CASE array_length(tokens,
1)
403 times_token:=gate_one();
405 times_token:=filtered_tokens[
1];
407 times_token := uuid_generate_v5(uuid_ns_provsql(),concat(
'times',filtered_tokens));
409 PERFORM create_gate(times_token,
'times', ARRAY_AGG(t))
FROM UNNEST(filtered_tokens)
AS t
WHERE t
IS NOT NULL;
414$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public SECURITY DEFINER PARALLEL SAFE;
422CREATE OR REPLACE
FUNCTION provenance_monus(token1 UUID, token2 UUID)
428 IF token1
IS NULL THEN
429 RAISE EXCEPTION
USING MESSAGE=
'provenance_monus is called with first argument NULL';
432 IF token2
IS NULL THEN
438 IF token1 = token2
THEN
440 monus_token:=gate_zero();
441 ELSIF token1 = gate_zero()
THEN
443 monus_token:=gate_zero();
444 ELSIF token2 = gate_zero()
THEN
448 monus_token:=uuid_generate_v5(uuid_ns_provsql(),concat(
'monus',token1,token2));
449 PERFORM create_gate(monus_token,
'monus',
ARRAY[token1::UUID, token2::UUID]);
454$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public SECURITY DEFINER PARALLEL SAFE IMMUTABLE;
464CREATE OR REPLACE
FUNCTION provenance_project(token UUID, VARIADIC positions
INT[])
471 project_token:=uuid_generate_v5(uuid_ns_provsql(),concat(
'project', token, positions));
472 PERFORM create_gate(project_token,
'project',
ARRAY[token]);
473 PERFORM set_extra(project_token, ARRAY_AGG(pair)::TEXT)
475 SELECT ARRAY[(
CASE WHEN info=
0 THEN NULL ELSE info
END), idx]
AS pair
476 FROM unnest(positions)
WITH ORDINALITY
AS a(info, idx)
480 RETURN project_token;
482$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public SECURITY DEFINER PARALLEL SAFE IMMUTABLE;
491CREATE OR REPLACE
FUNCTION provenance_eq(token UUID, pos1
INT, pos2
INT)
498 eq_token:=uuid_generate_v5(uuid_ns_provsql(),concat(
'eq',token,pos1,
',',pos2));
500 PERFORM create_gate(eq_token,
'eq',
ARRAY[token::UUID]);
501 PERFORM set_infos(eq_token, pos1, pos2);
504$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public SECURITY DEFINER PARALLEL SAFE IMMUTABLE;
512CREATE OR REPLACE
FUNCTION provenance_plus(tokens UUID[])
518 filtered_tokens UUID[];
520 SELECT array_agg(t)
FROM unnest(tokens) t
521 WHERE t
IS NOT NULL AND t <> gate_zero()
522 INTO filtered_tokens;
524 c:=array_length(filtered_tokens,
1);
527 plus_token := gate_zero();
529 plus_token := filtered_tokens[
1];
531 plus_token := uuid_generate_v5(
533 concat(
'plus', filtered_tokens));
535 PERFORM create_gate(plus_token,
'plus', filtered_tokens);
540$$
LANGUAGE plpgsql STRICT
SET search_path=provsql,pg_temp,public SECURITY DEFINER PARALLEL SAFE IMMUTABLE;
549CREATE OR REPLACE
FUNCTION provenance_cmp(
560 cmp_token := public.uuid_generate_v5(
562 concat(
'cmp', left_token::TEXT, comparison_op::TEXT, right_token::TEXT)
565 PERFORM create_gate(cmp_token,
'cmp',
ARRAY[left_token, right_token]);
566 PERFORM set_infos(cmp_token, comparison_op::
INTEGER);
593CREATE OR REPLACE
FUNCTION provenance_evaluate_compiled(
595 token2value REGCLASS,
597 element_one ANYELEMENT)
599 'provsql',
'provenance_evaluate_compiled' LANGUAGE C PARALLEL SAFE STABLE;
618CREATE OR REPLACE
FUNCTION provenance_evaluate(
620 token2value REGCLASS,
621 element_one ANYELEMENT,
623 plus_function REGPROC,
624 times_function REGPROC,
625 monus_function REGPROC,
626 delta_function REGPROC)
627 RETURNS ANYELEMENT
AS
630 gate_type PROVENANCE_GATE;
637 SELECT get_gate_type(token)
INTO gate_type;
639 IF gate_type
IS NULL THEN
642 ELSIF gate_type =
'input' THEN
643 EXECUTE format(
'SELECT value FROM %s WHERE provenance=%L', token2value, token)
645 IF result IS NULL THEN
646 result := element_one;
648 ELSIF gate_type =
'mulinput' THEN
649 SELECT concat(
'{',(get_children(token))[
1]::TEXT,
'=',(get_infos(token)).info1,
'}')
651 ELSIF gate_type=
'update' THEN
652 EXECUTE format(
'SELECT value FROM %s WHERE provenance=%L',token2value,token)
INTO result;
653 IF result IS NULL THEN
656 ELSIF gate_type =
'plus' THEN
657 EXECUTE format(
'SELECT %s(provsql.provenance_evaluate(t,%L,%L::%s,%L,%L,%L,%L,%L)) FROM unnest(get_children(%L)) AS t',
658 plus_function, token2value, element_one, value_type, value_type, plus_function, times_function, monus_function, delta_function, token)
661 ELSIF gate_type =
'times' THEN
662 EXECUTE format(
'SELECT %s(provsql.provenance_evaluate(t,%L,%L::%s,%L,%L,%L,%L,%L)) FROM unnest(get_children(%L)) AS t',
663 times_function, token2value, element_one, value_type, value_type, plus_function, times_function, monus_function, delta_function, token)
666 ELSIF gate_type =
'monus' THEN
667 IF monus_function
IS NULL THEN
668 RAISE EXCEPTION
USING MESSAGE=
'Provenance with negation evaluated over a semiring without monus function';
670 EXECUTE format(
'SELECT %s(a1,a2) FROM (SELECT provsql.provenance_evaluate(c[1],%L,%L::%s,%L,%L,%L,%L,%L) AS a1, ' ||
671 'provsql.provenance_evaluate(c[2],%L,%L::%s,%L,%L,%L,%L,%L) AS a2 FROM get_children(%L) c) tmp',
672 monus_function, token2value, element_one, value_type, value_type, plus_function, times_function, monus_function, delta_function,
673 token2value, element_one, value_type, value_type, plus_function, times_function, monus_function, delta_function, token)
677 ELSIF gate_type =
'eq' THEN
678 EXECUTE format(
'SELECT provsql.provenance_evaluate((get_children(%L))[1],%L,%L::%s,%L,%L,%L,%L,%L)',
679 token, token2value, element_one, value_type, value_type, plus_function, times_function, monus_function, delta_function)
700 ELSIF gate_type =
'delta' THEN
701 IF delta_function
IS NULL THEN
702 RAISE EXCEPTION
USING MESSAGE=
'Provenance with aggregation evaluated over a semiring without delta function';
704 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',
705 delta_function, token, token2value, element_one, value_type, value_type, plus_function, times_function, monus_function, delta_function)
709 ELSIF gate_type =
'zero' THEN
710 EXECUTE format(
'SELECT %I(a) FROM (SELECT %L::%I AS a WHERE FALSE) temp', plus_function, element_one, value_type)
713 ELSIF gate_type =
'one' THEN
714 EXECUTE format(
'SELECT %L::%I', element_one, value_type)
717 ELSIF gate_type =
'project' THEN
718 EXECUTE format(
'SELECT provsql.provenance_evaluate((get_children(%L))[1],%L,%L::%s,%L,%L,%L,%L,%L)',
719 token, token2value, element_one, value_type, value_type, plus_function, times_function, monus_function, delta_function)
723 RAISE EXCEPTION
USING MESSAGE=
'Unknown gate type';
728$$
LANGUAGE plpgsql PARALLEL SAFE STABLE;
748CREATE OR REPLACE
FUNCTION aggregation_evaluate(
750 token2value REGCLASS,
751 agg_function_final REGPROC,
752 agg_function REGPROC,
753 semimod_function REGPROC,
754 element_one ANYELEMENT,
756 plus_function REGPROC,
757 times_function REGPROC,
758 monus_function REGPROC,
759 delta_function REGPROC)
760 RETURNS ANYELEMENT
AS
766 SELECT get_gate_type(token)
INTO gt;
771 EXECUTE format(
'SELECT %I(%I(provsql.aggregation_evaluate(t,%L,%L,%L,%L,%L::%s,%L,%L,%L,%L,%L)),pp.proname::varchar) FROM
772 unnest(get_children(%L)) AS t, pg_proc pp
773 WHERE pp.oid=(get_infos(%L)).info1
774 GROUP BY pp.proname',
775 agg_function_final, agg_function,token2value,agg_function_final,agg_function,semimod_function,element_one,value_type,value_type,plus_function,times_function,
776 monus_function,delta_function,token,token)
780 EXECUTE format(
'SELECT %I(get_extra((get_children(%L))[2]),provsql.provenance_evaluate((get_children(%L))[1],%L,%L::%s,%L,%L,%L,%L,%L))',
781 semimod_function,token,token,token2value,element_one,value_type,value_type,plus_function,times_function,monus_function,delta_function)
786$$
LANGUAGE plpgsql PARALLEL SAFE STABLE;
802CREATE OR REPLACE
FUNCTION provenance_evaluate(
804 token2value REGCLASS,
805 element_one ANYELEMENT,
806 plus_function REGPROC,
807 times_function REGPROC,
808 monus_function REGPROC =
NULL,
809 delta_function REGPROC =
NULL)
810 RETURNS ANYELEMENT
AS
811 'provsql',
'provenance_evaluate' LANGUAGE C STABLE;
814CREATE OR REPLACE
FUNCTION aggregation_evaluate(
816 token2value REGCLASS,
817 agg_function_final REGPROC,
818 agg_function REGPROC,
819 semimod_function REGPROC,
820 element_one ANYELEMENT,
821 plus_function REGPROC,
822 times_function REGPROC,
823 monus_function REGPROC =
NULL,
824 delta_function REGPROC =
NULL)
825 RETURNS ANYELEMENT
AS
826 'provsql',
'aggregation_evaluate' LANGUAGE C STABLE;
837CREATE TYPE GATE_WITH_DESC
AS (f UUID, t UUID, gate_type PROVENANCE_GATE, desc_str
CHARACTER VARYING, infos
INTEGER[], extra TEXT);
849CREATE OR REPLACE
FUNCTION sub_circuit_with_desc(
851 token2desc REGCLASS)
RETURNS SETOF GATE_WITH_DESC
AS
855 'WITH RECURSIVE transitive_closure(f,t,gate_type) AS (
856 SELECT $1,t,provsql.get_gate_type($1) FROM unnest(provsql.get_children($1)) AS t
858 SELECT p1.t,u,provsql.get_gate_type(p1.t) FROM transitive_closure p1, unnest(provsql.get_children(p1.t)) AS u)
859 SELECT *, ARRAY[(get_infos(f)).info1, (get_infos(f)).info2], get_extra(f) FROM (
860 SELECT f::UUID,t::UUID,gate_type,NULL FROM transitive_closure
862 SELECT p2.provenance::UUID as f, NULL::UUID, ''input'', CAST (p2.value AS varchar) FROM transitive_closure p1 JOIN ' || token2desc ||
' AS p2
865 SELECT provenance::UUID as f, NULL::UUID, ''input'', CAST (value AS varchar) FROM ' || token2desc ||
' WHERE provenance=$1
870$$
LANGUAGE plpgsql PARALLEL SAFE;
882CREATE OR REPLACE
FUNCTION identify_token(
883 token UUID,
OUT table_name REGCLASS,
OUT nb_columns
INTEGER)
AS
893 (
SELECT count(*)
FROM pg_attribute a2
WHERE a2.attrelid=a1.attrelid
AND attnum>
0 AND atttypid<>
0)-1 c
894 FROM pg_attribute a1
JOIN pg_type
ON atttypid=pg_type.oid
895 JOIN pg_class
ON attrelid=pg_class.oid
896 JOIN pg_namespace
ON relnamespace=pg_namespace.oid
897 WHERE typname=
'UUID' AND relkind=
'r'
898 AND nspname<>
'provsql'
899 AND attname=
'provsql'
901 EXECUTE format(
'SELECT * FROM %I WHERE provsql=%L',t.relname,token)
INTO result;
902 IF result IS NOT NULL THEN
903 table_name:=t.relname;
909$$
LANGUAGE plpgsql STRICT;
917CREATE OR REPLACE
FUNCTION sub_circuit_for_where(token UUID)
918 RETURNS TABLE(f UUID, t UUID, gate_type PROVENANCE_GATE, table_name REGCLASS, nb_columns
INTEGER, infos
INTEGER[], extra TEXT)
AS
920 WITH RECURSIVE transitive_closure(f,t,idx,gate_type)
AS (
921 SELECT $
1,t,id,provsql.get_gate_type($
1)
FROM unnest(provsql.get_children($
1))
WITH ORDINALITY
AS a(t,id)
923 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)
924 )
SELECT f, t, gate_type, table_name, nb_columns,
ARRAY[(get_infos(f)).info1, (get_infos(f)).info2], get_extra(f)
FROM (
925 SELECT f, t::UUID, idx, gate_type,
NULL AS table_name,
NULL AS nb_columns
FROM transitive_closure
927 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
929 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
947CREATE TYPE AGG_TOKEN;
950CREATE OR REPLACE
FUNCTION agg_token_in(CSTRING)
952 AS 'provsql',
'agg_token_in' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
955CREATE OR REPLACE
FUNCTION agg_token_out(AGG_TOKEN)
957 AS 'provsql',
'agg_token_out' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
960CREATE OR REPLACE
FUNCTION agg_token_cast(AGG_TOKEN)
962 AS 'provsql',
'agg_token_cast' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
964CREATE TYPE AGG_TOKEN (
965 internallength =
117,
966 input = agg_token_in,
967 output = agg_token_out,
972CREATE OR REPLACE
FUNCTION agg_token_uuid(aggtok AGG_TOKEN)
976 RETURN agg_token_cast(aggtok)::UUID;
978$$
LANGUAGE plpgsql STRICT
SET search_path=provsql,pg_temp,public SECURITY DEFINER IMMUTABLE PARALLEL SAFE;
981CREATE CAST (AGG_TOKEN
AS UUID)
WITH FUNCTION agg_token_uuid(AGG_TOKEN)
AS IMPLICIT;
990CREATE OR REPLACE
FUNCTION agg_token_comp_numeric(a AGG_TOKEN, b
NUMERIC)
993IMMUTABLE STRICT PARALLEL SAFE
996 RAISE EXCEPTION
'Comparison AGG_TOKEN-NUMERIC not implemented, should be replaced by ProvSQL behavior';
1006CREATE OR REPLACE
FUNCTION numeric_comp_agg_token(a
NUMERIC, b AGG_TOKEN)
1009IMMUTABLE STRICT PARALLEL SAFE
1012 RAISE EXCEPTION
'Comparison NUMERIC-AGG_TOKEN not implemented, should be replaced by ProvSQL behavior';
1018 LEFTARG = AGG_TOKEN,
1020 PROCEDURE = agg_token_comp_numeric,
1027 RIGHTARG = AGG_TOKEN,
1028 PROCEDURE = numeric_comp_agg_token,
1035 LEFTARG = AGG_TOKEN,
1037 PROCEDURE = agg_token_comp_numeric,
1044 RIGHTARG = AGG_TOKEN,
1045 PROCEDURE = numeric_comp_agg_token,
1052 LEFTARG = AGG_TOKEN,
1054 PROCEDURE = agg_token_comp_numeric,
1061 RIGHTARG = AGG_TOKEN,
1062 PROCEDURE = numeric_comp_agg_token,
1069 LEFTARG = AGG_TOKEN,
1071 PROCEDURE = agg_token_comp_numeric,
1078 RIGHTARG = AGG_TOKEN,
1079 PROCEDURE = numeric_comp_agg_token,
1086 LEFTARG = AGG_TOKEN,
1088 PROCEDURE = agg_token_comp_numeric,
1095 RIGHTARG = AGG_TOKEN,
1096 PROCEDURE = numeric_comp_agg_token,
1103 LEFTARG = AGG_TOKEN,
1105 PROCEDURE = agg_token_comp_numeric,
1112 RIGHTARG = AGG_TOKEN,
1113 PROCEDURE = numeric_comp_agg_token,
1132CREATE OR REPLACE
FUNCTION provenance_delta
1139 IF token = gate_zero()
OR token = gate_one()
THEN
1143 IF token
IS NULL THEN
1147 delta_token:=uuid_generate_v5(uuid_ns_provsql(),concat(
'delta',token));
1149 PERFORM create_gate(delta_token,
'delta',
ARRAY[token::UUID]);
1153$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp,public SECURITY DEFINER PARALLEL SAFE;
1167CREATE OR REPLACE
FUNCTION provenance_aggregate(
1172 RETURNS AGG_TOKEN
AS
1179 c:=array_length(tokens,
1);
1181 agg_val =
CAST(val
as VARCHAR);
1184 agg_tok := gate_zero();
1186 agg_tok := uuid_generate_v5(
1188 concat(
'agg',tokens));
1189 PERFORM create_gate(agg_tok,
'agg', tokens);
1190 PERFORM set_infos(agg_tok, aggfnoid, aggtype);
1191 PERFORM set_extra(agg_tok, agg_val);
1194 RETURN '( '||agg_tok||
' , '||agg_val||
' )';
1196$$
LANGUAGE plpgsql PARALLEL SAFE STRICT
SET search_path=provsql,pg_temp,public SECURITY DEFINER;
1207CREATE OR REPLACE
FUNCTION provenance_semimod(val ANYELEMENT, token UUID)
1214 SELECT uuid_generate_v5(uuid_ns_provsql(),concat(
'value',
CAST(val
AS VARCHAR)))
1216 SELECT uuid_generate_v5(uuid_ns_provsql(),concat(
'semimod',value_token,token))
1220 PERFORM create_gate(value_token,
'value');
1221 PERFORM set_extra(value_token,
CAST(val
AS VARCHAR));
1224 PERFORM create_gate(semimod_token,
'semimod',
ARRAY[token::UUID,value_token]);
1226 RETURN semimod_token;
1228$$
LANGUAGE plpgsql PARALLEL SAFE
SET search_path=provsql,pg_temp,public SECURITY DEFINER;
1249CREATE OR REPLACE
FUNCTION probability_evaluate(
1252 arguments TEXT =
NULL)
1253 RETURNS DOUBLE PRECISION AS
1254 'provsql',
'probability_evaluate' LANGUAGE C STABLE;
1268CREATE OR REPLACE
FUNCTION expected(
1270 prov UUID = gate_one(),
1272 arguments TEXT =
NULL)
1273 RETURNS DOUBLE PRECISION AS $$
1275 aggregation_function
VARCHAR;
1277 result DOUBLE PRECISION;
1278 total_probability
DOUBLE PRECISION;
1280 token :=
input::AGG_TOKEN;
1281 IF token
IS NULL THEN
1284 IF get_gate_type(token) <>
'agg' THEN
1285 RAISE EXCEPTION
USING MESSAGE=
'Wrong gate type for expected value computation';
1287 SELECT pp.proname::
varchar FROM pg_proc pp
WHERE oid=(get_infos(token)).info1
INTO aggregation_function;
1288 IF aggregation_function =
'sum' THEN
1290 SELECT SUM(probability_evaluate((get_children(c))[
1],
method, arguments) *
CAST(get_extra((get_children(c))[
2])
AS DOUBLE PRECISION))
1291 FROM UNNEST(get_children(token))
AS c
INTO result;
1292 ELSIF aggregation_function =
'min' OR aggregation_function =
'max' THEN
1295 SELECT (get_children(c))[
1]
AS tok, (
CASE WHEN aggregation_function=
'max' THEN -1
ELSE 1 END) *
CAST(get_extra((get_children(c))[
2])
AS DOUBLE PRECISION)
AS v
1296 FROM UNNEST(get_children(token))
AS c
1297 )
SELECT probability_evaluate(provenance_monus(prov, provenance_plus(ARRAY_AGG(tok))))
FROM tok_value
INTO total_probability;
1298 IF total_probability > epsilon()
THEN
1299 result := (
CASE WHEN aggregation_function=
'max' THEN -1
ELSE 1 END) *
CAST(
'Infinity' AS DOUBLE PRECISION);
1302 SELECT (get_children(c))[
1]
AS tok, (
CASE WHEN aggregation_function=
'max' THEN -1
ELSE 1 END) *
CAST(get_extra((get_children(c))[
2])
AS DOUBLE PRECISION)
AS v
1303 FROM UNNEST(get_children(token))
AS c
1305 (
CASE WHEN aggregation_function=
'max' THEN -1
ELSE 1 END) * SUM(p*v)
FROM
1306 (
SELECT t1.v
AS v, probability_evaluate(provenance_monus(provenance_plus(ARRAY_AGG(t1.tok)),provenance_plus(ARRAY_AGG(t2.tok))),
method, arguments)
AS p
1307 FROM tok_value t1
LEFT OUTER JOIN tok_value t2
ON t1.v > t2.v
1308 GROUP BY t1.v) t
INTO result;
1311 RAISE EXCEPTION
USING MESSAGE=
'Cannot compute expected value for aggregation function ' || aggregation_function;
1313 IF prov <> gate_one()
AND result <>
0.
AND result <>
'Infinity' AND result <>
'-Infinity' THEN
1314 result :=
result/probability_evaluate(prov,
method, arguments);
1318$$
LANGUAGE plpgsql PARALLEL SAFE
SET search_path=provsql SECURITY DEFINER;;
1332CREATE OR REPLACE
FUNCTION shapley(
1336 arguments TEXT =
NULL,
1337 banzhaf
BOOLEAN =
'f')
1338 RETURNS DOUBLE PRECISION AS
1339 'provsql',
'shapley' LANGUAGE C STABLE;
1342CREATE OR REPLACE
FUNCTION shapley_all_vars(
1344 IN method TEXT =
NULL,
1345 IN arguments TEXT =
NULL,
1346 IN banzhaf
BOOLEAN =
'f',
1348 OUT value DOUBLE PRECISION)
1349 RETURNS SETOF RECORD
AS
1350 'provsql',
'shapley_all_vars'
1354CREATE OR REPLACE
FUNCTION banzhaf(
1358 arguments TEXT =
NULL)
1359 RETURNS DOUBLE PRECISION AS
1360 $$
SELECT provsql.shapley(token, variable,
method, arguments,
't') $$
1364CREATE OR REPLACE
FUNCTION banzhaf_all_vars(
1366 IN method TEXT =
NULL,
1367 IN arguments TEXT =
NULL,
1369 OUT value DOUBLE PRECISION)
1370 RETURNS SETOF RECORD
AS
1371 $$
SELECT *
FROM provsql.shapley_all_vars(token,
method, arguments,
't') $$
1389CREATE OR REPLACE
FUNCTION view_circuit(
1391 token2desc REGCLASS,
1394 'provsql',
'view_circuit' LANGUAGE C;
1402CREATE OR REPLACE
FUNCTION to_provxml(
1404 token2desc REGCLASS =
NULL)
1406 'provsql',
'to_provxml' LANGUAGE C;
1409CREATE OR REPLACE
FUNCTION provenance()
RETURNS UUID
AS
1410 'provsql',
'provenance' LANGUAGE C;
1418CREATE OR REPLACE
FUNCTION where_provenance(token UUID)
1420 'provsql',
'where_provenance' LANGUAGE C;
1431CREATE OR REPLACE
FUNCTION reset_constants_cache()
1433 'provsql',
'reset_constants_cache' LANGUAGE C;
1435SELECT reset_constants_cache();
1437SELECT create_gate(gate_zero(),
'zero');
1438SELECT create_gate(gate_one(),
'one');
1443CREATE TYPE QUERY_TYPE_ENUM
AS ENUM (
1456CREATE FUNCTION sr_formula(token ANYELEMENT, token2value REGCLASS)
1460 RETURN provsql.provenance_evaluate_compiled(
1467$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
1470CREATE FUNCTION sr_counting(token ANYELEMENT, token2value REGCLASS)
1474 RETURN provsql.provenance_evaluate_compiled(
1481$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
1484CREATE FUNCTION sr_why(token ANYELEMENT, token2value REGCLASS)
1488 RETURN provsql.provenance_evaluate_compiled(
1495$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
1498CREATE FUNCTION sr_boolexpr(token ANYELEMENT)
1502 RETURN provsql.provenance_evaluate_compiled(
1509$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
1512CREATE FUNCTION sr_boolean(token ANYELEMENT, token2value REGCLASS)
1516 RETURN provsql.provenance_evaluate_compiled(
1523$$
LANGUAGE plpgsql STRICT PARALLEL SAFE STABLE;
1534CREATE FUNCTION choose_function(state ANYELEMENT, data ANYELEMENT)
1535 RETURNS ANYELEMENT
AS
1538 IF state
IS NULL THEN
1544$$
LANGUAGE plpgsql PARALLEL SAFE IMMUTABLE;
1547CREATE AGGREGATE choose(ANYELEMENT) (
1548 SFUNC = choose_function,
1554GRANT USAGE
ON SCHEMA provsql
TO PUBLIC;
1556SET search_path
TO public;
1557SET search_path
TO provsql;
1572CREATE TABLE update_provenance (
1575 query_type QUERY_TYPE_ENUM,
1577 ts
TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
1578 valid_time TSTZMULTIRANGE
DEFAULT TSTZMULTIRANGE(tstzrange(
CURRENT_TIMESTAMP,
NULL))
1584CREATE OR REPLACE
FUNCTION add_provenance(_tbl REGCLASS)
1588 EXECUTE format(
'ALTER TABLE %s ADD COLUMN provsql UUID UNIQUE DEFAULT public.uuid_generate_v4()', _tbl);
1589 EXECUTE format(
'SELECT provsql.create_gate(provsql, ''input'') FROM %s', _tbl);
1590 EXECUTE format(
'CREATE TRIGGER add_gate BEFORE INSERT ON %s FOR EACH ROW EXECUTE PROCEDURE provsql.add_gate_trigger()',_tbl);
1592 EXECUTE format(
'CREATE TRIGGER insert_statement AFTER INSERT ON %s REFERENCING NEW TABLE AS NEW_TABLE FOR EACH STATEMENT EXECUTE PROCEDURE provsql.insert_statement_trigger()', _tbl);
1593 EXECUTE format(
'CREATE TRIGGER delete_statement AFTER DELETE ON %s REFERENCING OLD TABLE AS OLD_TABLE FOR EACH STATEMENT EXECUTE PROCEDURE provsql.delete_statement_trigger()', _tbl);
1594 EXECUTE format(
'CREATE TRIGGER update_statement AFTER UPDATE ON %s REFERENCING OLD TABLE AS OLD_TABLE NEW TABLE AS NEW_TABLE FOR EACH STATEMENT EXECUTE PROCEDURE provsql.update_statement_trigger()', _tbl);
1597$$
LANGUAGE plpgsql SECURITY DEFINER;
1603CREATE OR REPLACE
FUNCTION delete_statement_trigger()
1612 enable_trigger BOOL;
1614 enable_trigger := current_setting(
'provsql.update_provenance',
true);
1615 IF enable_trigger =
'f' THEN
1618 delete_token := public.uuid_generate_v4();
1620 PERFORM create_gate(delete_token,
'update');
1624 FROM pg_stat_activity
1625 WHERE pid = pg_backend_pid();
1627 INSERT INTO update_provenance (provsql, query, query_type, username, ts, valid_time)
1628 VALUES (delete_token, query_text,
'DELETE',
current_user,
CURRENT_TIMESTAMP, TSTZMULTIRANGE(tstzrange(
CURRENT_TIMESTAMP,
NULL)));
1630 PERFORM set_config(
'provsql.update_provenance',
'off',
false);
1631 EXECUTE format(
'INSERT INTO %I.%I SELECT * FROM OLD_TABLE;', TG_TABLE_SCHEMA, TG_TABLE_NAME);
1632 PERFORM set_config(
'provsql.update_provenance',
'on',
false);
1634 FOR r
IN (
SELECT *
FROM OLD_TABLE) LOOP
1635 old_token := r.provsql;
1636 new_token := provenance_monus(old_token, delete_token);
1638 PERFORM set_config(
'provsql.update_provenance',
'off',
false);
1639 EXECUTE format(
'UPDATE %I.%I SET provsql = $1 WHERE provsql = $2;', TG_TABLE_SCHEMA, TG_TABLE_NAME)
1640 USING new_token, old_token;
1641 PERFORM set_config(
'provsql.update_provenance',
'on',
false);
1646$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp SECURITY DEFINER;
1655CREATE OR REPLACE
FUNCTION insert_statement_trigger()
1664 enable_trigger BOOL;
1666 enable_trigger := current_setting(
'provsql.update_provenance',
true);
1667 IF enable_trigger =
'f' THEN
1671 insert_token := public.uuid_generate_v4();
1673 PERFORM create_gate(insert_token,
'update');
1677 FROM pg_stat_activity
1678 WHERE pid = pg_backend_pid();
1680 INSERT INTO update_provenance (provsql, query, query_type, username, ts, valid_time)
1681 VALUES (insert_token, query_text,
'INSERT',
current_user,
CURRENT_TIMESTAMP, TSTZMULTIRANGE(tstzrange(
CURRENT_TIMESTAMP,
NULL)));
1683 FOR r
IN (
SELECT *
FROM NEW_TABLE) LOOP
1684 old_token := r.provsql;
1685 new_token := provenance_times(old_token, insert_token);
1686 PERFORM set_config(
'provsql.update_provenance',
'off',
false);
1687 EXECUTE format(
'UPDATE %I.%I SET provsql = $1 WHERE provsql = $2;', TG_TABLE_SCHEMA, TG_TABLE_NAME)
1688 USING new_token, old_token;
1689 PERFORM set_config(
'provsql.update_provenance',
'on',
false);
1694$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp SECURITY DEFINER;
1702CREATE OR REPLACE
FUNCTION update_statement_trigger()
1711 enable_trigger BOOL;
1713 enable_trigger := current_setting(
'provsql.update_provenance',
true);
1714 IF enable_trigger =
'f' THEN
1717 update_token := public.uuid_generate_v4();
1719 PERFORM create_gate(update_token,
'update');
1723 FROM pg_stat_activity
1724 WHERE pid = pg_backend_pid();
1726 INSERT INTO update_provenance (provsql, query, query_type, username, ts, valid_time)
1727 VALUES (update_token, query_text,
'UPDATE',
current_user,
CURRENT_TIMESTAMP, TSTZMULTIRANGE(tstzrange(
CURRENT_TIMESTAMP,
NULL)));
1729 FOR r
IN (
SELECT *
FROM NEW_TABLE) LOOP
1730 old_token := r.provsql;
1731 new_token := provenance_times(old_token, update_token);
1733 PERFORM set_config(
'provsql.update_provenance',
'off',
false);
1734 EXECUTE format(
'UPDATE %I.%I SET provsql = $1 WHERE provsql = $2;', TG_TABLE_SCHEMA, TG_TABLE_NAME)
1735 USING new_token, old_token;
1736 PERFORM set_config(
'provsql.update_provenance',
'on',
false);
1739 PERFORM set_config(
'provsql.update_provenance',
'off',
false);
1740 EXECUTE format(
'INSERT INTO %I.%I SELECT * FROM OLD_TABLE;', TG_TABLE_SCHEMA, TG_TABLE_NAME);
1741 PERFORM set_config(
'provsql.update_provenance',
'on',
false);
1743 FOR r
IN (
SELECT *
FROM OLD_TABLE) LOOP
1744 old_token := r.provsql;
1745 new_token := provenance_monus(old_token, update_token);
1747 PERFORM set_config(
'provsql.update_provenance',
'off',
false);
1748 EXECUTE format(
'UPDATE %I.%I SET provsql = $1 WHERE provsql = $2;', TG_TABLE_SCHEMA, TG_TABLE_NAME)
1749 USING new_token, old_token;
1750 PERFORM set_config(
'provsql.update_provenance',
'on',
false);
1755$$
LANGUAGE plpgsql
SET search_path=provsql,pg_temp SECURITY DEFINER;
1768SET search_path
TO provsql;
1769CREATE OR REPLACE
FUNCTION union_tstzintervals_plus_state(
1770 state TSTZMULTIRANGE,
1771 value TSTZMULTIRANGE
1773RETURNS TSTZMULTIRANGE
AS
1775 SELECT CASE WHEN state
IS NULL THEN value ELSE state +
value END
1776$$
LANGUAGE SQL IMMUTABLE;
1779CREATE OR REPLACE
FUNCTION union_tstzintervals_times_state(
1780 state TSTZMULTIRANGE,
1781 value TSTZMULTIRANGE
1783RETURNS TSTZMULTIRANGE
AS
1785 SELECT CASE WHEN state
IS NULL THEN value ELSE state *
value END
1786$$
LANGUAGE SQL IMMUTABLE;
1789CREATE OR REPLACE AGGREGATE union_tstzintervals_plus(TSTZMULTIRANGE)
1791 sfunc = union_tstzintervals_plus_state,
1792 stype = TSTZMULTIRANGE,
1797CREATE OR REPLACE AGGREGATE union_tstzintervals_times(TSTZMULTIRANGE)
1799 sfunc = union_tstzintervals_times_state,
1800 stype = TSTZMULTIRANGE,
1805CREATE OR REPLACE
FUNCTION union_tstzintervals_monus(
1806 state TSTZMULTIRANGE,
1807 value TSTZMULTIRANGE
1809RETURNS TSTZMULTIRANGE
AS
1811 SELECT CASE WHEN state <@
value THEN '{}'::TSTZMULTIRANGE
ELSE state -
value END
1812$$
LANGUAGE SQL IMMUTABLE STRICT;
1823CREATE OR REPLACE
FUNCTION union_tstzintervals(
1825 token2value REGCLASS
1827RETURNS TSTZMULTIRANGE
AS
1830 RETURN provenance_evaluate(
1833 '{(,)}'::TSTZMULTIRANGE,
1834 'union_tstzintervals_plus',
1835 'union_tstzintervals_times',
1836 'union_tstzintervals_monus'
1839$$
LANGUAGE plpgsql PARALLEL SAFE;
1852CREATE OR REPLACE
FUNCTION create_provenance_mapping_view(
1856 preserve_case BOOL
DEFAULT false
1863 IF preserve_case
THEN
1865 'CREATE OR REPLACE VIEW %I AS SELECT %s AS value, provsql AS provenance FROM %s',
1872 'CREATE OR REPLACE VIEW %s AS SELECT %s AS value, provsql AS provenance FROM %s',
1889CREATE OR REPLACE
FUNCTION timetravel(
1898 RETURN QUERY
EXECUTE format(
1902 union_tstzintervals(provenance(), ''%2$I'')
1906 union_tstzintervals(provenance(), ''%2$I'') @> %3$L::TIMESTAMPTZ
1909 'time_validity_view',
1924CREATE OR REPLACE
FUNCTION timeslice(
1926 from_time TIMESTAMPTZ,
1934 RETURN QUERY
EXECUTE format(
1938 union_tstzintervals(provenance(), ''%2$I'')
1942 union_tstzintervals(provenance(), ''%2$I'')
1943 && tstzrange(%3$L::TIMESTAMPTZ, %4$L::TIMESTAMPTZ)
1946 'time_validity_view',
1963CREATE OR REPLACE
FUNCTION history(
1973 condition TEXT :=
'';
1976 IF array_length(col_names,
1)
IS NULL
1977 OR array_length(col_values,
1)
IS NULL
1978 OR array_length(col_names,
1) != array_length(col_values,
1)
1980 RAISE EXCEPTION
'col_names and col_values must have the same (non-null) length';
1983 FOR i
IN 1..array_length(col_names,
1)
1986 condition := condition ||
' AND ';
1988 condition := condition || format(
'%I = %L', col_names[i], col_values[i]);
1991 RETURN QUERY
EXECUTE format(
1995 union_tstzintervals(provenance(), ''%I'')
2002 'time_validity_view',
2015CREATE OR REPLACE
FUNCTION get_valid_time(
2019RETURNS TSTZMULTIRANGE
2023 result TSTZMULTIRANGE;
2028 union_tstzintervals(provenance(), %L)
2034 'time_validity_view',
2053CREATE OR REPLACE
FUNCTION undo(
2068 SELECT query
INTO undone_query
2069 FROM update_provenance
2073 IF undone_query
IS NULL THEN
2074 RAISE NOTICE
'Unable to find % in update_provenance', c;
2080 FROM pg_stat_activity
2081 WHERE pid = pg_backend_pid();
2083 undo_token := public.uuid_generate_v4();
2084 PERFORM create_gate(undo_token,
'update');
2085 INSERT INTO update_provenance(provsql, query, query_type, username, ts, valid_time)
2092 TSTZMULTIRANGE(tstzrange(
CURRENT_TIMESTAMP,
NULL))
2095 PERFORM set_config(
'provsql.update_provenance',
'off',
false);
2100 WHERE nspname
NOT IN (
'pg_catalog',
'information_schema',
'pg_toast',
'pg_temp_1',
'pg_toast_temp_1')
2103 EXECUTE format(
'SELECT tablename AS tname FROM pg_tables WHERE schemaname = %L', schema_rec.nspname)
2107 FROM information_schema.columns
2108 WHERE table_schema = schema_rec.nspname
2109 AND table_name = table_rec.tname
2110 AND table_name <>
'update_provenance'
2111 AND column_name =
'provsql'
2114 EXECUTE format(
'SELECT provsql AS x FROM %I.%I', schema_rec.nspname, table_rec.tname)
2116 new_x := replace_the_circuit(row_rec.x, c, undo_token);
2117 EXECUTE format(
'UPDATE %I.%I SET provsql = $1 WHERE provsql = $2',
2118 schema_rec.nspname, table_rec.tname)
2119 USING new_x, row_rec.x;
2125 PERFORM set_config(
'provsql.update_provenance',
'on',
false);
2141CREATE OR REPLACE
FUNCTION replace_the_circuit(
2153 ntype PROVENANCE_GATE;
2156 RETURN provenance_monus(c, u);
2158 ELSIF get_gate_type(x) =
'update' OR get_gate_type(x) =
'input' THEN
2162 FOREACH child
IN ARRAY get_children(x)
2164 nchildren := array_append(nchildren, replace_the_circuit(child, c, u));
2167 ntoken := public.uuid_generate_v4();
2168 ntype := get_gate_type(x);
2170 PERFORM create_gate(ntoken, ntype, nchildren);
2176SELECT create_provenance_mapping_view(
'time_validity_view',
'update_provenance',
'valid_time');
2180SET search_path
TO public;