From: | Lars Heidieker <lars(at)heidieker(dot)de> |
---|---|
To: | Alban Hertroys <alban(at)magproductions(dot)nl> |
Cc: | pgsql-general(at)postgresql(dot)org |
Subject: | Re: Stored Procedure and Trigger they puzzle me |
Date: | 2006-12-18 22:55:05 |
Message-ID: | BC9AF4CE-1827-47DC-A3BA-69838E59C839@heidieker.de |
Views: | Raw Message | Whole Thread | Download mbox | Resend email |
Thread: | |
Lists: | pgsql-general |
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
On 18 Dec 2006, at 09:37, Alban Hertroys wrote:
> 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.
>
Yes, that is an option (and I am thinking about it) I only need
single parent nodes, I'll have a look at the ltree package,
the database is just quickly ported from another DBMS and I tried to
get my hands into the stored procedures.
>> type int2 NOT NULL default '0',
>
> Why the typecast? A string isn't an integer, you know...
True the create script was automatically created and I haven changed
it much.....
(Sure it needs a rewrite)
>
>> 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.
>
That's a left over from the automatic conversion as well.
>> 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;
>
That's good to hear that it can be written more easy (no dynamic SQL
necessary in this case)
In your example I don't get the self reference I have to check if I
need to rewrite some other queries for that,
but sure the self reference is actually useless data.
>> 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.
>
Not sure as I deleted them before, but currently I cant reproduce it.
I just get the following now:
ERROR: insert or update on table "ltlocationpath" violates foreign
key constraint "ltlocancester_fkey"
DETAIL: Key (ltlocancester_id)=(18999) is not present in table
"ltlocation".
CONTEXT: SQL statement "UPDATE ONLY "public"."ltlocationpath" SET
"ltlocation_id" = $1 WHERE "ltlocation_id" = $2"
on: UPDATE ltlocation SET id = 45555 WHERE id = 18999;
which I don't get if:
IF tg_op = 'UPDATE' THEN
DELETE FROM ltlocationpath WHERE ltlocation_id = old.id;
END IF;
is executed.
Probably I am running in some bad interaction between triggers and
foreign key constraints (cascading)
I'll just continue to play around to get a better understanding.
- --
Viele Grüße,
Lars Heidieker
lars(at)heidieker(dot)de
http://paradoxon.info
- ------------------------------------
Mystische Erklärungen.
Die mystischen Erklärungen gelten für tief;
die Wahrheit ist, dass sie noch nicht einmal oberflächlich sind.
-- Friedrich Nietzsche
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (Darwin)
iD8DBQFFhxxKcxuYqjT7GRYRAgzpAJ9A74MnEFgu7huobM/U6aCK9Y/PlACgxRwW
UHI7RENIUipoarw3UY+Zn9w=
=hJSD
-----END PGP SIGNATURE-----
From | Date | Subject | |
---|---|---|---|
Next Message | Richard Broersma Jr | 2006-12-18 23:06:39 | Re: feature request for Postgresql Rule system. |
Previous Message | Erik Jones | 2006-12-18 22:39:04 | Re: Changes in 8.2's PHP behaviour? |