Hey list,
I'm stuck on a problem that I can't figure out (postgres 9.3).
In short, using an
INSERT INTO __view_with_trigger__ ... RETURNING gid INTO _gid;
INSERT INTO __view_with_trigger__ ... RETURNING gid INTO _gid;
returns nothing.
I need this feature because I use views on tables as user interface.
This must have to do with the postgres order of execution,
because inserting into a table instead of the view of the table returns the expected result.
Here is a synthetic example (of course the real use really requires this kind of architecture),
any help is much appreciated,
because I don't see any work-around (except not using view at all, which would be terrible data duplication in my case)
Cheers,
Rémi-C
------------------------------------------------
-- test inserting and instead of trigger --
-----------------------------------------------
CREATE SCHEMA IF NOT EXISTS test ;
SET search_path to test, public ;
DROP TABLE IF EXISTS generic_object CASCADE;
CREATE TABLE generic_object (
gid SERIAL PRIMARY KEY
, orientation float
) ;
DROP VIEW IF EXISTS editing_generic_object ;
CREATE VIEW editing_generic_object AS(
SELECT gid,
degrees(orientation) AS orientation
FROM generic_object
) ;
DROP TABLE IF EXISTS specific_object CASCADE ;
CREATE TABLE specific_object (
gid int references generic_object (gid) ON DELETE CASCADE
, width float
) ;
DROP VIEW IF EXISTS editing_specific_object ;
CREATE VIEW editing_specific_object AS(
SELECT g.gid
, g.orientation
, so.width
FROM specific_object AS so LEFT OUTER JOIN
generic_object AS g USING (gid)
) ;
DROP FUNCTION IF EXISTS test.rc_editing_generic_object() CASCADE ;
CREATE OR REPLACE FUNCTION test.rc_editing_generic_object( )
RETURNS trigger AS $BODY$
/** @brief : this trigger deals with editing generic object*/
DECLARE
BEGIN
IF TG_OP = 'DELETE' THEN DELETE FROM test.generic_object WHERE gid = OLD.gid ; RETURN OLD ;
ELSIF TG_OP = 'INSERT' THEN INSERT INTO test.generic_object (orientation) VALUES (radians(NEW.orientation) ) ;
ELSE UPDATE test.generic_object SET orientation = radians(NEW.orientation) ;
END IF ;
RETURN NEW ;
END ;
$BODY$ LANGUAGE plpgsql VOLATILE;
DROP TRIGGER IF EXISTS rc_editing_generic_object ON test.editing_generic_object ;
CREATE TRIGGER rc_edit_street_object_pedestrian INSTEAD OF UPDATE OR INSERT OR DELETE
ON test.editing_generic_object
FOR ROW EXECUTE PROCEDURE rc_editing_generic_object( ) ;
DROP FUNCTION IF EXISTS test.rc_editing_specific_object() CASCADE ;
CREATE OR REPLACE FUNCTION test.rc_editing_specific_object( )
RETURNS trigger AS $BODY$
/** @brief : this trigger deals with editing specific object*/
DECLARE
_gid int;
BEGIN
IF TG_OP = 'DELETE' THEN DELETE FROM test.generic_object WHERE gid = OLD.gid ; RETURN OLD ;
ELSIF TG_OP = 'INSERT' THEN
--does not works
INSERT INTO test.editing_generic_object (orientation) VALUES ( NEW.orientation) RETURNING gid INTO _gid;
--does works
--INSERT INTO test.generic_object (orientation) VALUES ( radians(NEW.orientation) ) RETURNING gid INTO _gid;
RAISE WARNING 'here is the gid deduced after insertion : %', _gid ;
INSERT INTO test.specific_object (gid, width) VALUES (_gid, NEW.width) ;
ELSE
UPDATE test.editing_generic_object AS e SET orientation = NEW.orientation WHERE e.gid = NEW.gid;
UPDATE test.specific_object AS s SET width = NEW.width WHERE s.gid = NEW.gid;
END IF ;
RETURN NEW ;
END ;
$BODY$ LANGUAGE plpgsql VOLATILE;
DROP TRIGGER IF EXISTS rc_editing_specific_object ON test.editing_specific_object ;
CREATE TRIGGER rc_editing_specific_object INSTEAD OF UPDATE OR INSERT OR DELETE
ON test.editing_specific_object
FOR ROW EXECUTE PROCEDURE rc_editing_specific_object( ) ;
--testing
--inserting into generic : works
INSERT INTO editing_generic_object ( orientation) VALUES (180) ;
SELECT *
FROM generic_object ;
------------------------------------------------
-- test inserting and instead of trigger --
-----------------------------------------------
CREATE SCHEMA IF NOT EXISTS test ;
SET search_path to test, public ;
DROP TABLE IF EXISTS generic_object CASCADE;
CREATE TABLE generic_object (
gid SERIAL PRIMARY KEY
, orientation float
) ;
DROP VIEW IF EXISTS editing_generic_object ;
CREATE VIEW editing_generic_object AS(
SELECT gid,
degrees(orientation) AS orientation
FROM generic_object
) ;
DROP TABLE IF EXISTS specific_object CASCADE ;
CREATE TABLE specific_object (
gid int references generic_object (gid) ON DELETE CASCADE
, width float
) ;
DROP VIEW IF EXISTS editing_specific_object ;
CREATE VIEW editing_specific_object AS(
SELECT g.gid
, g.orientation
, so.width
FROM specific_object AS so LEFT OUTER JOIN
generic_object AS g USING (gid)
) ;
DROP FUNCTION IF EXISTS test.rc_editing_generic_object() CASCADE ;
CREATE OR REPLACE FUNCTION test.rc_editing_generic_object( )
RETURNS trigger AS $BODY$
/** @brief : this trigger deals with editing generic object*/
DECLARE
BEGIN
IF TG_OP = 'DELETE' THEN DELETE FROM test.generic_object WHERE gid = OLD.gid ; RETURN OLD ;
ELSIF TG_OP = 'INSERT' THEN INSERT INTO test.generic_object (orientation) VALUES (radians(NEW.orientation) ) ;
ELSE UPDATE test.generic_object SET orientation = radians(NEW.orientation) ;
END IF ;
RETURN NEW ;
END ;
$BODY$ LANGUAGE plpgsql VOLATILE;
DROP TRIGGER IF EXISTS rc_editing_generic_object ON test.editing_generic_object ;
CREATE TRIGGER rc_edit_street_object_pedestrian INSTEAD OF UPDATE OR INSERT OR DELETE
ON test.editing_generic_object
FOR ROW EXECUTE PROCEDURE rc_editing_generic_object( ) ;
DROP FUNCTION IF EXISTS test.rc_editing_specific_object() CASCADE ;
CREATE OR REPLACE FUNCTION test.rc_editing_specific_object( )
RETURNS trigger AS $BODY$
/** @brief : this trigger deals with editing specific object*/
DECLARE
_gid int;
BEGIN
IF TG_OP = 'DELETE' THEN DELETE FROM test.generic_object WHERE gid = OLD.gid ; RETURN OLD ;
ELSIF TG_OP = 'INSERT' THEN
--does not works
INSERT INTO test.editing_generic_object (orientation) VALUES ( NEW.orientation) RETURNING gid INTO _gid;
--does works
--INSERT INTO test.generic_object (orientation) VALUES ( radians(NEW.orientation) ) RETURNING gid INTO _gid;
RAISE WARNING 'here is the gid deduced after insertion : %', _gid ;
INSERT INTO test.specific_object (gid, width) VALUES (_gid, NEW.width) ;
ELSE
UPDATE test.editing_generic_object AS e SET orientation = NEW.orientation WHERE e.gid = NEW.gid;
UPDATE test.specific_object AS s SET width = NEW.width WHERE s.gid = NEW.gid;
END IF ;
RETURN NEW ;
END ;
$BODY$ LANGUAGE plpgsql VOLATILE;
DROP TRIGGER IF EXISTS rc_editing_specific_object ON test.editing_specific_object ;
CREATE TRIGGER rc_editing_specific_object INSTEAD OF UPDATE OR INSERT OR DELETE
ON test.editing_specific_object
FOR ROW EXECUTE PROCEDURE rc_editing_specific_object( ) ;
--testing
--inserting into generic : works
INSERT INTO editing_generic_object ( orientation) VALUES (180) ;
SELECT *
FROM generic_object ;
-- insert into specific : don't work
INSERT INTO editing_specific_object ( orientation,width) VALUES (180, 123) ;
SELECT *
FROM specific_object ;
SELECT *
FROM specific_object ;