Code

PostRR_update(): Fixed handling of multiple columns in the same table.
[postrr.git] / src / postrr.sql.in
index 01cd65f8a6be9b2c49339c629f6f0efcc72a6f4e..a3bff336ae94ef5288b4ab927a7a3c4704359d83 100644 (file)
@@ -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;