Thread: plpgsql, fk inherited tables

plpgsql, fk inherited tables

From
Nico
Date:
Hi!

I'm trying to get the unique foreign key feature for inherited tables.
There's a problem with plpgsql that I don't understand, could you see
what's wrong?
Comments are well appreciated.

I created a function that given a <name>, tries to return the sequence from
<name>_id_seq

CREATE FUNCTION next_seq_inh_key(text) RETURNS int4 AS '
  DECLARE
         rec RECORD;
         t text;
  BEGIN
         t := $1 || ''_id_seq'';
         SELECT INTO rec nextval( t::text) as id;
         RETURN rec.id;
  END;
' LANGUAGE 'plpgsql';


This works well when invoked manually from psql.
But from the following function (that is triggered) it doesn't work
properly, it yields the following
ERROR:  parser: parse error at or near "$1"

CREATE FUNCTION update_tree() RETURNS OPAQUE AS ' --
    DECLARE
         sequence int4;
         rec RECORD;
         treename text;
         currtable text;
         keytable text;
         typetable text;
         t text;

    BEGIN
         treename := TG_ARGV[0];
         currtable := TG_RELNAME;
         sequence := next_seq_inh_key(treename); -- !!! this is problemful

         -- t := treename || ''_id_seq''; -- !!! even this way is problemful
         -- sequence := nextval( t::text); -- !!!

         keytable := ''inhkeys_'' || treename;
         typetable := ''inhtypes_'' || treename;

         IF TG_OP = ''INSERT'' THEN
          SELECT INTO rec * FROM typetable WHERE "tablename" = currtable;
          INSERT INTO keytable ("id", "type") VALUES (sequence, rec.type);
          NEW.id := sequence;
      RETURN NEW;

         ELSEIF TG_OP = ''DELETE'' THEN
          DELETE FROM keytable WHERE "id" = OLD.id;

--       ELSEIF TG_OP = ''UPDATE''  --

         END IF;

    END;
' LANGUAGE 'plpgsql';



=============================================
Here's the complete script that you may use for testing the problem:

CREATE FUNCTION next_seq_inh_key(text) RETURNS int4 AS '
  DECLARE
    rec RECORD;
         -- n int4;
         t text;

  BEGIN
         t := $1 || ''_id_seq'';
         SELECT INTO rec nextval( t::text) as id;
         RETURN rec.id;
  END;
' LANGUAGE 'plpgsql';



CREATE FUNCTION update_tree() RETURNS OPAQUE AS ' --
    DECLARE
         sequence int4;
         rec RECORD;
         treename text;
         currtable text;
         keytable text;
         typetable text;
         t text;

    BEGIN
         treename := TG_ARGV[0];
         currtable := TG_RELNAME;
         -- sequence := next_seq_inh_key(treename);
         t := treename || ''_id_seq'';
         sequence := nextval( t::text);
         keytable := ''inhkeys_'' || treename;
         typetable := ''inhtypes_'' || treename;

         IF TG_OP = ''INSERT'' THEN
          SELECT INTO rec * FROM typetable WHERE "tablename" = currtable;
          INSERT INTO keytable ("id", "type") VALUES (sequence, rec.type);
          NEW.id := sequence;
      RETURN NEW;

         ELSEIF TG_OP = ''DELETE'' THEN
          DELETE FROM keytable WHERE "id" = OLD.id;

--       ELSEIF TG_OP = ''UPDATE'' -- c

         END IF;

    END;
' LANGUAGE 'plpgsql';

-------------------------------------------------

CREATE SEQUENCE "people_id_seq"  increment 1  minvalue 10000  maxvalue
2147483600  start 10000  cache 1  ;
SELECT * from "people_id_seq";

CREATE TABLE "inhkeys_people" (
  "id" int4, -- the unique key across all elements across inherited tables
  "type" int2
);
CREATE UNIQUE INDEX inhkeys_uidx_id ON inhkeys_people(id);

CREATE TABLE "inhtypes_people" (
  "type" int2,
  "tablename" text
);





INSERT INTO "inhtypes_people" (type, tablename)
  VALUES (10, 'people');

CREATE TABLE "people" (
  "id" int4,
  "info" text
);


CREATE TRIGGER people_refkey BEFORE INSERT OR DELETE ON people
         FOR EACH ROW EXECUTE PROCEDURE update_tree('people');

ALTER TABLE "people" ADD CONSTRAINT people_fk_inhkeys_people
         FOREIGN KEY (id) REFERENCES inhkeys_people(id) INITIALLY DEFERRED;

CREATE UNIQUE INDEX people_uidx_id ON people(id);





INSERT INTO "inhtypes_people" (type, tablename)
  VALUES (20, 'student');

CREATE TABLE "student" (
  "matr" text
) inherits ("people");

ALTER TABLE "student" ADD CONSTRAINT student_fk_inhkeys_people
         FOREIGN KEY (id) REFERENCES inhkeys_people(id) INITIALLY DEFERRED;

CREATE UNIQUE INDEX student_uidx_id ON student(id);

CREATE TRIGGER student_refkey BEFORE INSERT OR DELETE ON student
         FOR EACH ROW EXECUTE PROCEDURE update_tree('people');


INSERT INTO student ('info', 'matr') VALUES ('blabla', '333');

Nico