Code

PostRR_update(): Use rrtimeslice_cmp() to decide how to do the update.
[postrr.git] / src / postrr.sql.in
index 22ce15ca3eaa2affab83f5188a30a25244fa63b2..9f34f22100cfd04151da1afb56ca23ec2c3538d8 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,45 +108,64 @@ CREATE CAST (rrtimeslice AS rrtimeslice)
        WITH FUNCTION RRTimeslice(rrtimeslice, integer, boolean)
        AS IMPLICIT;
 
-CREATE OR REPLACE FUNCTION RRTimeslice_eq(rrtimeslice, rrtimeslice)
+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 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_eq'
+       AS 'postrr-@POSTRR_MAJOR_VERSION@.@POSTRR_MINOR_VERSION@', 'rrtimeslice_seq_eq'
        LANGUAGE 'C' IMMUTABLE STRICT;
 
-CREATE OR REPLACE FUNCTION RRTimeslice_ne(rrtimeslice, rrtimeslice)
+CREATE OR REPLACE FUNCTION rrtimeslice_seq_ne(rrtimeslice, rrtimeslice)
        RETURNS boolean
-       AS 'postrr-@POSTRR_MAJOR_VERSION@.@POSTRR_MINOR_VERSION@', 'rrtimeslice_ne'
+       AS 'postrr-@POSTRR_MAJOR_VERSION@.@POSTRR_MINOR_VERSION@', 'rrtimeslice_seq_ne'
        LANGUAGE 'C' IMMUTABLE STRICT;
 
-CREATE OR REPLACE FUNCTION RRTimeslice_lt(rrtimeslice, rrtimeslice)
+CREATE OR REPLACE FUNCTION rrtimeslice_seq_lt(rrtimeslice, rrtimeslice)
        RETURNS boolean
-       AS 'postrr-@POSTRR_MAJOR_VERSION@.@POSTRR_MINOR_VERSION@', 'rrtimeslice_lt'
+       AS 'postrr-@POSTRR_MAJOR_VERSION@.@POSTRR_MINOR_VERSION@', 'rrtimeslice_seq_lt'
        LANGUAGE 'C' IMMUTABLE STRICT;
 
-CREATE OR REPLACE FUNCTION RRTimeslice_le(rrtimeslice, rrtimeslice)
+CREATE OR REPLACE FUNCTION rrtimeslice_seq_le(rrtimeslice, rrtimeslice)
        RETURNS boolean
-       AS 'postrr-@POSTRR_MAJOR_VERSION@.@POSTRR_MINOR_VERSION@', 'rrtimeslice_le'
+       AS 'postrr-@POSTRR_MAJOR_VERSION@.@POSTRR_MINOR_VERSION@', 'rrtimeslice_seq_le'
        LANGUAGE 'C' IMMUTABLE STRICT;
 
-CREATE OR REPLACE FUNCTION RRTimeslice_gt(rrtimeslice, rrtimeslice)
+CREATE OR REPLACE FUNCTION rrtimeslice_seq_gt(rrtimeslice, rrtimeslice)
        RETURNS boolean
-       AS 'postrr-@POSTRR_MAJOR_VERSION@.@POSTRR_MINOR_VERSION@', 'rrtimeslice_gt'
+       AS 'postrr-@POSTRR_MAJOR_VERSION@.@POSTRR_MINOR_VERSION@', 'rrtimeslice_seq_gt'
        LANGUAGE 'C' IMMUTABLE STRICT;
 
-CREATE OR REPLACE FUNCTION RRTimeslice_ge(rrtimeslice, rrtimeslice)
+CREATE OR REPLACE FUNCTION rrtimeslice_seq_ge(rrtimeslice, rrtimeslice)
        RETURNS boolean
-       AS 'postrr-@POSTRR_MAJOR_VERSION@.@POSTRR_MINOR_VERSION@', 'rrtimeslice_ge'
+       AS 'postrr-@POSTRR_MAJOR_VERSION@.@POSTRR_MINOR_VERSION@', 'rrtimeslice_seq_ge'
        LANGUAGE 'C' IMMUTABLE STRICT;
 
-CREATE OR REPLACE FUNCTION RRTimeslice_cmp(rrtimeslice, rrtimeslice)
+CREATE OR REPLACE FUNCTION rrtimeslice_seq_cmp(rrtimeslice, rrtimeslice)
        RETURNS integer
