OSSP CVS Repository

ossp - Check-in [3411]
Not logged in
[Honeypot]  [Browse]  [Home]  [Login]  [Reports
[Search]  [Ticket]  [Timeline
  [Patchset]  [Tagging/Branching

Check-in Number: 3411
Date: 2003-May-29 12:11:15 (local)
2003-May-29 10:11:15 (UTC)
User:rse
Branch:
Comment: add our AS stand-alone SQL and PL/pgSQL basic research stuff to CVS, too
Tickets:
Inspections:
Files:
ossp-pkg/as/as-db/bres/bres-cfg.sql      added-> 1.1
ossp-pkg/as/as-db/bres/bres-history.sql      added-> 1.1
ossp-pkg/as/as-db/bres/bres-index.sql      added-> 1.1
ossp-pkg/as/as-db/bres/bres-name2oid.sql      added-> 1.1
ossp-pkg/as/as-db/bres/bres-nonoverlap.sql      added-> 1.1
ossp-pkg/as/as-db/bres/bres-rule.sql      added-> 1.1
ossp-pkg/as/as-db/bres/bres-varval.sql      added-> 1.1

ossp-pkg/as/as-db/bres/bres-cfg.sql -> 1.1

*** /dev/null    Sat Nov 23 08:18:19 2024
--- -    Sat Nov 23 08:18:19 2024
***************
*** 0 ****
--- 1,74 ----
+ 
+ DROP TABLE as_config CASCADE;
+ CREATE TABLE as_config (
+     cf_var   TEXT,
+     cf_val   TEXT
+ );
+ DROP TABLE as_config_session CASCADE;
+ CREATE TABLE as_config_session (
+     cf_var   TEXT,
+     cf_val   TEXT
+ );
+ 
+ CREATE OR REPLACE FUNCTION as_session_start ()
+ RETURNS VOID LANGUAGE 'plpgsql' STABLE AS '
+ BEGIN
+     CREATE LOCAL TEMPORARY TABLE as_config
+         AS SELECT * FROM as_config;
+     RETURN;
+ END;
+ ';
+ CREATE OR REPLACE FUNCTION as_session_end ()
+ RETURNS VOID LANGUAGE 'sql' STABLE AS '
+     DROP TABLE as_config;
+ ';
+ CREATE OR REPLACE FUNCTION as_session_var (TEXT)
+ RETURNS TEXT LANGUAGE 'sql' STABLE AS '
+     SELECT cf_val FROM as_config WHERE cf_var = $1;
+ ';
+ CREATE OR REPLACE FUNCTION as_session_var (TEXT, TEXT)
+ RETURNS TEXT LANGUAGE 'plpgsql' STABLE AS '
+ DECLARE
+     old TEXT;
+ BEGIN
+     old := (SELECT cf_val FROM as_config WHERE cf_var = $1);
+     UPDATE as_config SET cf_val = $2 WHERE cf_var = $1;
+     return old;
+ END;
+ ';
+ 
+ CREATE OR REPLACE FUNCTION as_config_val (TEXT)
+ RETURNS TEXT LANGUAGE 'plpgsql' STABLE AS '
+ DECLARE
+     var ALIAS FOR $1; 
+     val TEXT;
+ BEGIN
+     val := NULL;
+     IF (SELECT tablename FROM pg_tables
+         WHERE tablename = ''as_config_session'') IS NOT NULL THEN
+         val := (SELECT cf_val FROM as_config_session WHERE cf_var = var);
+     END IF;
+     IF val IS NULL THEN
+         val := (SELECT cf_val FROM as_config WHERE cf_var = var);
+     END IF;
+     RETURN val;
+ END;
+ ';
+ 
+ INSERT INTO as_config VALUES ('foo', '1');
+ INSERT INTO as_config VALUES ('bar',  '2');
+ -- INSERT INTO as_config_session VALUES ('quux', '3');
+ -- INSERT INTO as_config_session VALUES ('bar', '4');
+ 
+ -- SELECT * FROM as_config;
+ -- SELECT * FROM as_config_session;
+ 
+ SELECT as_session_start();
+ SELECT as_session_var('non-existing');
+ SELECT as_session_var('foo');
+ SELECT as_session_var('bar');
+ SELECT as_session_var('quux');
+ SELECT as_session_end();
+ 
+ SELECT cf_var,as_session_var(cf_var) FROM as_config UNION (SELECT cf_var,cf_val FROM as_config_session);
+ 


ossp-pkg/as/as-db/bres/bres-history.sql -> 1.1

*** /dev/null    Sat Nov 23 08:18:19 2024
--- -    Sat Nov 23 08:18:19 2024
***************
*** 0 ****
--- 1,296 ----
+ 
+ -- ##
+ -- ##  Create Database Schema
+ -- ##
+ 
+ DROP TABLE ac CASCADE;
+ CREATE TABLE ac(
+     ac_oid    INTEGER,
+     ac_name   TEXT,
+     ac_hid    INTEGER
+ );
+ 
+ DROP SEQUENCE st_seq CASCADE;
+ CREATE SEQUENCE st_seq
+     INCREMENT 1 MINVALUE 1 START 1;
+ 
+ DROP TABLE st CASCADE;
+ CREATE TABLE st (
+     st_oid    INTEGER,
+     st_hid    INTEGER DEFAULT nextval('st_seq') NOT NULL,
+               -- discrete monton increasing value assigned to system time
+     st_beg    INTEGER
+               -- system time when system change occurred
+ );
+ 
+ DROP TABLE ut CASCADE;
+ CREATE TABLE ut (
+     ut_oid    INTEGER,
+     ut_beg    INTEGER,
+     ut_end    INTEGER,
+     ut_hid    INTEGER
+ );
+ 
+ DROP TABLE ut_no CASCADE;
+ CREATE TABLE ut_no (
+     ut_oid    INTEGER,
+     ut_beg    INTEGER,
+     ut_end    INTEGER,
+     ut_hid    INTEGER,
+     ut_shid   INTEGER
+ );
+ 
+ -- ##
+ -- ##  Update ut_no table for ut change on particular OID
+ -- ##
+ 
+ --  Update function
+ DROP FUNCTION ut_update(INTEGER, INTEGER) CASCADE;
+ CREATE FUNCTION ut_update(INTEGER, INTEGER) 
+ RETURNS VOID LANGUAGE 'plpgsql' STABLE AS '
+ DECLARE
+     oid INTEGER;
+     hid INTEGER;
+     pos_prev INTEGER;
+     pos_this INTEGER;
+     pos_next INTEGER;
+     alt_this INTEGER;
+     alt_prev INTEGER;
+ BEGIN
+     oid := $1;
+     hid := $2;
+ 
+     --  delete all old entries corresponding to OID
+     DELETE FROM ut_no WHERE ut_oid = oid AND ut_shid = hid;
+ 
+     --  initialize iteration variables
+     pos_prev := -1;
+     pos_this := -1;
+     pos_next := NULL;
+     alt_this := NULL;
+     alt_prev := NULL;
+ 
+     LOOP
+         --  determine next position from existing begin/end positions
+         pos_next := (
+             SELECT min(v) FROM (
+                     (SELECT min(ut_beg) FROM ut WHERE ut_beg > pos_this AND ut_oid = oid AND ut_hid <= hid)
+               UNION (SELECT min(ut_end) FROM ut WHERE ut_end > pos_this AND ut_oid = oid AND ut_hid <= hid)
+             ) AS result (v)
+         );
+         IF pos_next IS NULL THEN
+             pos_next := 9999;
+         END IF;
+ 
+         --  determine current altidude
+         alt_this := (
+             SELECT max(ut_hid) FROM ut
+             WHERE ut_beg <= pos_this AND pos_this < ut_end AND ut_oid = oid AND ut_hid <= hid
+         );
+         IF alt_this IS NULL THEN
+             alt_this := -1;
+         END IF;
+ 
+         -- RAISE NOTICE ''pos_this = %, pos_next = %, alt_this = %'', pos_this, pos_next, alt_this;
+ 
+         IF alt_this = -1 THEN
+             -- RAISE NOTICE ''hit ground - pruning entry'';
+         ELSE
+             IF alt_this = alt_prev THEN
+                 -- RAISE NOTICE ''keeping altitude - consolidating entry'';
+                 UPDATE ut_no SET ut_end = pos_next
+                     WHERE ut_hid = alt_this AND ut_beg = pos_prev AND ut_end = pos_this AND ut_oid = oid AND ut_shid = hid;
+             ELSE
+                 -- RAISE NOTICE ''changing altitude - new entry'';
+                 INSERT INTO ut_no (ut_hid, ut_oid, ut_beg, ut_end, ut_shid)
+                     VALUES (alt_this, oid, pos_this, pos_next, hid);
+                 pos_prev := pos_this;
+             END IF;
+         END IF;
+ 
+         --  stop if maximum is reached
+         IF pos_next >= 9999 THEN
+            EXIT;
+         END IF;
+ 
+         --  move one step
+         pos_this := pos_next;
+         alt_prev := alt_this;
+     END LOOP;
+     RETURN;
+ END;
+ ';
+ 
+ --  Trigger Stub Function
+ DROP FUNCTION ut_trigger() CASCADE;
+ CREATE FUNCTION ut_trigger() 
+ RETURNS TRIGGER LANGUAGE 'plpgsql' STABLE AS '
+ BEGIN
+     IF TG_OP = ''INSERT'' OR TG_OP = ''UPDATE'' THEN
+         PERFORM ut_update(NEW.ut_oid, NEW.ut_hid);
+     ELSE
+         IF TG_OP = ''DELETE'' THEN
+             PERFORM ut_update(OLD.ut_oid, OLD.ut_hid);
+         END IF;
+     END IF;
+     RETURN NULL;
+ END;
+ ';
+ 
+ --  Global Trigger
+ -- DROP TRIGGER ut_trigger ON ut CASCADE;
+ CREATE TRIGGER ut_trigger
+     AFTER INSERT OR UPDATE OR DELETE
+     ON ut FOR EACH ROW
+     EXECUTE PROCEDURE ut_trigger ();
+ 
+ -- ##
+ -- ##   Dynamic History Table
+ -- ##   <oid, hid-max>* := as_hs(ut_beg, ut_end[, st_beg, st_end[, st_max]])
+ -- ##
+ 
+ -- This finds (optionally only maximum) oid/hid combinations between
+ -- st_beg and st_end (both inclusive) system time, for which the
+ -- user time touches the time range between ut_beg and ut_end (both
+ -- inclusive).
+ 
+ DROP TYPE as_hs_t CASCADE;
+ CREATE TYPE as_hs_t AS (
+     hs_oid INTEGER,
+     hs_hid INTEGER
+ );
+ CREATE OR REPLACE FUNCTION as_hs(INTEGER, INTEGER, INTEGER, INTEGER, INTEGER)
+ RETURNS SETOF as_hs_t LANGUAGE 'plpgsql' STABLE AS '
+ DECLARE
+     arg_ut_beg INTEGER; -- user   time begin (including)
+     arg_ut_end INTEGER; -- user   time end   (including)
+     arg_st_beg INTEGER; -- system time begin (including)
+     arg_st_end INTEGER; -- system time end   (including)
+     arg_st_max INTEGER; -- whether to take only maximum system time into account
+     rec RECORD;
+ BEGIN
+     --  pre-process input arguments by providing reasonable defaults
+     arg_ut_beg := $1; IF arg_ut_beg IS NULL THEN arg_ut_beg := 0;    END IF;
+     arg_ut_end := $2; IF arg_ut_end IS NULL THEN arg_ut_end := 9999; END IF;
+     arg_st_beg := $3; IF arg_st_beg IS NULL THEN arg_st_beg := 0;    END IF;
+     arg_st_end := $4; IF arg_st_end IS NULL THEN arg_st_end := 9999; END IF;
+     arg_st_max := $5; IF arg_st_max IS NULL THEN arg_st_max := 1;    END IF;
+     
+     --  perform the query operation
+     IF arg_st_max = 1 THEN
+         --  variant 1: take only maximum system time for each user time and oid
+         FOR rec IN
+            SELECT ut_oid, ut_hid
+            FROM ut_no, (
+                SELECT   st_oid, max(st_hid) AS st_hid
+                FROM     st 
+                WHERE    (arg_st_beg <= st_beg AND st_beg <= arg_st_end)
+                GROUP BY st_oid
+            ) AS st
+            WHERE
+                ut_oid = st_oid AND ut_shid = st_hid
+                AND (ut_beg <= arg_ut_end AND arg_ut_beg < ut_end)
+         LOOP
+            RETURN NEXT rec;
+         END LOOP;
+     ELSE
+         --  variant 2: take all system times for each user time and oid
+         FOR rec IN
+            SELECT ut_oid, ut_hid
+            FROM ut_no, (
+                SELECT   st_oid, st_hid
+                FROM     st 
+                WHERE    (arg_st_beg <= st_beg AND st_beg <= arg_st_end)
+            ) AS st
+            WHERE
+                ut_oid  = st_oid AND ut_shid = st_hid
+                AND (ut_beg <= arg_ut_end AND arg_ut_beg < ut_end)
+         LOOP
+            RETURN NEXT rec;
+         END LOOP;
+     END IF;
+     RETURN;
+ END;
+ ';
+ 
+ --  convinience overloaded function: without "st_max"
+ CREATE OR REPLACE FUNCTION as_hs(INTEGER, INTEGER, INTEGER, INTEGER)
+ RETURNS SETOF as_hs_t LANGUAGE 'sql' STABLE AS '
+     SELECT * FROM as_hs($1, $2, $3, $4, NULL);
+ ';
+ 
+ --  convinience overloaded function: without "st" at all
+ CREATE OR REPLACE FUNCTION as_hs(INTEGER, INTEGER)
+ RETURNS SETOF as_hs_t LANGUAGE 'sql' STABLE AS '
+     SELECT * FROM as_hs($1, $2, NULL, NULL, NULL);
+ ';
+ 
+ --  convinience overloaded function: without "ut" and "st" at all
+ CREATE OR REPLACE FUNCTION as_hs()
+ RETURNS SETOF as_hs_t LANGUAGE 'sql' STABLE AS '
+     SELECT * FROM as_hs(NULL, NULL, NULL, NULL, NULL);
+ ';
+ 
+ -- ##
+ -- ##  Test Data
+ -- ##
+ 
+ -- INSERT INTO ac VALUES (11, 'foo',  1);
+ -- INSERT INTO ac VALUES (10, 'foo2', 3);
+ -- INSERT INTO ac VALUES (10, 'foo3', 5);
+ -- INSERT INTO ac VALUES (10, 'foo',  7);
+ -- INSERT INTO ac VALUES (10, 'foo',  9);
+ -- 
+ -- INSERT INTO ac VALUES (20, 'bar',  2);
+ -- INSERT INTO ac VALUES (20, 'bar2', 4);
+ -- INSERT INTO ac VALUES (20, 'bar3', 6);
+ -- INSERT INTO ac VALUES (20, 'bar',  8);
+ -- INSERT INTO ac VALUES (20, 'bar',  10);
+ -- 
+ -- INSERT INTO st (st_oid,st_beg) VALUES (10, 100);
+ -- INSERT INTO st (st_oid,st_beg) VALUES (20, 110);
+ -- INSERT INTO st (st_oid,st_beg) VALUES (10, 120);
+ -- INSERT INTO st (st_oid,st_beg) VALUES (20, 130);
+ -- INSERT INTO st (st_oid,st_beg) VALUES (10, 140);
+ -- INSERT INTO st (st_oid,st_beg) VALUES (20, 150);
+ -- INSERT INTO st (st_oid,st_beg) VALUES (10, 160);
+ -- INSERT INTO st (st_oid,st_beg) VALUES (20, 170);
+ -- 
+ -- INSERT INTO ut VALUES (10, 100, 9999, 1);
+ -- INSERT INTO ut VALUES (10, 102, 9999, 3);
+ -- INSERT INTO ut VALUES (10, 104, 9999, 5);
+ -- INSERT INTO ut VALUES (10, 106, 9999, 7);
+ -- INSERT INTO ut VALUES (10, 100, 200,  9);
+ -- 
+ -- INSERT INTO ut VALUES (20, 101, 9999,  2);
+ -- INSERT INTO ut VALUES (20, 103, 9999,  4);
+ -- INSERT INTO ut VALUES (20, 105, 9999,  6);
+ -- INSERT INTO ut VALUES (20, 107, 9999,  8);
+ -- INSERT INTO ut VALUES (20, 100, 200,  10);
+ -- INSERT INTO ut VALUES (20, 300, 400,  10);
+ -- INSERT INTO ut VALUES (20, 500, 600,  10);
+ 
+ INSERT INTO st (st_oid,st_beg) VALUES (10, 2001);
+ INSERT INTO ut VALUES (10, 100, 200, currval('st_seq'));
+ INSERT INTO ac VALUES (10, 'foo', currval('st_seq'));
+ 
+ INSERT INTO st (st_oid,st_beg) VALUES (10, 2002);
+ INSERT INTO ut VALUES (10, 200, 300, currval('st_seq'));
+ INSERT INTO ac VALUES (10, 'bar', currval('st_seq'));
+ 
+ INSERT INTO st (st_oid,st_beg) VALUES (10, 2004);
+ INSERT INTO ut VALUES (10, 100, 9999, currval('st_seq'));
+ INSERT INTO ac VALUES (10, 'foo', currval('st_seq'));
+ 
+ INSERT INTO st (st_oid,st_beg) VALUES (20, 2005);
+ INSERT INTO ut VALUES (20, 100, 9999, currval('st_seq'));
+ INSERT INTO ac VALUES (20, 'bar1', currval('st_seq'));
+ 
+ INSERT INTO st (st_oid,st_beg) VALUES (20, 2006);
+ INSERT INTO ut VALUES (20, 200, 9999, currval('st_seq'));
+ INSERT INTO ac VALUES (20, 'bar2', currval('st_seq'));
+ 
+ INSERT INTO st (st_oid,st_beg) VALUES (20, 2007);
+ INSERT INTO ut VALUES (20, 200, 300, currval('st_seq'));
+ INSERT INTO ac VALUES (20, 'bar3', currval('st_seq'));
+ 


ossp-pkg/as/as-db/bres/bres-index.sql -> 1.1

*** /dev/null    Sat Nov 23 08:18:19 2024
--- -    Sat Nov 23 08:18:19 2024
***************
*** 0 ****
--- 1,25 ----
+ 
+ DROP TABLE bar;
+ CREATE TABLE bar (
+     id     INTEGER,
+     parent INTEGER,
+     name   TEXT
+ );
+ 
+ CREATE UNIQUE INDEX bar_idx1 ON bar USING btree (id);
+ CREATE UNIQUE INDEX bar_idx2 ON bar USING btree (name);
+ CREATE UNIQUE INDEX bar_idx3 ON bar USING btree (id, name);
+ 
+ INSERT INTO bar VALUES (1, 1, '');
+ INSERT INTO bar VALUES (2, 1, 'a');
+ INSERT INTO bar VALUES (3, 2, 'b');
+ INSERT INTO bar VALUES (4, 3, 'c');
+ INSERT INTO bar VALUES (5, 3, 'C');
+ INSERT INTO bar VALUES (6, 1, 'x');
+ INSERT INTO bar VALUES (7, 6, 'y');
+ INSERT INTO bar VALUES (8, 7, 'z');
+ INSERT INTO bar VALUES (9, 7, 'Z');
+ 
+ 
+ SELECT * FROM bar;
+ 


ossp-pkg/as/as-db/bres/bres-name2oid.sql -> 1.1

*** /dev/null    Sat Nov 23 08:18:19 2024
--- -    Sat Nov 23 08:18:19 2024
***************
*** 0 ****
--- 1,116 ----
+ 
+ DROP TABLE foo;
+ CREATE TABLE foo (
+     id     INTEGER,
+     parent INTEGER,
+     name   TEXT
+ );
+ 
+ INSERT INTO foo VALUES (1, 1, '');
+ INSERT INTO foo VALUES (2, 1, 'a');
+ INSERT INTO foo VALUES (3, 2, 'b');
+ INSERT INTO foo VALUES (4, 3, 'c');
+ INSERT INTO foo VALUES (5, 3, 'C');
+ INSERT INTO foo VALUES (6, 1, 'x');
+ INSERT INTO foo VALUES (7, 6, 'y');
+ INSERT INTO foo VALUES (8, 7, 'z');
+ INSERT INTO foo VALUES (9, 7, 'Z');
+ 
+ DROP FUNCTION name2oid(TEXT);
+ CREATE FUNCTION name2oid(TEXT) 
+ RETURNS INTEGER LANGUAGE 'plpgsql' STABLE AS '
+ DECLARE
+     comp TEXT;
+     path TEXT;
+     oid INTEGER;
+ BEGIN
+     RAISE NOTICE ''name2oid(%)'', $1;
+     path := $1;
+     IF substr(path, 1, 1) != ''/'' THEN
+         RAISE EXCEPTION ''name2oid(%): path not starting with slash'', $1;
+     END IF;
+     oid := (SELECT id FROM foo
+         WHERE name = '''' AND parent = id);
+     IF oid IS NULL THEN
+         RAISE EXCEPTION ''name2oid(%): root path component not found'', $1;
+     END IF;
+     path := substr(path, 2);
+     -- RAISE NOTICE ''name2oid: "/" -> %'', oid;
+     WHILE path != '''' LOOP
+         comp := substring(path from ''^([^/]+)/*'');
+         path := substring(path from ''^[^/]+/*(.*)$'');
+         oid := (SELECT id FROM foo
+             WHERE name = comp AND parent = oid);
+         IF oid IS NULL THEN
+             RAISE EXCEPTION ''name2oid(%): path component "%" not found'', $1, comp, path;
+         END IF;
+         -- RAISE NOTICE ''name2oid: "%" -> %'', comp, oid;
+     END LOOP;
+     RAISE NOTICE ''name2oid(%) = %'', $1, oid;
+     RETURN oid;
+ END;
+ ';
+ 
+ DROP FUNCTION oid2name(TEXT);
+ CREATE FUNCTION oid2name(TEXT) 
+ RETURNS TEXT LANGUAGE 'plpgsql' AS '
+ DECLARE
+     oid INTEGER;
+     name TEXT;
+     obj RECORD;
+ BEGIN
+     RAISE NOTICE ''oid2name(%)'', $1;
+     oid := $1;
+     name := '''';
+     LOOP
+         SELECT * INTO obj FROM foo WHERE id = oid;
+         IF NOT FOUND THEN
+             RAISE EXCEPTION ''oid2name(%): object % not found'', $1, oid;
+         END IF;
+         -- RAISE NOTICE ''oid2name: % -> "%"'', oid, obj.name;
+         IF obj.parent = oid THEN
+             EXIT;
+         END IF;
+         name := ''/'' || obj.name || name;
+         oid := obj.parent;
+     END LOOP;
+     IF name = '''' THEN
+         name = ''/'';
+     END IF;
+     RAISE NOTICE ''oid2name(%) = %'', $1, name;
+     RETURN name;
+ END;
+ ';
+ 
+ SELECT * FROM foo WHERE id = (SELECT name2oid('/'));
+ SELECT * FROM foo WHERE id = (SELECT name2oid('/a/b/c'));
+ SELECT * FROM foo WHERE id = (SELECT name2oid('/x/y/z'));
+ 
+ SELECT oid2name(1);
+ SELECT oid2name(4);
+ SELECT oid2name(8);
+ SELECT *,oid2name(id) from foo;
+ 
+ BEGIN TRANSACTION;
+ SELECT * FROM foo WHERE id = name2oid('/x/y/z');
+ SELECT * FROM foo WHERE id = name2oid('/x/y/z');
+ COMMIT;
+ 
+ DROP FUNCTION fuck(TEXT);
+ CREATE FUNCTION fuck(TEXT) 
+ RETURNS TEXT LANGUAGE 'plpgsql' STABLE AS '
+ DECLARE
+     foo RECORD;
+ BEGIN
+     RAISE NOTICE ''fuck'';
+     SELECT * INTO foo FROM foo;
+     RETURN foo.name;
+ END;
+ ';
+ 
+ BEGIN TRANSACTION;
+ SELECT * FROM foo WHERE fuck('foo') != 'fuck';
+ SELECT * FROM foo WHERE fuck('foo') != 'fuck';
+ SELECT * FROM foo WHERE fuck('foo') != 'fuck';
+ COMMIT;
+ 


ossp-pkg/as/as-db/bres/bres-nonoverlap.sql -> 1.1

*** /dev/null    Sat Nov 23 08:18:19 2024
--- -    Sat Nov 23 08:18:19 2024
***************
*** 0 ****
--- 1,128 ----
+ 
+ DROP TABLE ht;
+ CREATE TABLE ht (
+     ht_hid    INTEGER,
+     ht_oid    INTEGER,
+     ht_vb     INTEGER,
+     ht_ve     INTEGER
+ );
+ 
+ DROP TABLE htno;
+ CREATE TABLE htno (
+     ht_hid    INTEGER,
+     ht_oid    INTEGER,
+     ht_vb     INTEGER,
+     ht_ve     INTEGER
+ );
+ 
+ --  Update htno table for ht change on particular OID
+ DROP FUNCTION ht2htno(INTEGER);
+ CREATE FUNCTION ht2htno(INTEGER) 
+ RETURNS INTEGER LANGUAGE 'plpgsql' STABLE AS '
+ DECLARE
+     oid INTEGER;
+     pos_prev INTEGER;
+     pos_this INTEGER;
+     pos_next INTEGER;
+     alt_this INTEGER;
+     alt_prev INTEGER;
+ BEGIN
+     oid := $1;
+ 
+     --  delete all old entries corresponding to OID
+     DELETE FROM htno WHERE ht_oid = oid;
+ 
+     --  initialize iteration variables
+     pos_prev := -1;
+     pos_this := -1;
+     pos_next := NULL;
+     alt_this := NULL;
+     alt_prev := NULL;
+ 
+     LOOP
+         --  determine next position from existing begin/end positions
+         pos_next := (
+             SELECT min(v) FROM (
+                     (SELECT min(ht_vb) FROM ht WHERE ht_vb > pos_this AND ht_oid = oid)
+               UNION (SELECT min(ht_ve) FROM ht WHERE ht_ve > pos_this AND ht_oid = oid)
+             ) AS result (v)
+         );
+         IF pos_next IS NULL THEN
+             pos_next := 9999;
+         END IF;
+ 
+         --  determine current altidude
+         alt_this := (SELECT max(ht_hid) FROM ht WHERE ht_vb <= pos_this AND pos_this < ht_ve AND ht_oid = oid);
+         IF alt_this IS NULL THEN
+             alt_this := -1;
+         END IF;
+ 
+         -- RAISE NOTICE ''pos_this = %, pos_next = %, alt_this = %'', pos_this, pos_next, alt_this;
+ 
+         IF alt_this = -1 THEN
+             -- RAISE NOTICE ''hit ground - pruning entry'';
+         ELSE
+             IF alt_this = alt_prev THEN
+                 -- RAISE NOTICE ''keeping altitude - consolidating entry'';
+                 UPDATE htno SET ht_ve = pos_next
+                     WHERE ht_hid = alt_this AND ht_vb = pos_prev AND ht_ve = pos_this AND ht_oid = oid;
+             ELSE
+                 -- RAISE NOTICE ''changing altitude - new entry'';
+                 INSERT INTO htno (ht_hid, ht_oid, ht_vb, ht_ve)
+                     VALUES (alt_this, oid, pos_this, pos_next);
+                 pos_prev := pos_this;
+             END IF;
+         END IF;
+ 
+         --  stop if maximum is reached
+         IF pos_next >= 9999 THEN
+            EXIT;
+         END IF;
+ 
+         --  move one step
+         pos_this := pos_next;
+         alt_prev := alt_this;
+     END LOOP;
+     RETURN 0;
+ END;
+ ';
+ 
+ --  Trigger Stub Function
+ DROP FUNCTION ht_trigger();
+ CREATE FUNCTION ht_trigger() 
+ RETURNS TRIGGER LANGUAGE 'plpgsql' STABLE AS '
+ BEGIN
+     IF TG_OP = ''INSERT'' OR TG_OP = ''UPDATE'' THEN
+         PERFORM ht2htno(NEW.ht_oid);
+     ELSE
+         IF TG_OP = ''DELETE'' THEN
+             PERFORM ht2htno(OLD.ht_oid);
+         END IF;
+     END IF;
+     RETURN NULL;
+ END;
+ ';
+ 
+ --  Global Trigger
+ CREATE TRIGGER ht_trigger
+     AFTER INSERT OR UPDATE OR DELETE
+     ON ht FOR EACH ROW
+     EXECUTE PROCEDURE ht_trigger ();
+ 
+ INSERT INTO ht VALUES (1, 1, 2, 4);
+ INSERT INTO ht VALUES (2, 1, 3, 6);
+ INSERT INTO ht VALUES (3, 1, 8, 9);
+ INSERT INTO ht VALUES (4, 1, 5, 6);
+ INSERT INTO ht VALUES (5, 1, 3, 5);
+ INSERT INTO ht VALUES (6, 1, 7, 8);
+ INSERT INTO ht VALUES (7, 1, 7, 9);
+ 
+ INSERT INTO ht VALUES (30, 2, 10, 14);
+ INSERT INTO ht VALUES (31, 2, 12, 17);
+ INSERT INTO ht VALUES (32, 2, 13, 15);
+ INSERT INTO ht VALUES (33, 2, 16, 19);
+ INSERT INTO ht VALUES (34, 2, 20, 22);
+ 
+ SELECT * FROM ht ORDER BY ht_hid;
+ SELECT * FROM htno ORDER BY ht_hid;
+ 


ossp-pkg/as/as-db/bres/bres-rule.sql -> 1.1

*** /dev/null    Sat Nov 23 08:18:19 2024
--- -    Sat Nov 23 08:18:19 2024
***************
*** 0 ****
--- 1,56 ----
+ 
+ -- Create Database Schema
+ DROP TABLE ac CASCADE;
+ CREATE TABLE ac(
+     ac_oid    INTEGER DEFAULT 100,
+     ac_name   TEXT,
+     ac_hid    INTEGER
+ );
+ 
+ DROP TABLE fo CASCADE;
+ CREATE TABLE fo(
+     ac_oid    INTEGER DEFAULT 100,
+     ac_name   TEXT,
+     ac_hid    INTEGER
+ );
+ 
+ -- DROP RULE "_RETURN";
+ -- CREATE OR REPLACE RULE "_RETURN" AS
+ --     ON SELECT TO fo
+ --     DO INSTEAD
+ --         -- SELECT * FROM ac WHERE ac_hid = 1;
+ --         -- SELECT ac_oid,ac_name,max(ac_hid) AS ac_hid FROM ac GROUP BY ac_oid,ac_name;
+ --         ( SELECT ac.ac_oid,ac.ac_name,ac.ac_hid FROM ac, ( SELECT ac_oid,max(ac_hid) AS ac_hid
+ --            FROM ac GROUP BY ac_oid) AS result WHERE ac.ac_oid = result.ac_oid AND
+ --           ac.ac_hid = result.ac_hid );
+ 
+ CREATE OR REPLACE RULE "fuck" AS
+     ON INSERT TO fo
+     DO INSTEAD
+         ( INSERT INTO ac VALUES (NEW.ac_oid, NEW.ac_name, NEW.ac_hid); );
+ 
+ CREATE OR REPLACE FUNCTION fo_func (INTEGER)
+ RETURNS SETOF fo LANGUAGE 'sql' AS '
+     SELECT * FROM ac WHERE ac_hid = $1;
+ ';
+ 
+ INSERT INTO ac VALUES (10, 'foo1', 1);
+ INSERT INTO ac VALUES (10, 'foo2', 2);
+ INSERT INTO ac VALUES (10, 'foo3', 3);
+ INSERT INTO ac VALUES (20, 'bar4', 1);
+ INSERT INTO ac VALUES (20, 'bar5', 2);
+ INSERT INTO ac VALUES (20, 'bar6', 3);
+ 
+ SELECT * FROM ac;
+ SELECT * FROM fo;
+ SELECT * FROM ac WHERE ac_oid = 10;
+ SELECT * FROM fo WHERE ac_oid = 10;
+ 
+ SELECT ac_name FROM (SELECT * FROM ac WHERE ac_hid = 1) AS foo WHERE ac_oid = 10;
+ SELECT ac_name FROM fo WHERE ac_oid = 10;
+ SELECT ac_name FROM fo_func(1) AS foo WHERE ac_oid = 10;
+ 
+ INSERT INTO fo (ac_name, ac_hid) VALUES ('quux1', 4);
+ 
+ -- Problem: fo requires same defaults for columns than ac!
+ 


ossp-pkg/as/as-db/bres/bres-varval.sql -> 1.1

*** /dev/null    Sat Nov 23 08:18:19 2024
--- -    Sat Nov 23 08:18:19 2024
***************
*** 0 ****
--- 1,11 ----
+ 
+ create table as_cfg (hid INTEGER DEFAULT 1, var TEXT UNIQUE, val TEXT);
+ create table as_cfg_tmp (hid INTEGER DEFAULT 2, var TEXT UNIQUE, val TEXT) inherits (as_cfg);
+ 
+ # select single variable
+ select var,val from as_cfg where var = 'foo' order by hid desc limit 1;
+ 
+ # select all variables
+ select as_cfg.var,as_cfg.val from as_cfg, ( select var,max(hid) as hid
+ from as_cfg group by var ) as foo where foo.var = as_cfg.var and foo.hid = as_cfg.hid;
+ 

CVSTrac 2.0.1