Search Postgresql Archives

Re: Stored Procedure and Trigger they puzzle me

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Lars Heidieker wrote:
> Hi all,
> 
> I just started to write my first stored procedure in plpgsql and
> installed a trigger for it.
> 
> The two Tables are:
> 
> CREATE TABLE ltlocation (
>   "id" integer DEFAULT nextval('ltlocation_id_seq'::text) NOT NULL,
>   name varchar(30) NOT NULL default '',
>   "description" varchar(254) NOT NULL default '',
>   "parent" int4,

I think you can do without this column; it's already defined by your
location path and it constrains your hierarchy to single parent nodes.

If you're sure single parent nodes are sufficient, you're probably
better off using the ltree contrib package. You'll still have to handle
tree integrity yourself, but you'll have an optimized index and
functions to navigate the tree.

>   type int2 NOT NULL default '0',

Why the typecast? A string isn't an integer, you know...

>   PRIMARY KEY  (id)
> )  ;
> 
> just to hold a tree Structure and the second one is:
> 
> CREATE TABLE ltlocationpath (
>   "ltlocation_id" int4 NOT NULL default '0',
>   "ltlocancester_id" int4 NOT NULL default '0',

And you're "forcing" your column names to lower case here; whether you
need to is up to you, of course.

>   PRIMARY KEY  (ltlocation_id,ltlocancester_id)
> )  ;


> The Stored Procedure is:
> 
> CREATE OR REPLACE FUNCTION populatelocationpath() RETURNS trigger AS $$
> DECLARE
>     workid integer := 0;
> BEGIN   
>     IF tg_op = 'UPDATE' THEN
>         DELETE FROM ltlocationpath WHERE ltlocation_id = old.id;
>     END IF;
>     
>     workid := new.id;

Are you sure you want locations to reference themselves? That may also
be where your unique constraint violation originates.

I think I'd use something along the lines of:

workid := new.parent;
LOOP
	INSERT INTO ltlocationpath (ltlocation_id, ltlocancester_id)
	VALUES (new.id, workid);

	SELECT INTO workid ...

	-- Assuming the top nodes have NULL parents
	EXIT WHEN parent IS NULL;
END LOOP;

>     WHILE workid > 0 LOOP
>         BEGIN
>             EXECUTE 'INSERT INTO ltlocationpath (ltlocation_id,
> ltlocancester_id) '
>                 || 'VALUES (' || new.id || ', ' || workid || ')';

I don't think you need a dynamic query here (see my example).

>         EXCEPTION WHEN unique_violation THEN
>             -- do nothing
>         END;
>                
>         SELECT INTO workid parent FROM ltlocation WHERE id = workid;
>     END LOOP;
>     RETURN new;
> END;
> $$ LANGUAGE plpgsql;
> 
> And the Trigger is defined as:
> 
> CREATE TRIGGER ltlocationpathtrigger AFTER INSERT OR UPDATE ON
> ltlocation FOR EACH ROW EXECUTE PROCEDURE populatelocationpath();
> 
> The strange thing is:
> insert is OK (materialized path gets populated)
> update of parent column is OK old values get delete and new ones get
> inserted
> but if the exception handling of the unique_violation exception is
> removed an update on the id column fails, with
> an duplicate pkey violation an the self reference in the materialized
> path eg for the values (25, 25)

I think that is because your workid will be back at 25 in the next
iteration when that happens, because of the self-reference.

> 
> It works OK with ignoring the exception but why is the exception thrown
> in the first place.
> 
> The postgresql version 8.1.5

---------------------------(end of broadcast)---------------------------
TIP 6: explain analyze is your friend


-- 
Alban Hertroys
alban@xxxxxxxxxxxxxxxxx

magproductions b.v.

T: ++31(0)534346874
F: ++31(0)534346876
M:
I: www.magproductions.nl
A: Postbus 416
   7500 AK Enschede

// Integrate Your World //


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Postgresql Jobs]     [Postgresql Admin]     [Postgresql Performance]     [Linux Clusters]     [PHP Home]     [PHP on Windows]     [Kernel Newbies]     [PHP Classes]     [PHP Books]     [PHP Databases]     [Postgresql & PHP]     [Yosemite]
  Powered by Linux