diff --git a/doc/src/sgml/plpgsql.sgml b/doc/src/sgml/plpgsql.sgml
index eea6ec5..5be8086 100644
*** a/doc/src/sgml/plpgsql.sgml
--- b/doc/src/sgml/plpgsql.sgml
*************** RAISE unique_violation USING MESSAGE = '
*** 3383,3388 ****
--- 3383,3398 ----
      </varlistentry>
  
      <varlistentry>
+      <term><varname>TG_DEPTH</varname></term>
+      <listitem>
+       <para>
+        Data type <type>integer</type>; the current number of levels of
+        nesting within trigger execution.
+       </para>
+      </listitem>
+     </varlistentry>
+ 
+     <varlistentry>
       <term><varname>TG_NARGS</varname></term>
       <listitem>
        <para>
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 2ca1c14..273fcae 100644
*** a/src/backend/access/transam/xact.c
--- b/src/backend/access/transam/xact.c
*************** typedef struct TransactionStateData
*** 147,152 ****
--- 147,153 ----
  	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;
*************** static TransactionStateData TopTransacti
*** 176,181 ****
--- 177,183 ----
  	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 */
  };
*************** CommitSubTransaction(void)
*** 4039,4044 ****
--- 4041,4048 ----
  	 */
  	XactReadOnly = s->prevXactReadOnly;
  
+ 	tg_depth = s->prevTgDepth;
+ 
  	CurrentResourceOwner = s->parent->curTransactionOwner;
  	CurTransactionResourceOwner = s->parent->curTransactionOwner;
  	ResourceOwnerDelete(s->curTransactionOwner);
*************** AbortSubTransaction(void)
*** 4157,4162 ****
--- 4161,4168 ----
  	 */
  	XactReadOnly = s->prevXactReadOnly;
  
+ 	tg_depth = s->prevTgDepth;
+ 
  	RESUME_INTERRUPTS();
  }
  
*************** PushTransaction(void)
*** 4239,4244 ****
--- 4245,4251 ----
  	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 ce36ea8..a9cb0a0 100644
*** a/src/backend/commands/trigger.c
--- b/src/backend/commands/trigger.c
***************
*** 56,61 ****
--- 56,64 ----
  #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;
  
