summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Grittner2011-01-28 21:15:48 +0000
committerKevin Grittner2011-01-28 21:15:48 +0000
commitdf7a5756dbca0a755dd7397f49c273d66ce6afa8 (patch)
tree6f1c25310caf77042a0e942e11bf08da16433029
parentb2826ad52d72195317a13c2074a5cd002c98a338 (diff)
Add support for TG_DEPTH to PL/pgSQL trigger functions.
-rw-r--r--src/backend/access/transam/xact.c7
-rw-r--r--src/backend/commands/trigger.c8
-rw-r--r--src/backend/tcop/pquery.c4
-rw-r--r--src/include/commands/trigger.h2
-rw-r--r--src/pl/plpgsql/src/pl_comp.c6
-rw-r--r--src/pl/plpgsql/src/pl_exec.c5
-rw-r--r--src/pl/plpgsql/src/plpgsql.h1
7 files changed, 32 insertions, 1 deletions
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 1e31e07ec9..ddfbd3a1fd 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -142,6 +142,7 @@ typedef struct TransactionStateData
Oid prevUser; /* previous CurrentUserId setting */
int prevSecContext; /* previous SecurityRestrictionContext */
bool prevXactReadOnly; /* entry-time xact r/o state */
+ int prevTgDepth; /* previous trigger depth */
bool startedInRecovery; /* did we start in recovery? */
struct TransactionStateData *parent; /* back link to parent */
} TransactionStateData;
@@ -171,6 +172,7 @@ static TransactionStateData TopTransactionStateData = {
InvalidOid, /* previous CurrentUserId setting */
0, /* previous SecurityRestrictionContext */
false, /* entry-time xact r/o state */
+ 0, /* previous trigger depth */
false, /* startedInRecovery */
NULL /* link to parent state block */
};
@@ -3996,6 +3998,8 @@ CommitSubTransaction(void)
*/
XactReadOnly = s->prevXactReadOnly;
+ tg_depth = s->prevTgDepth;
+
CurrentResourceOwner = s->parent->curTransactionOwner;
CurTransactionResourceOwner = s->parent->curTransactionOwner;
ResourceOwnerDelete(s->curTransactionOwner);
@@ -4114,6 +4118,8 @@ AbortSubTransaction(void)
*/
XactReadOnly = s->prevXactReadOnly;
+ tg_depth = s->prevTgDepth;
+
RESUME_INTERRUPTS();
}
@@ -4196,6 +4202,7 @@ PushTransaction(void)
s->blockState = TBLOCK_SUBBEGIN;
GetUserIdAndSecContext(&s->prevUser, &s->prevSecContext);
s->prevXactReadOnly = XactReadOnly;
+ s->prevTgDepth = tg_depth;
CurrentTransactionState = s;
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 48021388fc..056b656fc2 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -55,10 +55,12 @@
#include "utils/tqual.h"
+/* How many levels deep into trigger execution are we? */
+int tg_depth = 0;
+
/* GUC variables */
int SessionReplicationRole = SESSION_REPLICATION_ROLE_ORIGIN;
-
#define GetModifiedColumns(relinfo, estate) \
(rt_fetch((relinfo)->ri_RangeTableIndex, (estate)->es_range_table)->modifiedCols)
@@ -1807,6 +1809,8 @@ ExecCallTriggerFunc(TriggerData *trigdata,
if (instr)
InstrStartNode(instr + tgindx);
+ tg_depth++;
+
/*
* Do the function evaluation in the per-tuple memory context, so that
* leaked memory will be reclaimed once per tuple. Note in particular that
@@ -1828,6 +1832,8 @@ ExecCallTriggerFunc(TriggerData *trigdata,
MemoryContextSwitchTo(oldContext);
+ tg_depth--;
+
/*
* Trigger protocol allows function to return a null pointer, but NOT to
* set the isnull result flag.
diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c
index 0b108ac134..5b67346388 100644
--- a/src/backend/tcop/pquery.c
+++ b/src/backend/tcop/pquery.c
@@ -748,6 +748,8 @@ PortalRun(Portal portal, long count, bool isTopLevel,
errmsg("portal \"%s\" cannot be run", portal->name)));
portal->status = PORTAL_ACTIVE;
+ tg_depth = 0;
+
/*
* Set up global portal context pointers.
*
@@ -1371,6 +1373,8 @@ PortalRunFetch(Portal portal,
errmsg("portal \"%s\" cannot be run", portal->name)));
portal->status = PORTAL_ACTIVE;
+ tg_depth = 0;
+
/*
* Set up global portal context pointers.
*/
diff --git a/src/include/commands/trigger.h b/src/include/commands/trigger.h
index c213ac7a4e..90a3ea7a61 100644
--- a/src/include/commands/trigger.h
+++ b/src/include/commands/trigger.h
@@ -108,6 +108,8 @@ extern PGDLLIMPORT int SessionReplicationRole;
#define TRIGGER_FIRES_ON_REPLICA 'R'
#define TRIGGER_DISABLED 'D'
+extern int tg_depth;
+
extern Oid CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
Oid constraintOid, Oid indexOid,
bool isInternal);
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index 41188a2369..175ad7ab85 100644
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -633,6 +633,12 @@ do_compile(FunctionCallInfo fcinfo,
true);
function->tg_table_schema_varno = var->dno;
+ /* add the variable tg_depth */
+ var = plpgsql_build_variable("tg_depth", 0,
+ plpgsql_build_datatype(INT4OID, -1),
+ true);
+ function->tg_depth_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 3e40945e35..82b73a0490 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -625,6 +625,11 @@ plpgsql_exec_trigger(PLpgSQL_function *func,
var->isnull = false;
var->freeval = true;
+ var = (PLpgSQL_var *) (estate.datums[func->tg_depth_varno]);
+ var->value = Int16GetDatum(tg_depth);
+ var->isnull = false;
+ var->freeval = false;
+
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 0ad7e28136..2165526957 100644
--- a/src/pl/plpgsql/src/plpgsql.h
+++ b/src/pl/plpgsql/src/plpgsql.h
@@ -668,6 +668,7 @@ typedef struct PLpgSQL_function
int tg_relname_varno;
int tg_table_name_varno;
int tg_table_schema_varno;
+ int tg_depth_varno;
int tg_nargs_varno;
int tg_argv_varno;