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;
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 */
};
*/
XactReadOnly = s->prevXactReadOnly;
+ tg_depth = s->prevTgDepth;
+
CurrentResourceOwner = s->parent->curTransactionOwner;
CurTransactionResourceOwner = s->parent->curTransactionOwner;
ResourceOwnerDelete(s->curTransactionOwner);
*/
XactReadOnly = s->prevXactReadOnly;
+ tg_depth = s->prevTgDepth;
+
RESUME_INTERRUPTS();
}
s->blockState = TBLOCK_SUBBEGIN;
GetUserIdAndSecContext(&s->prevUser, &s->prevSecContext);
s->prevXactReadOnly = XactReadOnly;
+ s->prevTgDepth = tg_depth;
CurrentTransactionState = s;
#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)
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
MemoryContextSwitchTo(oldContext);
+ tg_depth--;
+
/*
* Trigger protocol allows function to return a null pointer, but NOT to
* set the isnull result flag.
errmsg("portal \"%s\" cannot be run", portal->name)));
portal->status = PORTAL_ACTIVE;
+ tg_depth = 0;
+
/*
* Set up global portal context pointers.
*
errmsg("portal \"%s\" cannot be run", portal->name)));
portal->status = PORTAL_ACTIVE;
+ tg_depth = 0;
+
/*
* Set up global portal context pointers.
*/
#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);
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),
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;
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;