-       AS 'postrr-@POSTRR_MAJOR_VERSION@.@POSTRR_MINOR_VERSION@', 'rrtimeslice_cmp'
+       AS 'postrr-@POSTRR_MAJOR_VERSION@.@POSTRR_MINOR_VERSION@', 'rrtimeslice_seq_cmp'
+       LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION rrtimeslice_seq_hash(rrtimeslice)
+       RETURNS integer
+       AS 'postrr-@POSTRR_MAJOR_VERSION@.@POSTRR_MINOR_VERSION@', 'rrtimeslice_seq_hash'
        LANGUAGE 'C' IMMUTABLE STRICT;
 
 CREATE OPERATOR = (
        LEFTARG    = RRTimeslice,
        RIGHTARG   = RRTimeslice,
-       PROCEDURE  = RRTimeslice_eq,
+       PROCEDURE  = rrtimeslice_seq_eq,
        COMMUTATOR = =,
        NEGATOR    = <>,
        RESTRICT   = eqsel
@@ -147,7 +174,7 @@ CREATE OPERATOR = (
 CREATE OPERATOR <> (
        LEFTARG    = RRTimeslice,
        RIGHTARG   = RRTimeslice,
-       PROCEDURE  = RRTimeslice_ne,
+       PROCEDURE  = rrtimeslice_seq_ne,
        COMMUTATOR = <>,
        NEGATOR    = =,
        RESTRICT   = neqsel
@@ -156,7 +183,7 @@ CREATE OPERATOR <> (
 CREATE OPERATOR < (
        LEFTARG    = RRTimeslice,
        RIGHTARG   = RRTimeslice,
-       PROCEDURE  = RRTimeslice_lt,
+       PROCEDURE  = rrtimeslice_seq_lt,
        COMMUTATOR = >,
        NEGATOR    = <=,
        RESTRICT   = scalarltsel
@@ -165,7 +192,7 @@ CREATE OPERATOR < (
 CREATE OPERATOR <= (
        LEFTARG    = RRTimeslice,
        RIGHTARG   = RRTimeslice,
-       PROCEDURE  = RRTimeslice_le,
+       PROCEDURE  = rrtimeslice_seq_le,
        COMMUTATOR = >=,
        NEGATOR    = <,
        RESTRICT   = scalarltsel
@@ -174,7 +201,7 @@ CREATE OPERATOR <= (
 CREATE OPERATOR > (
        LEFTARG    = RRTimeslice,
        RIGHTARG   = RRTimeslice,
-       PROCEDURE  = RRTimeslice_gt,
+       PROCEDURE  = rrtimeslice_seq_gt,
        COMMUTATOR = <,
        NEGATOR    = >=,
        RESTRICT   = scalargtsel
@@ -183,7 +210,7 @@ CREATE OPERATOR > (
 CREATE OPERATOR >= (
        LEFTARG    = RRTimeslice,
        RIGHTARG   = RRTimeslice,
-       PROCEDURE  = RRTimeslice_ge,
+       PROCEDURE  = rrtimeslice_seq_ge,
        COMMUTATOR = <=,
        NEGATOR    = >,
        RESTRICT   = scalargtsel
@@ -196,7 +223,12 @@ CREATE OPERATOR CLASS rrtimeslice_ops
                OPERATOR 3 = ,
                OPERATOR 4 >= ,
                OPERATOR 5 > ,
-               FUNCTION 1 RRTimeslice_cmp(rrtimeslice, rrtimeslice);
+               FUNCTION 1 rrtimeslice_seq_cmp(rrtimeslice, rrtimeslice);
+
+CREATE OPERATOR CLASS rrtimeslice_hash_ops
+       FOR TYPE RRTimeslice USING hash AS
+               OPERATOR 1 = ,
+               FUNCTION 1 rrtimeslice_seq_hash(rrtimeslice);
 
 CREATE TYPE CData;
 
@@ -219,14 +251,150 @@ CREATE OR REPLACE FUNCTION CData_out(CData)
        AS 'postrr-@POSTRR_MAJOR_VERSION@.@POSTRR_MINOR_VERSION@', 'cdata_out'
        LANGUAGE 'C' IMMUTABLE STRICT;
 
+CREATE OR REPLACE FUNCTION CData_typmodin(cstring[])
+       RETURNS integer
+       AS 'postrr-@POSTRR_MAJOR_VERSION@.@POSTRR_MINOR_VERSION@', 'cdata_typmodin'
+       LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION CData_typmodout(integer)
+       RETURNS cstring
+       AS 'postrr-@POSTRR_MAJOR_VERSION@.@POSTRR_MINOR_VERSION@', 'cdata_typmodout'
+       LANGUAGE 'C' IMMUTABLE STRICT;
+
 CREATE TYPE CData (
        INTERNALLENGTH = 24,
        INPUT          = CData_in,
        OUTPUT         = CData_out,
+       TYPMOD_IN      = CData_typmodin,
+       TYPMOD_OUT     = CData_typmodout,
        ALIGNMENT      = double,
        STORAGE        = plain
 );
 
+CREATE OR REPLACE FUNCTION CData(cdata, integer, boolean)
+       RETURNS cdata
+       AS 'postrr-@POSTRR_MAJOR_VERSION@.@POSTRR_MINOR_VERSION@', 'cdata_to_cdata'
+       LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE CAST (cdata AS cdata)
+       WITH FUNCTION CData(cdata, integer, boolean)
+       AS IMPLICIT;
+
+CREATE CAST (numeric AS cdata)
+       WITH INOUT
+       AS ASSIGNMENT;
+
+CREATE OR REPLACE FUNCTION CData(integer, integer, boolean)
+       RETURNS cdata
+       AS 'postrr-@POSTRR_MAJOR_VERSION@.@POSTRR_MINOR_VERSION@', 'int32_to_cdata'
+       LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE CAST (integer AS cdata)
+       WITH FUNCTION CData(integer, integer, boolean)
+       AS ASSIGNMENT;
+
+CREATE OR REPLACE FUNCTION Float8(cdata)
+       RETURNS double precision
+       AS 'postrr-@POSTRR_MAJOR_VERSION@.@POSTRR_MINOR_VERSION@', 'cdata_to_float8'
+       LANGUAGE 'C' IMMUTABLE STRICT;
+
+CREATE CAST (cdata AS double precision)
+       WITH FUNCTION Float8(cdata);
+       -- EXPLICIT
+
+CREATE OR REPLACE FUNCTION CData_update(cdata, cdata)
+       RETURNS 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
+
+       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;