diff --git a/src/postrr.sql.in b/src/postrr.sql.in
index 546a9dffa1b5003bf723fe6d1bac71012dca4887..eb197452a5ca6e1e4a771398854efc0d0d625975 100644 (file)
--- a/src/postrr.sql.in
+++ b/src/postrr.sql.in
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'
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
+
+ BEGIN
+ EXECUTE '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
+ -- 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;
+$$;
+
+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;