X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fpostrr.sql.in;h=a3bff336ae94ef5288b4ab927a7a3c4704359d83;hb=2072e784f2fab50bff6aa25831d14424d0f575ec;hp=01cd65f8a6be9b2c49339c629f6f0efcc72a6f4e;hpb=ec00d193ed161a58be46f62fed81adfc5612cfde;p=postrr.git diff --git a/src/postrr.sql.in b/src/postrr.sql.in index 01cd65f..a3bff33 100644 --- a/src/postrr.sql.in +++ b/src/postrr.sql.in @@ -45,6 +45,14 @@ CREATE TABLE postrr.rrtimeslices ( tsnum integer NOT NULL ); +CREATE TABLE postrr.rrarchives ( + rraname text NOT NULL, + tbl name NOT NULL, + tscol name NOT NULL, + vcol name NOT NULL, + UNIQUE (rraname, tbl, tscol, vcol) +); + CREATE OR REPLACE FUNCTION PostRR_Version() RETURNS cstring AS 'postrr-@POSTRR_MAJOR_VERSION@.@POSTRR_MINOR_VERSION@', 'postrr_version' @@ -100,15 +108,29 @@ CREATE CAST (rrtimeslice AS rrtimeslice) WITH FUNCTION RRTimeslice(rrtimeslice, integer, boolean) AS IMPLICIT; -CREATE OR REPLACE FUNCTION Tstamp(rrtimeslice) - RETURNS timestamp - AS 'postrr-@POSTRR_MAJOR_VERSION@.@POSTRR_MINOR_VERSION@', 'rrtimeslice_to_timestamp' +CREATE OR REPLACE FUNCTION RRTimeslice(timestamptz, integer, boolean) + RETURNS rrtimeslice + AS 'postrr-@POSTRR_MAJOR_VERSION@.@POSTRR_MINOR_VERSION@', 'timestamptz_to_rrtimeslice' + LANGUAGE 'C' IMMUTABLE STRICT; + +CREATE CAST (timestamptz AS rrtimeslice) + WITH FUNCTION RRTimeslice(timestamptz, integer, boolean) + AS IMPLICIT; + +CREATE OR REPLACE FUNCTION Tstamptz(rrtimeslice) + RETURNS timestamptz + AS 'postrr-@POSTRR_MAJOR_VERSION@.@POSTRR_MINOR_VERSION@', 'rrtimeslice_to_timestamptz' LANGUAGE 'C' IMMUTABLE STRICT; -CREATE CAST (rrtimeslice AS timestamp) - WITH FUNCTION Tstamp(rrtimeslice); +CREATE CAST (rrtimeslice AS timestamptz) + WITH FUNCTION Tstamptz(rrtimeslice); -- EXPLICIT +CREATE OR REPLACE FUNCTION rrtimeslice_cmp(rrtimeslice, rrtimeslice) + RETURNS integer + AS 'postrr-@POSTRR_MAJOR_VERSION@.@POSTRR_MINOR_VERSION@', 'rrtimeslice_cmp' + LANGUAGE 'C' IMMUTABLE STRICT; + CREATE OR REPLACE FUNCTION rrtimeslice_seq_eq(rrtimeslice, rrtimeslice) RETURNS boolean AS 'postrr-@POSTRR_MAJOR_VERSION@.@POSTRR_MINOR_VERSION@', 'rrtimeslice_seq_eq' @@ -294,6 +316,98 @@ CREATE OR REPLACE FUNCTION CData_update(cdata, cdata) AS 'postrr-@POSTRR_MAJOR_VERSION@.@POSTRR_MINOR_VERSION@', 'cdata_update' LANGUAGE 'C' IMMUTABLE; +CREATE OR REPLACE FUNCTION PostRR_update(name, name, name, timestamptz, double precision) + RETURNS cdata + LANGUAGE plpgsql + AS $$ +DECLARE + tbl ALIAS FOR $1; + tscol ALIAS FOR $2; + vcol ALIAS FOR $3; + ts ALIAS FOR $4; + value ALIAS FOR $5; + ts_str text; + v_str text; + update_qry text; + status integer; + newts rrtimeslice; + new cdata; +BEGIN + tscol := quote_ident(tscol); + vcol := quote_ident(vcol); + ts_str := quote_literal(ts); + v_str := quote_literal(value); + + update_qry = 'CData_update(' || vcol || ', ' || v_str || ')'; + + -- XXX: handle race conditions + + LOOP + BEGIN + -- removing matching (by sequence no) old entries + EXECUTE 'DELETE FROM ' || tbl + || ' WHERE rrtimeslice_cmp(' || tscol || ', ' || ts_str + || ') = -1; ' + || 'SELECT rrtimeslice_cmp(' || tscol || ', ' || ts_str + || ') AS status FROM ' || tbl + || ' WHERE ' || tscol || ' = ' || ts_str + INTO STRICT status; + + EXCEPTION + WHEN NO_DATA_FOUND THEN + EXECUTE 'INSERT INTO ' || tbl + || ' (' || tscol || ', ' || vcol + || ') VALUES (' || ts_str || ', ' || v_str + || ') RETURNING ' || tscol || ', ' || vcol + INTO newts, new; + -- use strict again; on exception retry? + RETURN new; + WHEN TOO_MANY_ROWS THEN + RAISE EXCEPTION '% is not unique in %.%', + ts_str, tbl, tscol; + END; + + IF status = 0 THEN + -- timestamps match + EXECUTE 'UPDATE ' || tbl + || ' SET ' || vcol || ' = ' || update_qry + || ' WHERE ' || tscol || ' = ' || ts_str + || ' RETURNING ' || tscol || ', ' || vcol + INTO STRICT newts, new; + ELSIF status < 0 THEN + -- someone else inserted older data in the meantime + -- => try again + CONTINUE; + ELSE + RAISE EXCEPTION '% is too old in %.%', ts_str, tbl, tscol; + END IF; + EXIT; + END LOOP; + RETURN new; +END; +$$; + +CREATE OR REPLACE FUNCTION PostRR_update(text, timestamptz, double precision) + RETURNS SETOF cdata + LANGUAGE plpgsql + AS $$ +DECLARE + -- $1: rraname + -- $2: timestamp + -- $3: value + adef RECORD; + new cdata; +BEGIN + FOR adef IN SELECT tbl, tscol, vcol FROM postrr.rrarchives + WHERE postrr.rrarchives.rraname = $1 LOOP + SELECT PostRR_update(adef.tbl, adef.tscol, adef.vcol, $2, $3) + INTO new; + RETURN NEXT new; + END LOOP; + RETURN; +END; +$$; + COMMIT; SET client_min_messages TO DEFAULT;