*************** ExecCallTriggerFunc(TriggerData *trigdat
*** 1811,1816 ****
--- 1814,1821 ----
  	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
*************** ExecCallTriggerFunc(TriggerData *trigdat
*** 1833,1838 ****
--- 1838,1845 ----
  
  	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 b7649c6..a784b32 100644
*** a/src/backend/tcop/pquery.c
--- b/src/backend/tcop/pquery.c
*************** PortalRun(Portal portal, long count, boo
*** 738,743 ****
--- 738,745 ----
  				 errmsg("portal \"%s\" cannot be run", portal->name)));
  	portal->status = PORTAL_ACTIVE;
  
+ 	tg_depth = 0;
+ 
  	/*
  	 * Set up global portal context pointers.
  	 *
*************** PortalRunFetch(Portal portal,
*** 1401,1406 ****
--- 1403,1410 ----
  				 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 ad97871..349341e 100644
*** a/src/include/commands/trigger.h
--- b/src/include/commands/trigger.h
*************** extern PGDLLIMPORT int SessionReplicatio
*** 108,113 ****
--- 108,115 ----
  #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 75098ec..83c60e8 100644
*** a/src/pl/plpgsql/src/pl_comp.c
--- b/src/pl/plpgsql/src/pl_comp.c
*************** do_compile(FunctionCallInfo fcinfo,
*** 655,660 ****
--- 655,668 ----
  										 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,
+ 																InvalidOid),
+ 										 true);
+ 			function->tg_depth_varno = var->dno;
+ 
  			/* Add the variable tg_nargs */
  			var = plpgsql_build_variable("tg_nargs", 0,
  										 plpgsql_build_datatype(INT4OID,
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 906a485..13f7238 100644
*** a/src/pl/plpgsql/src/pl_exec.c
--- b/src/pl/plpgsql/src/pl_exec.c
*************** plpgsql_exec_trigger(PLpgSQL_function *f
*** 627,632 ****
--- 627,637 ----
  	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 89103ae..a5512fb 100644
*** a/src/pl/plpgsql/src/plpgsql.h
--- b/src/pl/plpgsql/src/plpgsql.h
*************** typedef struct PLpgSQL_function
*** 690,695 ****
--- 690,696 ----
  	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;
  
diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out
index bfabcbc..1f36944 100644
*** a/src/test/regress/expected/plpgsql.out
--- b/src/test/regress/expected/plpgsql.out
*************** NOTICE:  {"(35,78)","(88,76)"}
*** 4434,4436 ****
--- 4434,4511 ----
  
  drop function foreach_test(anyarray);
  drop type xy_tuple;
+ -- Test TG_DEPTH
+ create table tg_depth_a (id int not null primary key);
+ NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "tg_depth_a_pkey" for table "tg_depth_a"
+ create table tg_depth_b (id int not null primary key);
+ NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "tg_depth_b_pkey" for table "tg_depth_b"
+ create table tg_depth_c (id int not null primary key);
+ NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "tg_depth_c_pkey" for table "tg_depth_c"
+ create function tg_depth_a_tf() returns trigger
+   language plpgsql as $$
+ begin
+   raise notice '%: tg_depth = %', tg_name, tg_depth;
+   insert into tg_depth_b values (new.id);
+   raise notice '%: tg_depth = %', tg_name, tg_depth;
+   return new;
+ end;
+ $$;
+ create trigger tg_depth_a_tr before insert on tg_depth_a
+   for each row execute procedure tg_depth_a_tf();
+ create function tg_depth_b_tf() returns trigger
+   language plpgsql as $$
+ begin
+   raise notice '%: tg_depth = %', tg_name, tg_depth;
+   begin
+     execute 'insert into tg_depth_c values (' || new.id::text || ')';
+   exception
+     when sqlstate 'U9999' then
+       raise notice 'SQLSTATE = U9999: tg_depth = %', tg_depth;
+   end;
+   raise notice '%: tg_depth = %', tg_name, tg_depth;
+   execute 'insert into tg_depth_c values (' || new.id::text || ')';
+   return new;
+ end;
+ $$;
+ create trigger tg_depth_b_tr before insert on tg_depth_b
+   for each row execute procedure tg_depth_b_tf();
+ create function tg_depth_c_tf() returns trigger
+   language plpgsql as $$
+ begin
+   raise notice '%: tg_depth = %', tg_name, tg_depth;
+   raise exception sqlstate 'U9999';
+   return new;
+ end;
+ $$;
+ create trigger tg_depth_c_tr before insert on tg_depth_c
+   for each row execute procedure tg_depth_c_tf();
+ insert into tg_depth_a values (999);
+ NOTICE:  tg_depth_a_tr: tg_depth = 1
+ NOTICE:  tg_depth_b_tr: tg_depth = 2
+ CONTEXT:  SQL statement "insert into tg_depth_b values (new.id)"
+ PL/pgSQL function "tg_depth_a_tf" line 4 at SQL statement
+ NOTICE:  tg_depth_c_tr: tg_depth = 3
+ CONTEXT:  SQL statement "insert into tg_depth_c values (999)"
+ PL/pgSQL function "tg_depth_b_tf" line 5 at EXECUTE statement
+ SQL statement "insert into tg_depth_b values (new.id)"
+ PL/pgSQL function "tg_depth_a_tf" line 4 at SQL statement
+ NOTICE:  SQLSTATE = U9999: tg_depth = 2
+ CONTEXT:  SQL statement "insert into tg_depth_b values (new.id)"
+ PL/pgSQL function "tg_depth_a_tf" line 4 at SQL statement
+ NOTICE:  tg_depth_b_tr: tg_depth = 2
+ CONTEXT:  SQL statement "insert into tg_depth_b values (new.id)"
+ PL/pgSQL function "tg_depth_a_tf" line 4 at SQL statement
+ NOTICE:  tg_depth_c_tr: tg_depth = 3
+ CONTEXT:  SQL statement "insert into tg_depth_c values (999)"
+ PL/pgSQL function "tg_depth_b_tf" line 11 at EXECUTE statement
+ SQL statement "insert into tg_depth_b values (new.id)"
+ PL/pgSQL function "tg_depth_a_tf" line 4 at SQL statement
+ ERROR:  U9999
+ CONTEXT:  SQL statement "insert into tg_depth_c values (999)"
+ PL/pgSQL function "tg_depth_b_tf" line 11 at EXECUTE statement
+ SQL statement "insert into tg_depth_b values (new.id)"
+ PL/pgSQL function "tg_depth_a_tf" line 4 at SQL statement
+ drop table tg_depth_a, tg_depth_b, tg_depth_c;
+ drop function tg_depth_a_tf();
+ drop function tg_depth_b_tf();
+ drop function tg_depth_c_tf();
diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql
index 14fb457..46ebef1 100644
*** a/src/test/regress/sql/plpgsql.sql
--- b/src/test/regress/sql/plpgsql.sql
*************** select foreach_test(ARRAY[[(10,20),(40,6
*** 3489,3491 ****
--- 3489,3547 ----
  
  drop function foreach_test(anyarray);
  drop type xy_tuple;
+ 
+ 
+ -- Test TG_DEPTH
+ 
+ create table tg_depth_a (id int not null primary key);
+ create table tg_depth_b (id int not null primary key);
+ create table tg_depth_c (id int not null primary key);
+ 
+ create function tg_depth_a_tf() returns trigger
+   language plpgsql as $$
+ begin
+   raise notice '%: tg_depth = %', tg_name, tg_depth;
+   insert into tg_depth_b values (new.id);
+   raise notice '%: tg_depth = %', tg_name, tg_depth;
+   return new;
+ end;
+ $$;
+ create trigger tg_depth_a_tr before insert on tg_depth_a
+   for each row execute procedure tg_depth_a_tf();
+ 
+ create function tg_depth_b_tf() returns trigger
+   language plpgsql as $$
+ begin
+   raise notice '%: tg_depth = %', tg_name, tg_depth;
+   begin
+     execute 'insert into tg_depth_c values (' || new.id::text || ')';
+   exception
+     when sqlstate 'U9999' then
+       raise notice 'SQLSTATE = U9999: tg_depth = %', tg_depth;
+   end;
+   raise notice '%: tg_depth = %', tg_name, tg_depth;
+   execute 'insert into tg_depth_c values (' || new.id::text || ')';
+   return new;
+ end;
+ $$;
+ create trigger tg_depth_b_tr before insert on tg_depth_b
+   for each row execute procedure tg_depth_b_tf();
+ 
+ create function tg_depth_c_tf() returns trigger
+   language plpgsql as $$
+ begin
+   raise notice '%: tg_depth = %', tg_name, tg_depth;
+   raise exception sqlstate 'U9999';
+   return new;
+ end;
+ $$;
+ create trigger tg_depth_c_tr before insert on tg_depth_c
+   for each row execute procedure tg_depth_c_tf();
+ 
+ insert into tg_depth_a values (999);
+ 
+ drop table tg_depth_a, tg_depth_b, tg_depth_c;
+ drop function tg_depth_a_tf();
+ drop function tg_depth_b_tf();
+ drop function tg_depth_c_tf();
+ 
