Code

PostRR_update(): Use rrtimeslice_cmp() to decide how to do the update.
[postrr.git] / src / postrr.sql.in
index 10aeb777815720620e55c6a71f75ece9504ddadc..9f34f22100cfd04151da1afb56ca23ec2c3538d8 100644 (file)
@@ -117,6 +117,11 @@ 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'
@@ -315,6 +320,7 @@ DECLARE
        ts_str text;
        v_str text;
        update_qry text;
+       status integer;
        newts rrtimeslice;
        new cdata;
 BEGIN
@@ -325,13 +331,13 @@ BEGIN
 
        update_qry = 'CData_update(' || vcol || ', ' || v_str || ')';
 
+       -- XXX: handle race conditions
+
        BEGIN
-               EXECUTE 'UPDATE ' || tbl
-                       || ' SET ' || tscol || ' = ' || ts_str
-                       || ', ' || vcol || ' = ' || update_qry
+               EXECUTE 'SELECT rrtimeslice_cmp(' || tscol || ', ' || ts_str
+                       || ') AS status FROM ' || tbl
                        || ' WHERE ' || tscol || ' = ' || ts_str
-                       || ' RETURNING ' || tscol || ', ' || vcol
-                       INTO STRICT newts, new;
+                       INTO STRICT status;
 
                EXCEPTION
                        WHEN NO_DATA_FOUND THEN
@@ -341,9 +347,29 @@ BEGIN
                                        || ') 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
+               -- given timestamp is newer than in the database
+               EXECUTE 'UPDATE ' || tbl
+                       || ' SET ' || tscol || ' = ' || ts_str
+                       || ', ' || vcol || ' = ' || v_str
+                       || ' WHERE ' || tscol || ' = ' || ts_str
+                       || ' RETURNING ' || tscol || ', ' || vcol
+                       INTO STRICT newts, new;
+       ELSE
+               RAISE EXCEPTION '% is too old in %.%', ts_str, tbl, tscol;
+       END IF;
        RETURN new;
 END;
 $$;
@@ -353,20 +379,15 @@ CREATE OR REPLACE FUNCTION PostRR_update(text, timestamptz, double precision)
        LANGUAGE plpgsql
        AS $$
 DECLARE
-       rraname ALIAS FOR $1;
-       ts ALIAS FOR $2;
-       value ALIAS FOR $3;
+       -- $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
-               EXECUTE 'SELECT PostRR_update('
-                       || quote_literal(adef.tbl) || ', '
-                       || quote_literal(adef.tscol) || ', '
-                       || quote_literal(adef.vcol) || ', '
-                       || quote_literal(ts) || ', '
-                       || quote_literal(value) || ')'
+               SELECT PostRR_update(adef.tbl, adef.tscol, adef.vcol, $2, $3)
                        INTO new;
                RETURN NEXT new;
        END LOOP;