From a06f4ecc0ff2fe149d4a6183f32f868c527405b5 Mon Sep 17 00:00:00 2001 From: Thomas Munro Date: Mon, 3 Apr 2017 15:26:29 +1200 Subject: [PATCH] Support transition tables in PL/tcl triggers. If a trigger is created with transition tables using the new syntax REFERENCING OLD/NEW TABLE AS ..., allow SQL executed by a PL/tcl trigger to see the transient tables. --- src/pl/tcl/expected/pltcl_queries.out | 21 +++++++++++++++++++++ src/pl/tcl/pltcl.c | 32 ++++++++++++++++++++++++++++++++ src/pl/tcl/sql/pltcl_queries.sql | 20 ++++++++++++++++++++ 3 files changed, 73 insertions(+) diff --git a/src/pl/tcl/expected/pltcl_queries.out b/src/pl/tcl/expected/pltcl_queries.out index 7300b315d64..5f50f468878 100644 --- a/src/pl/tcl/expected/pltcl_queries.out +++ b/src/pl/tcl/expected/pltcl_queries.out @@ -660,3 +660,24 @@ select tcl_eval($$ (1 row) +-- test transition table visibility +create table transition_table_test (id int, name text); +insert into transition_table_test values (1, 'a'); +create function transition_table_test_f() returns trigger language pltcl as +$$ + spi_exec -array C "SELECT id, name FROM old_table" { + elog INFO "old: $C(id) -> $C(name)" + } + spi_exec -array C "SELECT id, name FROM new_table" { + elog INFO "new: $C(id) -> $C(name)" + } + return OK +$$; +CREATE TRIGGER a_t AFTER UPDATE ON transition_table_test + REFERENCING OLD TABLE AS old_table NEW TABLE AS new_table + FOR EACH STATEMENT EXECUTE PROCEDURE transition_table_test_f(); +update transition_table_test set name = 'b'; +INFO: old: 1 -> a +INFO: new: 1 -> b +drop table transition_table_test; +drop function transition_table_test_f(); diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c index b8fcf0673d3..a6365560de0 100644 --- a/src/pl/tcl/pltcl.c +++ b/src/pl/tcl/pltcl.c @@ -1046,6 +1046,38 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS, pltcl_call_state *call_state, if (SPI_connect() != SPI_OK_CONNECT) elog(ERROR, "could not connect to SPI manager"); + /* Make transition tables visible to this SPI connection */ + if (trigdata->tg_newtable) + { + EphemeralNamedRelation enr = + palloc(sizeof(EphemeralNamedRelationData)); + int rc PG_USED_FOR_ASSERTS_ONLY; + + enr->md.name = trigdata->tg_trigger->tgnewtable; + enr->md.reliddesc = trigdata->tg_relation->rd_id; + enr->md.tupdesc = NULL; + enr->md.enrtype = ENR_NAMED_TUPLESTORE; + enr->md.enrtuples = tuplestore_tuple_count(trigdata->tg_oldtable); + enr->reldata = trigdata->tg_newtable; + rc = SPI_register_relation(enr); + Assert(rc >= 0); + } + if (trigdata->tg_oldtable) + { + EphemeralNamedRelation enr = + palloc(sizeof(EphemeralNamedRelationData)); + int rc PG_USED_FOR_ASSERTS_ONLY; + + enr->md.name = trigdata->tg_trigger->tgoldtable; + enr->md.reliddesc = trigdata->tg_relation->rd_id; + enr->md.tupdesc = NULL; + enr->md.enrtype = ENR_NAMED_TUPLESTORE; + enr->md.enrtuples = tuplestore_tuple_count(trigdata->tg_oldtable); + enr->reldata = trigdata->tg_oldtable; + rc = SPI_register_relation(enr); + Assert(rc >= 0); + } + /* Find or compile the function */ prodesc = compile_pltcl_function(fcinfo->flinfo->fn_oid, RelationGetRelid(trigdata->tg_relation), diff --git a/src/pl/tcl/sql/pltcl_queries.sql b/src/pl/tcl/sql/pltcl_queries.sql index 29ed616cd0b..dabd8cd35f0 100644 --- a/src/pl/tcl/sql/pltcl_queries.sql +++ b/src/pl/tcl/sql/pltcl_queries.sql @@ -216,3 +216,23 @@ select tcl_eval($$ after 100 {set ::tcl_vwait 1} vwait ::tcl_vwait unset -nocomplain ::tcl_vwait$$); + +-- test transition table visibility +create table transition_table_test (id int, name text); +insert into transition_table_test values (1, 'a'); +create function transition_table_test_f() returns trigger language pltcl as +$$ + spi_exec -array C "SELECT id, name FROM old_table" { + elog INFO "old: $C(id) -> $C(name)" + } + spi_exec -array C "SELECT id, name FROM new_table" { + elog INFO "new: $C(id) -> $C(name)" + } + return OK +$$; +CREATE TRIGGER a_t AFTER UPDATE ON transition_table_test + REFERENCING OLD TABLE AS old_table NEW TABLE AS new_table + FOR EACH STATEMENT EXECUTE PROCEDURE transition_table_test_f(); +update transition_table_test set name = 'b'; +drop table transition_table_test; +drop function transition_table_test_f(); -- 2.12.2