From 3a9ae3d2068334bbd0e54efaa729e7590994ccc8 Mon Sep 17 00:00:00 2001 From: Andrew Dunstan Date: Sun, 28 May 2006 03:03:17 +0000 Subject: [PATCH] TG_table_name and TG_table_schema for plpgsql, plus docs and regression. --- doc/src/sgml/plpgsql.sgml | 25 ++++++- src/pl/plpgsql/src/pl_comp.c | 16 +++- src/pl/plpgsql/src/pl_exec.c | 17 ++++- src/pl/plpgsql/src/plpgsql.h | 4 +- src/test/regress/expected/triggers.out | 100 +++++++++++++++++++++++++ src/test/regress/sql/triggers.sql | 72 ++++++++++++++++++ 6 files changed, 229 insertions(+), 5 deletions(-) diff --git a/doc/src/sgml/plpgsql.sgml b/doc/src/sgml/plpgsql.sgml index 2d1351d9c7..4f302a858e 100644 --- a/doc/src/sgml/plpgsql.sgml +++ b/doc/src/sgml/plpgsql.sgml @@ -1,4 +1,4 @@ - + <application>PL/pgSQL</application> - <acronym>SQL</acronym> Procedural Language @@ -2745,7 +2745,28 @@ RAISE EXCEPTION 'Nonexistent ID --> %', user_id; Data type name; the name of the table that caused the trigger - invocation. + invocation. This is now deprecated, and could disappear in a future + release. Use TG_TABLE_NAME instead. + + + + + + TG_TABLE_NAME + + + Data type name; the name of the table that + caused the trigger invocation. + + + + + + TG_TABLE_SCHEMA + + + Data type name; the name of the schema of the + table that caused the trigger invocation. diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c index 93814db166..673ae54ca6 100644 --- a/src/pl/plpgsql/src/pl_comp.c +++ b/src/pl/plpgsql/src/pl_comp.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.101 2006/03/14 22:48:23 tgl Exp $ + * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.102 2006/05/28 03:03:17 adunstan Exp $ * *------------------------------------------------------------------------- */ @@ -581,6 +581,20 @@ do_compile(FunctionCallInfo fcinfo, true); function->tg_relname_varno = var->dno; + /* tg_table_name is now preferred to tg_relname */ + var = plpgsql_build_variable("tg_table_name", 0, + plpgsql_build_datatype(NAMEOID, -1), + true); + function->tg_table_name_varno = var->dno; + + + /* add variable tg_table_schema */ + var = plpgsql_build_variable("tg_table_schema", 0, + plpgsql_build_datatype(NAMEOID, -1), + true); + function->tg_table_schema_varno = var->dno; + + /* Add the variable tg_nargs */ var = plpgsql_build_variable("tg_nargs", 0, plpgsql_build_datatype(INT4OID, -1), diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index ee30902ded..d2ff1fffd5 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.164 2006/04/22 01:26:01 tgl Exp $ + * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.165 2006/05/28 03:03:17 adunstan Exp $ * *------------------------------------------------------------------------- */ @@ -539,6 +539,21 @@ plpgsql_exec_trigger(PLpgSQL_function *func, var->isnull = false; var->freeval = true; + var = (PLpgSQL_var *) (estate.datums[func->tg_table_name_varno]); + var->value = DirectFunctionCall1(namein, + CStringGetDatum(RelationGetRelationName(trigdata->tg_relation))); + var->isnull = false; + var->freeval = true; + + var = (PLpgSQL_var *) (estate.datums[func->tg_table_schema_varno]); + var->value = DirectFunctionCall1(namein, + CStringGetDatum( + get_namespace_name( + RelationGetNamespace( + trigdata->tg_relation)))); + var->isnull = false; + var->freeval = true; + var = (PLpgSQL_var *) (estate.datums[func->tg_nargs_varno]); var->value = Int16GetDatum(trigdata->tg_trigger->tgnargs); var->isnull = false; diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h index 43b912287b..50fe382b32 100644 --- a/src/pl/plpgsql/src/plpgsql.h +++ b/src/pl/plpgsql/src/plpgsql.h @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.69 2006/03/09 21:29:38 momjian Exp $ + * $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.70 2006/05/28 03:03:17 adunstan Exp $ * *------------------------------------------------------------------------- */ @@ -572,6 +572,8 @@ typedef struct PLpgSQL_function int tg_op_varno; int tg_relid_varno; int tg_relname_varno; + int tg_table_name_varno; + int tg_table_schema_varno; int tg_nargs_varno; int ndatums; diff --git a/src/test/regress/expected/triggers.out b/src/test/regress/expected/triggers.out index e91c5a3632..6d8a436f50 100644 --- a/src/test/regress/expected/triggers.out +++ b/src/test/regress/expected/triggers.out @@ -386,3 +386,103 @@ select * from trigtest; drop table trigtest2; drop table trigtest; +-- dump trigger data +CREATE TABLE trigger_test ( + i int, + v varchar +); +CREATE OR REPLACE FUNCTION trigger_data() RETURNS trigger +LANGUAGE plpgsql AS $$ + +declare + + argstr text; + relid text; + +begin + + relid := TG_relid::regclass; + + -- plpgsql can't discover it's trigger data in a hash like perl and python + -- can, or by a sort of reflection like tcl can, + -- so we have to hard code the names. + raise NOTICE 'TG_NAME: %', TG_name; + raise NOTICE 'TG_WHEN: %', TG_when; + raise NOTICE 'TG_LEVEL: %', TG_level; + raise NOTICE 'TG_OP: %', TG_op; + raise NOTICE 'TG_RELID::regclass: %', relid; + raise NOTICE 'TG_RELNAME: %', TG_relname; + raise NOTICE 'TG_TABLE_NAME: %', TG_table_name; + raise NOTICE 'TG_TABLE_SCHEMA: %', TG_table_schema; + raise NOTICE 'TG_NARGS: %', TG_nargs; + + argstr := '['; + for i in 0 .. TG_nargs - 1 loop + if i > 0 then + argstr := argstr || ', '; + end if; + argstr := argstr || TG_argv[i]; + end loop; + argstr := argstr || ']'; + raise NOTICE 'TG_ARGV: %', argstr; + + if TG_OP != 'INSERT' then + raise NOTICE 'OLD: %', OLD; + end if; + + if TG_OP != 'DELETE' then + raise NOTICE 'NEW: %', NEW; + end if; + if TG_OP = 'DELETE' then + return OLD; + else + return NEW; + end if; + +end; +$$; +CREATE TRIGGER show_trigger_data_trig +BEFORE INSERT OR UPDATE OR DELETE ON trigger_test +FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo'); +insert into trigger_test values(1,'insert'); +NOTICE: TG_NAME: show_trigger_data_trig +NOTICE: TG_WHEN: BEFORE +NOTICE: TG_LEVEL: ROW +NOTICE: TG_OP: INSERT +NOTICE: TG_RELID::regclass: trigger_test +NOTICE: TG_RELNAME: trigger_test +NOTICE: TG_TABLE_NAME: trigger_test +NOTICE: TG_TABLE_SCHEMA: public +NOTICE: TG_NARGS: 2 +NOTICE: TG_ARGV: [23, skidoo] +NOTICE: NEW: (1,insert) +update trigger_test set v = 'update' where i = 1; +NOTICE: TG_NAME: show_trigger_data_trig +NOTICE: TG_WHEN: BEFORE +NOTICE: TG_LEVEL: ROW +NOTICE: TG_OP: UPDATE +NOTICE: TG_RELID::regclass: trigger_test +NOTICE: TG_RELNAME: trigger_test +NOTICE: TG_TABLE_NAME: trigger_test +NOTICE: TG_TABLE_SCHEMA: public +NOTICE: TG_NARGS: 2 +NOTICE: TG_ARGV: [23, skidoo] +NOTICE: OLD: (1,insert) +NOTICE: NEW: (1,update) +delete from trigger_test; +NOTICE: TG_NAME: show_trigger_data_trig +NOTICE: TG_WHEN: BEFORE +NOTICE: TG_LEVEL: ROW +NOTICE: TG_OP: DELETE +NOTICE: TG_RELID::regclass: trigger_test +NOTICE: TG_RELNAME: trigger_test +NOTICE: TG_TABLE_NAME: trigger_test +NOTICE: TG_TABLE_SCHEMA: public +NOTICE: TG_NARGS: 2 +NOTICE: TG_ARGV: [23, skidoo] +NOTICE: OLD: (1,update) + +DROP TRIGGER show_trigger_data_trig on trigger_test; + +DROP FUNCTION trigger_data(); +DROP TABLE trigger_test; diff --git a/src/test/regress/sql/triggers.sql b/src/test/regress/sql/triggers.sql index 140b0f2d48..fc688a08f9 100644 --- a/src/test/regress/sql/triggers.sql +++ b/src/test/regress/sql/triggers.sql @@ -294,3 +294,75 @@ insert into trigtest default values; select * from trigtest; drop table trigtest2; drop table trigtest; + + +-- dump trigger data +CREATE TABLE trigger_test ( + i int, + v varchar +); + +CREATE OR REPLACE FUNCTION trigger_data() RETURNS trigger +LANGUAGE plpgsql AS $$ + +declare + + argstr text; + relid text; + +begin + + relid := TG_relid::regclass; + + -- plpgsql can't discover it's trigger data in a hash like perl and python + -- can, or by a sort of reflection like tcl can, + -- so we have to hard code the names. + raise NOTICE 'TG_NAME: %', TG_name; + raise NOTICE 'TG_WHEN: %', TG_when; + raise NOTICE 'TG_LEVEL: %', TG_level; + raise NOTICE 'TG_OP: %', TG_op; + raise NOTICE 'TG_RELID::regclass: %', relid; + raise NOTICE 'TG_RELNAME: %', TG_relname; + raise NOTICE 'TG_TABLE_NAME: %', TG_table_name; + raise NOTICE 'TG_TABLE_SCHEMA: %', TG_table_schema; + raise NOTICE 'TG_NARGS: %', TG_nargs; + + argstr := '['; + for i in 0 .. TG_nargs - 1 loop + if i > 0 then + argstr := argstr || ', '; + end if; + argstr := argstr || TG_argv[i]; + end loop; + argstr := argstr || ']'; + raise NOTICE 'TG_ARGV: %', argstr; + + if TG_OP != 'INSERT' then + raise NOTICE 'OLD: %', OLD; + end if; + + if TG_OP != 'DELETE' then + raise NOTICE 'NEW: %', NEW; + end if; + if TG_OP = 'DELETE' then + return OLD; + else + return NEW; + end if; + +end; +$$; + +CREATE TRIGGER show_trigger_data_trig +BEFORE INSERT OR UPDATE OR DELETE ON trigger_test +FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo'); + +insert into trigger_test values(1,'insert'); +update trigger_test set v = 'update' where i = 1; +delete from trigger_test; + +DROP TRIGGER show_trigger_data_trig on trigger_test; + +DROP FUNCTION trigger_data(); + +DROP TABLE trigger_test;