From: | "J(dot) Greg Davidson" <jgd(at)well(dot)com> |
---|---|
To: | PostgreSQL General <pgsql-general(at)postgresql(dot)org> |
Cc: | lynn <lynn(at)creditlink(dot)com>, /Blank Page/ <blankpage2008(at)gmail(dot)com> |
Subject: | Danger of idiomatic plpgsql loop for merging data |
Date: | 2010-07-28 21:27:16 |
Message-ID: | 573538171.3904.1280352436483.JavaMail.root@zimbra.well.com |
Views: | Raw Message | Whole Thread | Download mbox | Resend email |
Thread: | |
Lists: | pgsql-general |
Hi fellow PostgreSQL hackers,
I just got burned by the idiomatic loop
documented in the PostgreSQL manual as
Example 39-2. Exceptions with UPDATE/INSERT
I have now replaced this "standard" idiom
with a safer one described below.
What went wrong:
It seems that the table I was either
inserting into or selecting from had
a trigger inserting some associated
data which was sometimes raising a
unique_violation exception, turning the
"standard" idiom into an infinite loop!
My (simplified) old code looked like this:
CREATE TABLE foos (
foo_ foo PRIMARY KEY DEFAULT next_foo();
name_ text UNIQUE NOT NULL;
);
CREATE OR REPLACE
FUNCTION get_foo(text) RETURNS foo AS $$
DECLARE
_foo foo;
BEGIN
LOOP
SELECT foo_ INTO _foo
FROM foos WHERE name_ = $1;
IF FOUND THEN RETURN _foo; END IF;
BEGIN
INSERT INTO foos(name_) VALUES($1);
EXCEPTION
WHEN unique_violation THEN
-- maybe another thread?
END;
END LOOP;
END;
$$ LANGUAGE plpgsql STRICT;
My (simplified) new code is longer but
more flexible, safer and adds logging:
CREATE OR REPLACE
FUNCTION old_foo(text) RETURNS foo AS $$
SELECT foo_ FROM foos WHERE name_ = $1
$$ LANGUAGE SQL STRICT;
CREATE OR REPLACE
FUNCTION new_foo(text) RETURNS foo AS $$
DECLARE
this regprocedure := 'new_foo(text)';
_foo foo;
BEGIN
INSERT INTO foos(name_) VALUES ($1)
RETURNING foo_ INTO _foo;
RETURN _ref;
EXCEPTION
WHEN unique_violation THEN
-- maybe another thread?
RAISE NOTICE '% "%" unique_violation', this, $1;
RETURN NULL;
END;
$$ LANGUAGE plpgsql STRICT;
CREATE OR REPLACE
FUNCTION get_foo(text) RETURNS foo AS $$
SELECT COALESCE(
old_foo($1), new_foo($1), old_foo($1)
)
$$ LANGUAGE sql STRICT;
_Greg
From | Date | Subject | |
---|---|---|---|
Next Message | Ivan Sergio Borgonovo | 2010-07-28 21:42:58 | Re: Which CMS/Ecommerce/Shopping cart ? |
Previous Message | Tom Lane | 2010-07-28 20:42:26 | Re: Need help with full text index configuration |