PL/pgSQL, RAISE and error context

Started by Marko Tiikkajaover 12 years ago114 messages
#1Marko Tiikkaja
marko@joh.to

Hi,

By default, PL/pgSQL does not print the error context of a RAISE
statement, for example:

=# create function foof() returns void as $$ begin raise exception
'foo'; end $$ language plpgsql;
CREATE FUNCTION

=# create function bar() returns void as $$ begin perform foof(); end $$
language plpgsql;
CREATE FUNCTION

=# select bar();
ERROR: foo
CONTEXT: SQL statement "SELECT foof()"
PL/pgSQL function "bar" line 1 at PERFORM

I find this extremely surprising, since if you raise the same exception
(or a DEBUG/NOTICE message) in multiple places, the error context is
missing valuable information. With a trivial change the last error
could be:

=# select bar();
ERROR: foo
CONTEXT: PL/pgSQL function "foof" line 1 RAISE
SQL statement "SELECT foof()"
PL/pgSQL function "bar" line 1 at PERFORM

which I find a lot better.

Thoughts?

Regards,
Marko Tiikkaja

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#2Pavel Stehule
pavel.stehule@gmail.com
In reply to: Marko Tiikkaja (#1)
Re: PL/pgSQL, RAISE and error context

2013/8/21 Marko Tiikkaja <marko@joh.to>

Hi,

By default, PL/pgSQL does not print the error context of a RAISE
statement, for example:

=# create function foof() returns void as $$ begin raise exception 'foo';
end $$ language plpgsql;
CREATE FUNCTION

=# create function bar() returns void as $$ begin perform foof(); end $$
language plpgsql;
CREATE FUNCTION

=# select bar();
ERROR: foo
CONTEXT: SQL statement "SELECT foof()"
PL/pgSQL function "bar" line 1 at PERFORM

I find this extremely surprising, since if you raise the same exception
(or a DEBUG/NOTICE message) in multiple places, the error context is
missing valuable information. With a trivial change the last error could
be:

=# select bar();
ERROR: foo
CONTEXT: PL/pgSQL function "foof" line 1 RAISE
SQL statement "SELECT foof()"
PL/pgSQL function "bar" line 1 at PERFORM

which I find a lot better.

+1

Pavel

Show quoted text

Thoughts?

Regards,
Marko Tiikkaja

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/**mailpref/pgsql-hackers&lt;http://www.postgresql.org/mailpref/pgsql-hackers&gt;

#3Marko Tiikkaja
marko@joh.to
In reply to: Marko Tiikkaja (#1)
Re: PL/pgSQL, RAISE and error context

On 8/21/13 2:28 PM, I wrote:

By default, PL/pgSQL does not print the error context of a RAISE
statement, for example:

An even worse example:

=# create function foof() returns void as $$ begin raise exception
'foo'; end $$ language plpgsql;
CREATE FUNCTION

=# create function barf() returns void as $$ declare _ record; begin for
_ in execute 'select foof()' loop end loop; end $$ language plpgsql;
CREATE FUNCTION

=# select barf();
ERROR: foo
CONTEXT: PL/pgSQL function "barf" line 1 at FOR over EXECUTE statement

Notice how there's no mention at all about the function the error came
from, and compare that to:

=# select barf();
ERROR: foo
CONTEXT: PL/pgSQL function "foof" line 1 RAISE
PL/pgSQL function "barf" line 1 at FOR over EXECUTE statement

Regards,
Marko Tiikkaja

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#4Tom Lane
tgl@sss.pgh.pa.us
In reply to: Marko Tiikkaja (#1)
Re: PL/pgSQL, RAISE and error context

Marko Tiikkaja <marko@joh.to> writes:

By default, PL/pgSQL does not print the error context of a RAISE
statement, for example:

It used to do so, in the beginning when we first added context-printing.
There were complaints that the result was too verbose; for instance if you
had a RAISE NOTICE inside a loop for progress-monitoring purposes, you'd
get two lines for every one you wanted. I think if we undid this we'd
get the same complaints again. I agree that in complicated nests of
functions the location info is more interesting than it is in trivial
cases, but that doesn't mean you're not going to hear such complaints from
people with trivial functions.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#5Marko Tiikkaja
marko@joh.to
In reply to: Tom Lane (#4)
Re: PL/pgSQL, RAISE and error context

On 8/21/13 4:22 PM, Tom Lane wrote:

Marko Tiikkaja <marko@joh.to> writes:

By default, PL/pgSQL does not print the error context of a RAISE
statement, for example:

It used to do so, in the beginning when we first added context-printing.
There were complaints that the result was too verbose; for instance if you
had a RAISE NOTICE inside a loop for progress-monitoring purposes, you'd
get two lines for every one you wanted. I think if we undid this we'd
get the same complaints again. I agree that in complicated nests of
functions the location info is more interesting than it is in trivial
cases, but that doesn't mean you're not going to hear such complaints from
people with trivial functions.

They have an option: they can reduce verbosity in their client. I
currently don't have any real options.

Regards,
Marko Tiikkaja

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#6Merlin Moncure
mmoncure@gmail.com
In reply to: Tom Lane (#4)
Re: PL/pgSQL, RAISE and error context

On Wed, Aug 21, 2013 at 9:22 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Marko Tiikkaja <marko@joh.to> writes:

By default, PL/pgSQL does not print the error context of a RAISE
statement, for example:

It used to do so, in the beginning when we first added context-printing.
There were complaints that the result was too verbose; for instance if you
had a RAISE NOTICE inside a loop for progress-monitoring purposes, you'd
get two lines for every one you wanted. I think if we undid this we'd
get the same complaints again. I agree that in complicated nests of
functions the location info is more interesting than it is in trivial
cases, but that doesn't mean you're not going to hear such complaints from
people with trivial functions.

It *is* (apologies for the hijack) too verbose but whatever context
suppressing we added doesn't work in pretty much any interesting case.
What is basically needed is for the console to honor
log_error_verbosity (which I would prefer) or a separate GUC in manage
the console logging verbosity:

set log_error_verbosity = 'terse';
SET

CREATE OR REPLACE FUNCTION Notice(_msg TEXT) RETURNS VOID AS
$$
BEGIN
RAISE NOTICE '[%] %', clock_timestamp()::timestamp(0)::text, _msg;
END;
$$ LANGUAGE PLPGSQL;

CREATE OR REPLACE FUNCTION foo() RETURNS VOID AS
$$
BEGIN
PERFORM Notice('test');
END;
$$ LANGUAGE PLPGSQL;

-- context will print
postgres=# select foo();
NOTICE: [2013-08-21 09:52:08] test
CONTEXT: SQL statement "SELECT Notice('test')"
PL/pgSQL function foo() line 4 at PERFORM

CREATE OR REPLACE FUNCTION bar() RETURNS VOID AS
$$
SELECT Notice('test');
$$ LANGUAGE SQL;

-- context will not print
postgres=# select bar();
NOTICE: [2013-08-21 09:54:55] test

-- context will print
CREATE OR REPLACE FUNCTION baz() RETURNS VOID AS
$$
select 0;
SELECT Notice('test');
$$ LANGUAGE SQL;

postgres=# select baz();
NOTICE: [2013-08-21 09:55:26] test
CONTEXT: SQL function "baz" statement 2

merlin

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#7Marko Tiikkaja
marko@joh.to
In reply to: Merlin Moncure (#6)
Re: PL/pgSQL, RAISE and error context

On 8/21/13 5:05 PM, Merlin Moncure wrote:

On Wed, Aug 21, 2013 at 9:22 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Marko Tiikkaja <marko@joh.to> writes:

By default, PL/pgSQL does not print the error context of a RAISE
statement, for example:

It used to do so, in the beginning when we first added context-printing.
There were complaints that the result was too verbose; for instance if you
had a RAISE NOTICE inside a loop for progress-monitoring purposes, you'd
get two lines for every one you wanted. I think if we undid this we'd
get the same complaints again. I agree that in complicated nests of
functions the location info is more interesting than it is in trivial
cases, but that doesn't mean you're not going to hear such complaints from
people with trivial functions.

It *is* (apologies for the hijack) too verbose but whatever context
suppressing we added doesn't work in pretty much any interesting case.
What is basically needed is for the console to honor
log_error_verbosity (which I would prefer) or a separate GUC in manage
the console logging verbosity:

Why does \set VERBOSITY 'terse' not work for you?

Regards,
Marko Tiikkaja

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#8Merlin Moncure
mmoncure@gmail.com
In reply to: Marko Tiikkaja (#7)
Re: PL/pgSQL, RAISE and error context

On Wed, Aug 21, 2013 at 10:07 AM, Marko Tiikkaja <marko@joh.to> wrote:

On 8/21/13 5:05 PM, Merlin Moncure wrote:

On Wed, Aug 21, 2013 at 9:22 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Marko Tiikkaja <marko@joh.to> writes:

By default, PL/pgSQL does not print the error context of a RAISE
statement, for example:

It used to do so, in the beginning when we first added context-printing.
There were complaints that the result was too verbose; for instance if
you
had a RAISE NOTICE inside a loop for progress-monitoring purposes, you'd
get two lines for every one you wanted. I think if we undid this we'd
get the same complaints again. I agree that in complicated nests of
functions the location info is more interesting than it is in trivial
cases, but that doesn't mean you're not going to hear such complaints
from
people with trivial functions.

It *is* (apologies for the hijack) too verbose but whatever context
suppressing we added doesn't work in pretty much any interesting case.
What is basically needed is for the console to honor
log_error_verbosity (which I would prefer) or a separate GUC in manage
the console logging verbosity:

Why does \set VERBOSITY 'terse' not work for you?

Because it can't be controlled mid-function...that would suppress all
context of errors as well as messages and so it's useless. Also psql
directives for this purpose is a hack anyways -- what if I'm using a
non-psql client?

what I really want is:
SET LOCAL log_console_verbosity = 'x'

merlin

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#9Pavel Stehule
pavel.stehule@gmail.com
In reply to: Merlin Moncure (#8)
Re: PL/pgSQL, RAISE and error context

2013/8/21 Merlin Moncure <mmoncure@gmail.com>

On Wed, Aug 21, 2013 at 10:07 AM, Marko Tiikkaja <marko@joh.to> wrote:

On 8/21/13 5:05 PM, Merlin Moncure wrote:

On Wed, Aug 21, 2013 at 9:22 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Marko Tiikkaja <marko@joh.to> writes:

By default, PL/pgSQL does not print the error context of a RAISE
statement, for example:

It used to do so, in the beginning when we first added

context-printing.

There were complaints that the result was too verbose; for instance if
you
had a RAISE NOTICE inside a loop for progress-monitoring purposes,

you'd

get two lines for every one you wanted. I think if we undid this we'd
get the same complaints again. I agree that in complicated nests of
functions the location info is more interesting than it is in trivial
cases, but that doesn't mean you're not going to hear such complaints
from
people with trivial functions.

It *is* (apologies for the hijack) too verbose but whatever context
suppressing we added doesn't work in pretty much any interesting case.
What is basically needed is for the console to honor
log_error_verbosity (which I would prefer) or a separate GUC in manage
the console logging verbosity:

Why does \set VERBOSITY 'terse' not work for you?

Because it can't be controlled mid-function...that would suppress all
context of errors as well as messages and so it's useless. Also psql
directives for this purpose is a hack anyways -- what if I'm using a
non-psql client?

what I really want is:
SET LOCAL log_console_verbosity = 'x'

it is not bad idea

Pavel

Show quoted text

merlin

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#10Marko Tiikkaja
marko@joh.to
In reply to: Merlin Moncure (#8)
Re: PL/pgSQL, RAISE and error context

On 2013-08-21 17:18, Merlin Moncure wrote:

On Wed, Aug 21, 2013 at 10:07 AM, Marko Tiikkaja <marko@joh.to> wrote:

Why does \set VERBOSITY 'terse' not work for you?

Because it can't be controlled mid-function...that would suppress all
context of errors as well as messages and so it's useless.

Fair enough.

what I really want is:
SET LOCAL log_console_verbosity = 'x'

log_min_messages vs. client_min_messages, so client_error_verbosity
sounds more appropriate IMO.

Regards,
Marko Tiikkaja

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#11Tom Lane
tgl@sss.pgh.pa.us
In reply to: Merlin Moncure (#8)
Re: PL/pgSQL, RAISE and error context

Merlin Moncure <mmoncure@gmail.com> writes:

On Wed, Aug 21, 2013 at 10:07 AM, Marko Tiikkaja <marko@joh.to> wrote:

Why does \set VERBOSITY 'terse' not work for you?

Because it can't be controlled mid-function...that would suppress all
context of errors as well as messages and so it's useless. Also psql
directives for this purpose is a hack anyways -- what if I'm using a
non-psql client?

what I really want is:
SET LOCAL log_console_verbosity = 'x'

There was a protocol design decision a long time ago that verbosity
ought to be controlled on the client side. If we start suppressing
fields server-side I think we're going to have problems. In particular,
I'm going to throw the "what if I'm not using psql" argument right back
at you: what's the reason for thinking that a different client/application
would have the identical desires about what fields to see? It seems
unlikely that a Java application, say, would want the server to be
selective about what information it sends.

I'm entirely prepared to believe that psql's VERBOSITY behavior could
use more options, though.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#12Merlin Moncure
mmoncure@gmail.com
In reply to: Tom Lane (#11)
Re: PL/pgSQL, RAISE and error context

On Wed, Aug 21, 2013 at 10:47 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Merlin Moncure <mmoncure@gmail.com> writes:

On Wed, Aug 21, 2013 at 10:07 AM, Marko Tiikkaja <marko@joh.to> wrote:

Why does \set VERBOSITY 'terse' not work for you?

Because it can't be controlled mid-function...that would suppress all
context of errors as well as messages and so it's useless. Also psql
directives for this purpose is a hack anyways -- what if I'm using a
non-psql client?

what I really want is:
SET LOCAL log_console_verbosity = 'x'

There was a protocol design decision a long time ago that verbosity
ought to be controlled on the client side. If we start suppressing
fields server-side I think we're going to have problems. In particular,
I'm going to throw the "what if I'm not using psql" argument right back
at you: what's the reason for thinking that a different client/application
would have the identical desires about what fields to see? It seems
unlikely that a Java application, say, would want the server to be
selective about what information it sends.

I didn't like that decision then and I don't like it now. Why should
the protocol mandate that error context always be sent? Why does this
have anything to do with the protocol at all? Just because we can't
imagine a case where a java application would not want context to be
sent in some or all contexts doesn't mean that operators should not
have control over it being emitted. What harm could providing an
option possibly cause?

I'm entirely prepared to believe that psql's VERBOSITY behavior could
use more options, though.

How would that be structured... \set VERBOSITY 'NOTICE:terse'?

merlin

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#13Pavel Stehule
pavel.stehule@gmail.com
In reply to: Merlin Moncure (#12)
1 attachment(s)
Re: PL/pgSQL, RAISE and error context

Hello

I played with this topic little bit

If I understand, the main problem is in console (or pgAdmin) output.

create or replace function foo()
returns void as $$
begin
for i in 1..5
loop
raise notice '>>>>> *****';
end loop;
raise exception '***************';
end;
$$ language plpgsql;

postgres=# select foo();
NOTICE: >>>>> *****
NOTICE: >>>>> *****
NOTICE: >>>>> *****
NOTICE: >>>>> *****
NOTICE: >>>>> *****
ERROR: ***************
Time: 2.024 ms
postgres=# \set VER
VERBOSITY VERSION
postgres=# \set VERBOSITY

postgres=# \set VERBOSITY

postgres=# \set VERBOSITY terse
postgres=# select foo();
NOTICE: >>>>> *****
NOTICE: >>>>> *****
NOTICE: >>>>> *****
NOTICE: >>>>> *****
NOTICE: >>>>> *****
ERROR: ***************
Time: 0.908 ms
postgres=# \set VERBOSITY verbose
postgres=# select foo();
NOTICE: 00000: >>>>> *****
LOCATION: exec_stmt_raise, pl_exec.c:3051
NOTICE: 00000: >>>>> *****
LOCATION: exec_stmt_raise, pl_exec.c:3051
NOTICE: 00000: >>>>> *****
LOCATION: exec_stmt_raise, pl_exec.c:3051
NOTICE: 00000: >>>>> *****
LOCATION: exec_stmt_raise, pl_exec.c:3051
NOTICE: 00000: >>>>> *****
LOCATION: exec_stmt_raise, pl_exec.c:3051
ERROR: P0001: ***************
LOCATION: exec_stmt_raise, pl_exec.c:3051

Time: 0.314 ms

I see a two little bit not nice issues:

a) in terse mode missing a CONTEXT for RAISED error
b) in verbose mode missing a CONTEXT for messages, for error too, and
useless LOCATION is showed.

LOCATION is absolutely useless for custom messages.

so I removed a context filtering

postgres=# select foo();
NOTICE: >>>>> *****
CONTEXT: PL/pgSQL function foo() line 5 at RAISE
NOTICE: >>>>> *****
CONTEXT: PL/pgSQL function foo() line 5 at RAISE
NOTICE: >>>>> *****
CONTEXT: PL/pgSQL function foo() line 5 at RAISE
NOTICE: >>>>> *****
CONTEXT: PL/pgSQL function foo() line 5 at RAISE
NOTICE: >>>>> *****
CONTEXT: PL/pgSQL function foo() line 5 at RAISE
ERROR: ***************
CONTEXT: PL/pgSQL function foo() line 7 at RAISE
Time: 3.842 ms
postgres=# \set VERBOSITY verbose
postgres=# select foo();
NOTICE: 00000: >>>>> *****
CONTEXT: PL/pgSQL function foo() line 5 at RAISE
LOCATION: exec_stmt_raise, pl_exec.c:3046
NOTICE: 00000: >>>>> *****
CONTEXT: PL/pgSQL function foo() line 5 at RAISE
LOCATION: exec_stmt_raise, pl_exec.c:3046
NOTICE: 00000: >>>>> *****
CONTEXT: PL/pgSQL function foo() line 5 at RAISE
LOCATION: exec_stmt_raise, pl_exec.c:3046
NOTICE: 00000: >>>>> *****
CONTEXT: PL/pgSQL function foo() line 5 at RAISE
LOCATION: exec_stmt_raise, pl_exec.c:3046
NOTICE: 00000: >>>>> *****
CONTEXT: PL/pgSQL function foo() line 5 at RAISE
LOCATION: exec_stmt_raise, pl_exec.c:3046
ERROR: P0001: ***************
CONTEXT: PL/pgSQL function foo() line 7 at RAISE
LOCATION: exec_stmt_raise, pl_exec.c:3046
Time: 0.761 ms

We should not see a CONTEXT for DEFAULT verbosity and NOTICE level, after
little bit change I got a satisfied output

postgres=# select foo();

NOTICE: >>>>> *****
NOTICE: >>>>> *****
NOTICE: >>>>> *****
NOTICE: >>>>> *****
NOTICE: >>>>> *****

ERROR: ***************
CONTEXT: PL/pgSQL function foo() line 7 at RAISE
Time: 2.434 ms
postgres=# \set VERBOSITY verbose
postgres=# select foo();

NOTICE: 00000: >>>>> *****

CONTEXT: PL/pgSQL function foo() line 5 at RAISE
LOCATION: exec_stmt_raise, pl_exec.c:3046

NOTICE: 00000: >>>>> *****

CONTEXT: PL/pgSQL function foo() line 5 at RAISE
LOCATION: exec_stmt_raise, pl_exec.c:3046

NOTICE: 00000: >>>>> *****

CONTEXT: PL/pgSQL function foo() line 5 at RAISE
LOCATION: exec_stmt_raise, pl_exec.c:3046

NOTICE: 00000: >>>>> *****

CONTEXT: PL/pgSQL function foo() line 5 at RAISE
LOCATION: exec_stmt_raise, pl_exec.c:3046

NOTICE: 00000: >>>>> *****

CONTEXT: PL/pgSQL function foo() line 5 at RAISE
LOCATION: exec_stmt_raise, pl_exec.c:3046
ERROR: P0001: ***************
CONTEXT: PL/pgSQL function foo() line 7 at RAISE
LOCATION: exec_stmt_raise, pl_exec.c:3046
Time: 0.594 ms

Probably we can introduce a new level of verbosity, but I am thinking so
this behave is reasonable. Everybody who use a VERBOSE level expect lot of
balast and it show expected info (context of error)

Can be this design good enough for you?

Regards

Pavel

Attachments:

plpgsql_raise_context.patchapplication/octet-stream; name=plpgsql_raise_context.patchDownload
*** a/src/interfaces/libpq/fe-protocol3.c
--- b/src/interfaces/libpq/fe-protocol3.c
***************
*** 914,922 **** pqGetErrorNotice3(PGconn *conn, bool isError)
  		val = PQresultErrorField(res, PG_DIAG_INTERNAL_QUERY);
  		if (val)
  			appendPQExpBuffer(&workBuf, libpq_gettext("QUERY:  %s\n"), val);
! 		val = PQresultErrorField(res, PG_DIAG_CONTEXT);
! 		if (val)
! 			appendPQExpBuffer(&workBuf, libpq_gettext("CONTEXT:  %s\n"), val);
  	}
  	if (conn->verbosity == PQERRORS_VERBOSE)
  	{
--- 914,926 ----
  		val = PQresultErrorField(res, PG_DIAG_INTERNAL_QUERY);
  		if (val)
  			appendPQExpBuffer(&workBuf, libpq_gettext("QUERY:  %s\n"), val);
! 
! 		if (isError || conn->verbosity == PQERRORS_VERBOSE)
! 		{
! 			val = PQresultErrorField(res, PG_DIAG_CONTEXT);
! 			if (val)
! 				appendPQExpBuffer(&workBuf, libpq_gettext("CONTEXT:  %s\n"), val);
! 		}
  	}
  	if (conn->verbosity == PQERRORS_VERBOSE)
  	{
*** a/src/pl/plpgsql/src/pl_exec.c
--- b/src/pl/plpgsql/src/pl_exec.c
***************
*** 39,46 ****
  #include "utils/typcache.h"
  
  
- static const char *const raise_skip_msg = "RAISE";
- 
  typedef struct
  {
  	int			nargs;			/* number of arguments */
--- 39,44 ----
***************
*** 868,875 **** plpgsql_exec_error_callback(void *arg)
  	PLpgSQL_execstate *estate = (PLpgSQL_execstate *) arg;
  
  	/* if we are doing RAISE, don't report its location */
- 	if (estate->err_text == raise_skip_msg)
- 		return;
  
  	if (estate->err_text != NULL)
  	{
--- 866,871 ----
***************
*** 3032,3038 **** exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
  	/*
  	 * Throw the error (may or may not come back)
  	 */
- 	estate->err_text = raise_skip_msg;	/* suppress traceback of raise */
  
  	ereport(stmt->elog_level,
  			(err_code ? errcode(err_code) : 0,
--- 3028,3033 ----
#14Merlin Moncure
mmoncure@gmail.com
In reply to: Pavel Stehule (#13)
Re: PL/pgSQL, RAISE and error context

On Thu, Aug 22, 2013 at 2:08 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

Probably we can introduce a new level of verbosity, but I am thinking so
this behave is reasonable. Everybody who use a VERBOSE level expect lot of
balast and it show expected info (context of error)

Can be this design good enough for you?

yep :-).

merlin

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#15Marko Tiikkaja
marko@joh.to
In reply to: Pavel Stehule (#13)
Re: PL/pgSQL, RAISE and error context

On 8/22/13 9:08 AM, Pavel Stehule wrote:

Probably we can introduce a new level of verbosity, but I am thinking so
this behave is reasonable. Everybody who use a VERBOSE level expect lot of
balast and it show expected info (context of error)

Can be this design good enough for you?

I like the idea, but I think this should be a new verbosity level. With
this patch you would have to go full VERBOSE just to debug PL/pgSQL code
with NOTICEs and DEBUGs in it, and that output then becomes harder to
parse with the useless C-code information.

Regards,
Marko Tiikkaja

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#16Pavel Stehule
pavel.stehule@gmail.com
In reply to: Marko Tiikkaja (#15)
Re: PL/pgSQL, RAISE and error context

2013/8/22 Marko Tiikkaja <marko@joh.to>

On 8/22/13 9:08 AM, Pavel Stehule wrote:

Probably we can introduce a new level of verbosity, but I am thinking so
this behave is reasonable. Everybody who use a VERBOSE level expect lot of
balast and it show expected info (context of error)

Can be this design good enough for you?

I like the idea, but I think this should be a new verbosity level. With
this patch you would have to go full VERBOSE just to debug PL/pgSQL code
with NOTICEs and DEBUGs in it, and that output then becomes harder to parse
with the useless C-code information.

word "DEBUG" is not good - it is used for Postgres debugging as log level

Pavel

Show quoted text

Regards,
Marko Tiikkaja

#17Pavel Stehule
pavel.stehule@gmail.com
In reply to: Marko Tiikkaja (#15)
Re: PL/pgSQL, RAISE and error context

2013/8/22 Marko Tiikkaja <marko@joh.to>

On 8/22/13 9:08 AM, Pavel Stehule wrote:

Probably we can introduce a new level of verbosity, but I am thinking so
this behave is reasonable. Everybody who use a VERBOSE level expect lot of
balast and it show expected info (context of error)

Can be this design good enough for you?

I like the idea, but I think this should be a new verbosity level. With
this patch you would have to go full VERBOSE just to debug PL/pgSQL code
with NOTICEs and DEBUGs in it, and that output then becomes harder to parse
with the useless C-code information.

do you prepare patch ?

Pavel

Show quoted text

Regards,
Marko Tiikkaja

#18Marko Tiikkaja
marko@joh.to
In reply to: Pavel Stehule (#17)
Re: PL/pgSQL, RAISE and error context

On 8/23/13 8:38 AM, Pavel Stehule wrote:

2013/8/22 Marko Tiikkaja <marko@joh.to>

I like the idea, but I think this should be a new verbosity level. With
this patch you would have to go full VERBOSE just to debug PL/pgSQL code
with NOTICEs and DEBUGs in it, and that output then becomes harder to parse
with the useless C-code information.

do you prepare patch ?

I should have the time to produce one for the September commitfest, but
if you (or anyone else) want to work on this, I won't object.

My opinion at this very moment is that we should leave the the DEFAULT
verbosity alone and add a new one (call it COMPACT or such) with the
suppressed context for non-ERRORs.

Regards,
Marko Tiikkaja

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#19Pavel Stehule
pavel.stehule@gmail.com
In reply to: Marko Tiikkaja (#18)
Re: PL/pgSQL, RAISE and error context

2013/8/23 Marko Tiikkaja <marko@joh.to>

On 8/23/13 8:38 AM, Pavel Stehule wrote:

2013/8/22 Marko Tiikkaja <marko@joh.to>

I like the idea, but I think this should be a new verbosity level. With
this patch you would have to go full VERBOSE just to debug PL/pgSQL code
with NOTICEs and DEBUGs in it, and that output then becomes harder to
parse
with the useless C-code information.

do you prepare patch ?

I should have the time to produce one for the September commitfest, but if
you (or anyone else) want to work on this, I won't object.

My opinion at this very moment is that we should leave the the DEFAULT
verbosity alone and add a new one (call it COMPACT or such) with the
suppressed context for non-ERRORs.

The name is not important. What I would, for DEFAULT verbosity, to see a
context when RAISE EXCEPTION is used. It is a bug now, I think

Regards

Pavel

Show quoted text

Regards,
Marko Tiikkaja

#20Marko Tiikkaja
marko@joh.to
In reply to: Marko Tiikkaja (#18)
1 attachment(s)
Re: PL/pgSQL, RAISE and error context

On 23/08/2013 10:36, I wrote:

On 8/23/13 8:38 AM, Pavel Stehule wrote:

do you prepare patch ?

I should have the time to produce one for the September commitfest, but
if you (or anyone else) want to work on this, I won't object.

My opinion at this very moment is that we should leave the the DEFAULT
verbosity alone and add a new one (call it COMPACT or such) with the
suppressed context for non-ERRORs.

Well, turns out there isn't really any way to preserve complete
backwards compatibility if we want to do this change.

The attached patch (based on Pavel's patch) changes the default to be
slightly more verbose (the CONTEXT lines which were previously omitted
will be visible), but adds a new PGVerbosity called COMPACT which
suppresses CONTEXT in non-error messages. Now DEFAULT will be more
useful when debugging PL/PgSQL, and people who are annoyed by the new
behaviour can use the COMPACT mode.

Any thoughts?

Regards,
Marko Tiikkaja

Attachments:

raise_context.patchtext/plain; charset=windows-1252; name=raise_context.patchDownload
*** a/doc/src/sgml/libpq.sgml
--- b/doc/src/sgml/libpq.sgml
***************
*** 5418,5423 **** int PQsetClientEncoding(PGconn *<replaceable>conn</replaceable>, const char *<re
--- 5418,5424 ----
  typedef enum
  {
      PQERRORS_TERSE,
+     PQERRORS_COMPACT,
      PQERRORS_DEFAULT,
      PQERRORS_VERBOSE
  } PGVerbosity;
***************
*** 5430,5439 **** PGVerbosity PQsetErrorVerbosity(PGconn *conn, PGVerbosity verbosity);
        returned messages include severity, primary text, and position only;
        this will normally fit on a single line.  The default mode produces
        messages that include the above plus any detail, hint, or context
!       fields (these might span multiple lines).  The <firstterm>VERBOSE</>
!       mode includes all available fields.  Changing the verbosity does not
!       affect the messages available from already-existing
!       <structname>PGresult</> objects, only subsequently-created ones.
       </para>
      </listitem>
     </varlistentry>
--- 5431,5442 ----
        returned messages include severity, primary text, and position only;
        this will normally fit on a single line.  The default mode produces
        messages that include the above plus any detail, hint, or context
!       fields (these might span multiple lines).  The COMPACT mode is otherwise
!       the same as the default, except the context field will be omitted for
!       non-error messages.  The <firstterm>VERBOSE</> mode includes all
!       available fields.  Changing the verbosity does not affect the messages
!       available from already-existing <structname>PGresult</> objects, only
!       subsequently-created ones.
       </para>
      </listitem>
     </varlistentry>
*** a/src/bin/psql/startup.c
--- b/src/bin/psql/startup.c
***************
*** 796,801 **** verbosity_hook(const char *newval)
--- 796,803 ----
  		pset.verbosity = PQERRORS_DEFAULT;
  	else if (strcmp(newval, "terse") == 0)
  		pset.verbosity = PQERRORS_TERSE;
+ 	else if (strcmp(newval, "compact") == 0)
+ 		pset.verbosity = PQERRORS_COMPACT;
  	else if (strcmp(newval, "verbose") == 0)
  		pset.verbosity = PQERRORS_VERBOSE;
  	else
*** a/src/interfaces/libpq/fe-protocol3.c
--- b/src/interfaces/libpq/fe-protocol3.c
***************
*** 915,920 **** pqGetErrorNotice3(PGconn *conn, bool isError)
--- 915,924 ----
  		if (val)
  			appendPQExpBuffer(&workBuf, libpq_gettext("QUERY:  %s\n"), val);
  		val = PQresultErrorField(res, PG_DIAG_CONTEXT);
+ 	}
+ 	if (isError || (conn->verbosity != PQERRORS_TERSE &&
+ 					conn->verbosity != PQERRORS_COMPACT))
+ 	{
  		if (val)
  			appendPQExpBuffer(&workBuf, libpq_gettext("CONTEXT:  %s\n"), val);
  	}
*** a/src/interfaces/libpq/libpq-fe.h
--- b/src/interfaces/libpq/libpq-fe.h
***************
*** 106,111 **** typedef enum
--- 106,112 ----
  typedef enum
  {
  	PQERRORS_TERSE,				/* single-line error messages */
+ 	PQERRORS_COMPACT,			/* single-line error messages on non-error messags */
  	PQERRORS_DEFAULT,			/* recommended style */
  	PQERRORS_VERBOSE			/* all the facts, ma'am */
  } PGVerbosity;
*** a/src/pl/plpgsql/src/pl_exec.c
--- b/src/pl/plpgsql/src/pl_exec.c
***************
*** 39,46 ****
  #include "utils/typcache.h"
  
  
- static const char *const raise_skip_msg = "RAISE";
- 
  typedef struct
  {
  	int			nargs;			/* number of arguments */
--- 39,44 ----
***************
*** 867,876 **** plpgsql_exec_error_callback(void *arg)
  {
  	PLpgSQL_execstate *estate = (PLpgSQL_execstate *) arg;
  
- 	/* if we are doing RAISE, don't report its location */
- 	if (estate->err_text == raise_skip_msg)
- 		return;
- 
  	if (estate->err_text != NULL)
  	{
  		/*
--- 865,870 ----
***************
*** 3032,3038 **** exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
  	/*
  	 * Throw the error (may or may not come back)
  	 */
- 	estate->err_text = raise_skip_msg;	/* suppress traceback of raise */
  
  	ereport(stmt->elog_level,
  			(err_code ? errcode(err_code) : 0,
--- 3026,3031 ----
#21Pavel Stehule
pavel.stehule@gmail.com
In reply to: Marko Tiikkaja (#20)
Re: PL/pgSQL, RAISE and error context

2013/9/14 Marko Tiikkaja <marko@joh.to>

On 23/08/2013 10:36, I wrote:

On 8/23/13 8:38 AM, Pavel Stehule wrote:

do you prepare patch ?

I should have the time to produce one for the September commitfest, but
if you (or anyone else) want to work on this, I won't object.

My opinion at this very moment is that we should leave the the DEFAULT
verbosity alone and add a new one (call it COMPACT or such) with the
suppressed context for non-ERRORs.

Well, turns out there isn't really any way to preserve complete backwards
compatibility if we want to do this change.

The attached patch (based on Pavel's patch) changes the default to be
slightly more verbose (the CONTEXT lines which were previously omitted will
be visible), but adds a new PGVerbosity called COMPACT which suppresses
CONTEXT in non-error messages. Now DEFAULT will be more useful when
debugging PL/PgSQL, and people who are annoyed by the new behaviour can use
the COMPACT mode.

Any thoughts?

+1

Regards

Pavel

Show quoted text

Regards,
Marko Tiikkaja

#22Peter Eisentraut
peter_e@gmx.net
In reply to: Marko Tiikkaja (#20)
Re: PL/pgSQL, RAISE and error context

On Sat, 2013-09-14 at 04:58 +0200, Marko Tiikkaja wrote:

The attached patch (based on Pavel's patch) changes the default to be
slightly more verbose (the CONTEXT lines which were previously
omitted
will be visible), but adds a new PGVerbosity called COMPACT which
suppresses CONTEXT in non-error messages. Now DEFAULT will be more
useful when debugging PL/PgSQL, and people who are annoyed by the new
behaviour can use the COMPACT mode.

Your patch fails the regression tests.

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#23Marko Tiikkaja
marko@joh.to
In reply to: Peter Eisentraut (#22)
1 attachment(s)
Re: PL/pgSQL, RAISE and error context

On 15/09/2013 04:05, Peter Eisentraut wrote:

On Sat, 2013-09-14 at 04:58 +0200, Marko Tiikkaja wrote:

The attached patch (based on Pavel's patch) changes the default to be
slightly more verbose (the CONTEXT lines which were previously
omitted
will be visible), but adds a new PGVerbosity called COMPACT which
suppresses CONTEXT in non-error messages. Now DEFAULT will be more
useful when debugging PL/PgSQL, and people who are annoyed by the new
behaviour can use the COMPACT mode.

Your patch fails the regression tests.

Attached is an updated patch with the regression test fixes. No other
changes included.

Regards,
Marko Tiikkaja

Attachments:

raise_context_v2.patchtext/plain; charset=windows-1252; name=raise_context_v2.patchDownload
*** a/doc/src/sgml/libpq.sgml
--- b/doc/src/sgml/libpq.sgml
***************
*** 5418,5423 **** int PQsetClientEncoding(PGconn *<replaceable>conn</replaceable>, const char *<re
--- 5418,5424 ----
  typedef enum
  {
      PQERRORS_TERSE,
+     PQERRORS_COMPACT,
      PQERRORS_DEFAULT,
      PQERRORS_VERBOSE
  } PGVerbosity;
***************
*** 5430,5439 **** PGVerbosity PQsetErrorVerbosity(PGconn *conn, PGVerbosity verbosity);
        returned messages include severity, primary text, and position only;
        this will normally fit on a single line.  The default mode produces
        messages that include the above plus any detail, hint, or context
!       fields (these might span multiple lines).  The <firstterm>VERBOSE</>
!       mode includes all available fields.  Changing the verbosity does not
!       affect the messages available from already-existing
!       <structname>PGresult</> objects, only subsequently-created ones.
       </para>
      </listitem>
     </varlistentry>
--- 5431,5442 ----
        returned messages include severity, primary text, and position only;
        this will normally fit on a single line.  The default mode produces
        messages that include the above plus any detail, hint, or context
!       fields (these might span multiple lines).  The COMPACT mode is otherwise
!       the same as the default, except the context field will be omitted for
!       non-error messages.  The <firstterm>VERBOSE</> mode includes all
!       available fields.  Changing the verbosity does not affect the messages
!       available from already-existing <structname>PGresult</> objects, only
!       subsequently-created ones.
       </para>
      </listitem>
     </varlistentry>
*** a/src/bin/psql/startup.c
--- b/src/bin/psql/startup.c
***************
*** 796,801 **** verbosity_hook(const char *newval)
--- 796,803 ----
  		pset.verbosity = PQERRORS_DEFAULT;
  	else if (strcmp(newval, "terse") == 0)
  		pset.verbosity = PQERRORS_TERSE;
+ 	else if (strcmp(newval, "compact") == 0)
+ 		pset.verbosity = PQERRORS_COMPACT;
  	else if (strcmp(newval, "verbose") == 0)
  		pset.verbosity = PQERRORS_VERBOSE;
  	else
*** a/src/interfaces/libpq/fe-protocol3.c
--- b/src/interfaces/libpq/fe-protocol3.c
***************
*** 915,920 **** pqGetErrorNotice3(PGconn *conn, bool isError)
--- 915,924 ----
  		if (val)
  			appendPQExpBuffer(&workBuf, libpq_gettext("QUERY:  %s\n"), val);
  		val = PQresultErrorField(res, PG_DIAG_CONTEXT);
+ 	}
+ 	if (isError || (conn->verbosity != PQERRORS_TERSE &&
+ 					conn->verbosity != PQERRORS_COMPACT))
+ 	{
  		if (val)
  			appendPQExpBuffer(&workBuf, libpq_gettext("CONTEXT:  %s\n"), val);
  	}
*** a/src/interfaces/libpq/libpq-fe.h
--- b/src/interfaces/libpq/libpq-fe.h
***************
*** 106,111 **** typedef enum
--- 106,112 ----
  typedef enum
  {
  	PQERRORS_TERSE,				/* single-line error messages */
+ 	PQERRORS_COMPACT,			/* single-line error messages on non-error messags */
  	PQERRORS_DEFAULT,			/* recommended style */
  	PQERRORS_VERBOSE			/* all the facts, ma'am */
  } PGVerbosity;
*** a/src/pl/plpgsql/src/pl_exec.c
--- b/src/pl/plpgsql/src/pl_exec.c
***************
*** 39,46 ****
  #include "utils/typcache.h"
  
  
- static const char *const raise_skip_msg = "RAISE";
- 
  typedef struct
  {
  	int			nargs;			/* number of arguments */
--- 39,44 ----
***************
*** 867,876 **** plpgsql_exec_error_callback(void *arg)
  {
  	PLpgSQL_execstate *estate = (PLpgSQL_execstate *) arg;
  
- 	/* if we are doing RAISE, don't report its location */
- 	if (estate->err_text == raise_skip_msg)
- 		return;
- 
  	if (estate->err_text != NULL)
  	{
  		/*
--- 865,870 ----
***************
*** 3032,3038 **** exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
  	/*
  	 * Throw the error (may or may not come back)
  	 */
- 	estate->err_text = raise_skip_msg;	/* suppress traceback of raise */
  
  	ereport(stmt->elog_level,
  			(err_code ? errcode(err_code) : 0,
--- 3026,3031 ----
*** a/src/test/regress/expected/alter_table.out
--- b/src/test/regress/expected/alter_table.out
***************
*** 361,371 **** CREATE FUNCTION boo(int) RETURNS int IMMUTABLE STRICT LANGUAGE plpgsql AS $$ BEG
--- 361,374 ----
  INSERT INTO tmp7 VALUES (8, 18);
  ALTER TABLE tmp7 ADD CONSTRAINT identity CHECK (b = boo(b));
  NOTICE:  boo: 18
+ CONTEXT:  PL/pgSQL function boo(integer) line 1 at RAISE
  ALTER TABLE tmp3 ADD CONSTRAINT IDENTITY check (b = boo(b)) NOT VALID;
  NOTICE:  merging constraint "identity" with inherited definition
  ALTER TABLE tmp3 VALIDATE CONSTRAINT identity;
  NOTICE:  boo: 16
+ CONTEXT:  PL/pgSQL function boo(integer) line 1 at RAISE
  NOTICE:  boo: 20
+ CONTEXT:  PL/pgSQL function boo(integer) line 1 at RAISE
  -- Try (and fail) to create constraint from tmp5(a) to tmp4(a) - unique constraint on
  -- tmp4 is a,b
  ALTER TABLE tmp5 add constraint tmpconstr foreign key(a) references tmp4(a) match full;
*** a/src/test/regress/expected/event_trigger.out
--- b/src/test/regress/expected/event_trigger.out
***************
*** 70,79 **** alter event trigger regress_event_trigger disable;
--- 70,82 ----
  -- regress_event_trigger
  create table event_trigger_fire1 (a int);
  NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+ CONTEXT:  PL/pgSQL function test_event_trigger() line 3 at RAISE
  NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+ CONTEXT:  PL/pgSQL function test_event_trigger() line 3 at RAISE
  -- regress_event_trigger_end should fire here
  drop table event_trigger_fire1;
  NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
+ CONTEXT:  PL/pgSQL function test_event_trigger() line 3 at RAISE
  -- alter owner to non-superuser should fail
  alter event trigger regress_event_trigger owner to regression_bob;
  ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
***************
*** 194,200 **** PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three"
  PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  ERROR:  object audit_tbls.schema_two_table_three of type table cannot be dropped
! CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three"
  PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  DELETE FROM undroppable_objs WHERE object_identity = 'audit_tbls.schema_two_table_three';
  DROP SCHEMA schema_one, schema_two CASCADE;
--- 197,204 ----
  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three"
  PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  ERROR:  object audit_tbls.schema_two_table_three of type table cannot be dropped
! CONTEXT:  PL/pgSQL function undroppable() line 14 at RAISE
! SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three"
  PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  DELETE FROM undroppable_objs WHERE object_identity = 'audit_tbls.schema_two_table_three';
  DROP SCHEMA schema_one, schema_two CASCADE;
***************
*** 224,229 **** NOTICE:  table "schema_one_table_three" does not exist, skipping
--- 228,234 ----
  CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_one_table_three"
  PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  ERROR:  object schema_one.table_three of type table cannot be dropped
+ CONTEXT:  PL/pgSQL function undroppable() line 14 at RAISE
  DELETE FROM undroppable_objs WHERE object_identity = 'schema_one.table_three';
  DROP SCHEMA schema_one, schema_two CASCADE;
  NOTICE:  drop cascades to 7 other objects
*** a/src/test/regress/expected/plancache.out
--- b/src/test/regress/expected/plancache.out
***************
*** 237,244 **** NOTICE:  table "temptable" does not exist, skipping
--- 237,247 ----
  CONTEXT:  SQL statement "drop table if exists temptable cascade"
  PL/pgSQL function cachebug() line 4 at SQL statement
  NOTICE:  1
+ CONTEXT:  PL/pgSQL function cachebug() line 8 at RAISE
  NOTICE:  2
+ CONTEXT:  PL/pgSQL function cachebug() line 8 at RAISE
  NOTICE:  3
+ CONTEXT:  PL/pgSQL function cachebug() line 8 at RAISE
   cachebug 
  ----------
   
***************
*** 249,256 **** NOTICE:  drop cascades to view vv
--- 252,262 ----
  CONTEXT:  SQL statement "drop table if exists temptable cascade"
  PL/pgSQL function cachebug() line 4 at SQL statement
  NOTICE:  1
+ CONTEXT:  PL/pgSQL function cachebug() line 8 at RAISE
  NOTICE:  2
+ CONTEXT:  PL/pgSQL function cachebug() line 8 at RAISE
  NOTICE:  3
+ CONTEXT:  PL/pgSQL function cachebug() line 8 at RAISE
   cachebug 
  ----------
   
*** a/src/test/regress/expected/plpgsql.out
--- b/src/test/regress/expected/plpgsql.out
***************
*** 1518,1544 **** ERROR:  duplicate key value violates unique constraint "pfield_name"
  DETAIL:  Key (name)=(PF1_1) already exists.
  update PSlot set backlink = 'WS.not.there' where slotname = 'PS.base.a1';
  ERROR:  WS.not.there         does not exist
! CONTEXT:  PL/pgSQL function tg_backlink_a() line 17 at assignment
  update PSlot set backlink = 'XX.illegal' where slotname = 'PS.base.a1';
  ERROR:  illegal backlink beginning with XX
! CONTEXT:  PL/pgSQL function tg_backlink_a() line 17 at assignment
  update PSlot set slotlink = 'PS.not.there' where slotname = 'PS.base.a1';
  ERROR:  PS.not.there         does not exist
! CONTEXT:  PL/pgSQL function tg_slotlink_a() line 17 at assignment
  update PSlot set slotlink = 'XX.illegal' where slotname = 'PS.base.a1';
  ERROR:  illegal slotlink beginning with XX
! CONTEXT:  PL/pgSQL function tg_slotlink_a() line 17 at assignment
  insert into HSlot values ('HS', 'base.hub1', 1, '');
  ERROR:  duplicate key value violates unique constraint "hslot_name"
  DETAIL:  Key (slotname)=(HS.base.hub1.1      ) already exists.
  insert into HSlot values ('HS', 'base.hub1', 20, '');
  ERROR:  no manual manipulation of HSlot
  delete from HSlot;
  ERROR:  no manual manipulation of HSlot
  insert into IFace values ('IF', 'notthere', 'eth0', '');
  ERROR:  system "notthere" does not exist
  insert into IFace values ('IF', 'orion', 'ethernet_interface_name_too_long', '');
  ERROR:  IFace slotname "IF.orion.ethernet_interface_name_too_long" too long (20 char max)
  --
  -- The following tests are unrelated to the scenario outlined above;
  -- they merely exercise specific parts of PL/pgSQL
--- 1518,1552 ----
  DETAIL:  Key (name)=(PF1_1) already exists.
  update PSlot set backlink = 'WS.not.there' where slotname = 'PS.base.a1';
  ERROR:  WS.not.there         does not exist
! CONTEXT:  PL/pgSQL function tg_backlink_set(character,character) line 30 at RAISE
! PL/pgSQL function tg_backlink_a() line 17 at assignment
  update PSlot set backlink = 'XX.illegal' where slotname = 'PS.base.a1';
  ERROR:  illegal backlink beginning with XX
! CONTEXT:  PL/pgSQL function tg_backlink_set(character,character) line 47 at RAISE
! PL/pgSQL function tg_backlink_a() line 17 at assignment
  update PSlot set slotlink = 'PS.not.there' where slotname = 'PS.base.a1';
  ERROR:  PS.not.there         does not exist
! CONTEXT:  PL/pgSQL function tg_slotlink_set(character,character) line 30 at RAISE
! PL/pgSQL function tg_slotlink_a() line 17 at assignment
  update PSlot set slotlink = 'XX.illegal' where slotname = 'PS.base.a1';
  ERROR:  illegal slotlink beginning with XX
! CONTEXT:  PL/pgSQL function tg_slotlink_set(character,character) line 77 at RAISE
! PL/pgSQL function tg_slotlink_a() line 17 at assignment
  insert into HSlot values ('HS', 'base.hub1', 1, '');
  ERROR:  duplicate key value violates unique constraint "hslot_name"
  DETAIL:  Key (slotname)=(HS.base.hub1.1      ) already exists.
  insert into HSlot values ('HS', 'base.hub1', 20, '');
  ERROR:  no manual manipulation of HSlot
+ CONTEXT:  PL/pgSQL function tg_hslot_biu() line 12 at RAISE
  delete from HSlot;
  ERROR:  no manual manipulation of HSlot
+ CONTEXT:  PL/pgSQL function tg_hslot_bd() line 12 at RAISE
  insert into IFace values ('IF', 'notthere', 'eth0', '');
  ERROR:  system "notthere" does not exist
+ CONTEXT:  PL/pgSQL function tg_iface_biu() line 8 at RAISE
  insert into IFace values ('IF', 'orion', 'ethernet_interface_name_too_long', '');
  ERROR:  IFace slotname "IF.orion.ethernet_interface_name_too_long" too long (20 char max)
+ CONTEXT:  PL/pgSQL function tg_iface_biu() line 14 at RAISE
  --
  -- The following tests are unrelated to the scenario outlined above;
  -- they merely exercise specific parts of PL/pgSQL
***************
*** 1934,1941 **** begin
--- 1942,1952 ----
  end$$ language plpgsql;
  select trap_zero_divide(50);
  NOTICE:  should see this
+ CONTEXT:  PL/pgSQL function trap_zero_divide(integer) line 6 at RAISE
  NOTICE:  should see this only if 50 <> 0
+ CONTEXT:  PL/pgSQL function trap_zero_divide(integer) line 8 at RAISE
  NOTICE:  should see this only if 50 fits in smallint
+ CONTEXT:  PL/pgSQL function trap_zero_divide(integer) line 10 at RAISE
   trap_zero_divide 
  ------------------
                  2
***************
*** 1943,1949 **** NOTICE:  should see this only if 50 fits in smallint
--- 1954,1962 ----
  
  select trap_zero_divide(0);
  NOTICE:  should see this
+ CONTEXT:  PL/pgSQL function trap_zero_divide(integer) line 6 at RAISE
  NOTICE:  caught division_by_zero
+ CONTEXT:  PL/pgSQL function trap_zero_divide(integer) line 16 at RAISE
   trap_zero_divide 
  ------------------
                 -1
***************
*** 1951,1958 **** NOTICE:  caught division_by_zero
--- 1964,1974 ----
  
  select trap_zero_divide(100000);
  NOTICE:  should see this
+ CONTEXT:  PL/pgSQL function trap_zero_divide(integer) line 6 at RAISE
  NOTICE:  should see this only if 100000 <> 0
+ CONTEXT:  PL/pgSQL function trap_zero_divide(integer) line 8 at RAISE
  NOTICE:  caught numeric_value_out_of_range
+ CONTEXT:  PL/pgSQL function trap_zero_divide(integer) line 19 at RAISE
   trap_zero_divide 
  ------------------
                 -2
***************
*** 1960,1968 **** NOTICE:  caught numeric_value_out_of_range
--- 1976,1988 ----
  
  select trap_zero_divide(-100);
  NOTICE:  should see this
+ CONTEXT:  PL/pgSQL function trap_zero_divide(integer) line 6 at RAISE
  NOTICE:  should see this only if -100 <> 0
+ CONTEXT:  PL/pgSQL function trap_zero_divide(integer) line 8 at RAISE
  NOTICE:  should see this only if -100 fits in smallint
+ CONTEXT:  PL/pgSQL function trap_zero_divide(integer) line 10 at RAISE
  ERROR:  -100 is less than zero
+ CONTEXT:  PL/pgSQL function trap_zero_divide(integer) line 12 at RAISE
  create function trap_matching_test(int) returns int as $$
  declare x int;
  	sx smallint;
***************
*** 1991,1996 **** select trap_matching_test(50);
--- 2011,2017 ----
  
  select trap_matching_test(0);
  NOTICE:  caught data_exception
+ CONTEXT:  PL/pgSQL function trap_matching_test(integer) line 13 at RAISE
   trap_matching_test 
  --------------------
                   -1
***************
*** 1998,2003 **** NOTICE:  caught data_exception
--- 2019,2025 ----
  
  select trap_matching_test(100000);
  NOTICE:  caught data_exception
+ CONTEXT:  PL/pgSQL function trap_matching_test(integer) line 13 at RAISE
   trap_matching_test 
  --------------------
                   -1
***************
*** 2005,2010 **** NOTICE:  caught data_exception
--- 2027,2033 ----
  
  select trap_matching_test(1);
  NOTICE:  caught numeric_value_out_of_range or cardinality_violation
+ CONTEXT:  PL/pgSQL function trap_matching_test(integer) line 16 at RAISE
   trap_matching_test 
  --------------------
                   -2
***************
*** 2035,2040 **** end$$ language plpgsql;
--- 2058,2064 ----
  set statement_timeout to 2000;
  select blockme();
  NOTICE:  nyeah nyeah, can't stop me
+ CONTEXT:  PL/pgSQL function blockme() line 16 at RAISE
   blockme 
  ---------
        20
***************
*** 2066,2078 **** begin
  end$$ language plpgsql;
  select test_variable_storage();
  NOTICE:  should see this
! CONTEXT:  SQL statement "SELECT trap_zero_divide(-100)"
  PL/pgSQL function test_variable_storage() line 8 at PERFORM
  NOTICE:  should see this only if -100 <> 0
! CONTEXT:  SQL statement "SELECT trap_zero_divide(-100)"
  PL/pgSQL function test_variable_storage() line 8 at PERFORM
  NOTICE:  should see this only if -100 fits in smallint
! CONTEXT:  SQL statement "SELECT trap_zero_divide(-100)"
  PL/pgSQL function test_variable_storage() line 8 at PERFORM
   test_variable_storage 
  -----------------------
--- 2090,2105 ----
  end$$ language plpgsql;
  select test_variable_storage();
  NOTICE:  should see this
! CONTEXT:  PL/pgSQL function trap_zero_divide(integer) line 6 at RAISE
! SQL statement "SELECT trap_zero_divide(-100)"
  PL/pgSQL function test_variable_storage() line 8 at PERFORM
  NOTICE:  should see this only if -100 <> 0
! CONTEXT:  PL/pgSQL function trap_zero_divide(integer) line 8 at RAISE
! SQL statement "SELECT trap_zero_divide(-100)"
  PL/pgSQL function test_variable_storage() line 8 at PERFORM
  NOTICE:  should see this only if -100 fits in smallint
! CONTEXT:  PL/pgSQL function trap_zero_divide(integer) line 10 at RAISE
! SQL statement "SELECT trap_zero_divide(-100)"
  PL/pgSQL function test_variable_storage() line 8 at PERFORM
   test_variable_storage 
  -----------------------
***************
*** 2119,2124 **** select trap_foreign_key(1);
--- 2146,2152 ----
  
  select trap_foreign_key(2);	-- detects FK violation
  NOTICE:  caught foreign_key_violation
+ CONTEXT:  PL/pgSQL function trap_foreign_key(integer) line 7 at RAISE
   trap_foreign_key 
  ------------------
                  0
***************
*** 2139,2144 **** DETAIL:  Key (f1)=(2) is not present in table "master".
--- 2167,2173 ----
    rollback to x;
    select trap_foreign_key_2();  -- detects FK violation
  NOTICE:  caught foreign_key_violation
+ CONTEXT:  PL/pgSQL function trap_foreign_key_2() line 7 at RAISE
   trap_foreign_key_2 
  --------------------
                    0
***************
*** 2481,2487 **** END;
--- 2510,2518 ----
  $$ LANGUAGE plpgsql;
  SELECT reraise_test();
  NOTICE:  exception syntax_error thrown in inner block, reraising
+ CONTEXT:  PL/pgSQL function reraise_test() line 8 at RAISE
  NOTICE:  RIGHT - exception syntax_error caught in inner block
+ CONTEXT:  PL/pgSQL function reraise_test() line 12 at RAISE
   reraise_test 
  --------------
   
***************
*** 2576,2583 **** begin
--- 2607,2617 ----
  end; $$ language plpgsql;
  select execute_into_test('eifoo');
  NOTICE:  10 1
+ CONTEXT:  PL/pgSQL function execute_into_test(character varying) line 12 at RAISE
  NOTICE:  10 15
+ CONTEXT:  PL/pgSQL function execute_into_test(character varying) line 14 at RAISE
  NOTICE:  10 15 20
+ CONTEXT:  PL/pgSQL function execute_into_test(character varying) line 16 at RAISE
   execute_into_test 
  -------------------
   (1,2)
***************
*** 2636,2644 **** begin
--- 2670,2682 ----
  end; $$ language plpgsql;
  select excpt_test3();
  NOTICE:  caught exception P0001 user exception
+ CONTEXT:  PL/pgSQL function excpt_test3() line 6 at RAISE
  NOTICE:  P0001 user exception
+ CONTEXT:  PL/pgSQL function excpt_test3() line 8 at RAISE
  NOTICE:  caught exception 22012 division by zero
+ CONTEXT:  PL/pgSQL function excpt_test3() line 15 at RAISE
  NOTICE:  P0001 user exception
+ CONTEXT:  PL/pgSQL function excpt_test3() line 17 at RAISE
   excpt_test3 
  -------------
   
***************
*** 2659,2664 **** begin
--- 2697,2703 ----
  end;$$ language plpgsql;
  select raise_exprs();
  NOTICE:  {10,20,30}; 20; xyz; xyzabc; (10,aaa,,30); <NULL>
+ CONTEXT:  PL/pgSQL function raise_exprs() line 8 at RAISE
   raise_exprs 
  -------------
   
***************
*** 2750,2807 **** begin
--- 2789,2899 ----
  end; $$ language plpgsql;
  select continue_test1();
  NOTICE:  ---1---
+ CONTEXT:  PL/pgSQL function continue_test1() line 4 at RAISE
  NOTICE:  1
+ CONTEXT:  PL/pgSQL function continue_test1() line 7 at RAISE
  NOTICE:  2
+ CONTEXT:  PL/pgSQL function continue_test1() line 7 at RAISE
  NOTICE:  3
+ CONTEXT:  PL/pgSQL function continue_test1() line 7 at RAISE
  NOTICE:  4
+ CONTEXT:  PL/pgSQL function continue_test1() line 7 at RAISE
  NOTICE:  5
+ CONTEXT:  PL/pgSQL function continue_test1() line 7 at RAISE
  NOTICE:  6
+ CONTEXT:  PL/pgSQL function continue_test1() line 7 at RAISE
  NOTICE:  7
+ CONTEXT:  PL/pgSQL function continue_test1() line 7 at RAISE
  NOTICE:  8
+ CONTEXT:  PL/pgSQL function continue_test1() line 7 at RAISE
  NOTICE:  9
+ CONTEXT:  PL/pgSQL function continue_test1() line 7 at RAISE
  NOTICE:  10
+ CONTEXT:  PL/pgSQL function continue_test1() line 7 at RAISE
  NOTICE:  ---2---
+ CONTEXT:  PL/pgSQL function continue_test1() line 12 at RAISE
  NOTICE:  9
+ CONTEXT:  PL/pgSQL function continue_test1() line 17 at RAISE
  NOTICE:  8
+ CONTEXT:  PL/pgSQL function continue_test1() line 17 at RAISE
  NOTICE:  7
+ CONTEXT:  PL/pgSQL function continue_test1() line 17 at RAISE
  NOTICE:  6
+ CONTEXT:  PL/pgSQL function continue_test1() line 17 at RAISE
  NOTICE:  5
+ CONTEXT:  PL/pgSQL function continue_test1() line 17 at RAISE
  NOTICE:  4
+ CONTEXT:  PL/pgSQL function continue_test1() line 17 at RAISE
  NOTICE:  3
+ CONTEXT:  PL/pgSQL function continue_test1() line 17 at RAISE
  NOTICE:  2
+ CONTEXT:  PL/pgSQL function continue_test1() line 17 at RAISE
  NOTICE:  1
+ CONTEXT:  PL/pgSQL function continue_test1() line 17 at RAISE
  NOTICE:  0
+ CONTEXT:  PL/pgSQL function continue_test1() line 17 at RAISE
  NOTICE:  ---3---
+ CONTEXT:  PL/pgSQL function continue_test1() line 23 at RAISE
  NOTICE:  1
+ CONTEXT:  PL/pgSQL function continue_test1() line 28 at RAISE
  NOTICE:  3
+ CONTEXT:  PL/pgSQL function continue_test1() line 28 at RAISE
  NOTICE:  5
+ CONTEXT:  PL/pgSQL function continue_test1() line 28 at RAISE
  NOTICE:  7
+ CONTEXT:  PL/pgSQL function continue_test1() line 28 at RAISE
  NOTICE:  9
+ CONTEXT:  PL/pgSQL function continue_test1() line 28 at RAISE
  NOTICE:  ---4---
+ CONTEXT:  PL/pgSQL function continue_test1() line 31 at RAISE
  NOTICE:  5
+ CONTEXT:  PL/pgSQL function continue_test1() line 36 at RAISE
  NOTICE:  6
+ CONTEXT:  PL/pgSQL function continue_test1() line 36 at RAISE
  NOTICE:  7
+ CONTEXT:  PL/pgSQL function continue_test1() line 36 at RAISE
  NOTICE:  8
+ CONTEXT:  PL/pgSQL function continue_test1() line 36 at RAISE
  NOTICE:  9
+ CONTEXT:  PL/pgSQL function continue_test1() line 36 at RAISE
  NOTICE:  10
+ CONTEXT:  PL/pgSQL function continue_test1() line 36 at RAISE
  NOTICE:  ---5---
+ CONTEXT:  PL/pgSQL function continue_test1() line 40 at RAISE
  NOTICE:  30
+ CONTEXT:  PL/pgSQL function continue_test1() line 43 at RAISE
  NOTICE:  40
+ CONTEXT:  PL/pgSQL function continue_test1() line 43 at RAISE
  NOTICE:  ---6---
+ CONTEXT:  PL/pgSQL function continue_test1() line 46 at RAISE
  NOTICE:  30
+ CONTEXT:  PL/pgSQL function continue_test1() line 49 at RAISE
  NOTICE:  40
+ CONTEXT:  PL/pgSQL function continue_test1() line 49 at RAISE
  NOTICE:  ---7---
+ CONTEXT:  PL/pgSQL function continue_test1() line 52 at RAISE
  NOTICE:  1
+ CONTEXT:  PL/pgSQL function continue_test1() line 54 at RAISE
  NOTICE:  2
+ CONTEXT:  PL/pgSQL function continue_test1() line 54 at RAISE
  NOTICE:  3
+ CONTEXT:  PL/pgSQL function continue_test1() line 54 at RAISE
  NOTICE:  ---8---
+ CONTEXT:  PL/pgSQL function continue_test1() line 58 at RAISE
  NOTICE:  1
+ CONTEXT:  PL/pgSQL function continue_test1() line 61 at RAISE
  NOTICE:  2
+ CONTEXT:  PL/pgSQL function continue_test1() line 61 at RAISE
  NOTICE:  3
+ CONTEXT:  PL/pgSQL function continue_test1() line 61 at RAISE
  NOTICE:  ---9---
+ CONTEXT:  PL/pgSQL function continue_test1() line 66 at RAISE
  NOTICE:  10
+ CONTEXT:  PL/pgSQL function continue_test1() line 68 at RAISE
  NOTICE:  ---10---
+ CONTEXT:  PL/pgSQL function continue_test1() line 72 at RAISE
  NOTICE:  10
+ CONTEXT:  PL/pgSQL function continue_test1() line 74 at RAISE
   continue_test1 
  ----------------
   
***************
*** 2924,2947 **** end;
--- 3016,3058 ----
  $proc$ language plpgsql;
  select for_vect();
  NOTICE:  1
+ CONTEXT:  PL/pgSQL function for_vect() line 6 at RAISE
  NOTICE:  2
+ CONTEXT:  PL/pgSQL function for_vect() line 6 at RAISE
  NOTICE:  3
+ CONTEXT:  PL/pgSQL function for_vect() line 6 at RAISE
  NOTICE:  1 BB CC
+ CONTEXT:  PL/pgSQL function for_vect() line 10 at RAISE
  NOTICE:  2 BB CC
+ CONTEXT:  PL/pgSQL function for_vect() line 10 at RAISE
  NOTICE:  3 BB CC
+ CONTEXT:  PL/pgSQL function for_vect() line 10 at RAISE
  NOTICE:  4 BB CC
+ CONTEXT:  PL/pgSQL function for_vect() line 10 at RAISE
  NOTICE:  1
+ CONTEXT:  PL/pgSQL function for_vect() line 14 at RAISE
  NOTICE:  2
+ CONTEXT:  PL/pgSQL function for_vect() line 14 at RAISE
  NOTICE:  3
+ CONTEXT:  PL/pgSQL function for_vect() line 14 at RAISE
  NOTICE:  4
+ CONTEXT:  PL/pgSQL function for_vect() line 14 at RAISE
  NOTICE:  1 BB CC
+ CONTEXT:  PL/pgSQL function for_vect() line 18 at RAISE
  NOTICE:  2 BB CC
+ CONTEXT:  PL/pgSQL function for_vect() line 18 at RAISE
  NOTICE:  3 BB CC
+ CONTEXT:  PL/pgSQL function for_vect() line 18 at RAISE
  NOTICE:  4 BB CC
+ CONTEXT:  PL/pgSQL function for_vect() line 18 at RAISE
  NOTICE:  1 bb cc
+ CONTEXT:  PL/pgSQL function for_vect() line 22 at RAISE
  NOTICE:  2 bb cc
+ CONTEXT:  PL/pgSQL function for_vect() line 22 at RAISE
  NOTICE:  3 bb cc
+ CONTEXT:  PL/pgSQL function for_vect() line 22 at RAISE
  NOTICE:  4 bb cc
+ CONTEXT:  PL/pgSQL function for_vect() line 22 at RAISE
   for_vect 
  ----------
   
***************
*** 2981,2986 **** begin
--- 3092,3098 ----
  end$$ language plpgsql;
  select footest();
  NOTICE:  x.f1 = 5, x.f2 = 6
+ CONTEXT:  PL/pgSQL function footest() line 6 at RAISE
   footest 
  ---------
   
***************
*** 3005,3010 **** begin
--- 3117,3123 ----
  end$$ language plpgsql;
  select footest();
  NOTICE:  x.f1 = 5, x.f2 = 6
+ CONTEXT:  PL/pgSQL function footest() line 6 at RAISE
   footest 
  ---------
   
***************
*** 3019,3024 **** begin
--- 3132,3138 ----
  end$$ language plpgsql;
  select footest();
  NOTICE:  x.f1 = 7, x.f2 = 8
+ CONTEXT:  PL/pgSQL function footest() line 6 at RAISE
   footest 
  ---------
   
***************
*** 3044,3049 **** begin
--- 3158,3164 ----
  end$$ language plpgsql;
  select footest();
  NOTICE:  x.f1 = 3, x.f2 = 4
+ CONTEXT:  PL/pgSQL function footest() line 6 at RAISE
   footest 
  ---------
   
***************
*** 3078,3083 **** begin
--- 3193,3199 ----
  end$$ language plpgsql;
  select footest();
  NOTICE:  x.f1 = 3, x.f2 = 4
+ CONTEXT:  PL/pgSQL function footest() line 6 at RAISE
   footest 
  ---------
   
***************
*** 3282,3290 **** end;
--- 3398,3410 ----
  $$ language plpgsql;
  select pl_qual_names(42);
  NOTICE:  param1 = 2
+ CONTEXT:  PL/pgSQL function pl_qual_names(integer) line 10 at RAISE
  NOTICE:  pl_qual_names.param1 = 42
+ CONTEXT:  PL/pgSQL function pl_qual_names(integer) line 11 at RAISE
  NOTICE:  outerblock.param1 = 1
+ CONTEXT:  PL/pgSQL function pl_qual_names(integer) line 12 at RAISE
  NOTICE:  innerblock.param1 = 2
+ CONTEXT:  PL/pgSQL function pl_qual_names(integer) line 13 at RAISE
   pl_qual_names 
  ---------------
   
***************
*** 3353,3363 **** end
--- 3473,3489 ----
  $$ language plpgsql;
  select exc_using(5, 'foobar');
  NOTICE:  1
+ CONTEXT:  PL/pgSQL function exc_using(integer,text) line 5 at RAISE
  NOTICE:  2
+ CONTEXT:  PL/pgSQL function exc_using(integer,text) line 5 at RAISE
  NOTICE:  3
+ CONTEXT:  PL/pgSQL function exc_using(integer,text) line 5 at RAISE
  NOTICE:  4
+ CONTEXT:  PL/pgSQL function exc_using(integer,text) line 5 at RAISE
  NOTICE:  5
+ CONTEXT:  PL/pgSQL function exc_using(integer,text) line 5 at RAISE
  NOTICE:  6
+ CONTEXT:  PL/pgSQL function exc_using(integer,text) line 5 at RAISE
   exc_using 
  -----------
          26
***************
*** 3381,3391 **** end;
--- 3507,3523 ----
  $$ language plpgsql;
  select exc_using(5);
  NOTICE:  1
+ CONTEXT:  PL/pgSQL function exc_using(integer) line 10 at RAISE
  NOTICE:  2
+ CONTEXT:  PL/pgSQL function exc_using(integer) line 10 at RAISE
  NOTICE:  3
+ CONTEXT:  PL/pgSQL function exc_using(integer) line 10 at RAISE
  NOTICE:  4
+ CONTEXT:  PL/pgSQL function exc_using(integer) line 10 at RAISE
  NOTICE:  5
+ CONTEXT:  PL/pgSQL function exc_using(integer) line 10 at RAISE
  NOTICE:  6
+ CONTEXT:  PL/pgSQL function exc_using(integer) line 10 at RAISE
   exc_using 
  -----------
   
***************
*** 3430,3451 **** end;
--- 3562,3600 ----
  $$ language plpgsql;
  select forc01();
  NOTICE:  5 from c
+ CONTEXT:  PL/pgSQL function forc01() line 9 at RAISE
  NOTICE:  6 from c
+ CONTEXT:  PL/pgSQL function forc01() line 9 at RAISE
  NOTICE:  7 from c
+ CONTEXT:  PL/pgSQL function forc01() line 9 at RAISE
  NOTICE:  9 from c
+ CONTEXT:  PL/pgSQL function forc01() line 13 at RAISE
  NOTICE:  10 from c
+ CONTEXT:  PL/pgSQL function forc01() line 13 at RAISE
  NOTICE:  41 from c2
+ CONTEXT:  PL/pgSQL function forc01() line 17 at RAISE
  NOTICE:  42 from c2
+ CONTEXT:  PL/pgSQL function forc01() line 17 at RAISE
  NOTICE:  43 from c2
+ CONTEXT:  PL/pgSQL function forc01() line 17 at RAISE
  NOTICE:  after loop, c2 = c2
+ CONTEXT:  PL/pgSQL function forc01() line 20 at RAISE
  NOTICE:  41 from special_name
+ CONTEXT:  PL/pgSQL function forc01() line 23 at RAISE
  NOTICE:  42 from special_name
+ CONTEXT:  PL/pgSQL function forc01() line 23 at RAISE
  NOTICE:  43 from special_name
+ CONTEXT:  PL/pgSQL function forc01() line 23 at RAISE
  NOTICE:  after loop, c2 = special_name
+ CONTEXT:  PL/pgSQL function forc01() line 25 at RAISE
  NOTICE:  41
+ CONTEXT:  PL/pgSQL function forc01() line 30 at RAISE
  NOTICE:  42
+ CONTEXT:  PL/pgSQL function forc01() line 30 at RAISE
  NOTICE:  43
+ CONTEXT:  PL/pgSQL function forc01() line 30 at RAISE
  NOTICE:  after loop, c2 = <NULL>
+ CONTEXT:  PL/pgSQL function forc01() line 32 at RAISE
   forc01 
  --------
   
***************
*** 3466,3480 **** end;
--- 3615,3639 ----
  $$ language plpgsql;
  select forc01();
  NOTICE:  1, 1
+ CONTEXT:  PL/pgSQL function forc01() line 6 at RAISE
  NOTICE:  2, 2
+ CONTEXT:  PL/pgSQL function forc01() line 6 at RAISE
  NOTICE:  3, 3
+ CONTEXT:  PL/pgSQL function forc01() line 6 at RAISE
  NOTICE:  4, 4
+ CONTEXT:  PL/pgSQL function forc01() line 6 at RAISE
  NOTICE:  5, 5
+ CONTEXT:  PL/pgSQL function forc01() line 6 at RAISE
  NOTICE:  6, 6
+ CONTEXT:  PL/pgSQL function forc01() line 6 at RAISE
  NOTICE:  7, 7
+ CONTEXT:  PL/pgSQL function forc01() line 6 at RAISE
  NOTICE:  8, 8
+ CONTEXT:  PL/pgSQL function forc01() line 6 at RAISE
  NOTICE:  9, 9
+ CONTEXT:  PL/pgSQL function forc01() line 6 at RAISE
  NOTICE:  10, 10
+ CONTEXT:  PL/pgSQL function forc01() line 6 at RAISE
   forc01 
  --------
   
***************
*** 3512,3526 **** end;
--- 3671,3695 ----
  $$ language plpgsql;
  select forc01();
  NOTICE:  100, 2
+ CONTEXT:  PL/pgSQL function forc01() line 10 at RAISE
  NOTICE:  200, 4
+ CONTEXT:  PL/pgSQL function forc01() line 10 at RAISE
  NOTICE:  300, 6
+ CONTEXT:  PL/pgSQL function forc01() line 10 at RAISE
  NOTICE:  400, 8
+ CONTEXT:  PL/pgSQL function forc01() line 10 at RAISE
  NOTICE:  500, 10
+ CONTEXT:  PL/pgSQL function forc01() line 10 at RAISE
  NOTICE:  600, 12
+ CONTEXT:  PL/pgSQL function forc01() line 10 at RAISE
  NOTICE:  700, 14
+ CONTEXT:  PL/pgSQL function forc01() line 10 at RAISE
  NOTICE:  800, 16
+ CONTEXT:  PL/pgSQL function forc01() line 10 at RAISE
  NOTICE:  900, 18
+ CONTEXT:  PL/pgSQL function forc01() line 10 at RAISE
  NOTICE:  1000, 20
+ CONTEXT:  PL/pgSQL function forc01() line 10 at RAISE
   forc01 
  --------
   
***************
*** 3769,3776 **** select raise_test();
--- 3938,3947 ----
  NOTICE:  1 2 3
  DETAIL:  some detail info
  HINT:  some hint
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  ERROR:  1 2 3
  DETAIL:  some detail info
+ CONTEXT:  PL/pgSQL function raise_test() line 5 at RAISE
  -- Since we can't actually see the thrown SQLSTATE in default psql output,
  -- test it like this; this also tests re-RAISE
  create or replace function raise_test() returns void as $$
***************
*** 3785,3792 **** end;
--- 3956,3965 ----
  $$ language plpgsql;
  select raise_test();
  NOTICE:  SQLSTATE: 22012 SQLERRM: check me
+ CONTEXT:  PL/pgSQL function raise_test() line 7 at RAISE
  ERROR:  check me
  DETAIL:  some detail info
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise 'check me'
***************
*** 3799,3806 **** end;
--- 3972,3981 ----
  $$ language plpgsql;
  select raise_test();
  NOTICE:  SQLSTATE: 1234F SQLERRM: check me
+ CONTEXT:  PL/pgSQL function raise_test() line 7 at RAISE
  ERROR:  check me
  DETAIL:  some detail info
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  -- SQLSTATE specification in WHEN
  create or replace function raise_test() returns void as $$
  begin
***************
*** 3814,3821 **** end;
--- 3989,3998 ----
  $$ language plpgsql;
  select raise_test();
  NOTICE:  SQLSTATE: 1234F SQLERRM: check me
+ CONTEXT:  PL/pgSQL function raise_test() line 7 at RAISE
  ERROR:  check me
  DETAIL:  some detail info
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise division_by_zero using detail = 'some detail info';
***************
*** 3827,3834 **** end;
--- 4004,4013 ----
  $$ language plpgsql;
  select raise_test();
  NOTICE:  SQLSTATE: 22012 SQLERRM: division_by_zero
+ CONTEXT:  PL/pgSQL function raise_test() line 6 at RAISE
  ERROR:  division_by_zero
  DETAIL:  some detail info
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise division_by_zero;
***************
*** 3836,3841 **** end;
--- 4015,4021 ----
  $$ language plpgsql;
  select raise_test();
  ERROR:  division_by_zero
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise sqlstate '1234F';
***************
*** 3843,3848 **** end;
--- 4023,4029 ----
  $$ language plpgsql;
  select raise_test();
  ERROR:  1234F
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise division_by_zero using message = 'custom' || ' message';
***************
*** 3850,3855 **** end;
--- 4031,4037 ----
  $$ language plpgsql;
  select raise_test();
  ERROR:  custom message
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise using message = 'custom' || ' message', errcode = '22012';
***************
*** 3857,3862 **** end;
--- 4039,4045 ----
  $$ language plpgsql;
  select raise_test();
  ERROR:  custom message
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  -- conflict on message
  create or replace function raise_test() returns void as $$
  begin
***************
*** 3915,3920 **** end;
--- 4098,4104 ----
  $$ language plpgsql;
  select stacked_diagnostics_test();
  NOTICE:  sqlstate: 22012, message: division by zero, context: [PL/pgSQL function zero_divide() line 4 at RETURN <- SQL statement "SELECT zero_divide()" <- PL/pgSQL function stacked_diagnostics_test() line 6 at PERFORM]
+ CONTEXT:  PL/pgSQL function stacked_diagnostics_test() line 12 at RAISE
   stacked_diagnostics_test 
  --------------------------
   
***************
*** 3936,3941 **** end;
--- 4120,4126 ----
  $$ language plpgsql;
  select stacked_diagnostics_test();
  NOTICE:  message: custom exception, detail: some detail of custom exception, hint: some hint related to custom exception
+ CONTEXT:  PL/pgSQL function stacked_diagnostics_test() line 12 at RAISE
   stacked_diagnostics_test 
  --------------------------
   
***************
*** 3972,3978 **** end;
--- 4157,4165 ----
  $$ language plpgsql;
  select raise_test();
  NOTICE:  22012
+ CONTEXT:  PL/pgSQL function raise_test() line 6 at RAISE
  ERROR:  substitute message
+ CONTEXT:  PL/pgSQL function raise_test() line 7 at RAISE
  drop function raise_test();
  -- test passing column_name, constraint_name, datatype_name, table_name
  -- and schema_name error fields
***************
*** 4002,4007 **** end;
--- 4189,4195 ----
  $$ language plpgsql;
  select stacked_diagnostics_test();
  NOTICE:  column >>some column name<<, constraint >>some constraint name<<, type >>some datatype name<<, table >>some table name<<, schema >>some schema name<<
+ CONTEXT:  PL/pgSQL function stacked_diagnostics_test() line 21 at RAISE
   stacked_diagnostics_test 
  --------------------------
   
***************
*** 4093,4098 **** end
--- 4281,4287 ----
  $$ language plpgsql;
  select catch();
  NOTICE:  caught case_not_found 20000 case not found
+ CONTEXT:  PL/pgSQL function catch() line 6 at RAISE
   catch 
  -------
   
***************
*** 4148,4157 **** begin
--- 4337,4351 ----
  $$ language plpgsql;
  select vari(1,2,3,4,5);
  NOTICE:  1
+ CONTEXT:  PL/pgSQL function vari(integer[]) line 4 at RAISE
  NOTICE:  2
+ CONTEXT:  PL/pgSQL function vari(integer[]) line 4 at RAISE
  NOTICE:  3
+ CONTEXT:  PL/pgSQL function vari(integer[]) line 4 at RAISE
  NOTICE:  4
+ CONTEXT:  PL/pgSQL function vari(integer[]) line 4 at RAISE
  NOTICE:  5
+ CONTEXT:  PL/pgSQL function vari(integer[]) line 4 at RAISE
   vari 
  ------
   
***************
*** 4159,4166 **** NOTICE:  5
--- 4353,4363 ----
  
  select vari(3,4,5);
  NOTICE:  3
+ CONTEXT:  PL/pgSQL function vari(integer[]) line 4 at RAISE
  NOTICE:  4
+ CONTEXT:  PL/pgSQL function vari(integer[]) line 4 at RAISE
  NOTICE:  5
+ CONTEXT:  PL/pgSQL function vari(integer[]) line 4 at RAISE
   vari 
  ------
   
***************
*** 4168,4175 **** NOTICE:  5
--- 4365,4375 ----
  
  select vari(variadic array[5,6,7]);
  NOTICE:  5
+ CONTEXT:  PL/pgSQL function vari(integer[]) line 4 at RAISE
  NOTICE:  6
+ CONTEXT:  PL/pgSQL function vari(integer[]) line 4 at RAISE
  NOTICE:  7
+ CONTEXT:  PL/pgSQL function vari(integer[]) line 4 at RAISE
   vari 
  ------
   
***************
*** 4221,4226 **** end;
--- 4421,4427 ----
  $$ language plpgsql immutable strict;
  select pleast(10);
  NOTICE:  non-variadic function called
+ CONTEXT:  PL/pgSQL function pleast(numeric) line 3 at RAISE
   pleast 
  --------
       10
***************
*** 4280,4288 **** end;
--- 4481,4493 ----
  $$ language plpgsql;
  select * from rttest();
  NOTICE:  t 2
+ CONTEXT:  PL/pgSQL function rttest() line 6 at RAISE
  NOTICE:  f 0
+ CONTEXT:  PL/pgSQL function rttest() line 9 at RAISE
  NOTICE:  t 2
+ CONTEXT:  PL/pgSQL function rttest() line 12 at RAISE
  NOTICE:  f 0
+ CONTEXT:  PL/pgSQL function rttest() line 15 at RAISE
   rttest 
  --------
       10
***************
*** 4458,4463 **** LINE 4:   return 'foo\\bar\041baz';
--- 4663,4669 ----
  HINT:  Use the escape string syntax for backslashes, e.g., E'\\'.
  select strtest();
  NOTICE:  foo\bar!baz
+ CONTEXT:  PL/pgSQL function strtest() line 3 at RAISE
  WARNING:  nonstandard use of \\ in a string literal
  LINE 1: SELECT 'foo\\bar\041baz'
                 ^
***************
*** 4477,4482 **** end
--- 4683,4689 ----
  $$ language plpgsql;
  select strtest();
  NOTICE:  foo\bar!baz
+ CONTEXT:  PL/pgSQL function strtest() line 3 at RAISE
     strtest   
  -------------
   foo\bar!baz
***************
*** 4491,4496 **** end
--- 4698,4704 ----
  $$ language plpgsql;
  select strtest();
  NOTICE:  foo\\bar\041baz\
+ CONTEXT:  PL/pgSQL function strtest() line 3 at RAISE
       strtest      
  ------------------
   foo\\bar\041baz\
***************
*** 4504,4509 **** end
--- 4712,4718 ----
  $$ language plpgsql;
  select strtest();
  NOTICE:  foo\bar!baz
+ CONTEXT:  PL/pgSQL function strtest() line 3 at RAISE
     strtest   
  -------------
   foo\bar!baz
***************
*** 4520,4534 **** BEGIN
--- 4729,4753 ----
      END LOOP;
  END$$;
  NOTICE:  001, Entrance
+ CONTEXT:  PL/pgSQL function inline_code_block line 6 at RAISE
  NOTICE:  002, Office
+ CONTEXT:  PL/pgSQL function inline_code_block line 6 at RAISE
  NOTICE:  003, Office
+ CONTEXT:  PL/pgSQL function inline_code_block line 6 at RAISE
  NOTICE:  004, Technical
+ CONTEXT:  PL/pgSQL function inline_code_block line 6 at RAISE
  NOTICE:  101, Office
+ CONTEXT:  PL/pgSQL function inline_code_block line 6 at RAISE
  NOTICE:  102, Conference
+ CONTEXT:  PL/pgSQL function inline_code_block line 6 at RAISE
  NOTICE:  103, Restroom
+ CONTEXT:  PL/pgSQL function inline_code_block line 6 at RAISE
  NOTICE:  104, Technical
+ CONTEXT:  PL/pgSQL function inline_code_block line 6 at RAISE
  NOTICE:  105, Office
+ CONTEXT:  PL/pgSQL function inline_code_block line 6 at RAISE
  NOTICE:  106, Office
+ CONTEXT:  PL/pgSQL function inline_code_block line 6 at RAISE
  -- these are to check syntax error reporting
  DO LANGUAGE plpgsql $$begin return 1; end$$;
  ERROR:  RETURN cannot have a parameter in function returning void
***************
*** 4656,4664 **** begin
--- 4875,4887 ----
  $$ language plpgsql;
  select foreach_test(ARRAY[1,2,3,4]);
  NOTICE:  1
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
  NOTICE:  2
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
  NOTICE:  3
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
  NOTICE:  4
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
   foreach_test 
  --------------
   
***************
*** 4666,4674 **** NOTICE:  4
--- 4889,4901 ----
  
  select foreach_test(ARRAY[[1,2],[3,4]]);
  NOTICE:  1
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
  NOTICE:  2
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
  NOTICE:  3
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
  NOTICE:  4
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
   foreach_test 
  --------------
   
***************
*** 4703,4708 **** begin
--- 4930,4936 ----
  $$ language plpgsql;
  select foreach_test(ARRAY[1,2,3,4]);
  NOTICE:  {1,2,3,4}
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
   foreach_test 
  --------------
   
***************
*** 4710,4716 **** NOTICE:  {1,2,3,4}
--- 4938,4946 ----
  
  select foreach_test(ARRAY[[1,2],[3,4]]);
  NOTICE:  {1,2}
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
  NOTICE:  {3,4}
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
   foreach_test 
  --------------
   
***************
*** 4734,4739 **** CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 4 at FOREACH over array
--- 4964,4970 ----
  -- ok
  select foreach_test(ARRAY[[1,2],[3,4]]);
  NOTICE:  {{1,2},{3,4}}
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
   foreach_test 
  --------------
   
***************
*** 4741,4747 **** NOTICE:  {{1,2},{3,4}}
--- 4972,4980 ----
  
  select foreach_test(ARRAY[[[1,2]],[[3,4]]]);
  NOTICE:  {{1,2}}
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
  NOTICE:  {{3,4}}
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
   foreach_test 
  --------------
   
***************
*** 4761,4768 **** begin
--- 4994,5004 ----
  $$ language plpgsql;
  select foreach_test(ARRAY[(10,20),(40,69),(35,78)]::xy_tuple[]);
  NOTICE:  (10,20)
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
  NOTICE:  (40,69)
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
  NOTICE:  (35,78)
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
   foreach_test 
  --------------
   
***************
*** 4770,4778 **** NOTICE:  (35,78)
--- 5006,5018 ----
  
  select foreach_test(ARRAY[[(10,20),(40,69)],[(35,78),(88,76)]]::xy_tuple[]);
  NOTICE:  (10,20)
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
  NOTICE:  (40,69)
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
  NOTICE:  (35,78)
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
  NOTICE:  (88,76)
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
   foreach_test 
  --------------
   
***************
*** 4790,4797 **** begin
--- 5030,5040 ----
  $$ language plpgsql;
  select foreach_test(ARRAY[(10,20),(40,69),(35,78)]::xy_tuple[]);
  NOTICE:  x = 10, y = 20
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
  NOTICE:  x = 40, y = 69
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
  NOTICE:  x = 35, y = 78
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
   foreach_test 
  --------------
   
***************
*** 4799,4807 **** NOTICE:  x = 35, y = 78
--- 5042,5054 ----
  
  select foreach_test(ARRAY[[(10,20),(40,69)],[(35,78),(88,76)]]::xy_tuple[]);
  NOTICE:  x = 10, y = 20
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
  NOTICE:  x = 40, y = 69
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
  NOTICE:  x = 35, y = 78
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
  NOTICE:  x = 88, y = 76
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
   foreach_test 
  --------------
   
***************
*** 4820,4825 **** begin
--- 5067,5073 ----
  $$ language plpgsql;
  select foreach_test(ARRAY[(10,20),(40,69),(35,78)]::xy_tuple[]);
  NOTICE:  {"(10,20)","(40,69)","(35,78)"}
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
   foreach_test 
  --------------
   
***************
*** 4827,4833 **** NOTICE:  {"(10,20)","(40,69)","(35,78)"}
--- 5075,5083 ----
  
  select foreach_test(ARRAY[[(10,20),(40,69)],[(35,78),(88,76)]]::xy_tuple[]);
  NOTICE:  {"(10,20)","(40,69)"}
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
  NOTICE:  {"(35,78)","(88,76)"}
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
   foreach_test 
  --------------
   
***************
*** 4935,4958 **** end;
  $$ language plpgsql;
  select outer_outer_func(10);
  NOTICE:  calling down into outer_func()
  NOTICE:  calling down into inner_func()
! CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 4 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
! CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 7 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
! CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  lets make sure we didnt break anything
! CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  inner_func() done
! CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  outer_func() done
   outer_outer_func 
  ------------------
                 20
--- 5185,5215 ----
  $$ language plpgsql;
  select outer_outer_func(10);
  NOTICE:  calling down into outer_func()
+ CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 5 at RAISE
  NOTICE:  calling down into inner_func()
! CONTEXT:  PL/pgSQL function outer_func(integer) line 5 at RAISE
! PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 4 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
! CONTEXT:  PL/pgSQL function inner_func(integer) line 5 at RAISE
! PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 7 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
! CONTEXT:  PL/pgSQL function inner_func(integer) line 8 at RAISE
! PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  lets make sure we didnt break anything
! CONTEXT:  PL/pgSQL function inner_func(integer) line 9 at RAISE
! PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  inner_func() done
! CONTEXT:  PL/pgSQL function outer_func(integer) line 7 at RAISE
! PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  outer_func() done
+ CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 7 at RAISE
   outer_outer_func 
  ------------------
                 20
***************
*** 4961,4984 **** NOTICE:  outer_func() done
  -- repeated call should to work
  select outer_outer_func(20);
  NOTICE:  calling down into outer_func()
  NOTICE:  calling down into inner_func()
! CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 4 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
! CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 7 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
! CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  lets make sure we didnt break anything
! CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  inner_func() done
! CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  outer_func() done
   outer_outer_func 
  ------------------
                 40
--- 5218,5248 ----
  -- repeated call should to work
  select outer_outer_func(20);
  NOTICE:  calling down into outer_func()
+ CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 5 at RAISE
  NOTICE:  calling down into inner_func()
! CONTEXT:  PL/pgSQL function outer_func(integer) line 5 at RAISE
! PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 4 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
! CONTEXT:  PL/pgSQL function inner_func(integer) line 5 at RAISE
! PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 7 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
! CONTEXT:  PL/pgSQL function inner_func(integer) line 8 at RAISE
! PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  lets make sure we didnt break anything
! CONTEXT:  PL/pgSQL function inner_func(integer) line 9 at RAISE
! PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  inner_func() done
! CONTEXT:  PL/pgSQL function outer_func(integer) line 7 at RAISE
! PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  outer_func() done
+ CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 7 at RAISE
   outer_outer_func 
  ------------------
                 40
***************
*** 5033,5056 **** end;
  $$ language plpgsql;
  select outer_outer_func(10);
  NOTICE:  calling down into outer_func()
  NOTICE:  calling down into inner_func()
! CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 10 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
! CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 15 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
! CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  lets make sure we didnt break anything
! CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  inner_func() done
! CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  outer_func() done
   outer_outer_func 
  ------------------
                 20
--- 5297,5327 ----
  $$ language plpgsql;
  select outer_outer_func(10);
  NOTICE:  calling down into outer_func()
+ CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 5 at RAISE
  NOTICE:  calling down into inner_func()
! CONTEXT:  PL/pgSQL function outer_func(integer) line 5 at RAISE
! PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 10 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
! CONTEXT:  PL/pgSQL function inner_func(integer) line 11 at RAISE
! PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 15 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
! CONTEXT:  PL/pgSQL function inner_func(integer) line 16 at RAISE
! PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  lets make sure we didnt break anything
! CONTEXT:  PL/pgSQL function inner_func(integer) line 17 at RAISE
! PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  inner_func() done
! CONTEXT:  PL/pgSQL function outer_func(integer) line 7 at RAISE
! PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  outer_func() done
+ CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 7 at RAISE
   outer_outer_func 
  ------------------
                 20
***************
*** 5059,5082 **** NOTICE:  outer_func() done
  -- repeated call should to work
  select outer_outer_func(20);
  NOTICE:  calling down into outer_func()
  NOTICE:  calling down into inner_func()
! CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 10 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
! CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 15 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
! CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  lets make sure we didnt break anything
! CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  inner_func() done
! CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  outer_func() done
   outer_outer_func 
  ------------------
                 40
--- 5330,5360 ----
  -- repeated call should to work
  select outer_outer_func(20);
  NOTICE:  calling down into outer_func()
+ CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 5 at RAISE
  NOTICE:  calling down into inner_func()
! CONTEXT:  PL/pgSQL function outer_func(integer) line 5 at RAISE
! PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 10 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
! CONTEXT:  PL/pgSQL function inner_func(integer) line 11 at RAISE
! PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 15 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
! CONTEXT:  PL/pgSQL function inner_func(integer) line 16 at RAISE
! PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  lets make sure we didnt break anything
! CONTEXT:  PL/pgSQL function inner_func(integer) line 17 at RAISE
! PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  inner_func() done
! CONTEXT:  PL/pgSQL function outer_func(integer) line 7 at RAISE
! PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  outer_func() done
+ CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 7 at RAISE
   outer_outer_func 
  ------------------
                 40
*** a/src/test/regress/expected/polymorphism.out
--- b/src/test/regress/expected/polymorphism.out
***************
*** 555,564 **** select case when $1 then $2 else $3 end $$ language sql;
--- 555,569 ----
  -- if the CASE expression were not successfully inlined
  select f1, sql_if(f1 > 0, bleat(f1), bleat(f1 + 1)) from int4_tbl;
  NOTICE:  bleat 1
+ CONTEXT:  PL/pgSQL function bleat(integer) line 3 at RAISE
  NOTICE:  bleat 123456
+ CONTEXT:  PL/pgSQL function bleat(integer) line 3 at RAISE
  NOTICE:  bleat -123455
+ CONTEXT:  PL/pgSQL function bleat(integer) line 3 at RAISE
  NOTICE:  bleat 2147483647
+ CONTEXT:  PL/pgSQL function bleat(integer) line 3 at RAISE
  NOTICE:  bleat -2147483646
+ CONTEXT:  PL/pgSQL function bleat(integer) line 3 at RAISE
       f1      |   sql_if    
  -------------+-------------
             0 |           1
*** a/src/test/regress/expected/rangefuncs.out
--- b/src/test/regress/expected/rangefuncs.out
***************
*** 1366,1374 **** create trigger tnoticetrigger after insert on tt for each row
  execute procedure noticetrigger();
  select insert_tt2('foolme','barme') limit 1;
  NOTICE:  noticetrigger 11 foolme
! CONTEXT:  SQL function "insert_tt2" statement 1
  NOTICE:  noticetrigger 12 barme
! CONTEXT:  SQL function "insert_tt2" statement 1
   insert_tt2 
  ------------
           11
--- 1366,1376 ----
  execute procedure noticetrigger();
  select insert_tt2('foolme','barme') limit 1;
  NOTICE:  noticetrigger 11 foolme
! CONTEXT:  PL/pgSQL function noticetrigger() line 3 at RAISE
! SQL function "insert_tt2" statement 1
  NOTICE:  noticetrigger 12 barme
! CONTEXT:  PL/pgSQL function noticetrigger() line 3 at RAISE
! SQL function "insert_tt2" statement 1
   insert_tt2 
  ------------
           11
***************
*** 1397,1405 **** create rule insert_tt_rule as on insert to tt do also
    insert into tt_log values(new.*);
  select insert_tt2('foollog','barlog') limit 1;
  NOTICE:  noticetrigger 13 foollog
! CONTEXT:  SQL function "insert_tt2" statement 1
  NOTICE:  noticetrigger 14 barlog
! CONTEXT:  SQL function "insert_tt2" statement 1
   insert_tt2 
  ------------
           13
--- 1399,1409 ----
    insert into tt_log values(new.*);
  select insert_tt2('foollog','barlog') limit 1;
  NOTICE:  noticetrigger 13 foollog
! CONTEXT:  PL/pgSQL function noticetrigger() line 3 at RAISE
! SQL function "insert_tt2" statement 1
  NOTICE:  noticetrigger 14 barlog
! CONTEXT:  PL/pgSQL function noticetrigger() line 3 at RAISE
! SQL function "insert_tt2" statement 1
   insert_tt2 
  ------------
           13
*** a/src/test/regress/expected/select_views.out
--- b/src/test/regress/expected/select_views.out
***************
*** 467,472 **** SELECT name, #thepath FROM iexit ORDER BY 1, 2;
--- 467,486 ----
   I- 580                             |       21
   I- 580                             |       22
   I- 580                             |       22
+  I- 580/I-680                  Ramp |        2
+  I- 580/I-680                  Ramp |        2
+  I- 580/I-680                  Ramp |        2
+  I- 580/I-680                  Ramp |        2
+  I- 580/I-680                  Ramp |        2
+  I- 580/I-680                  Ramp |        2
+  I- 580/I-680                  Ramp |        4
+  I- 580/I-680                  Ramp |        4
+  I- 580/I-680                  Ramp |        4
+  I- 580/I-680                  Ramp |        4
+  I- 580/I-680                  Ramp |        5
+  I- 580/I-680                  Ramp |        6
+  I- 580/I-680                  Ramp |        6
+  I- 580/I-680                  Ramp |        6
   I- 580                        Ramp |        2
   I- 580                        Ramp |        2
   I- 580                        Ramp |        2
***************
*** 717,736 **** SELECT name, #thepath FROM iexit ORDER BY 1, 2;
   I- 580                        Ramp |        8
   I- 580                        Ramp |        8
   I- 580                        Ramp |        8
-  I- 580/I-680                  Ramp |        2
-  I- 580/I-680                  Ramp |        2
-  I- 580/I-680                  Ramp |        2
-  I- 580/I-680                  Ramp |        2
-  I- 580/I-680                  Ramp |        2
-  I- 580/I-680                  Ramp |        2
-  I- 580/I-680                  Ramp |        4
-  I- 580/I-680                  Ramp |        4
-  I- 580/I-680                  Ramp |        4
-  I- 580/I-680                  Ramp |        4
-  I- 580/I-680                  Ramp |        5
-  I- 580/I-680                  Ramp |        6
-  I- 580/I-680                  Ramp |        6
-  I- 580/I-680                  Ramp |        6
   I- 680                             |        2
   I- 680                             |        2
   I- 680                             |        2
--- 731,736 ----
***************
*** 1318,1325 **** SET SESSION AUTHORIZATION regress_alice;
--- 1318,1328 ----
  --
  SELECT * FROM my_property_normal WHERE f_leak(passwd);
  NOTICE:  f_leak => passwd123
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
  NOTICE:  f_leak => beafsteak
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
  NOTICE:  f_leak => hamburger
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
   cid |     name      |       tel        |  passwd   
  -----+---------------+------------------+-----------
   101 | regress_alice | +81-12-3456-7890 | passwd123
***************
*** 1334,1339 **** EXPLAIN (COSTS OFF) SELECT * FROM my_property_normal WHERE f_leak(passwd);
--- 1337,1343 ----
  
  SELECT * FROM my_property_secure WHERE f_leak(passwd);
  NOTICE:  f_leak => passwd123
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
   cid |     name      |       tel        |  passwd   
  -----+---------------+------------------+-----------
   101 | regress_alice | +81-12-3456-7890 | passwd123
***************
*** 1355,1362 **** EXPLAIN (COSTS OFF) SELECT * FROM my_property_secure WHERE f_leak(passwd);
--- 1359,1369 ----
  --
  SELECT * FROM my_credit_card_normal WHERE f_leak(cnum);
  NOTICE:  f_leak => 1111-2222-3333-4444
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
  NOTICE:  f_leak => 5555-6666-7777-8888
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
  NOTICE:  f_leak => 9801-2345-6789-0123
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
   cid |     name      |       tel        |  passwd   |        cnum         | climit 
  -----+---------------+------------------+-----------+---------------------+--------
   101 | regress_alice | +81-12-3456-7890 | passwd123 | 1111-2222-3333-4444 |   4000
***************
*** 1376,1381 **** EXPLAIN (COSTS OFF) SELECT * FROM my_credit_card_normal WHERE f_leak(cnum);
--- 1383,1389 ----
  
  SELECT * FROM my_credit_card_secure WHERE f_leak(cnum);
  NOTICE:  f_leak => 1111-2222-3333-4444
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
   cid |     name      |       tel        |  passwd   |        cnum         | climit 
  -----+---------------+------------------+-----------+---------------------+--------
   101 | regress_alice | +81-12-3456-7890 | passwd123 | 1111-2222-3333-4444 |   4000
***************
*** 1402,1407 **** EXPLAIN (COSTS OFF) SELECT * FROM my_credit_card_secure WHERE f_leak(cnum);
--- 1410,1416 ----
  SELECT * FROM my_credit_card_usage_normal
         WHERE f_leak(cnum) AND ymd >= '2011-10-01' AND ymd < '2011-11-01';
  NOTICE:  f_leak => 1111-2222-3333-4444
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
   cid |     name      |       tel        |  passwd   |        cnum         | climit |    ymd     | usage 
  -----+---------------+------------------+-----------+---------------------+--------+------------+-------
   101 | regress_alice | +81-12-3456-7890 | passwd123 | 1111-2222-3333-4444 |   4000 | 10-05-2011 |    90
***************
*** 1431,1438 **** EXPLAIN (COSTS OFF) SELECT * FROM my_credit_card_usage_normal
--- 1440,1450 ----
  SELECT * FROM my_credit_card_usage_secure
         WHERE f_leak(cnum) AND ymd >= '2011-10-01' AND ymd < '2011-11-01';
  NOTICE:  f_leak => 1111-2222-3333-4444
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
  NOTICE:  f_leak => 1111-2222-3333-4444
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
  NOTICE:  f_leak => 1111-2222-3333-4444
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
   cid |     name      |       tel        |  passwd   |        cnum         | climit |    ymd     | usage 
  -----+---------------+------------------+-----------+---------------------+--------+------------+-------
   101 | regress_alice | +81-12-3456-7890 | passwd123 | 1111-2222-3333-4444 |   4000 | 10-05-2011 |    90
***************
*** 1467,1474 **** PREPARE p1 AS SELECT * FROM my_property_normal WHERE f_leak(passwd);
--- 1479,1489 ----
  PREPARE p2 AS SELECT * FROM my_property_secure WHERE f_leak(passwd);
  EXECUTE p1;
  NOTICE:  f_leak => passwd123
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
  NOTICE:  f_leak => beafsteak
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
  NOTICE:  f_leak => hamburger
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
   cid |     name      |       tel        |  passwd   
  -----+---------------+------------------+-----------
   101 | regress_alice | +81-12-3456-7890 | passwd123
***************
*** 1476,1481 **** NOTICE:  f_leak => hamburger
--- 1491,1497 ----
  
  EXECUTE p2;
  NOTICE:  f_leak => passwd123
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
   cid |     name      |       tel        |  passwd   
  -----+---------------+------------------+-----------
   101 | regress_alice | +81-12-3456-7890 | passwd123
***************
*** 1487,1492 **** ALTER VIEW my_property_secure SET (security_barrier=false);
--- 1503,1509 ----
  SET SESSION AUTHORIZATION regress_alice;
  EXECUTE p1;		-- To be perform as a view with security-barrier
  NOTICE:  f_leak => passwd123
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
   cid |     name      |       tel        |  passwd   
  -----+---------------+------------------+-----------
   101 | regress_alice | +81-12-3456-7890 | passwd123
***************
*** 1494,1501 **** NOTICE:  f_leak => passwd123
--- 1511,1521 ----
  
  EXECUTE p2;		-- To be perform as a view without security-barrier
  NOTICE:  f_leak => passwd123
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
  NOTICE:  f_leak => beafsteak
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
  NOTICE:  f_leak => hamburger
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
   cid |     name      |       tel        |  passwd   
  -----+---------------+------------------+-----------
   101 | regress_alice | +81-12-3456-7890 | passwd123
*** a/src/test/regress/expected/triggers.out
--- b/src/test/regress/expected/triggers.out
***************
*** 295,314 **** CREATE TRIGGER after_upd_row_trig AFTER UPDATE ON main_table
--- 295,324 ----
  FOR EACH ROW EXECUTE PROCEDURE trigger_func('after_upd_row');
  INSERT INTO main_table DEFAULT VALUES;
  NOTICE:  trigger_func(before_ins_stmt) called: action = INSERT, when = BEFORE, level = STATEMENT
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_ins_stmt) called: action = INSERT, when = AFTER, level = STATEMENT
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  UPDATE main_table SET a = a + 1 WHERE b < 30;
  NOTICE:  trigger_func(after_upd_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  -- UPDATE that effects zero rows should still call per-statement trigger
  UPDATE main_table SET a = a + 2 WHERE b > 100;
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  -- COPY should fire per-row and per-statement INSERT triggers
  COPY main_table (a, b) FROM stdin;
  NOTICE:  trigger_func(before_ins_stmt) called: action = INSERT, when = BEFORE, level = STATEMENT
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_ins_stmt) called: action = INSERT, when = AFTER, level = STATEMENT
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  SELECT * FROM main_table ORDER BY a, b;
   a  | b  
  ----+----
***************
*** 339,366 **** CREATE TRIGGER delete_when AFTER DELETE ON main_table
--- 349,396 ----
  FOR EACH STATEMENT WHEN (true) EXECUTE PROCEDURE trigger_func('delete_when');
  INSERT INTO main_table (a) VALUES (123), (456);
  NOTICE:  trigger_func(before_ins_stmt) called: action = INSERT, when = BEFORE, level = STATEMENT
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(insert_when) called: action = INSERT, when = BEFORE, level = STATEMENT
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(insert_a) called: action = INSERT, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_ins_stmt) called: action = INSERT, when = AFTER, level = STATEMENT
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  COPY main_table FROM stdin;
  NOTICE:  trigger_func(before_ins_stmt) called: action = INSERT, when = BEFORE, level = STATEMENT
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(insert_when) called: action = INSERT, when = BEFORE, level = STATEMENT
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(insert_a) called: action = INSERT, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_ins_stmt) called: action = INSERT, when = AFTER, level = STATEMENT
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  DELETE FROM main_table WHERE a IN (123, 456);
  NOTICE:  trigger_func(delete_a) called: action = DELETE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(delete_a) called: action = DELETE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(delete_when) called: action = DELETE, when = AFTER, level = STATEMENT
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  UPDATE main_table SET a = 50, b = 60;
  NOTICE:  trigger_func(modified_any) called: action = UPDATE, when = BEFORE, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(modified_any) called: action = UPDATE, when = BEFORE, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(modified_a) called: action = UPDATE, when = BEFORE, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(modified_a) called: action = UPDATE, when = BEFORE, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(modified_a) called: action = UPDATE, when = BEFORE, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(modified_a) called: action = UPDATE, when = BEFORE, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(modified_a) called: action = UPDATE, when = BEFORE, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  SELECT * FROM main_table ORDER BY a, b;
   a  | b  
  ----+----
***************
*** 418,451 **** SELECT pg_get_triggerdef(oid) FROM pg_trigger WHERE tgrelid = 'main_table'::regc
--- 448,509 ----
  
  UPDATE main_table SET a = 50;
  NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  UPDATE main_table SET b = 10;
  NOTICE:  trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  --
  -- Test case for bug with BEFORE trigger followed by AFTER trigger with WHEN
  --
***************
*** 468,479 **** CREATE TRIGGER some_trig_afterb AFTER UPDATE ON some_t FOR EACH ROW
--- 526,542 ----
  INSERT INTO some_t VALUES (TRUE);
  UPDATE some_t SET some_col = TRUE;
  NOTICE:  dummy_update_func(before) called: action = UPDATE, old = (t), new = (t)
+ CONTEXT:  PL/pgSQL function dummy_update_func() line 3 at RAISE
  UPDATE some_t SET some_col = FALSE;
  NOTICE:  dummy_update_func(before) called: action = UPDATE, old = (t), new = (f)
+ CONTEXT:  PL/pgSQL function dummy_update_func() line 3 at RAISE
  NOTICE:  dummy_update_func(afterb) called: action = UPDATE, old = (t), new = (f)
+ CONTEXT:  PL/pgSQL function dummy_update_func() line 3 at RAISE
  UPDATE some_t SET some_col = TRUE;
  NOTICE:  dummy_update_func(before) called: action = UPDATE, old = (f), new = (t)
+ CONTEXT:  PL/pgSQL function dummy_update_func() line 3 at RAISE
  NOTICE:  dummy_update_func(aftera) called: action = UPDATE, old = (f), new = (t)
+ CONTEXT:  PL/pgSQL function dummy_update_func() line 3 at RAISE
  DROP TABLE some_t;
  -- bogus cases
  CREATE TRIGGER error_upd_and_col BEFORE UPDATE OR UPDATE OF a ON main_table
***************
*** 546,568 **** create trigger trigtest_a_stmt_tg after insert or update or delete on trigtest
--- 609,640 ----
  for each statement execute procedure trigtest();
  insert into trigtest default values;
  NOTICE:  trigtest INSERT BEFORE STATEMENT
+ CONTEXT:  PL/pgSQL function trigtest() line 3 at RAISE
  NOTICE:  trigtest INSERT BEFORE ROW
+ CONTEXT:  PL/pgSQL function trigtest() line 3 at RAISE
  NOTICE:  trigtest INSERT AFTER ROW
+ CONTEXT:  PL/pgSQL function trigtest() line 3 at RAISE
  NOTICE:  trigtest INSERT AFTER STATEMENT
+ CONTEXT:  PL/pgSQL function trigtest() line 3 at RAISE
  alter table trigtest disable trigger trigtest_b_row_tg;
  insert into trigtest default values;
  NOTICE:  trigtest INSERT BEFORE STATEMENT
+ CONTEXT:  PL/pgSQL function trigtest() line 3 at RAISE
  NOTICE:  trigtest INSERT AFTER ROW
+ CONTEXT:  PL/pgSQL function trigtest() line 3 at RAISE
  NOTICE:  trigtest INSERT AFTER STATEMENT
+ CONTEXT:  PL/pgSQL function trigtest() line 3 at RAISE
  alter table trigtest disable trigger user;
  insert into trigtest default values;
  alter table trigtest enable trigger trigtest_a_stmt_tg;
  insert into trigtest default values;
  NOTICE:  trigtest INSERT AFTER STATEMENT
+ CONTEXT:  PL/pgSQL function trigtest() line 3 at RAISE
  insert into trigtest2 values(1);
  insert into trigtest2 values(2);
  delete from trigtest where i=2;
  NOTICE:  trigtest DELETE AFTER STATEMENT
+ CONTEXT:  PL/pgSQL function trigtest() line 3 at RAISE
  select * from trigtest2;
   i 
  ---
***************
*** 650,690 **** BEFORE INSERT OR UPDATE OR DELETE ON trigger_test
--- 722,796 ----
  FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
  insert into trigger_test values(1,'insert');
  NOTICE:  TG_NAME: show_trigger_data_trig
+ CONTEXT:  PL/pgSQL function trigger_data() line 15 at RAISE
  NOTICE:  TG_WHEN: BEFORE
+ CONTEXT:  PL/pgSQL function trigger_data() line 16 at RAISE
  NOTICE:  TG_LEVEL: ROW
+ CONTEXT:  PL/pgSQL function trigger_data() line 17 at RAISE
  NOTICE:  TG_OP: INSERT
+ CONTEXT:  PL/pgSQL function trigger_data() line 18 at RAISE
  NOTICE:  TG_RELID::regclass: trigger_test
+ CONTEXT:  PL/pgSQL function trigger_data() line 19 at RAISE
  NOTICE:  TG_RELNAME: trigger_test
+ CONTEXT:  PL/pgSQL function trigger_data() line 20 at RAISE
  NOTICE:  TG_TABLE_NAME: trigger_test
+ CONTEXT:  PL/pgSQL function trigger_data() line 21 at RAISE
  NOTICE:  TG_TABLE_SCHEMA: public
+ CONTEXT:  PL/pgSQL function trigger_data() line 22 at RAISE
  NOTICE:  TG_NARGS: 2
+ CONTEXT:  PL/pgSQL function trigger_data() line 23 at RAISE
  NOTICE:  TG_ARGV: [23, skidoo]
+ CONTEXT:  PL/pgSQL function trigger_data() line 33 at RAISE
  NOTICE:  NEW: (1,insert)
+ CONTEXT:  PL/pgSQL function trigger_data() line 40 at RAISE
  update trigger_test set v = 'update' where i = 1;
  NOTICE:  TG_NAME: show_trigger_data_trig
+ CONTEXT:  PL/pgSQL function trigger_data() line 15 at RAISE
  NOTICE:  TG_WHEN: BEFORE
+ CONTEXT:  PL/pgSQL function trigger_data() line 16 at RAISE
  NOTICE:  TG_LEVEL: ROW
+ CONTEXT:  PL/pgSQL function trigger_data() line 17 at RAISE
  NOTICE:  TG_OP: UPDATE
+ CONTEXT:  PL/pgSQL function trigger_data() line 18 at RAISE
  NOTICE:  TG_RELID::regclass: trigger_test
+ CONTEXT:  PL/pgSQL function trigger_data() line 19 at RAISE
  NOTICE:  TG_RELNAME: trigger_test
+ CONTEXT:  PL/pgSQL function trigger_data() line 20 at RAISE
  NOTICE:  TG_TABLE_NAME: trigger_test
+ CONTEXT:  PL/pgSQL function trigger_data() line 21 at RAISE
  NOTICE:  TG_TABLE_SCHEMA: public
+ CONTEXT:  PL/pgSQL function trigger_data() line 22 at RAISE
  NOTICE:  TG_NARGS: 2
+ CONTEXT:  PL/pgSQL function trigger_data() line 23 at RAISE
  NOTICE:  TG_ARGV: [23, skidoo]
+ CONTEXT:  PL/pgSQL function trigger_data() line 33 at RAISE
  NOTICE:  OLD: (1,insert)
+ CONTEXT:  PL/pgSQL function trigger_data() line 36 at RAISE
  NOTICE:  NEW: (1,update)
+ CONTEXT:  PL/pgSQL function trigger_data() line 40 at RAISE
  delete from trigger_test;
  NOTICE:  TG_NAME: show_trigger_data_trig
+ CONTEXT:  PL/pgSQL function trigger_data() line 15 at RAISE
  NOTICE:  TG_WHEN: BEFORE
+ CONTEXT:  PL/pgSQL function trigger_data() line 16 at RAISE
  NOTICE:  TG_LEVEL: ROW
+ CONTEXT:  PL/pgSQL function trigger_data() line 17 at RAISE
  NOTICE:  TG_OP: DELETE
+ CONTEXT:  PL/pgSQL function trigger_data() line 18 at RAISE
  NOTICE:  TG_RELID::regclass: trigger_test
+ CONTEXT:  PL/pgSQL function trigger_data() line 19 at RAISE
  NOTICE:  TG_RELNAME: trigger_test
+ CONTEXT:  PL/pgSQL function trigger_data() line 20 at RAISE
  NOTICE:  TG_TABLE_NAME: trigger_test
+ CONTEXT:  PL/pgSQL function trigger_data() line 21 at RAISE
  NOTICE:  TG_TABLE_SCHEMA: public
+ CONTEXT:  PL/pgSQL function trigger_data() line 22 at RAISE
  NOTICE:  TG_NARGS: 2
+ CONTEXT:  PL/pgSQL function trigger_data() line 23 at RAISE
  NOTICE:  TG_ARGV: [23, skidoo]
+ CONTEXT:  PL/pgSQL function trigger_data() line 33 at RAISE
  NOTICE:  OLD: (1,update)
+ CONTEXT:  PL/pgSQL function trigger_data() line 36 at RAISE
  DROP TRIGGER show_trigger_data_trig on trigger_test;
  DROP FUNCTION trigger_data();
  DROP TABLE trigger_test;
***************
*** 709,722 **** INSERT INTO trigger_test VALUES(1, 'foo', 'bar');
--- 815,834 ----
  INSERT INTO trigger_test VALUES(2, 'baz', 'quux');
  UPDATE trigger_test SET f3 = 'bar';
  NOTICE:  row 1 not changed
+ CONTEXT:  PL/pgSQL function mytrigger() line 4 at RAISE
  NOTICE:  row 2 changed
+ CONTEXT:  PL/pgSQL function mytrigger() line 6 at RAISE
  UPDATE trigger_test SET f3 = NULL;
  NOTICE:  row 1 changed
+ CONTEXT:  PL/pgSQL function mytrigger() line 6 at RAISE
  NOTICE:  row 2 changed
+ CONTEXT:  PL/pgSQL function mytrigger() line 6 at RAISE
  -- this demonstrates that the above isn't really working as desired:
  UPDATE trigger_test SET f3 = NULL;
  NOTICE:  row 1 changed
+ CONTEXT:  PL/pgSQL function mytrigger() line 6 at RAISE
  NOTICE:  row 2 changed
+ CONTEXT:  PL/pgSQL function mytrigger() line 6 at RAISE
  -- the right way when considering nulls is
  CREATE OR REPLACE FUNCTION mytrigger() RETURNS trigger LANGUAGE plpgsql as $$
  begin
***************
*** 729,741 **** begin
--- 841,859 ----
  end$$;
  UPDATE trigger_test SET f3 = 'bar';
  NOTICE:  row 1 changed
+ CONTEXT:  PL/pgSQL function mytrigger() line 4 at RAISE
  NOTICE:  row 2 changed
+ CONTEXT:  PL/pgSQL function mytrigger() line 4 at RAISE
  UPDATE trigger_test SET f3 = NULL;
  NOTICE:  row 1 changed
+ CONTEXT:  PL/pgSQL function mytrigger() line 4 at RAISE
  NOTICE:  row 2 changed
+ CONTEXT:  PL/pgSQL function mytrigger() line 4 at RAISE
  UPDATE trigger_test SET f3 = NULL;
  NOTICE:  row 1 not changed
+ CONTEXT:  PL/pgSQL function mytrigger() line 6 at RAISE
  NOTICE:  row 2 not changed
+ CONTEXT:  PL/pgSQL function mytrigger() line 6 at RAISE
  DROP TABLE trigger_test;
  DROP FUNCTION mytrigger();
  -- Test snapshot management in serializable transactions involving triggers
***************
*** 945,971 **** FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('after_view_del_stmt');
  -- Insert into view using trigger
  INSERT INTO main_view VALUES (20, 30);
  NOTICE:  main_view BEFORE INSERT STATEMENT (before_view_ins_stmt)
  NOTICE:  main_view INSTEAD OF INSERT ROW (instead_of_ins)
  NOTICE:  NEW: (20,30)
  NOTICE:  trigger_func(before_ins_stmt) called: action = INSERT, when = BEFORE, level = STATEMENT
! CONTEXT:  SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
  PL/pgSQL function view_trigger() line 17 at SQL statement
  NOTICE:  trigger_func(after_ins_stmt) called: action = INSERT, when = AFTER, level = STATEMENT
! CONTEXT:  SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
  PL/pgSQL function view_trigger() line 17 at SQL statement
  NOTICE:  main_view AFTER INSERT STATEMENT (after_view_ins_stmt)
  INSERT 0 1
  INSERT INTO main_view VALUES (21, 31) RETURNING a, b;
  NOTICE:  main_view BEFORE INSERT STATEMENT (before_view_ins_stmt)
  NOTICE:  main_view INSTEAD OF INSERT ROW (instead_of_ins)
  NOTICE:  NEW: (21,31)
  NOTICE:  trigger_func(before_ins_stmt) called: action = INSERT, when = BEFORE, level = STATEMENT
! CONTEXT:  SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
  PL/pgSQL function view_trigger() line 17 at SQL statement
  NOTICE:  trigger_func(after_ins_stmt) called: action = INSERT, when = AFTER, level = STATEMENT
! CONTEXT:  SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
  PL/pgSQL function view_trigger() line 17 at SQL statement
  NOTICE:  main_view AFTER INSERT STATEMENT (after_view_ins_stmt)
   a  | b  
  ----+----
   21 | 31
--- 1063,1101 ----
  -- Insert into view using trigger
  INSERT INTO main_view VALUES (20, 30);
  NOTICE:  main_view BEFORE INSERT STATEMENT (before_view_ins_stmt)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  NOTICE:  main_view INSTEAD OF INSERT ROW (instead_of_ins)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  NOTICE:  NEW: (20,30)
+ CONTEXT:  PL/pgSQL function view_trigger() line 16 at RAISE
  NOTICE:  trigger_func(before_ins_stmt) called: action = INSERT, when = BEFORE, level = STATEMENT
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
  PL/pgSQL function view_trigger() line 17 at SQL statement
  NOTICE:  trigger_func(after_ins_stmt) called: action = INSERT, when = AFTER, level = STATEMENT
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
  PL/pgSQL function view_trigger() line 17 at SQL statement
  NOTICE:  main_view AFTER INSERT STATEMENT (after_view_ins_stmt)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  INSERT 0 1
  INSERT INTO main_view VALUES (21, 31) RETURNING a, b;
  NOTICE:  main_view BEFORE INSERT STATEMENT (before_view_ins_stmt)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  NOTICE:  main_view INSTEAD OF INSERT ROW (instead_of_ins)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  NOTICE:  NEW: (21,31)
+ CONTEXT:  PL/pgSQL function view_trigger() line 16 at RAISE
  NOTICE:  trigger_func(before_ins_stmt) called: action = INSERT, when = BEFORE, level = STATEMENT
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
  PL/pgSQL function view_trigger() line 17 at SQL statement
  NOTICE:  trigger_func(after_ins_stmt) called: action = INSERT, when = AFTER, level = STATEMENT
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
  PL/pgSQL function view_trigger() line 17 at SQL statement
  NOTICE:  main_view AFTER INSERT STATEMENT (after_view_ins_stmt)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
   a  | b  
  ----+----
   21 | 31
***************
*** 975,1013 **** INSERT 0 1
  -- Table trigger will prevent updates
  UPDATE main_view SET b = 31 WHERE a = 20;
  NOTICE:  main_view BEFORE UPDATE STATEMENT (before_view_upd_stmt)
  NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
  NOTICE:  OLD: (20,30), NEW: (20,31)
  NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
! CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW
! CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
! CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
! CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
  UPDATE 0
  UPDATE main_view SET b = 32 WHERE a = 21 AND b = 31 RETURNING a, b;
  NOTICE:  main_view BEFORE UPDATE STATEMENT (before_view_upd_stmt)
  NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
  NOTICE:  OLD: (21,31), NEW: (21,32)
  NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
! CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW
! CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
! CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
! CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
   a | b 
  ---+---
  (0 rows)
--- 1105,1159 ----
  -- Table trigger will prevent updates
  UPDATE main_view SET b = 31 WHERE a = 20;
  NOTICE:  main_view BEFORE UPDATE STATEMENT (before_view_upd_stmt)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  NOTICE:  OLD: (20,30), NEW: (20,31)
+ CONTEXT:  PL/pgSQL function view_trigger() line 22 at RAISE
  NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  UPDATE 0
  UPDATE main_view SET b = 32 WHERE a = 21 AND b = 31 RETURNING a, b;
  NOTICE:  main_view BEFORE UPDATE STATEMENT (before_view_upd_stmt)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  NOTICE:  OLD: (21,31), NEW: (21,32)
+ CONTEXT:  PL/pgSQL function view_trigger() line 22 at RAISE
  NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
   a | b 
  ---+---
  (0 rows)
***************
*** 1018,1062 **** DROP TRIGGER before_upd_a_row_trig ON main_table;
  DROP TRIGGER
  UPDATE main_view SET b = 31 WHERE a = 20;
  NOTICE:  main_view BEFORE UPDATE STATEMENT (before_view_upd_stmt)
  NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
  NOTICE:  OLD: (20,30), NEW: (20,31)
  NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
! CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW
! CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW
! CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
! CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
! CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
  UPDATE 1
  UPDATE main_view SET b = 32 WHERE a = 21 AND b = 31 RETURNING a, b;
  NOTICE:  main_view BEFORE UPDATE STATEMENT (before_view_upd_stmt)
  NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
  NOTICE:  OLD: (21,31), NEW: (21,32)
  NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
! CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW
! CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW
! CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
! CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
! CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
   a  | b  
  ----+----
   21 | 32
--- 1164,1226 ----
  DROP TRIGGER
  UPDATE main_view SET b = 31 WHERE a = 20;
  NOTICE:  main_view BEFORE UPDATE STATEMENT (before_view_upd_stmt)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  NOTICE:  OLD: (20,30), NEW: (20,31)
+ CONTEXT:  PL/pgSQL function view_trigger() line 22 at RAISE
  NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  UPDATE 1
  UPDATE main_view SET b = 32 WHERE a = 21 AND b = 31 RETURNING a, b;
  NOTICE:  main_view BEFORE UPDATE STATEMENT (before_view_upd_stmt)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  NOTICE:  OLD: (21,31), NEW: (21,32)
+ CONTEXT:  PL/pgSQL function view_trigger() line 22 at RAISE
  NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
   a  | b  
  ----+----
   21 | 32
***************
*** 1066,1089 **** UPDATE 1
--- 1230,1267 ----
  -- Before and after stmt triggers should fire even when no rows are affected
  UPDATE main_view SET b = 0 WHERE false;
  NOTICE:  main_view BEFORE UPDATE STATEMENT (before_view_upd_stmt)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  UPDATE 0
  -- Delete from view using trigger
  DELETE FROM main_view WHERE a IN (20,21);
  NOTICE:  main_view BEFORE DELETE STATEMENT (before_view_del_stmt)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  NOTICE:  main_view INSTEAD OF DELETE ROW (instead_of_del)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  NOTICE:  OLD: (21,10)
+ CONTEXT:  PL/pgSQL function view_trigger() line 29 at RAISE
  NOTICE:  main_view INSTEAD OF DELETE ROW (instead_of_del)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  NOTICE:  OLD: (20,31)
+ CONTEXT:  PL/pgSQL function view_trigger() line 29 at RAISE
  NOTICE:  main_view INSTEAD OF DELETE ROW (instead_of_del)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  NOTICE:  OLD: (21,32)
+ CONTEXT:  PL/pgSQL function view_trigger() line 29 at RAISE
  NOTICE:  main_view AFTER DELETE STATEMENT (after_view_del_stmt)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  DELETE 3
  DELETE FROM main_view WHERE a = 31 RETURNING a, b;
  NOTICE:  main_view BEFORE DELETE STATEMENT (before_view_del_stmt)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  NOTICE:  main_view INSTEAD OF DELETE ROW (instead_of_del)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  NOTICE:  OLD: (31,10)
+ CONTEXT:  PL/pgSQL function view_trigger() line 29 at RAISE
  NOTICE:  main_view AFTER DELETE STATEMENT (after_view_del_stmt)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
   a  | b  
  ----+----
   31 | 10
***************
*** 1267,1272 **** INSERT 0 1
--- 1445,1451 ----
  -- UPDATE .. RETURNING
  UPDATE city_view SET country_name = 'Japon' WHERE city_name = 'Tokyo'; -- error
  ERROR:  No such country: "Japon"
+ CONTEXT:  PL/pgSQL function city_update() line 9 at RAISE
  UPDATE city_view SET country_name = 'Japan' WHERE city_name = 'Takyo'; -- no match
  UPDATE 0
  UPDATE city_view SET country_name = 'Japan' WHERE city_name = 'Tokyo' RETURNING *; -- OK
***************
*** 1478,1504 **** select pg_trigger_depth();
  
  insert into depth_a values (1);
  NOTICE:  depth_a_tr: depth = 1
  NOTICE:  depth_b_tr: depth = 2
! CONTEXT:  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_c_tr: depth = 3
! CONTEXT:  SQL statement "insert into depth_c values (1)"
  PL/pgSQL function depth_b_tf() line 5 at EXECUTE statement
  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  SQLSTATE = U9999: depth = 2
! CONTEXT:  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_b_tr: depth = 2
! CONTEXT:  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_c_tr: depth = 3
! CONTEXT:  SQL statement "insert into depth_c values (1)"
  PL/pgSQL function depth_b_tf() line 12 at EXECUTE statement
  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
  ERROR:  U9999
! CONTEXT:  SQL statement "insert into depth_c values (1)"
  PL/pgSQL function depth_b_tf() line 12 at EXECUTE statement
  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
--- 1657,1690 ----
  
  insert into depth_a values (1);
  NOTICE:  depth_a_tr: depth = 1
+ CONTEXT:  PL/pgSQL function depth_a_tf() line 3 at RAISE
  NOTICE:  depth_b_tr: depth = 2
! CONTEXT:  PL/pgSQL function depth_b_tf() line 3 at RAISE
! SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_c_tr: depth = 3
! CONTEXT:  PL/pgSQL function depth_c_tf() line 3 at RAISE
! SQL statement "insert into depth_c values (1)"
  PL/pgSQL function depth_b_tf() line 5 at EXECUTE statement
  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  SQLSTATE = U9999: depth = 2
! CONTEXT:  PL/pgSQL function depth_b_tf() line 8 at RAISE
! SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_b_tr: depth = 2
! CONTEXT:  PL/pgSQL function depth_b_tf() line 10 at RAISE
! SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_c_tr: depth = 3
! CONTEXT:  PL/pgSQL function depth_c_tf() line 3 at RAISE
! SQL statement "insert into depth_c values (1)"
  PL/pgSQL function depth_b_tf() line 12 at EXECUTE statement
  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
  ERROR:  U9999
! CONTEXT:  PL/pgSQL function depth_c_tf() line 5 at RAISE
! SQL statement "insert into depth_c values (1)"
  PL/pgSQL function depth_b_tf() line 12 at EXECUTE statement
  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
***************
*** 1510,1532 **** select pg_trigger_depth();
  
  insert into depth_a values (2);
  NOTICE:  depth_a_tr: depth = 1
  NOTICE:  depth_b_tr: depth = 2
! CONTEXT:  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_c_tr: depth = 3
! CONTEXT:  SQL statement "insert into depth_c values (2)"
  PL/pgSQL function depth_b_tf() line 5 at EXECUTE statement
  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_c_tr: depth = 3
! CONTEXT:  SQL statement "insert into depth_c values (2)"
  PL/pgSQL function depth_b_tf() line 5 at EXECUTE statement
  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_b_tr: depth = 2
! CONTEXT:  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_a_tr: depth = 1
  select pg_trigger_depth();
   pg_trigger_depth 
  ------------------
--- 1696,1724 ----
  
  insert into depth_a values (2);
  NOTICE:  depth_a_tr: depth = 1
+ CONTEXT:  PL/pgSQL function depth_a_tf() line 3 at RAISE
  NOTICE:  depth_b_tr: depth = 2
! CONTEXT:  PL/pgSQL function depth_b_tf() line 3 at RAISE
! SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_c_tr: depth = 3
! CONTEXT:  PL/pgSQL function depth_c_tf() line 3 at RAISE
! SQL statement "insert into depth_c values (2)"
  PL/pgSQL function depth_b_tf() line 5 at EXECUTE statement
  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_c_tr: depth = 3
! CONTEXT:  PL/pgSQL function depth_c_tf() line 7 at RAISE
! SQL statement "insert into depth_c values (2)"
  PL/pgSQL function depth_b_tf() line 5 at EXECUTE statement
  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_b_tr: depth = 2
! CONTEXT:  PL/pgSQL function depth_b_tf() line 10 at RAISE
! SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_a_tr: depth = 1
+ CONTEXT:  PL/pgSQL function depth_a_tf() line 5 at RAISE
  select pg_trigger_depth();
   pg_trigger_depth 
  ------------------
*** a/src/test/regress/expected/with.out
--- b/src/test/regress/expected/with.out
***************
*** 1903,1910 **** WITH t AS (
--- 1903,1913 ----
  )
  SELECT * FROM t;
  NOTICE:  y_trigger: a = 21
+ CONTEXT:  PL/pgSQL function y_trigger() line 3 at RAISE
  NOTICE:  y_trigger: a = 22
+ CONTEXT:  PL/pgSQL function y_trigger() line 3 at RAISE
  NOTICE:  y_trigger: a = 23
+ CONTEXT:  PL/pgSQL function y_trigger() line 3 at RAISE
   a  
  ----
   21
***************
*** 1943,1950 **** WITH t AS (
--- 1946,1956 ----
  )
  SELECT * FROM t LIMIT 1;
  NOTICE:  y_trigger: a = 31
+ CONTEXT:  PL/pgSQL function y_trigger() line 3 at RAISE
  NOTICE:  y_trigger: a = 32
+ CONTEXT:  PL/pgSQL function y_trigger() line 3 at RAISE
  NOTICE:  y_trigger: a = 33
+ CONTEXT:  PL/pgSQL function y_trigger() line 3 at RAISE
   a  
  ----
   31
***************
*** 1990,1995 **** WITH t AS (
--- 1996,2002 ----
  )
  SELECT * FROM t;
  NOTICE:  y_trigger
+ CONTEXT:  PL/pgSQL function y_trigger() line 3 at RAISE
   a  
  ----
   41
*** a/src/test/regress/expected/xml_1.out
--- b/src/test/regress/expected/xml_1.out
***************
*** 773,778 **** HINT:  You need to rebuild PostgreSQL using --with-libxml.
--- 773,779 ----
  \set VERBOSITY terse
  SELECT xpath('/*', '<invalidns xmlns=''&lt;''/>');
  ERROR:  unsupported XML feature at character 20
+ CONTEXT:  20
  \set VERBOSITY default
  -- Again, the XML isn't well-formed for namespace purposes
  SELECT xpath('/*', '<nosuchprefix:tag/>');
#24Marko Tiikkaja
marko@joh.to
In reply to: Marko Tiikkaja (#23)
Re: PL/pgSQL, RAISE and error context

On 15/09/2013 13:50, I wrote:

On 15/09/2013 04:05, Peter Eisentraut wrote:

On Sat, 2013-09-14 at 04:58 +0200, Marko Tiikkaja wrote:

The attached patch (based on Pavel's patch) changes the default to be
slightly more verbose (the CONTEXT lines which were previously
omitted
will be visible), but adds a new PGVerbosity called COMPACT which
suppresses CONTEXT in non-error messages. Now DEFAULT will be more
useful when debugging PL/PgSQL, and people who are annoyed by the new
behaviour can use the COMPACT mode.

Your patch fails the regression tests.

Attached is an updated patch with the regression test fixes. No other
changes included.

Hmm. I just noticed there's something weird going on in the select_view
test. I'm investigating this currently.

Regards,
Marko Tiikkaja

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#25Marko Tiikkaja
marko@joh.to
In reply to: Marko Tiikkaja (#24)
1 attachment(s)
Re: PL/pgSQL, RAISE and error context

On 15/09/2013 13:58, I wrote:

Hmm. I just noticed there's something weird going on in the select_view
test. I'm investigating this currently.

Seems that there's some magic going on and I overwrote the expected
results of the wrong file. However, I can't figure out how one is
supposed to be getting the output of expected/select_views.out, nor do I
find this documented anywhere (I know xml has a similar thing so I tried
grepping around for XML, to no avail).

Here's an updated patch, but I think expected/select_views.out is still
broken.

Regards,
Marko Tiikkaja

Attachments:

raise_context_v3.patchtext/plain; charset=windows-1252; name=raise_context_v3.patchDownload
*** a/doc/src/sgml/libpq.sgml
--- b/doc/src/sgml/libpq.sgml
***************
*** 5418,5423 **** int PQsetClientEncoding(PGconn *<replaceable>conn</replaceable>, const char *<re
--- 5418,5424 ----
  typedef enum
  {
      PQERRORS_TERSE,
+     PQERRORS_COMPACT,
      PQERRORS_DEFAULT,
      PQERRORS_VERBOSE
  } PGVerbosity;
***************
*** 5430,5439 **** PGVerbosity PQsetErrorVerbosity(PGconn *conn, PGVerbosity verbosity);
        returned messages include severity, primary text, and position only;
        this will normally fit on a single line.  The default mode produces
        messages that include the above plus any detail, hint, or context
!       fields (these might span multiple lines).  The <firstterm>VERBOSE</>
!       mode includes all available fields.  Changing the verbosity does not
!       affect the messages available from already-existing
!       <structname>PGresult</> objects, only subsequently-created ones.
       </para>
      </listitem>
     </varlistentry>
--- 5431,5442 ----
        returned messages include severity, primary text, and position only;
        this will normally fit on a single line.  The default mode produces
        messages that include the above plus any detail, hint, or context
!       fields (these might span multiple lines).  The COMPACT mode is otherwise
!       the same as the default, except the context field will be omitted for
!       non-error messages.  The <firstterm>VERBOSE</> mode includes all
!       available fields.  Changing the verbosity does not affect the messages
!       available from already-existing <structname>PGresult</> objects, only
!       subsequently-created ones.
       </para>
      </listitem>
     </varlistentry>
*** a/src/bin/psql/startup.c
--- b/src/bin/psql/startup.c
***************
*** 796,801 **** verbosity_hook(const char *newval)
--- 796,803 ----
  		pset.verbosity = PQERRORS_DEFAULT;
  	else if (strcmp(newval, "terse") == 0)
  		pset.verbosity = PQERRORS_TERSE;
+ 	else if (strcmp(newval, "compact") == 0)
+ 		pset.verbosity = PQERRORS_COMPACT;
  	else if (strcmp(newval, "verbose") == 0)
  		pset.verbosity = PQERRORS_VERBOSE;
  	else
*** a/src/interfaces/libpq/fe-protocol3.c
--- b/src/interfaces/libpq/fe-protocol3.c
***************
*** 915,920 **** pqGetErrorNotice3(PGconn *conn, bool isError)
--- 915,924 ----
  		if (val)
  			appendPQExpBuffer(&workBuf, libpq_gettext("QUERY:  %s\n"), val);
  		val = PQresultErrorField(res, PG_DIAG_CONTEXT);
+ 	}
+ 	if (isError || (conn->verbosity != PQERRORS_TERSE &&
+ 					conn->verbosity != PQERRORS_COMPACT))
+ 	{
  		if (val)
  			appendPQExpBuffer(&workBuf, libpq_gettext("CONTEXT:  %s\n"), val);
  	}
*** a/src/interfaces/libpq/libpq-fe.h
--- b/src/interfaces/libpq/libpq-fe.h
***************
*** 106,111 **** typedef enum
--- 106,112 ----
  typedef enum
  {
  	PQERRORS_TERSE,				/* single-line error messages */
+ 	PQERRORS_COMPACT,			/* single-line error messages on non-error messags */
  	PQERRORS_DEFAULT,			/* recommended style */
  	PQERRORS_VERBOSE			/* all the facts, ma'am */
  } PGVerbosity;
*** a/src/pl/plpgsql/src/pl_exec.c
--- b/src/pl/plpgsql/src/pl_exec.c
***************
*** 39,46 ****
  #include "utils/typcache.h"
  
  
- static const char *const raise_skip_msg = "RAISE";
- 
  typedef struct
  {
  	int			nargs;			/* number of arguments */
--- 39,44 ----
***************
*** 867,876 **** plpgsql_exec_error_callback(void *arg)
  {
  	PLpgSQL_execstate *estate = (PLpgSQL_execstate *) arg;
  
- 	/* if we are doing RAISE, don't report its location */
- 	if (estate->err_text == raise_skip_msg)
- 		return;
- 
  	if (estate->err_text != NULL)
  	{
  		/*
--- 865,870 ----
***************
*** 3032,3038 **** exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
  	/*
  	 * Throw the error (may or may not come back)
  	 */
- 	estate->err_text = raise_skip_msg;	/* suppress traceback of raise */
  
  	ereport(stmt->elog_level,
  			(err_code ? errcode(err_code) : 0,
--- 3026,3031 ----
*** a/src/test/regress/expected/alter_table.out
--- b/src/test/regress/expected/alter_table.out
***************
*** 361,371 **** CREATE FUNCTION boo(int) RETURNS int IMMUTABLE STRICT LANGUAGE plpgsql AS $$ BEG
--- 361,374 ----
  INSERT INTO tmp7 VALUES (8, 18);
  ALTER TABLE tmp7 ADD CONSTRAINT identity CHECK (b = boo(b));
  NOTICE:  boo: 18
+ CONTEXT:  PL/pgSQL function boo(integer) line 1 at RAISE
  ALTER TABLE tmp3 ADD CONSTRAINT IDENTITY check (b = boo(b)) NOT VALID;
  NOTICE:  merging constraint "identity" with inherited definition
  ALTER TABLE tmp3 VALIDATE CONSTRAINT identity;
  NOTICE:  boo: 16
+ CONTEXT:  PL/pgSQL function boo(integer) line 1 at RAISE
  NOTICE:  boo: 20
+ CONTEXT:  PL/pgSQL function boo(integer) line 1 at RAISE
  -- Try (and fail) to create constraint from tmp5(a) to tmp4(a) - unique constraint on
  -- tmp4 is a,b
  ALTER TABLE tmp5 add constraint tmpconstr foreign key(a) references tmp4(a) match full;
*** a/src/test/regress/expected/event_trigger.out
--- b/src/test/regress/expected/event_trigger.out
***************
*** 70,79 **** alter event trigger regress_event_trigger disable;
--- 70,82 ----
  -- regress_event_trigger
  create table event_trigger_fire1 (a int);
  NOTICE:  test_event_trigger: ddl_command_start CREATE TABLE
+ CONTEXT:  PL/pgSQL function test_event_trigger() line 3 at RAISE
  NOTICE:  test_event_trigger: ddl_command_end CREATE TABLE
+ CONTEXT:  PL/pgSQL function test_event_trigger() line 3 at RAISE
  -- regress_event_trigger_end should fire here
  drop table event_trigger_fire1;
  NOTICE:  test_event_trigger: ddl_command_end DROP TABLE
+ CONTEXT:  PL/pgSQL function test_event_trigger() line 3 at RAISE
  -- alter owner to non-superuser should fail
  alter event trigger regress_event_trigger owner to regression_bob;
  ERROR:  permission denied to change owner of event trigger "regress_event_trigger"
***************
*** 194,200 **** PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three"
  PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  ERROR:  object audit_tbls.schema_two_table_three of type table cannot be dropped
! CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three"
  PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  DELETE FROM undroppable_objs WHERE object_identity = 'audit_tbls.schema_two_table_three';
  DROP SCHEMA schema_one, schema_two CASCADE;
--- 197,204 ----
  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three"
  PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  ERROR:  object audit_tbls.schema_two_table_three of type table cannot be dropped
! CONTEXT:  PL/pgSQL function undroppable() line 14 at RAISE
! SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three"
  PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  DELETE FROM undroppable_objs WHERE object_identity = 'audit_tbls.schema_two_table_three';
  DROP SCHEMA schema_one, schema_two CASCADE;
***************
*** 224,229 **** NOTICE:  table "schema_one_table_three" does not exist, skipping
--- 228,234 ----
  CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_one_table_three"
  PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  ERROR:  object schema_one.table_three of type table cannot be dropped
+ CONTEXT:  PL/pgSQL function undroppable() line 14 at RAISE
  DELETE FROM undroppable_objs WHERE object_identity = 'schema_one.table_three';
  DROP SCHEMA schema_one, schema_two CASCADE;
  NOTICE:  drop cascades to 7 other objects
*** a/src/test/regress/expected/plancache.out
--- b/src/test/regress/expected/plancache.out
***************
*** 237,244 **** NOTICE:  table "temptable" does not exist, skipping
--- 237,247 ----
  CONTEXT:  SQL statement "drop table if exists temptable cascade"
  PL/pgSQL function cachebug() line 4 at SQL statement
  NOTICE:  1
+ CONTEXT:  PL/pgSQL function cachebug() line 8 at RAISE
  NOTICE:  2
+ CONTEXT:  PL/pgSQL function cachebug() line 8 at RAISE
  NOTICE:  3
+ CONTEXT:  PL/pgSQL function cachebug() line 8 at RAISE
   cachebug 
  ----------
   
***************
*** 249,256 **** NOTICE:  drop cascades to view vv
--- 252,262 ----
  CONTEXT:  SQL statement "drop table if exists temptable cascade"
  PL/pgSQL function cachebug() line 4 at SQL statement
  NOTICE:  1
+ CONTEXT:  PL/pgSQL function cachebug() line 8 at RAISE
  NOTICE:  2
+ CONTEXT:  PL/pgSQL function cachebug() line 8 at RAISE
  NOTICE:  3
+ CONTEXT:  PL/pgSQL function cachebug() line 8 at RAISE
   cachebug 
  ----------
   
*** a/src/test/regress/expected/plpgsql.out
--- b/src/test/regress/expected/plpgsql.out
***************
*** 1518,1544 **** ERROR:  duplicate key value violates unique constraint "pfield_name"
  DETAIL:  Key (name)=(PF1_1) already exists.
  update PSlot set backlink = 'WS.not.there' where slotname = 'PS.base.a1';
  ERROR:  WS.not.there         does not exist
! CONTEXT:  PL/pgSQL function tg_backlink_a() line 17 at assignment
  update PSlot set backlink = 'XX.illegal' where slotname = 'PS.base.a1';
  ERROR:  illegal backlink beginning with XX
! CONTEXT:  PL/pgSQL function tg_backlink_a() line 17 at assignment
  update PSlot set slotlink = 'PS.not.there' where slotname = 'PS.base.a1';
  ERROR:  PS.not.there         does not exist
! CONTEXT:  PL/pgSQL function tg_slotlink_a() line 17 at assignment
  update PSlot set slotlink = 'XX.illegal' where slotname = 'PS.base.a1';
  ERROR:  illegal slotlink beginning with XX
! CONTEXT:  PL/pgSQL function tg_slotlink_a() line 17 at assignment
  insert into HSlot values ('HS', 'base.hub1', 1, '');
  ERROR:  duplicate key value violates unique constraint "hslot_name"
  DETAIL:  Key (slotname)=(HS.base.hub1.1      ) already exists.
  insert into HSlot values ('HS', 'base.hub1', 20, '');
  ERROR:  no manual manipulation of HSlot
  delete from HSlot;
  ERROR:  no manual manipulation of HSlot
  insert into IFace values ('IF', 'notthere', 'eth0', '');
  ERROR:  system "notthere" does not exist
  insert into IFace values ('IF', 'orion', 'ethernet_interface_name_too_long', '');
  ERROR:  IFace slotname "IF.orion.ethernet_interface_name_too_long" too long (20 char max)
  --
  -- The following tests are unrelated to the scenario outlined above;
  -- they merely exercise specific parts of PL/pgSQL
--- 1518,1552 ----
  DETAIL:  Key (name)=(PF1_1) already exists.
  update PSlot set backlink = 'WS.not.there' where slotname = 'PS.base.a1';
  ERROR:  WS.not.there         does not exist
! CONTEXT:  PL/pgSQL function tg_backlink_set(character,character) line 30 at RAISE
! PL/pgSQL function tg_backlink_a() line 17 at assignment
  update PSlot set backlink = 'XX.illegal' where slotname = 'PS.base.a1';
  ERROR:  illegal backlink beginning with XX
! CONTEXT:  PL/pgSQL function tg_backlink_set(character,character) line 47 at RAISE
! PL/pgSQL function tg_backlink_a() line 17 at assignment
  update PSlot set slotlink = 'PS.not.there' where slotname = 'PS.base.a1';
  ERROR:  PS.not.there         does not exist
! CONTEXT:  PL/pgSQL function tg_slotlink_set(character,character) line 30 at RAISE
! PL/pgSQL function tg_slotlink_a() line 17 at assignment
  update PSlot set slotlink = 'XX.illegal' where slotname = 'PS.base.a1';
  ERROR:  illegal slotlink beginning with XX
! CONTEXT:  PL/pgSQL function tg_slotlink_set(character,character) line 77 at RAISE
! PL/pgSQL function tg_slotlink_a() line 17 at assignment
  insert into HSlot values ('HS', 'base.hub1', 1, '');
  ERROR:  duplicate key value violates unique constraint "hslot_name"
  DETAIL:  Key (slotname)=(HS.base.hub1.1      ) already exists.
  insert into HSlot values ('HS', 'base.hub1', 20, '');
  ERROR:  no manual manipulation of HSlot
+ CONTEXT:  PL/pgSQL function tg_hslot_biu() line 12 at RAISE
  delete from HSlot;
  ERROR:  no manual manipulation of HSlot
+ CONTEXT:  PL/pgSQL function tg_hslot_bd() line 12 at RAISE
  insert into IFace values ('IF', 'notthere', 'eth0', '');
  ERROR:  system "notthere" does not exist
+ CONTEXT:  PL/pgSQL function tg_iface_biu() line 8 at RAISE
  insert into IFace values ('IF', 'orion', 'ethernet_interface_name_too_long', '');
  ERROR:  IFace slotname "IF.orion.ethernet_interface_name_too_long" too long (20 char max)
+ CONTEXT:  PL/pgSQL function tg_iface_biu() line 14 at RAISE
  --
  -- The following tests are unrelated to the scenario outlined above;
  -- they merely exercise specific parts of PL/pgSQL
***************
*** 1934,1941 **** begin
--- 1942,1952 ----
  end$$ language plpgsql;
  select trap_zero_divide(50);
  NOTICE:  should see this
+ CONTEXT:  PL/pgSQL function trap_zero_divide(integer) line 6 at RAISE
  NOTICE:  should see this only if 50 <> 0
+ CONTEXT:  PL/pgSQL function trap_zero_divide(integer) line 8 at RAISE
  NOTICE:  should see this only if 50 fits in smallint
+ CONTEXT:  PL/pgSQL function trap_zero_divide(integer) line 10 at RAISE
   trap_zero_divide 
  ------------------
                  2
***************
*** 1943,1949 **** NOTICE:  should see this only if 50 fits in smallint
--- 1954,1962 ----
  
  select trap_zero_divide(0);
  NOTICE:  should see this
+ CONTEXT:  PL/pgSQL function trap_zero_divide(integer) line 6 at RAISE
  NOTICE:  caught division_by_zero
+ CONTEXT:  PL/pgSQL function trap_zero_divide(integer) line 16 at RAISE
   trap_zero_divide 
  ------------------
                 -1
***************
*** 1951,1958 **** NOTICE:  caught division_by_zero
--- 1964,1974 ----
  
  select trap_zero_divide(100000);
  NOTICE:  should see this
+ CONTEXT:  PL/pgSQL function trap_zero_divide(integer) line 6 at RAISE
  NOTICE:  should see this only if 100000 <> 0
+ CONTEXT:  PL/pgSQL function trap_zero_divide(integer) line 8 at RAISE
  NOTICE:  caught numeric_value_out_of_range
+ CONTEXT:  PL/pgSQL function trap_zero_divide(integer) line 19 at RAISE
   trap_zero_divide 
  ------------------
                 -2
***************
*** 1960,1968 **** NOTICE:  caught numeric_value_out_of_range
--- 1976,1988 ----
  
  select trap_zero_divide(-100);
  NOTICE:  should see this
+ CONTEXT:  PL/pgSQL function trap_zero_divide(integer) line 6 at RAISE
  NOTICE:  should see this only if -100 <> 0
+ CONTEXT:  PL/pgSQL function trap_zero_divide(integer) line 8 at RAISE
  NOTICE:  should see this only if -100 fits in smallint
+ CONTEXT:  PL/pgSQL function trap_zero_divide(integer) line 10 at RAISE
  ERROR:  -100 is less than zero
+ CONTEXT:  PL/pgSQL function trap_zero_divide(integer) line 12 at RAISE
  create function trap_matching_test(int) returns int as $$
  declare x int;
  	sx smallint;
***************
*** 1991,1996 **** select trap_matching_test(50);
--- 2011,2017 ----
  
  select trap_matching_test(0);
  NOTICE:  caught data_exception
+ CONTEXT:  PL/pgSQL function trap_matching_test(integer) line 13 at RAISE
   trap_matching_test 
  --------------------
                   -1
***************
*** 1998,2003 **** NOTICE:  caught data_exception
--- 2019,2025 ----
  
  select trap_matching_test(100000);
  NOTICE:  caught data_exception
+ CONTEXT:  PL/pgSQL function trap_matching_test(integer) line 13 at RAISE
   trap_matching_test 
  --------------------
                   -1
***************
*** 2005,2010 **** NOTICE:  caught data_exception
--- 2027,2033 ----
  
  select trap_matching_test(1);
  NOTICE:  caught numeric_value_out_of_range or cardinality_violation
+ CONTEXT:  PL/pgSQL function trap_matching_test(integer) line 16 at RAISE
   trap_matching_test 
  --------------------
                   -2
***************
*** 2035,2040 **** end$$ language plpgsql;
--- 2058,2064 ----
  set statement_timeout to 2000;
  select blockme();
  NOTICE:  nyeah nyeah, can't stop me
+ CONTEXT:  PL/pgSQL function blockme() line 16 at RAISE
   blockme 
  ---------
        20
***************
*** 2066,2078 **** begin
  end$$ language plpgsql;
  select test_variable_storage();
  NOTICE:  should see this
! CONTEXT:  SQL statement "SELECT trap_zero_divide(-100)"
  PL/pgSQL function test_variable_storage() line 8 at PERFORM
  NOTICE:  should see this only if -100 <> 0
! CONTEXT:  SQL statement "SELECT trap_zero_divide(-100)"
  PL/pgSQL function test_variable_storage() line 8 at PERFORM
  NOTICE:  should see this only if -100 fits in smallint
! CONTEXT:  SQL statement "SELECT trap_zero_divide(-100)"
  PL/pgSQL function test_variable_storage() line 8 at PERFORM
   test_variable_storage 
  -----------------------
--- 2090,2105 ----
  end$$ language plpgsql;
  select test_variable_storage();
  NOTICE:  should see this
! CONTEXT:  PL/pgSQL function trap_zero_divide(integer) line 6 at RAISE
! SQL statement "SELECT trap_zero_divide(-100)"
  PL/pgSQL function test_variable_storage() line 8 at PERFORM
  NOTICE:  should see this only if -100 <> 0
! CONTEXT:  PL/pgSQL function trap_zero_divide(integer) line 8 at RAISE
! SQL statement "SELECT trap_zero_divide(-100)"
  PL/pgSQL function test_variable_storage() line 8 at PERFORM
  NOTICE:  should see this only if -100 fits in smallint
! CONTEXT:  PL/pgSQL function trap_zero_divide(integer) line 10 at RAISE
! SQL statement "SELECT trap_zero_divide(-100)"
  PL/pgSQL function test_variable_storage() line 8 at PERFORM
   test_variable_storage 
  -----------------------
***************
*** 2119,2124 **** select trap_foreign_key(1);
--- 2146,2152 ----
  
  select trap_foreign_key(2);	-- detects FK violation
  NOTICE:  caught foreign_key_violation
+ CONTEXT:  PL/pgSQL function trap_foreign_key(integer) line 7 at RAISE
   trap_foreign_key 
  ------------------
                  0
***************
*** 2139,2144 **** DETAIL:  Key (f1)=(2) is not present in table "master".
--- 2167,2173 ----
    rollback to x;
    select trap_foreign_key_2();  -- detects FK violation
  NOTICE:  caught foreign_key_violation
+ CONTEXT:  PL/pgSQL function trap_foreign_key_2() line 7 at RAISE
   trap_foreign_key_2 
  --------------------
                    0
***************
*** 2481,2487 **** END;
--- 2510,2518 ----
  $$ LANGUAGE plpgsql;
  SELECT reraise_test();
  NOTICE:  exception syntax_error thrown in inner block, reraising
+ CONTEXT:  PL/pgSQL function reraise_test() line 8 at RAISE
  NOTICE:  RIGHT - exception syntax_error caught in inner block
+ CONTEXT:  PL/pgSQL function reraise_test() line 12 at RAISE
   reraise_test 
  --------------
   
***************
*** 2576,2583 **** begin
--- 2607,2617 ----
  end; $$ language plpgsql;
  select execute_into_test('eifoo');
  NOTICE:  10 1
+ CONTEXT:  PL/pgSQL function execute_into_test(character varying) line 12 at RAISE
  NOTICE:  10 15
+ CONTEXT:  PL/pgSQL function execute_into_test(character varying) line 14 at RAISE
  NOTICE:  10 15 20
+ CONTEXT:  PL/pgSQL function execute_into_test(character varying) line 16 at RAISE
   execute_into_test 
  -------------------
   (1,2)
***************
*** 2636,2644 **** begin
--- 2670,2682 ----
  end; $$ language plpgsql;
  select excpt_test3();
  NOTICE:  caught exception P0001 user exception
+ CONTEXT:  PL/pgSQL function excpt_test3() line 6 at RAISE
  NOTICE:  P0001 user exception
+ CONTEXT:  PL/pgSQL function excpt_test3() line 8 at RAISE
  NOTICE:  caught exception 22012 division by zero
+ CONTEXT:  PL/pgSQL function excpt_test3() line 15 at RAISE
  NOTICE:  P0001 user exception
+ CONTEXT:  PL/pgSQL function excpt_test3() line 17 at RAISE
   excpt_test3 
  -------------
   
***************
*** 2659,2664 **** begin
--- 2697,2703 ----
  end;$$ language plpgsql;
  select raise_exprs();
  NOTICE:  {10,20,30}; 20; xyz; xyzabc; (10,aaa,,30); <NULL>
+ CONTEXT:  PL/pgSQL function raise_exprs() line 8 at RAISE
   raise_exprs 
  -------------
   
***************
*** 2750,2807 **** begin
--- 2789,2899 ----
  end; $$ language plpgsql;
  select continue_test1();
  NOTICE:  ---1---
+ CONTEXT:  PL/pgSQL function continue_test1() line 4 at RAISE
  NOTICE:  1
+ CONTEXT:  PL/pgSQL function continue_test1() line 7 at RAISE
  NOTICE:  2
+ CONTEXT:  PL/pgSQL function continue_test1() line 7 at RAISE
  NOTICE:  3
+ CONTEXT:  PL/pgSQL function continue_test1() line 7 at RAISE
  NOTICE:  4
+ CONTEXT:  PL/pgSQL function continue_test1() line 7 at RAISE
  NOTICE:  5
+ CONTEXT:  PL/pgSQL function continue_test1() line 7 at RAISE
  NOTICE:  6
+ CONTEXT:  PL/pgSQL function continue_test1() line 7 at RAISE
  NOTICE:  7
+ CONTEXT:  PL/pgSQL function continue_test1() line 7 at RAISE
  NOTICE:  8
+ CONTEXT:  PL/pgSQL function continue_test1() line 7 at RAISE
  NOTICE:  9
+ CONTEXT:  PL/pgSQL function continue_test1() line 7 at RAISE
  NOTICE:  10
+ CONTEXT:  PL/pgSQL function continue_test1() line 7 at RAISE
  NOTICE:  ---2---
+ CONTEXT:  PL/pgSQL function continue_test1() line 12 at RAISE
  NOTICE:  9
+ CONTEXT:  PL/pgSQL function continue_test1() line 17 at RAISE
  NOTICE:  8
+ CONTEXT:  PL/pgSQL function continue_test1() line 17 at RAISE
  NOTICE:  7
+ CONTEXT:  PL/pgSQL function continue_test1() line 17 at RAISE
  NOTICE:  6
+ CONTEXT:  PL/pgSQL function continue_test1() line 17 at RAISE
  NOTICE:  5
+ CONTEXT:  PL/pgSQL function continue_test1() line 17 at RAISE
  NOTICE:  4
+ CONTEXT:  PL/pgSQL function continue_test1() line 17 at RAISE
  NOTICE:  3
+ CONTEXT:  PL/pgSQL function continue_test1() line 17 at RAISE
  NOTICE:  2
+ CONTEXT:  PL/pgSQL function continue_test1() line 17 at RAISE
  NOTICE:  1
+ CONTEXT:  PL/pgSQL function continue_test1() line 17 at RAISE
  NOTICE:  0
+ CONTEXT:  PL/pgSQL function continue_test1() line 17 at RAISE
  NOTICE:  ---3---
+ CONTEXT:  PL/pgSQL function continue_test1() line 23 at RAISE
  NOTICE:  1
+ CONTEXT:  PL/pgSQL function continue_test1() line 28 at RAISE
  NOTICE:  3
+ CONTEXT:  PL/pgSQL function continue_test1() line 28 at RAISE
  NOTICE:  5
+ CONTEXT:  PL/pgSQL function continue_test1() line 28 at RAISE
  NOTICE:  7
+ CONTEXT:  PL/pgSQL function continue_test1() line 28 at RAISE
  NOTICE:  9
+ CONTEXT:  PL/pgSQL function continue_test1() line 28 at RAISE
  NOTICE:  ---4---
+ CONTEXT:  PL/pgSQL function continue_test1() line 31 at RAISE
  NOTICE:  5
+ CONTEXT:  PL/pgSQL function continue_test1() line 36 at RAISE
  NOTICE:  6
+ CONTEXT:  PL/pgSQL function continue_test1() line 36 at RAISE
  NOTICE:  7
+ CONTEXT:  PL/pgSQL function continue_test1() line 36 at RAISE
  NOTICE:  8
+ CONTEXT:  PL/pgSQL function continue_test1() line 36 at RAISE
  NOTICE:  9
+ CONTEXT:  PL/pgSQL function continue_test1() line 36 at RAISE
  NOTICE:  10
+ CONTEXT:  PL/pgSQL function continue_test1() line 36 at RAISE
  NOTICE:  ---5---
+ CONTEXT:  PL/pgSQL function continue_test1() line 40 at RAISE
  NOTICE:  30
+ CONTEXT:  PL/pgSQL function continue_test1() line 43 at RAISE
  NOTICE:  40
+ CONTEXT:  PL/pgSQL function continue_test1() line 43 at RAISE
  NOTICE:  ---6---
+ CONTEXT:  PL/pgSQL function continue_test1() line 46 at RAISE
  NOTICE:  30
+ CONTEXT:  PL/pgSQL function continue_test1() line 49 at RAISE
  NOTICE:  40
+ CONTEXT:  PL/pgSQL function continue_test1() line 49 at RAISE
  NOTICE:  ---7---
+ CONTEXT:  PL/pgSQL function continue_test1() line 52 at RAISE
  NOTICE:  1
+ CONTEXT:  PL/pgSQL function continue_test1() line 54 at RAISE
  NOTICE:  2
+ CONTEXT:  PL/pgSQL function continue_test1() line 54 at RAISE
  NOTICE:  3
+ CONTEXT:  PL/pgSQL function continue_test1() line 54 at RAISE
  NOTICE:  ---8---
+ CONTEXT:  PL/pgSQL function continue_test1() line 58 at RAISE
  NOTICE:  1
+ CONTEXT:  PL/pgSQL function continue_test1() line 61 at RAISE
  NOTICE:  2
+ CONTEXT:  PL/pgSQL function continue_test1() line 61 at RAISE
  NOTICE:  3
+ CONTEXT:  PL/pgSQL function continue_test1() line 61 at RAISE
  NOTICE:  ---9---
+ CONTEXT:  PL/pgSQL function continue_test1() line 66 at RAISE
  NOTICE:  10
+ CONTEXT:  PL/pgSQL function continue_test1() line 68 at RAISE
  NOTICE:  ---10---
+ CONTEXT:  PL/pgSQL function continue_test1() line 72 at RAISE
  NOTICE:  10
+ CONTEXT:  PL/pgSQL function continue_test1() line 74 at RAISE
   continue_test1 
  ----------------
   
***************
*** 2924,2947 **** end;
--- 3016,3058 ----
  $proc$ language plpgsql;
  select for_vect();
  NOTICE:  1
+ CONTEXT:  PL/pgSQL function for_vect() line 6 at RAISE
  NOTICE:  2
+ CONTEXT:  PL/pgSQL function for_vect() line 6 at RAISE
  NOTICE:  3
+ CONTEXT:  PL/pgSQL function for_vect() line 6 at RAISE
  NOTICE:  1 BB CC
+ CONTEXT:  PL/pgSQL function for_vect() line 10 at RAISE
  NOTICE:  2 BB CC
+ CONTEXT:  PL/pgSQL function for_vect() line 10 at RAISE
  NOTICE:  3 BB CC
+ CONTEXT:  PL/pgSQL function for_vect() line 10 at RAISE
  NOTICE:  4 BB CC
+ CONTEXT:  PL/pgSQL function for_vect() line 10 at RAISE
  NOTICE:  1
+ CONTEXT:  PL/pgSQL function for_vect() line 14 at RAISE
  NOTICE:  2
+ CONTEXT:  PL/pgSQL function for_vect() line 14 at RAISE
  NOTICE:  3
+ CONTEXT:  PL/pgSQL function for_vect() line 14 at RAISE
  NOTICE:  4
+ CONTEXT:  PL/pgSQL function for_vect() line 14 at RAISE
  NOTICE:  1 BB CC
+ CONTEXT:  PL/pgSQL function for_vect() line 18 at RAISE
  NOTICE:  2 BB CC
+ CONTEXT:  PL/pgSQL function for_vect() line 18 at RAISE
  NOTICE:  3 BB CC
+ CONTEXT:  PL/pgSQL function for_vect() line 18 at RAISE
  NOTICE:  4 BB CC
+ CONTEXT:  PL/pgSQL function for_vect() line 18 at RAISE
  NOTICE:  1 bb cc
+ CONTEXT:  PL/pgSQL function for_vect() line 22 at RAISE
  NOTICE:  2 bb cc
+ CONTEXT:  PL/pgSQL function for_vect() line 22 at RAISE
  NOTICE:  3 bb cc
+ CONTEXT:  PL/pgSQL function for_vect() line 22 at RAISE
  NOTICE:  4 bb cc
+ CONTEXT:  PL/pgSQL function for_vect() line 22 at RAISE
   for_vect 
  ----------
   
***************
*** 2981,2986 **** begin
--- 3092,3098 ----
  end$$ language plpgsql;
  select footest();
  NOTICE:  x.f1 = 5, x.f2 = 6
+ CONTEXT:  PL/pgSQL function footest() line 6 at RAISE
   footest 
  ---------
   
***************
*** 3005,3010 **** begin
--- 3117,3123 ----
  end$$ language plpgsql;
  select footest();
  NOTICE:  x.f1 = 5, x.f2 = 6
+ CONTEXT:  PL/pgSQL function footest() line 6 at RAISE
   footest 
  ---------
   
***************
*** 3019,3024 **** begin
--- 3132,3138 ----
  end$$ language plpgsql;
  select footest();
  NOTICE:  x.f1 = 7, x.f2 = 8
+ CONTEXT:  PL/pgSQL function footest() line 6 at RAISE
   footest 
  ---------
   
***************
*** 3044,3049 **** begin
--- 3158,3164 ----
  end$$ language plpgsql;
  select footest();
  NOTICE:  x.f1 = 3, x.f2 = 4
+ CONTEXT:  PL/pgSQL function footest() line 6 at RAISE
   footest 
  ---------
   
***************
*** 3078,3083 **** begin
--- 3193,3199 ----
  end$$ language plpgsql;
  select footest();
  NOTICE:  x.f1 = 3, x.f2 = 4
+ CONTEXT:  PL/pgSQL function footest() line 6 at RAISE
   footest 
  ---------
   
***************
*** 3282,3290 **** end;
--- 3398,3410 ----
  $$ language plpgsql;
  select pl_qual_names(42);
  NOTICE:  param1 = 2
+ CONTEXT:  PL/pgSQL function pl_qual_names(integer) line 10 at RAISE
  NOTICE:  pl_qual_names.param1 = 42
+ CONTEXT:  PL/pgSQL function pl_qual_names(integer) line 11 at RAISE
  NOTICE:  outerblock.param1 = 1
+ CONTEXT:  PL/pgSQL function pl_qual_names(integer) line 12 at RAISE
  NOTICE:  innerblock.param1 = 2
+ CONTEXT:  PL/pgSQL function pl_qual_names(integer) line 13 at RAISE
   pl_qual_names 
  ---------------
   
***************
*** 3353,3363 **** end
--- 3473,3489 ----
  $$ language plpgsql;
  select exc_using(5, 'foobar');
  NOTICE:  1
+ CONTEXT:  PL/pgSQL function exc_using(integer,text) line 5 at RAISE
  NOTICE:  2
+ CONTEXT:  PL/pgSQL function exc_using(integer,text) line 5 at RAISE
  NOTICE:  3
+ CONTEXT:  PL/pgSQL function exc_using(integer,text) line 5 at RAISE
  NOTICE:  4
+ CONTEXT:  PL/pgSQL function exc_using(integer,text) line 5 at RAISE
  NOTICE:  5
+ CONTEXT:  PL/pgSQL function exc_using(integer,text) line 5 at RAISE
  NOTICE:  6
+ CONTEXT:  PL/pgSQL function exc_using(integer,text) line 5 at RAISE
   exc_using 
  -----------
          26
***************
*** 3381,3391 **** end;
--- 3507,3523 ----
  $$ language plpgsql;
  select exc_using(5);
  NOTICE:  1
+ CONTEXT:  PL/pgSQL function exc_using(integer) line 10 at RAISE
  NOTICE:  2
+ CONTEXT:  PL/pgSQL function exc_using(integer) line 10 at RAISE
  NOTICE:  3
+ CONTEXT:  PL/pgSQL function exc_using(integer) line 10 at RAISE
  NOTICE:  4
+ CONTEXT:  PL/pgSQL function exc_using(integer) line 10 at RAISE
  NOTICE:  5
+ CONTEXT:  PL/pgSQL function exc_using(integer) line 10 at RAISE
  NOTICE:  6
+ CONTEXT:  PL/pgSQL function exc_using(integer) line 10 at RAISE
   exc_using 
  -----------
   
***************
*** 3430,3451 **** end;
--- 3562,3600 ----
  $$ language plpgsql;
  select forc01();
  NOTICE:  5 from c
+ CONTEXT:  PL/pgSQL function forc01() line 9 at RAISE
  NOTICE:  6 from c
+ CONTEXT:  PL/pgSQL function forc01() line 9 at RAISE
  NOTICE:  7 from c
+ CONTEXT:  PL/pgSQL function forc01() line 9 at RAISE
  NOTICE:  9 from c
+ CONTEXT:  PL/pgSQL function forc01() line 13 at RAISE
  NOTICE:  10 from c
+ CONTEXT:  PL/pgSQL function forc01() line 13 at RAISE
  NOTICE:  41 from c2
+ CONTEXT:  PL/pgSQL function forc01() line 17 at RAISE
  NOTICE:  42 from c2
+ CONTEXT:  PL/pgSQL function forc01() line 17 at RAISE
  NOTICE:  43 from c2
+ CONTEXT:  PL/pgSQL function forc01() line 17 at RAISE
  NOTICE:  after loop, c2 = c2
+ CONTEXT:  PL/pgSQL function forc01() line 20 at RAISE
  NOTICE:  41 from special_name
+ CONTEXT:  PL/pgSQL function forc01() line 23 at RAISE
  NOTICE:  42 from special_name
+ CONTEXT:  PL/pgSQL function forc01() line 23 at RAISE
  NOTICE:  43 from special_name
+ CONTEXT:  PL/pgSQL function forc01() line 23 at RAISE
  NOTICE:  after loop, c2 = special_name
+ CONTEXT:  PL/pgSQL function forc01() line 25 at RAISE
  NOTICE:  41
+ CONTEXT:  PL/pgSQL function forc01() line 30 at RAISE
  NOTICE:  42
+ CONTEXT:  PL/pgSQL function forc01() line 30 at RAISE
  NOTICE:  43
+ CONTEXT:  PL/pgSQL function forc01() line 30 at RAISE
  NOTICE:  after loop, c2 = <NULL>
+ CONTEXT:  PL/pgSQL function forc01() line 32 at RAISE
   forc01 
  --------
   
***************
*** 3466,3480 **** end;
--- 3615,3639 ----
  $$ language plpgsql;
  select forc01();
  NOTICE:  1, 1
+ CONTEXT:  PL/pgSQL function forc01() line 6 at RAISE
  NOTICE:  2, 2
+ CONTEXT:  PL/pgSQL function forc01() line 6 at RAISE
  NOTICE:  3, 3
+ CONTEXT:  PL/pgSQL function forc01() line 6 at RAISE
  NOTICE:  4, 4
+ CONTEXT:  PL/pgSQL function forc01() line 6 at RAISE
  NOTICE:  5, 5
+ CONTEXT:  PL/pgSQL function forc01() line 6 at RAISE
  NOTICE:  6, 6
+ CONTEXT:  PL/pgSQL function forc01() line 6 at RAISE
  NOTICE:  7, 7
+ CONTEXT:  PL/pgSQL function forc01() line 6 at RAISE
  NOTICE:  8, 8
+ CONTEXT:  PL/pgSQL function forc01() line 6 at RAISE
  NOTICE:  9, 9
+ CONTEXT:  PL/pgSQL function forc01() line 6 at RAISE
  NOTICE:  10, 10
+ CONTEXT:  PL/pgSQL function forc01() line 6 at RAISE
   forc01 
  --------
   
***************
*** 3512,3526 **** end;
--- 3671,3695 ----
  $$ language plpgsql;
  select forc01();
  NOTICE:  100, 2
+ CONTEXT:  PL/pgSQL function forc01() line 10 at RAISE
  NOTICE:  200, 4
+ CONTEXT:  PL/pgSQL function forc01() line 10 at RAISE
  NOTICE:  300, 6
+ CONTEXT:  PL/pgSQL function forc01() line 10 at RAISE
  NOTICE:  400, 8
+ CONTEXT:  PL/pgSQL function forc01() line 10 at RAISE
  NOTICE:  500, 10
+ CONTEXT:  PL/pgSQL function forc01() line 10 at RAISE
  NOTICE:  600, 12
+ CONTEXT:  PL/pgSQL function forc01() line 10 at RAISE
  NOTICE:  700, 14
+ CONTEXT:  PL/pgSQL function forc01() line 10 at RAISE
  NOTICE:  800, 16
+ CONTEXT:  PL/pgSQL function forc01() line 10 at RAISE
  NOTICE:  900, 18
+ CONTEXT:  PL/pgSQL function forc01() line 10 at RAISE
  NOTICE:  1000, 20
+ CONTEXT:  PL/pgSQL function forc01() line 10 at RAISE
   forc01 
  --------
   
***************
*** 3769,3776 **** select raise_test();
--- 3938,3947 ----
  NOTICE:  1 2 3
  DETAIL:  some detail info
  HINT:  some hint
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  ERROR:  1 2 3
  DETAIL:  some detail info
+ CONTEXT:  PL/pgSQL function raise_test() line 5 at RAISE
  -- Since we can't actually see the thrown SQLSTATE in default psql output,
  -- test it like this; this also tests re-RAISE
  create or replace function raise_test() returns void as $$
***************
*** 3785,3792 **** end;
--- 3956,3965 ----
  $$ language plpgsql;
  select raise_test();
  NOTICE:  SQLSTATE: 22012 SQLERRM: check me
+ CONTEXT:  PL/pgSQL function raise_test() line 7 at RAISE
  ERROR:  check me
  DETAIL:  some detail info
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise 'check me'
***************
*** 3799,3806 **** end;
--- 3972,3981 ----
  $$ language plpgsql;
  select raise_test();
  NOTICE:  SQLSTATE: 1234F SQLERRM: check me
+ CONTEXT:  PL/pgSQL function raise_test() line 7 at RAISE
  ERROR:  check me
  DETAIL:  some detail info
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  -- SQLSTATE specification in WHEN
  create or replace function raise_test() returns void as $$
  begin
***************
*** 3814,3821 **** end;
--- 3989,3998 ----
  $$ language plpgsql;
  select raise_test();
  NOTICE:  SQLSTATE: 1234F SQLERRM: check me
+ CONTEXT:  PL/pgSQL function raise_test() line 7 at RAISE
  ERROR:  check me
  DETAIL:  some detail info
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise division_by_zero using detail = 'some detail info';
***************
*** 3827,3834 **** end;
--- 4004,4013 ----
  $$ language plpgsql;
  select raise_test();
  NOTICE:  SQLSTATE: 22012 SQLERRM: division_by_zero
+ CONTEXT:  PL/pgSQL function raise_test() line 6 at RAISE
  ERROR:  division_by_zero
  DETAIL:  some detail info
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise division_by_zero;
***************
*** 3836,3841 **** end;
--- 4015,4021 ----
  $$ language plpgsql;
  select raise_test();
  ERROR:  division_by_zero
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise sqlstate '1234F';
***************
*** 3843,3848 **** end;
--- 4023,4029 ----
  $$ language plpgsql;
  select raise_test();
  ERROR:  1234F
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise division_by_zero using message = 'custom' || ' message';
***************
*** 3850,3855 **** end;
--- 4031,4037 ----
  $$ language plpgsql;
  select raise_test();
  ERROR:  custom message
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise using message = 'custom' || ' message', errcode = '22012';
***************
*** 3857,3862 **** end;
--- 4039,4045 ----
  $$ language plpgsql;
  select raise_test();
  ERROR:  custom message
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  -- conflict on message
  create or replace function raise_test() returns void as $$
  begin
***************
*** 3915,3920 **** end;
--- 4098,4104 ----
  $$ language plpgsql;
  select stacked_diagnostics_test();
  NOTICE:  sqlstate: 22012, message: division by zero, context: [PL/pgSQL function zero_divide() line 4 at RETURN <- SQL statement "SELECT zero_divide()" <- PL/pgSQL function stacked_diagnostics_test() line 6 at PERFORM]
+ CONTEXT:  PL/pgSQL function stacked_diagnostics_test() line 12 at RAISE
   stacked_diagnostics_test 
  --------------------------
   
***************
*** 3936,3941 **** end;
--- 4120,4126 ----
  $$ language plpgsql;
  select stacked_diagnostics_test();
  NOTICE:  message: custom exception, detail: some detail of custom exception, hint: some hint related to custom exception
+ CONTEXT:  PL/pgSQL function stacked_diagnostics_test() line 12 at RAISE
   stacked_diagnostics_test 
  --------------------------
   
***************
*** 3972,3978 **** end;
--- 4157,4165 ----
  $$ language plpgsql;
  select raise_test();
  NOTICE:  22012
+ CONTEXT:  PL/pgSQL function raise_test() line 6 at RAISE
  ERROR:  substitute message
+ CONTEXT:  PL/pgSQL function raise_test() line 7 at RAISE
  drop function raise_test();
  -- test passing column_name, constraint_name, datatype_name, table_name
  -- and schema_name error fields
***************
*** 4002,4007 **** end;
--- 4189,4195 ----
  $$ language plpgsql;
  select stacked_diagnostics_test();
  NOTICE:  column >>some column name<<, constraint >>some constraint name<<, type >>some datatype name<<, table >>some table name<<, schema >>some schema name<<
+ CONTEXT:  PL/pgSQL function stacked_diagnostics_test() line 21 at RAISE
   stacked_diagnostics_test 
  --------------------------
   
***************
*** 4093,4098 **** end
--- 4281,4287 ----
  $$ language plpgsql;
  select catch();
  NOTICE:  caught case_not_found 20000 case not found
+ CONTEXT:  PL/pgSQL function catch() line 6 at RAISE
   catch 
  -------
   
***************
*** 4148,4157 **** begin
--- 4337,4351 ----
  $$ language plpgsql;
  select vari(1,2,3,4,5);
  NOTICE:  1
+ CONTEXT:  PL/pgSQL function vari(integer[]) line 4 at RAISE
  NOTICE:  2
+ CONTEXT:  PL/pgSQL function vari(integer[]) line 4 at RAISE
  NOTICE:  3
+ CONTEXT:  PL/pgSQL function vari(integer[]) line 4 at RAISE
  NOTICE:  4
+ CONTEXT:  PL/pgSQL function vari(integer[]) line 4 at RAISE
  NOTICE:  5
+ CONTEXT:  PL/pgSQL function vari(integer[]) line 4 at RAISE
   vari 
  ------
   
***************
*** 4159,4166 **** NOTICE:  5
--- 4353,4363 ----
  
  select vari(3,4,5);
  NOTICE:  3
+ CONTEXT:  PL/pgSQL function vari(integer[]) line 4 at RAISE
  NOTICE:  4
+ CONTEXT:  PL/pgSQL function vari(integer[]) line 4 at RAISE
  NOTICE:  5
+ CONTEXT:  PL/pgSQL function vari(integer[]) line 4 at RAISE
   vari 
  ------
   
***************
*** 4168,4175 **** NOTICE:  5
--- 4365,4375 ----
  
  select vari(variadic array[5,6,7]);
  NOTICE:  5
+ CONTEXT:  PL/pgSQL function vari(integer[]) line 4 at RAISE
  NOTICE:  6
+ CONTEXT:  PL/pgSQL function vari(integer[]) line 4 at RAISE
  NOTICE:  7
+ CONTEXT:  PL/pgSQL function vari(integer[]) line 4 at RAISE
   vari 
  ------
   
***************
*** 4221,4226 **** end;
--- 4421,4427 ----
  $$ language plpgsql immutable strict;
  select pleast(10);
  NOTICE:  non-variadic function called
+ CONTEXT:  PL/pgSQL function pleast(numeric) line 3 at RAISE
   pleast 
  --------
       10
***************
*** 4280,4288 **** end;
--- 4481,4493 ----
  $$ language plpgsql;
  select * from rttest();
  NOTICE:  t 2
+ CONTEXT:  PL/pgSQL function rttest() line 6 at RAISE
  NOTICE:  f 0
+ CONTEXT:  PL/pgSQL function rttest() line 9 at RAISE
  NOTICE:  t 2
+ CONTEXT:  PL/pgSQL function rttest() line 12 at RAISE
  NOTICE:  f 0
+ CONTEXT:  PL/pgSQL function rttest() line 15 at RAISE
   rttest 
  --------
       10
***************
*** 4458,4463 **** LINE 4:   return 'foo\\bar\041baz';
--- 4663,4669 ----
  HINT:  Use the escape string syntax for backslashes, e.g., E'\\'.
  select strtest();
  NOTICE:  foo\bar!baz
+ CONTEXT:  PL/pgSQL function strtest() line 3 at RAISE
  WARNING:  nonstandard use of \\ in a string literal
  LINE 1: SELECT 'foo\\bar\041baz'
                 ^
***************
*** 4477,4482 **** end
--- 4683,4689 ----
  $$ language plpgsql;
  select strtest();
  NOTICE:  foo\bar!baz
+ CONTEXT:  PL/pgSQL function strtest() line 3 at RAISE
     strtest   
  -------------
   foo\bar!baz
***************
*** 4491,4496 **** end
--- 4698,4704 ----
  $$ language plpgsql;
  select strtest();
  NOTICE:  foo\\bar\041baz\
+ CONTEXT:  PL/pgSQL function strtest() line 3 at RAISE
       strtest      
  ------------------
   foo\\bar\041baz\
***************
*** 4504,4509 **** end
--- 4712,4718 ----
  $$ language plpgsql;
  select strtest();
  NOTICE:  foo\bar!baz
+ CONTEXT:  PL/pgSQL function strtest() line 3 at RAISE
     strtest   
  -------------
   foo\bar!baz
***************
*** 4520,4534 **** BEGIN
--- 4729,4753 ----
      END LOOP;
  END$$;
  NOTICE:  001, Entrance
+ CONTEXT:  PL/pgSQL function inline_code_block line 6 at RAISE
  NOTICE:  002, Office
+ CONTEXT:  PL/pgSQL function inline_code_block line 6 at RAISE
  NOTICE:  003, Office
+ CONTEXT:  PL/pgSQL function inline_code_block line 6 at RAISE
  NOTICE:  004, Technical
+ CONTEXT:  PL/pgSQL function inline_code_block line 6 at RAISE
  NOTICE:  101, Office
+ CONTEXT:  PL/pgSQL function inline_code_block line 6 at RAISE
  NOTICE:  102, Conference
+ CONTEXT:  PL/pgSQL function inline_code_block line 6 at RAISE
  NOTICE:  103, Restroom
+ CONTEXT:  PL/pgSQL function inline_code_block line 6 at RAISE
  NOTICE:  104, Technical
+ CONTEXT:  PL/pgSQL function inline_code_block line 6 at RAISE
  NOTICE:  105, Office
+ CONTEXT:  PL/pgSQL function inline_code_block line 6 at RAISE
  NOTICE:  106, Office
+ CONTEXT:  PL/pgSQL function inline_code_block line 6 at RAISE
  -- these are to check syntax error reporting
  DO LANGUAGE plpgsql $$begin return 1; end$$;
  ERROR:  RETURN cannot have a parameter in function returning void
***************
*** 4656,4664 **** begin
--- 4875,4887 ----
  $$ language plpgsql;
  select foreach_test(ARRAY[1,2,3,4]);
  NOTICE:  1
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
  NOTICE:  2
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
  NOTICE:  3
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
  NOTICE:  4
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
   foreach_test 
  --------------
   
***************
*** 4666,4674 **** NOTICE:  4
--- 4889,4901 ----
  
  select foreach_test(ARRAY[[1,2],[3,4]]);
  NOTICE:  1
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
  NOTICE:  2
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
  NOTICE:  3
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
  NOTICE:  4
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
   foreach_test 
  --------------
   
***************
*** 4703,4708 **** begin
--- 4930,4936 ----
  $$ language plpgsql;
  select foreach_test(ARRAY[1,2,3,4]);
  NOTICE:  {1,2,3,4}
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
   foreach_test 
  --------------
   
***************
*** 4710,4716 **** NOTICE:  {1,2,3,4}
--- 4938,4946 ----
  
  select foreach_test(ARRAY[[1,2],[3,4]]);
  NOTICE:  {1,2}
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
  NOTICE:  {3,4}
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
   foreach_test 
  --------------
   
***************
*** 4734,4739 **** CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 4 at FOREACH over array
--- 4964,4970 ----
  -- ok
  select foreach_test(ARRAY[[1,2],[3,4]]);
  NOTICE:  {{1,2},{3,4}}
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
   foreach_test 
  --------------
   
***************
*** 4741,4747 **** NOTICE:  {{1,2},{3,4}}
--- 4972,4980 ----
  
  select foreach_test(ARRAY[[[1,2]],[[3,4]]]);
  NOTICE:  {{1,2}}
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
  NOTICE:  {{3,4}}
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
   foreach_test 
  --------------
   
***************
*** 4761,4768 **** begin
--- 4994,5004 ----
  $$ language plpgsql;
  select foreach_test(ARRAY[(10,20),(40,69),(35,78)]::xy_tuple[]);
  NOTICE:  (10,20)
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
  NOTICE:  (40,69)
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
  NOTICE:  (35,78)
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
   foreach_test 
  --------------
   
***************
*** 4770,4778 **** NOTICE:  (35,78)
--- 5006,5018 ----
  
  select foreach_test(ARRAY[[(10,20),(40,69)],[(35,78),(88,76)]]::xy_tuple[]);
  NOTICE:  (10,20)
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
  NOTICE:  (40,69)
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
  NOTICE:  (35,78)
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
  NOTICE:  (88,76)
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
   foreach_test 
  --------------
   
***************
*** 4790,4797 **** begin
--- 5030,5040 ----
  $$ language plpgsql;
  select foreach_test(ARRAY[(10,20),(40,69),(35,78)]::xy_tuple[]);
  NOTICE:  x = 10, y = 20
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
  NOTICE:  x = 40, y = 69
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
  NOTICE:  x = 35, y = 78
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
   foreach_test 
  --------------
   
***************
*** 4799,4807 **** NOTICE:  x = 35, y = 78
--- 5042,5054 ----
  
  select foreach_test(ARRAY[[(10,20),(40,69)],[(35,78),(88,76)]]::xy_tuple[]);
  NOTICE:  x = 10, y = 20
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
  NOTICE:  x = 40, y = 69
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
  NOTICE:  x = 35, y = 78
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
  NOTICE:  x = 88, y = 76
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
   foreach_test 
  --------------
   
***************
*** 4820,4825 **** begin
--- 5067,5073 ----
  $$ language plpgsql;
  select foreach_test(ARRAY[(10,20),(40,69),(35,78)]::xy_tuple[]);
  NOTICE:  {"(10,20)","(40,69)","(35,78)"}
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
   foreach_test 
  --------------
   
***************
*** 4827,4833 **** NOTICE:  {"(10,20)","(40,69)","(35,78)"}
--- 5075,5083 ----
  
  select foreach_test(ARRAY[[(10,20),(40,69)],[(35,78),(88,76)]]::xy_tuple[]);
  NOTICE:  {"(10,20)","(40,69)"}
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
  NOTICE:  {"(35,78)","(88,76)"}
+ CONTEXT:  PL/pgSQL function foreach_test(anyarray) line 6 at RAISE
   foreach_test 
  --------------
   
***************
*** 4935,4958 **** end;
  $$ language plpgsql;
  select outer_outer_func(10);
  NOTICE:  calling down into outer_func()
  NOTICE:  calling down into inner_func()
! CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 4 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
! CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 7 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
! CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  lets make sure we didnt break anything
! CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  inner_func() done
! CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  outer_func() done
   outer_outer_func 
  ------------------
                 20
--- 5185,5215 ----
  $$ language plpgsql;
  select outer_outer_func(10);
  NOTICE:  calling down into outer_func()
+ CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 5 at RAISE
  NOTICE:  calling down into inner_func()
! CONTEXT:  PL/pgSQL function outer_func(integer) line 5 at RAISE
! PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 4 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
! CONTEXT:  PL/pgSQL function inner_func(integer) line 5 at RAISE
! PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 7 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
! CONTEXT:  PL/pgSQL function inner_func(integer) line 8 at RAISE
! PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  lets make sure we didnt break anything
! CONTEXT:  PL/pgSQL function inner_func(integer) line 9 at RAISE
! PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  inner_func() done
! CONTEXT:  PL/pgSQL function outer_func(integer) line 7 at RAISE
! PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  outer_func() done
+ CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 7 at RAISE
   outer_outer_func 
  ------------------
                 20
***************
*** 4961,4984 **** NOTICE:  outer_func() done
  -- repeated call should to work
  select outer_outer_func(20);
  NOTICE:  calling down into outer_func()
  NOTICE:  calling down into inner_func()
! CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 4 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
! CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 7 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
! CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  lets make sure we didnt break anything
! CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  inner_func() done
! CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  outer_func() done
   outer_outer_func 
  ------------------
                 40
--- 5218,5248 ----
  -- repeated call should to work
  select outer_outer_func(20);
  NOTICE:  calling down into outer_func()
+ CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 5 at RAISE
  NOTICE:  calling down into inner_func()
! CONTEXT:  PL/pgSQL function outer_func(integer) line 5 at RAISE
! PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 4 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
! CONTEXT:  PL/pgSQL function inner_func(integer) line 5 at RAISE
! PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 7 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
! CONTEXT:  PL/pgSQL function inner_func(integer) line 8 at RAISE
! PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  lets make sure we didnt break anything
! CONTEXT:  PL/pgSQL function inner_func(integer) line 9 at RAISE
! PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  inner_func() done
! CONTEXT:  PL/pgSQL function outer_func(integer) line 7 at RAISE
! PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  outer_func() done
+ CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 7 at RAISE
   outer_outer_func 
  ------------------
                 40
***************
*** 5033,5056 **** end;
  $$ language plpgsql;
  select outer_outer_func(10);
  NOTICE:  calling down into outer_func()
  NOTICE:  calling down into inner_func()
! CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 10 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
! CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 15 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
! CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  lets make sure we didnt break anything
! CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  inner_func() done
! CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  outer_func() done
   outer_outer_func 
  ------------------
                 20
--- 5297,5327 ----
  $$ language plpgsql;
  select outer_outer_func(10);
  NOTICE:  calling down into outer_func()
+ CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 5 at RAISE
  NOTICE:  calling down into inner_func()
! CONTEXT:  PL/pgSQL function outer_func(integer) line 5 at RAISE
! PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 10 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
! CONTEXT:  PL/pgSQL function inner_func(integer) line 11 at RAISE
! PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 15 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
! CONTEXT:  PL/pgSQL function inner_func(integer) line 16 at RAISE
! PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  lets make sure we didnt break anything
! CONTEXT:  PL/pgSQL function inner_func(integer) line 17 at RAISE
! PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  inner_func() done
! CONTEXT:  PL/pgSQL function outer_func(integer) line 7 at RAISE
! PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  outer_func() done
+ CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 7 at RAISE
   outer_outer_func 
  ------------------
                 20
***************
*** 5059,5082 **** NOTICE:  outer_func() done
  -- repeated call should to work
  select outer_outer_func(20);
  NOTICE:  calling down into outer_func()
  NOTICE:  calling down into inner_func()
! CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 10 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
! CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 15 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
! CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  lets make sure we didnt break anything
! CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  inner_func() done
! CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  outer_func() done
   outer_outer_func 
  ------------------
                 40
--- 5330,5360 ----
  -- repeated call should to work
  select outer_outer_func(20);
  NOTICE:  calling down into outer_func()
+ CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 5 at RAISE
  NOTICE:  calling down into inner_func()
! CONTEXT:  PL/pgSQL function outer_func(integer) line 5 at RAISE
! PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 10 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
! CONTEXT:  PL/pgSQL function inner_func(integer) line 11 at RAISE
! PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 15 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
! CONTEXT:  PL/pgSQL function inner_func(integer) line 16 at RAISE
! PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  lets make sure we didnt break anything
! CONTEXT:  PL/pgSQL function inner_func(integer) line 17 at RAISE
! PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  inner_func() done
! CONTEXT:  PL/pgSQL function outer_func(integer) line 7 at RAISE
! PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  outer_func() done
+ CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 7 at RAISE
   outer_outer_func 
  ------------------
                 40
*** a/src/test/regress/expected/polymorphism.out
--- b/src/test/regress/expected/polymorphism.out
***************
*** 555,564 **** select case when $1 then $2 else $3 end $$ language sql;
--- 555,569 ----
  -- if the CASE expression were not successfully inlined
  select f1, sql_if(f1 > 0, bleat(f1), bleat(f1 + 1)) from int4_tbl;
  NOTICE:  bleat 1
+ CONTEXT:  PL/pgSQL function bleat(integer) line 3 at RAISE
  NOTICE:  bleat 123456
+ CONTEXT:  PL/pgSQL function bleat(integer) line 3 at RAISE
  NOTICE:  bleat -123455
+ CONTEXT:  PL/pgSQL function bleat(integer) line 3 at RAISE
  NOTICE:  bleat 2147483647
+ CONTEXT:  PL/pgSQL function bleat(integer) line 3 at RAISE
  NOTICE:  bleat -2147483646
+ CONTEXT:  PL/pgSQL function bleat(integer) line 3 at RAISE
       f1      |   sql_if    
  -------------+-------------
             0 |           1
*** a/src/test/regress/expected/rangefuncs.out
--- b/src/test/regress/expected/rangefuncs.out
***************
*** 1366,1374 **** create trigger tnoticetrigger after insert on tt for each row
  execute procedure noticetrigger();
  select insert_tt2('foolme','barme') limit 1;
  NOTICE:  noticetrigger 11 foolme
! CONTEXT:  SQL function "insert_tt2" statement 1
  NOTICE:  noticetrigger 12 barme
! CONTEXT:  SQL function "insert_tt2" statement 1
   insert_tt2 
  ------------
           11
--- 1366,1376 ----
  execute procedure noticetrigger();
  select insert_tt2('foolme','barme') limit 1;
  NOTICE:  noticetrigger 11 foolme
! CONTEXT:  PL/pgSQL function noticetrigger() line 3 at RAISE
! SQL function "insert_tt2" statement 1
  NOTICE:  noticetrigger 12 barme
! CONTEXT:  PL/pgSQL function noticetrigger() line 3 at RAISE
! SQL function "insert_tt2" statement 1
   insert_tt2 
  ------------
           11
***************
*** 1397,1405 **** create rule insert_tt_rule as on insert to tt do also
    insert into tt_log values(new.*);
  select insert_tt2('foollog','barlog') limit 1;
  NOTICE:  noticetrigger 13 foollog
! CONTEXT:  SQL function "insert_tt2" statement 1
  NOTICE:  noticetrigger 14 barlog
! CONTEXT:  SQL function "insert_tt2" statement 1
   insert_tt2 
  ------------
           13
--- 1399,1409 ----
    insert into tt_log values(new.*);
  select insert_tt2('foollog','barlog') limit 1;
  NOTICE:  noticetrigger 13 foollog
! CONTEXT:  PL/pgSQL function noticetrigger() line 3 at RAISE
! SQL function "insert_tt2" statement 1
  NOTICE:  noticetrigger 14 barlog
! CONTEXT:  PL/pgSQL function noticetrigger() line 3 at RAISE
! SQL function "insert_tt2" statement 1
   insert_tt2 
  ------------
           13
*** a/src/test/regress/expected/select_views_1.out
--- b/src/test/regress/expected/select_views_1.out
***************
*** 1318,1325 **** SET SESSION AUTHORIZATION regress_alice;
--- 1318,1328 ----
  --
  SELECT * FROM my_property_normal WHERE f_leak(passwd);
  NOTICE:  f_leak => passwd123
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
  NOTICE:  f_leak => beafsteak
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
  NOTICE:  f_leak => hamburger
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
   cid |     name      |       tel        |  passwd   
  -----+---------------+------------------+-----------
   101 | regress_alice | +81-12-3456-7890 | passwd123
***************
*** 1334,1339 **** EXPLAIN (COSTS OFF) SELECT * FROM my_property_normal WHERE f_leak(passwd);
--- 1337,1343 ----
  
  SELECT * FROM my_property_secure WHERE f_leak(passwd);
  NOTICE:  f_leak => passwd123
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
   cid |     name      |       tel        |  passwd   
  -----+---------------+------------------+-----------
   101 | regress_alice | +81-12-3456-7890 | passwd123
***************
*** 1355,1362 **** EXPLAIN (COSTS OFF) SELECT * FROM my_property_secure WHERE f_leak(passwd);
--- 1359,1369 ----
  --
  SELECT * FROM my_credit_card_normal WHERE f_leak(cnum);
  NOTICE:  f_leak => 1111-2222-3333-4444
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
  NOTICE:  f_leak => 5555-6666-7777-8888
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
  NOTICE:  f_leak => 9801-2345-6789-0123
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
   cid |     name      |       tel        |  passwd   |        cnum         | climit 
  -----+---------------+------------------+-----------+---------------------+--------
   101 | regress_alice | +81-12-3456-7890 | passwd123 | 1111-2222-3333-4444 |   4000
***************
*** 1376,1381 **** EXPLAIN (COSTS OFF) SELECT * FROM my_credit_card_normal WHERE f_leak(cnum);
--- 1383,1389 ----
  
  SELECT * FROM my_credit_card_secure WHERE f_leak(cnum);
  NOTICE:  f_leak => 1111-2222-3333-4444
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
   cid |     name      |       tel        |  passwd   |        cnum         | climit 
  -----+---------------+------------------+-----------+---------------------+--------
   101 | regress_alice | +81-12-3456-7890 | passwd123 | 1111-2222-3333-4444 |   4000
***************
*** 1402,1407 **** EXPLAIN (COSTS OFF) SELECT * FROM my_credit_card_secure WHERE f_leak(cnum);
--- 1410,1416 ----
  SELECT * FROM my_credit_card_usage_normal
         WHERE f_leak(cnum) AND ymd >= '2011-10-01' AND ymd < '2011-11-01';
  NOTICE:  f_leak => 1111-2222-3333-4444
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
   cid |     name      |       tel        |  passwd   |        cnum         | climit |    ymd     | usage 
  -----+---------------+------------------+-----------+---------------------+--------+------------+-------
   101 | regress_alice | +81-12-3456-7890 | passwd123 | 1111-2222-3333-4444 |   4000 | 10-05-2011 |    90
***************
*** 1431,1438 **** EXPLAIN (COSTS OFF) SELECT * FROM my_credit_card_usage_normal
--- 1440,1450 ----
  SELECT * FROM my_credit_card_usage_secure
         WHERE f_leak(cnum) AND ymd >= '2011-10-01' AND ymd < '2011-11-01';
  NOTICE:  f_leak => 1111-2222-3333-4444
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
  NOTICE:  f_leak => 1111-2222-3333-4444
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
  NOTICE:  f_leak => 1111-2222-3333-4444
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
   cid |     name      |       tel        |  passwd   |        cnum         | climit |    ymd     | usage 
  -----+---------------+------------------+-----------+---------------------+--------+------------+-------
   101 | regress_alice | +81-12-3456-7890 | passwd123 | 1111-2222-3333-4444 |   4000 | 10-05-2011 |    90
***************
*** 1467,1474 **** PREPARE p1 AS SELECT * FROM my_property_normal WHERE f_leak(passwd);
--- 1479,1489 ----
  PREPARE p2 AS SELECT * FROM my_property_secure WHERE f_leak(passwd);
  EXECUTE p1;
  NOTICE:  f_leak => passwd123
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
  NOTICE:  f_leak => beafsteak
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
  NOTICE:  f_leak => hamburger
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
   cid |     name      |       tel        |  passwd   
  -----+---------------+------------------+-----------
   101 | regress_alice | +81-12-3456-7890 | passwd123
***************
*** 1476,1481 **** NOTICE:  f_leak => hamburger
--- 1491,1497 ----
  
  EXECUTE p2;
  NOTICE:  f_leak => passwd123
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
   cid |     name      |       tel        |  passwd   
  -----+---------------+------------------+-----------
   101 | regress_alice | +81-12-3456-7890 | passwd123
***************
*** 1487,1492 **** ALTER VIEW my_property_secure SET (security_barrier=false);
--- 1503,1509 ----
  SET SESSION AUTHORIZATION regress_alice;
  EXECUTE p1;		-- To be perform as a view with security-barrier
  NOTICE:  f_leak => passwd123
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
   cid |     name      |       tel        |  passwd   
  -----+---------------+------------------+-----------
   101 | regress_alice | +81-12-3456-7890 | passwd123
***************
*** 1494,1501 **** NOTICE:  f_leak => passwd123
--- 1511,1521 ----
  
  EXECUTE p2;		-- To be perform as a view without security-barrier
  NOTICE:  f_leak => passwd123
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
  NOTICE:  f_leak => beafsteak
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
  NOTICE:  f_leak => hamburger
+ CONTEXT:  PL/pgSQL function f_leak(text) line 1 at RAISE
   cid |     name      |       tel        |  passwd   
  -----+---------------+------------------+-----------
   101 | regress_alice | +81-12-3456-7890 | passwd123
*** a/src/test/regress/expected/triggers.out
--- b/src/test/regress/expected/triggers.out
***************
*** 295,314 **** CREATE TRIGGER after_upd_row_trig AFTER UPDATE ON main_table
--- 295,324 ----
  FOR EACH ROW EXECUTE PROCEDURE trigger_func('after_upd_row');
  INSERT INTO main_table DEFAULT VALUES;
  NOTICE:  trigger_func(before_ins_stmt) called: action = INSERT, when = BEFORE, level = STATEMENT
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_ins_stmt) called: action = INSERT, when = AFTER, level = STATEMENT
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  UPDATE main_table SET a = a + 1 WHERE b < 30;
  NOTICE:  trigger_func(after_upd_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  -- UPDATE that effects zero rows should still call per-statement trigger
  UPDATE main_table SET a = a + 2 WHERE b > 100;
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  -- COPY should fire per-row and per-statement INSERT triggers
  COPY main_table (a, b) FROM stdin;
  NOTICE:  trigger_func(before_ins_stmt) called: action = INSERT, when = BEFORE, level = STATEMENT
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_ins_stmt) called: action = INSERT, when = AFTER, level = STATEMENT
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  SELECT * FROM main_table ORDER BY a, b;
   a  | b  
  ----+----
***************
*** 339,366 **** CREATE TRIGGER delete_when AFTER DELETE ON main_table
--- 349,396 ----
  FOR EACH STATEMENT WHEN (true) EXECUTE PROCEDURE trigger_func('delete_when');
  INSERT INTO main_table (a) VALUES (123), (456);
  NOTICE:  trigger_func(before_ins_stmt) called: action = INSERT, when = BEFORE, level = STATEMENT
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(insert_when) called: action = INSERT, when = BEFORE, level = STATEMENT
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(insert_a) called: action = INSERT, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_ins_stmt) called: action = INSERT, when = AFTER, level = STATEMENT
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  COPY main_table FROM stdin;
  NOTICE:  trigger_func(before_ins_stmt) called: action = INSERT, when = BEFORE, level = STATEMENT
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(insert_when) called: action = INSERT, when = BEFORE, level = STATEMENT
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(insert_a) called: action = INSERT, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_ins_stmt) called: action = INSERT, when = AFTER, level = STATEMENT
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  DELETE FROM main_table WHERE a IN (123, 456);
  NOTICE:  trigger_func(delete_a) called: action = DELETE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(delete_a) called: action = DELETE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(delete_when) called: action = DELETE, when = AFTER, level = STATEMENT
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  UPDATE main_table SET a = 50, b = 60;
  NOTICE:  trigger_func(modified_any) called: action = UPDATE, when = BEFORE, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(modified_any) called: action = UPDATE, when = BEFORE, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(modified_a) called: action = UPDATE, when = BEFORE, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(modified_a) called: action = UPDATE, when = BEFORE, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(modified_a) called: action = UPDATE, when = BEFORE, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(modified_a) called: action = UPDATE, when = BEFORE, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(modified_a) called: action = UPDATE, when = BEFORE, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  SELECT * FROM main_table ORDER BY a, b;
   a  | b  
  ----+----
***************
*** 418,451 **** SELECT pg_get_triggerdef(oid) FROM pg_trigger WHERE tgrelid = 'main_table'::regc
--- 448,509 ----
  
  UPDATE main_table SET a = 50;
  NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  UPDATE main_table SET b = 10;
  NOTICE:  trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
+ CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
  --
  -- Test case for bug with BEFORE trigger followed by AFTER trigger with WHEN
  --
***************
*** 468,479 **** CREATE TRIGGER some_trig_afterb AFTER UPDATE ON some_t FOR EACH ROW
--- 526,542 ----
  INSERT INTO some_t VALUES (TRUE);
  UPDATE some_t SET some_col = TRUE;
  NOTICE:  dummy_update_func(before) called: action = UPDATE, old = (t), new = (t)
+ CONTEXT:  PL/pgSQL function dummy_update_func() line 3 at RAISE
  UPDATE some_t SET some_col = FALSE;
  NOTICE:  dummy_update_func(before) called: action = UPDATE, old = (t), new = (f)
+ CONTEXT:  PL/pgSQL function dummy_update_func() line 3 at RAISE
  NOTICE:  dummy_update_func(afterb) called: action = UPDATE, old = (t), new = (f)
+ CONTEXT:  PL/pgSQL function dummy_update_func() line 3 at RAISE
  UPDATE some_t SET some_col = TRUE;
  NOTICE:  dummy_update_func(before) called: action = UPDATE, old = (f), new = (t)
+ CONTEXT:  PL/pgSQL function dummy_update_func() line 3 at RAISE
  NOTICE:  dummy_update_func(aftera) called: action = UPDATE, old = (f), new = (t)
+ CONTEXT:  PL/pgSQL function dummy_update_func() line 3 at RAISE
  DROP TABLE some_t;
  -- bogus cases
  CREATE TRIGGER error_upd_and_col BEFORE UPDATE OR UPDATE OF a ON main_table
***************
*** 546,568 **** create trigger trigtest_a_stmt_tg after insert or update or delete on trigtest
--- 609,640 ----
  for each statement execute procedure trigtest();
  insert into trigtest default values;
  NOTICE:  trigtest INSERT BEFORE STATEMENT
+ CONTEXT:  PL/pgSQL function trigtest() line 3 at RAISE
  NOTICE:  trigtest INSERT BEFORE ROW
+ CONTEXT:  PL/pgSQL function trigtest() line 3 at RAISE
  NOTICE:  trigtest INSERT AFTER ROW
+ CONTEXT:  PL/pgSQL function trigtest() line 3 at RAISE
  NOTICE:  trigtest INSERT AFTER STATEMENT
+ CONTEXT:  PL/pgSQL function trigtest() line 3 at RAISE
  alter table trigtest disable trigger trigtest_b_row_tg;
  insert into trigtest default values;
  NOTICE:  trigtest INSERT BEFORE STATEMENT
+ CONTEXT:  PL/pgSQL function trigtest() line 3 at RAISE
  NOTICE:  trigtest INSERT AFTER ROW
+ CONTEXT:  PL/pgSQL function trigtest() line 3 at RAISE
  NOTICE:  trigtest INSERT AFTER STATEMENT
+ CONTEXT:  PL/pgSQL function trigtest() line 3 at RAISE
  alter table trigtest disable trigger user;
  insert into trigtest default values;
  alter table trigtest enable trigger trigtest_a_stmt_tg;
  insert into trigtest default values;
  NOTICE:  trigtest INSERT AFTER STATEMENT
+ CONTEXT:  PL/pgSQL function trigtest() line 3 at RAISE
  insert into trigtest2 values(1);
  insert into trigtest2 values(2);
  delete from trigtest where i=2;
  NOTICE:  trigtest DELETE AFTER STATEMENT
+ CONTEXT:  PL/pgSQL function trigtest() line 3 at RAISE
  select * from trigtest2;
   i 
  ---
***************
*** 650,690 **** BEFORE INSERT OR UPDATE OR DELETE ON trigger_test
--- 722,796 ----
  FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
  insert into trigger_test values(1,'insert');
  NOTICE:  TG_NAME: show_trigger_data_trig
+ CONTEXT:  PL/pgSQL function trigger_data() line 15 at RAISE
  NOTICE:  TG_WHEN: BEFORE
+ CONTEXT:  PL/pgSQL function trigger_data() line 16 at RAISE
  NOTICE:  TG_LEVEL: ROW
+ CONTEXT:  PL/pgSQL function trigger_data() line 17 at RAISE
  NOTICE:  TG_OP: INSERT
+ CONTEXT:  PL/pgSQL function trigger_data() line 18 at RAISE
  NOTICE:  TG_RELID::regclass: trigger_test
+ CONTEXT:  PL/pgSQL function trigger_data() line 19 at RAISE
  NOTICE:  TG_RELNAME: trigger_test
+ CONTEXT:  PL/pgSQL function trigger_data() line 20 at RAISE
  NOTICE:  TG_TABLE_NAME: trigger_test
+ CONTEXT:  PL/pgSQL function trigger_data() line 21 at RAISE
  NOTICE:  TG_TABLE_SCHEMA: public
+ CONTEXT:  PL/pgSQL function trigger_data() line 22 at RAISE
  NOTICE:  TG_NARGS: 2
+ CONTEXT:  PL/pgSQL function trigger_data() line 23 at RAISE
  NOTICE:  TG_ARGV: [23, skidoo]
+ CONTEXT:  PL/pgSQL function trigger_data() line 33 at RAISE
  NOTICE:  NEW: (1,insert)
+ CONTEXT:  PL/pgSQL function trigger_data() line 40 at RAISE
  update trigger_test set v = 'update' where i = 1;
  NOTICE:  TG_NAME: show_trigger_data_trig
+ CONTEXT:  PL/pgSQL function trigger_data() line 15 at RAISE
  NOTICE:  TG_WHEN: BEFORE
+ CONTEXT:  PL/pgSQL function trigger_data() line 16 at RAISE
  NOTICE:  TG_LEVEL: ROW
+ CONTEXT:  PL/pgSQL function trigger_data() line 17 at RAISE
  NOTICE:  TG_OP: UPDATE
+ CONTEXT:  PL/pgSQL function trigger_data() line 18 at RAISE
  NOTICE:  TG_RELID::regclass: trigger_test
+ CONTEXT:  PL/pgSQL function trigger_data() line 19 at RAISE
  NOTICE:  TG_RELNAME: trigger_test
+ CONTEXT:  PL/pgSQL function trigger_data() line 20 at RAISE
  NOTICE:  TG_TABLE_NAME: trigger_test
+ CONTEXT:  PL/pgSQL function trigger_data() line 21 at RAISE
  NOTICE:  TG_TABLE_SCHEMA: public
+ CONTEXT:  PL/pgSQL function trigger_data() line 22 at RAISE
  NOTICE:  TG_NARGS: 2
+ CONTEXT:  PL/pgSQL function trigger_data() line 23 at RAISE
  NOTICE:  TG_ARGV: [23, skidoo]
+ CONTEXT:  PL/pgSQL function trigger_data() line 33 at RAISE
  NOTICE:  OLD: (1,insert)
+ CONTEXT:  PL/pgSQL function trigger_data() line 36 at RAISE
  NOTICE:  NEW: (1,update)
+ CONTEXT:  PL/pgSQL function trigger_data() line 40 at RAISE
  delete from trigger_test;
  NOTICE:  TG_NAME: show_trigger_data_trig
+ CONTEXT:  PL/pgSQL function trigger_data() line 15 at RAISE
  NOTICE:  TG_WHEN: BEFORE
+ CONTEXT:  PL/pgSQL function trigger_data() line 16 at RAISE
  NOTICE:  TG_LEVEL: ROW
+ CONTEXT:  PL/pgSQL function trigger_data() line 17 at RAISE
  NOTICE:  TG_OP: DELETE
+ CONTEXT:  PL/pgSQL function trigger_data() line 18 at RAISE
  NOTICE:  TG_RELID::regclass: trigger_test
+ CONTEXT:  PL/pgSQL function trigger_data() line 19 at RAISE
  NOTICE:  TG_RELNAME: trigger_test
+ CONTEXT:  PL/pgSQL function trigger_data() line 20 at RAISE
  NOTICE:  TG_TABLE_NAME: trigger_test
+ CONTEXT:  PL/pgSQL function trigger_data() line 21 at RAISE
  NOTICE:  TG_TABLE_SCHEMA: public
+ CONTEXT:  PL/pgSQL function trigger_data() line 22 at RAISE
  NOTICE:  TG_NARGS: 2
+ CONTEXT:  PL/pgSQL function trigger_data() line 23 at RAISE
  NOTICE:  TG_ARGV: [23, skidoo]
+ CONTEXT:  PL/pgSQL function trigger_data() line 33 at RAISE
  NOTICE:  OLD: (1,update)
+ CONTEXT:  PL/pgSQL function trigger_data() line 36 at RAISE
  DROP TRIGGER show_trigger_data_trig on trigger_test;
  DROP FUNCTION trigger_data();
  DROP TABLE trigger_test;
***************
*** 709,722 **** INSERT INTO trigger_test VALUES(1, 'foo', 'bar');
--- 815,834 ----
  INSERT INTO trigger_test VALUES(2, 'baz', 'quux');
  UPDATE trigger_test SET f3 = 'bar';
  NOTICE:  row 1 not changed
+ CONTEXT:  PL/pgSQL function mytrigger() line 4 at RAISE
  NOTICE:  row 2 changed
+ CONTEXT:  PL/pgSQL function mytrigger() line 6 at RAISE
  UPDATE trigger_test SET f3 = NULL;
  NOTICE:  row 1 changed
+ CONTEXT:  PL/pgSQL function mytrigger() line 6 at RAISE
  NOTICE:  row 2 changed
+ CONTEXT:  PL/pgSQL function mytrigger() line 6 at RAISE
  -- this demonstrates that the above isn't really working as desired:
  UPDATE trigger_test SET f3 = NULL;
  NOTICE:  row 1 changed
+ CONTEXT:  PL/pgSQL function mytrigger() line 6 at RAISE
  NOTICE:  row 2 changed
+ CONTEXT:  PL/pgSQL function mytrigger() line 6 at RAISE
  -- the right way when considering nulls is
  CREATE OR REPLACE FUNCTION mytrigger() RETURNS trigger LANGUAGE plpgsql as $$
  begin
***************
*** 729,741 **** begin
--- 841,859 ----
  end$$;
  UPDATE trigger_test SET f3 = 'bar';
  NOTICE:  row 1 changed
+ CONTEXT:  PL/pgSQL function mytrigger() line 4 at RAISE
  NOTICE:  row 2 changed
+ CONTEXT:  PL/pgSQL function mytrigger() line 4 at RAISE
  UPDATE trigger_test SET f3 = NULL;
  NOTICE:  row 1 changed
+ CONTEXT:  PL/pgSQL function mytrigger() line 4 at RAISE
  NOTICE:  row 2 changed
+ CONTEXT:  PL/pgSQL function mytrigger() line 4 at RAISE
  UPDATE trigger_test SET f3 = NULL;
  NOTICE:  row 1 not changed
+ CONTEXT:  PL/pgSQL function mytrigger() line 6 at RAISE
  NOTICE:  row 2 not changed
+ CONTEXT:  PL/pgSQL function mytrigger() line 6 at RAISE
  DROP TABLE trigger_test;
  DROP FUNCTION mytrigger();
  -- Test snapshot management in serializable transactions involving triggers
***************
*** 945,971 **** FOR EACH STATEMENT EXECUTE PROCEDURE view_trigger('after_view_del_stmt');
  -- Insert into view using trigger
  INSERT INTO main_view VALUES (20, 30);
  NOTICE:  main_view BEFORE INSERT STATEMENT (before_view_ins_stmt)
  NOTICE:  main_view INSTEAD OF INSERT ROW (instead_of_ins)
  NOTICE:  NEW: (20,30)
  NOTICE:  trigger_func(before_ins_stmt) called: action = INSERT, when = BEFORE, level = STATEMENT
! CONTEXT:  SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
  PL/pgSQL function view_trigger() line 17 at SQL statement
  NOTICE:  trigger_func(after_ins_stmt) called: action = INSERT, when = AFTER, level = STATEMENT
! CONTEXT:  SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
  PL/pgSQL function view_trigger() line 17 at SQL statement
  NOTICE:  main_view AFTER INSERT STATEMENT (after_view_ins_stmt)
  INSERT 0 1
  INSERT INTO main_view VALUES (21, 31) RETURNING a, b;
  NOTICE:  main_view BEFORE INSERT STATEMENT (before_view_ins_stmt)
  NOTICE:  main_view INSTEAD OF INSERT ROW (instead_of_ins)
  NOTICE:  NEW: (21,31)
  NOTICE:  trigger_func(before_ins_stmt) called: action = INSERT, when = BEFORE, level = STATEMENT
! CONTEXT:  SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
  PL/pgSQL function view_trigger() line 17 at SQL statement
  NOTICE:  trigger_func(after_ins_stmt) called: action = INSERT, when = AFTER, level = STATEMENT
! CONTEXT:  SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
  PL/pgSQL function view_trigger() line 17 at SQL statement
  NOTICE:  main_view AFTER INSERT STATEMENT (after_view_ins_stmt)
   a  | b  
  ----+----
   21 | 31
--- 1063,1101 ----
  -- Insert into view using trigger
  INSERT INTO main_view VALUES (20, 30);
  NOTICE:  main_view BEFORE INSERT STATEMENT (before_view_ins_stmt)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  NOTICE:  main_view INSTEAD OF INSERT ROW (instead_of_ins)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  NOTICE:  NEW: (20,30)
+ CONTEXT:  PL/pgSQL function view_trigger() line 16 at RAISE
  NOTICE:  trigger_func(before_ins_stmt) called: action = INSERT, when = BEFORE, level = STATEMENT
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
  PL/pgSQL function view_trigger() line 17 at SQL statement
  NOTICE:  trigger_func(after_ins_stmt) called: action = INSERT, when = AFTER, level = STATEMENT
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
  PL/pgSQL function view_trigger() line 17 at SQL statement
  NOTICE:  main_view AFTER INSERT STATEMENT (after_view_ins_stmt)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  INSERT 0 1
  INSERT INTO main_view VALUES (21, 31) RETURNING a, b;
  NOTICE:  main_view BEFORE INSERT STATEMENT (before_view_ins_stmt)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  NOTICE:  main_view INSTEAD OF INSERT ROW (instead_of_ins)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  NOTICE:  NEW: (21,31)
+ CONTEXT:  PL/pgSQL function view_trigger() line 16 at RAISE
  NOTICE:  trigger_func(before_ins_stmt) called: action = INSERT, when = BEFORE, level = STATEMENT
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
  PL/pgSQL function view_trigger() line 17 at SQL statement
  NOTICE:  trigger_func(after_ins_stmt) called: action = INSERT, when = AFTER, level = STATEMENT
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
  PL/pgSQL function view_trigger() line 17 at SQL statement
  NOTICE:  main_view AFTER INSERT STATEMENT (after_view_ins_stmt)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
   a  | b  
  ----+----
   21 | 31
***************
*** 975,1013 **** INSERT 0 1
  -- Table trigger will prevent updates
  UPDATE main_view SET b = 31 WHERE a = 20;
  NOTICE:  main_view BEFORE UPDATE STATEMENT (before_view_upd_stmt)
  NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
  NOTICE:  OLD: (20,30), NEW: (20,31)
  NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
! CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW
! CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
! CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
! CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
  UPDATE 0
  UPDATE main_view SET b = 32 WHERE a = 21 AND b = 31 RETURNING a, b;
  NOTICE:  main_view BEFORE UPDATE STATEMENT (before_view_upd_stmt)
  NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
  NOTICE:  OLD: (21,31), NEW: (21,32)
  NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
! CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW
! CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
! CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
! CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
   a | b 
  ---+---
  (0 rows)
--- 1105,1159 ----
  -- Table trigger will prevent updates
  UPDATE main_view SET b = 31 WHERE a = 20;
  NOTICE:  main_view BEFORE UPDATE STATEMENT (before_view_upd_stmt)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  NOTICE:  OLD: (20,30), NEW: (20,31)
+ CONTEXT:  PL/pgSQL function view_trigger() line 22 at RAISE
  NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  UPDATE 0
  UPDATE main_view SET b = 32 WHERE a = 21 AND b = 31 RETURNING a, b;
  NOTICE:  main_view BEFORE UPDATE STATEMENT (before_view_upd_stmt)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  NOTICE:  OLD: (21,31), NEW: (21,32)
+ CONTEXT:  PL/pgSQL function view_trigger() line 22 at RAISE
  NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
   a | b 
  ---+---
  (0 rows)
***************
*** 1018,1062 **** DROP TRIGGER before_upd_a_row_trig ON main_table;
  DROP TRIGGER
  UPDATE main_view SET b = 31 WHERE a = 20;
  NOTICE:  main_view BEFORE UPDATE STATEMENT (before_view_upd_stmt)
  NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
  NOTICE:  OLD: (20,30), NEW: (20,31)
  NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
! CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW
! CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW
! CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
! CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
! CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
  UPDATE 1
  UPDATE main_view SET b = 32 WHERE a = 21 AND b = 31 RETURNING a, b;
  NOTICE:  main_view BEFORE UPDATE STATEMENT (before_view_upd_stmt)
  NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
  NOTICE:  OLD: (21,31), NEW: (21,32)
  NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
! CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW
! CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW
! CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
! CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
! CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
   a  | b  
  ----+----
   21 | 32
--- 1164,1226 ----
  DROP TRIGGER
  UPDATE main_view SET b = 31 WHERE a = 20;
  NOTICE:  main_view BEFORE UPDATE STATEMENT (before_view_upd_stmt)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  NOTICE:  OLD: (20,30), NEW: (20,31)
+ CONTEXT:  PL/pgSQL function view_trigger() line 22 at RAISE
  NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  UPDATE 1
  UPDATE main_view SET b = 32 WHERE a = 21 AND b = 31 RETURNING a, b;
  NOTICE:  main_view BEFORE UPDATE STATEMENT (before_view_upd_stmt)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  NOTICE:  OLD: (21,31), NEW: (21,32)
+ CONTEXT:  PL/pgSQL function view_trigger() line 22 at RAISE
  NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
! CONTEXT:  PL/pgSQL function trigger_func() line 3 at RAISE
! SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
  PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
   a  | b  
  ----+----
   21 | 32
***************
*** 1066,1089 **** UPDATE 1
--- 1230,1267 ----
  -- Before and after stmt triggers should fire even when no rows are affected
  UPDATE main_view SET b = 0 WHERE false;
  NOTICE:  main_view BEFORE UPDATE STATEMENT (before_view_upd_stmt)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  UPDATE 0
  -- Delete from view using trigger
  DELETE FROM main_view WHERE a IN (20,21);
  NOTICE:  main_view BEFORE DELETE STATEMENT (before_view_del_stmt)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  NOTICE:  main_view INSTEAD OF DELETE ROW (instead_of_del)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  NOTICE:  OLD: (21,10)
+ CONTEXT:  PL/pgSQL function view_trigger() line 29 at RAISE
  NOTICE:  main_view INSTEAD OF DELETE ROW (instead_of_del)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  NOTICE:  OLD: (20,31)
+ CONTEXT:  PL/pgSQL function view_trigger() line 29 at RAISE
  NOTICE:  main_view INSTEAD OF DELETE ROW (instead_of_del)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  NOTICE:  OLD: (21,32)
+ CONTEXT:  PL/pgSQL function view_trigger() line 29 at RAISE
  NOTICE:  main_view AFTER DELETE STATEMENT (after_view_del_stmt)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  DELETE 3
  DELETE FROM main_view WHERE a = 31 RETURNING a, b;
  NOTICE:  main_view BEFORE DELETE STATEMENT (before_view_del_stmt)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  NOTICE:  main_view INSTEAD OF DELETE ROW (instead_of_del)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
  NOTICE:  OLD: (31,10)
+ CONTEXT:  PL/pgSQL function view_trigger() line 29 at RAISE
  NOTICE:  main_view AFTER DELETE STATEMENT (after_view_del_stmt)
+ CONTEXT:  PL/pgSQL function view_trigger() line 12 at RAISE
   a  | b  
  ----+----
   31 | 10
***************
*** 1267,1272 **** INSERT 0 1
--- 1445,1451 ----
  -- UPDATE .. RETURNING
  UPDATE city_view SET country_name = 'Japon' WHERE city_name = 'Tokyo'; -- error
  ERROR:  No such country: "Japon"
+ CONTEXT:  PL/pgSQL function city_update() line 9 at RAISE
  UPDATE city_view SET country_name = 'Japan' WHERE city_name = 'Takyo'; -- no match
  UPDATE 0
  UPDATE city_view SET country_name = 'Japan' WHERE city_name = 'Tokyo' RETURNING *; -- OK
***************
*** 1478,1504 **** select pg_trigger_depth();
  
  insert into depth_a values (1);
  NOTICE:  depth_a_tr: depth = 1
  NOTICE:  depth_b_tr: depth = 2
! CONTEXT:  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_c_tr: depth = 3
! CONTEXT:  SQL statement "insert into depth_c values (1)"
  PL/pgSQL function depth_b_tf() line 5 at EXECUTE statement
  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  SQLSTATE = U9999: depth = 2
! CONTEXT:  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_b_tr: depth = 2
! CONTEXT:  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_c_tr: depth = 3
! CONTEXT:  SQL statement "insert into depth_c values (1)"
  PL/pgSQL function depth_b_tf() line 12 at EXECUTE statement
  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
  ERROR:  U9999
! CONTEXT:  SQL statement "insert into depth_c values (1)"
  PL/pgSQL function depth_b_tf() line 12 at EXECUTE statement
  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
--- 1657,1690 ----
  
  insert into depth_a values (1);
  NOTICE:  depth_a_tr: depth = 1
+ CONTEXT:  PL/pgSQL function depth_a_tf() line 3 at RAISE
  NOTICE:  depth_b_tr: depth = 2
! CONTEXT:  PL/pgSQL function depth_b_tf() line 3 at RAISE
! SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_c_tr: depth = 3
! CONTEXT:  PL/pgSQL function depth_c_tf() line 3 at RAISE
! SQL statement "insert into depth_c values (1)"
  PL/pgSQL function depth_b_tf() line 5 at EXECUTE statement
  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  SQLSTATE = U9999: depth = 2
! CONTEXT:  PL/pgSQL function depth_b_tf() line 8 at RAISE
! SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_b_tr: depth = 2
! CONTEXT:  PL/pgSQL function depth_b_tf() line 10 at RAISE
! SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_c_tr: depth = 3
! CONTEXT:  PL/pgSQL function depth_c_tf() line 3 at RAISE
! SQL statement "insert into depth_c values (1)"
  PL/pgSQL function depth_b_tf() line 12 at EXECUTE statement
  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
  ERROR:  U9999
! CONTEXT:  PL/pgSQL function depth_c_tf() line 5 at RAISE
! SQL statement "insert into depth_c values (1)"
  PL/pgSQL function depth_b_tf() line 12 at EXECUTE statement
  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
***************
*** 1510,1532 **** select pg_trigger_depth();
  
  insert into depth_a values (2);
  NOTICE:  depth_a_tr: depth = 1
  NOTICE:  depth_b_tr: depth = 2
! CONTEXT:  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_c_tr: depth = 3
! CONTEXT:  SQL statement "insert into depth_c values (2)"
  PL/pgSQL function depth_b_tf() line 5 at EXECUTE statement
  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_c_tr: depth = 3
! CONTEXT:  SQL statement "insert into depth_c values (2)"
  PL/pgSQL function depth_b_tf() line 5 at EXECUTE statement
  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_b_tr: depth = 2
! CONTEXT:  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_a_tr: depth = 1
  select pg_trigger_depth();
   pg_trigger_depth 
  ------------------
--- 1696,1724 ----
  
  insert into depth_a values (2);
  NOTICE:  depth_a_tr: depth = 1
+ CONTEXT:  PL/pgSQL function depth_a_tf() line 3 at RAISE
  NOTICE:  depth_b_tr: depth = 2
! CONTEXT:  PL/pgSQL function depth_b_tf() line 3 at RAISE
! SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_c_tr: depth = 3
! CONTEXT:  PL/pgSQL function depth_c_tf() line 3 at RAISE
! SQL statement "insert into depth_c values (2)"
  PL/pgSQL function depth_b_tf() line 5 at EXECUTE statement
  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_c_tr: depth = 3
! CONTEXT:  PL/pgSQL function depth_c_tf() line 7 at RAISE
! SQL statement "insert into depth_c values (2)"
  PL/pgSQL function depth_b_tf() line 5 at EXECUTE statement
  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_b_tr: depth = 2
! CONTEXT:  PL/pgSQL function depth_b_tf() line 10 at RAISE
! SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_a_tr: depth = 1
+ CONTEXT:  PL/pgSQL function depth_a_tf() line 5 at RAISE
  select pg_trigger_depth();
   pg_trigger_depth 
  ------------------
*** a/src/test/regress/expected/with.out
--- b/src/test/regress/expected/with.out
***************
*** 1903,1910 **** WITH t AS (
--- 1903,1913 ----
  )
  SELECT * FROM t;
  NOTICE:  y_trigger: a = 21
+ CONTEXT:  PL/pgSQL function y_trigger() line 3 at RAISE
  NOTICE:  y_trigger: a = 22
+ CONTEXT:  PL/pgSQL function y_trigger() line 3 at RAISE
  NOTICE:  y_trigger: a = 23
+ CONTEXT:  PL/pgSQL function y_trigger() line 3 at RAISE
   a  
  ----
   21
***************
*** 1943,1950 **** WITH t AS (
--- 1946,1956 ----
  )
  SELECT * FROM t LIMIT 1;
  NOTICE:  y_trigger: a = 31
+ CONTEXT:  PL/pgSQL function y_trigger() line 3 at RAISE
  NOTICE:  y_trigger: a = 32
+ CONTEXT:  PL/pgSQL function y_trigger() line 3 at RAISE
  NOTICE:  y_trigger: a = 33
+ CONTEXT:  PL/pgSQL function y_trigger() line 3 at RAISE
   a  
  ----
   31
***************
*** 1990,1995 **** WITH t AS (
--- 1996,2002 ----
  )
  SELECT * FROM t;
  NOTICE:  y_trigger
+ CONTEXT:  PL/pgSQL function y_trigger() line 3 at RAISE
   a  
  ----
   41
*** a/src/test/regress/expected/xml_1.out
--- b/src/test/regress/expected/xml_1.out
***************
*** 773,778 **** HINT:  You need to rebuild PostgreSQL using --with-libxml.
--- 773,779 ----
  \set VERBOSITY terse
  SELECT xpath('/*', '<invalidns xmlns=''&lt;''/>');
  ERROR:  unsupported XML feature at character 20
+ CONTEXT:  20
  \set VERBOSITY default
  -- Again, the XML isn't well-formed for namespace purposes
  SELECT xpath('/*', '<nosuchprefix:tag/>');
#26Peter Eisentraut
peter_e@gmx.net
In reply to: Marko Tiikkaja (#25)
Re: PL/pgSQL, RAISE and error context

On Sun, 2013-09-15 at 14:28 +0200, Marko Tiikkaja wrote:

On 15/09/2013 13:58, I wrote:

Hmm. I just noticed there's something weird going on in the select_view
test. I'm investigating this currently.

Seems that there's some magic going on and I overwrote the expected
results of the wrong file. However, I can't figure out how one is
supposed to be getting the output of expected/select_views.out, nor do I
find this documented anywhere (I know xml has a similar thing so I tried
grepping around for XML, to no avail).

Here's an updated patch, but I think expected/select_views.out is still
broken.

You patch still fails the plperl regression tests.

I don't see a failure with select_views. Your issue might be that you
updated expected/select_views_1.out but not expected/select_views.out.
This documentation might help:
http://www.postgresql.org/docs/devel/static/regress-variant.html

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#27Jeevan Chalke
jeevan.chalke@enterprisedb.com
In reply to: Marko Tiikkaja (#25)
Re: PL/pgSQL, RAISE and error context

Hi Marko,

I have reviewed this patch.

1. Patch applies well.
2. make and make install is fine
3. make check is fine too.

But as Peter pointed out plperl regression tests are failing.

I just did grep on .sql files and found following files which has RAISE
statement into it. These files too need expected output changes. Please run
these testcases to get diffs.

./src/pl/plperl/sql/plperl_elog.sql
./src/pl/plpython/sql/plpython_error.sql
./src/pl/plpython/sql/plpython_setof.sql
./src/pl/plpython/sql/plpython_quote.sql
./contrib/sepgsql/sql/label.sql
./contrib/sepgsql/sql/ddl.sql

Code changes looks fine to me.

Thanks

--
Jeevan B Chalke
Principal Software Engineer, Product Development
EnterpriseDB Corporation

#28Marko Tiikkaja
marko@joh.to
In reply to: Marko Tiikkaja (#18)
Re: PL/pgSQL, RAISE and error context

Hello,

I just heard that there's going to be a fifth CF for 9.5 so I'm trying
to gather all the patches I'd like to see in 9.5..

On 8/23/13 10:36 AM, I wrote:

My opinion at this very moment is that we should leave the the DEFAULT
verbosity alone and add a new one (call it COMPACT or such) with the
suppressed context for non-ERRORs.

I wonder if a better option would be to add a GUC to control this from
the server side. plpgsql.suppress_simple_error_context or such,
defaulting to false to maintain full backwards compatibility. That
could be set to true for development installations and for client
programs which only care about having all information available, rather
than readability or aesthetics.

Or is that a stupid idea? I just think hacking libpq for something like
this is a huge overkill.

.marko

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#29Pavel Stehule
pavel.stehule@gmail.com
In reply to: Marko Tiikkaja (#28)
Re: PL/pgSQL, RAISE and error context

2015-01-22 12:37 GMT+01:00 Marko Tiikkaja <marko@joh.to>:

Hello,

I just heard that there's going to be a fifth CF for 9.5 so I'm trying to
gather all the patches I'd like to see in 9.5..

On 8/23/13 10:36 AM, I wrote:

My opinion at this very moment is that we should leave the the DEFAULT
verbosity alone and add a new one (call it COMPACT or such) with the
suppressed context for non-ERRORs.

I wonder if a better option would be to add a GUC to control this from the
server side. plpgsql.suppress_simple_error_context or such, defaulting
to false to maintain full backwards compatibility. That could be set to
true for development installations and for client programs which only care
about having all information available, rather than readability or
aesthetics.

Or is that a stupid idea? I just think hacking libpq for something like
this is a huge overkill.

I don't think so only plpgsql solution is satisfactory idea. There are
some mix plpgsql / plperl ... application - and it isn't possible to remove
error context from only one language.

Regards

Pavel

Show quoted text

.marko

#30Marko Tiikkaja
marko@joh.to
In reply to: Pavel Stehule (#29)
Re: PL/pgSQL, RAISE and error context

On 1/22/15 6:03 PM, Pavel Stehule wrote:

2015-01-22 12:37 GMT+01:00 Marko Tiikkaja <marko@joh.to>:

Or is that a stupid idea? I just think hacking libpq for something like
this is a huge overkill.

I don't think so only plpgsql solution is satisfactory idea. There are
some mix plpgsql / plperl ... application - and it isn't possible to remove
error context from only one language.

Yeah, not in libpq it isn't. Thing is, PL/PgSQL already is the
exception here, since it's the only language which does this error
message suppression. So if people did think this suppression was a good
idea, only the people using PL/PgSQL were vocal enough to get the
behavior changed. I'm not looking to change that.

I can see where it's a lot nicer not to have the context visible for
people who only care about the contents of the message, but the way it's
done in PL/PgSQL right now is just not good enough. On the other hand,
the backwards compatibility breakage of doing this in libpq is quite
extensive. The most simple option seems to be to just allow a GUC to
change PL/PgSQL's behavior to match what all other PLs are doing.

.marko

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#31Pavel Stehule
pavel.stehule@gmail.com
In reply to: Marko Tiikkaja (#30)
Re: PL/pgSQL, RAISE and error context

2015-01-26 13:02 GMT+01:00 Marko Tiikkaja <marko@joh.to>:

On 1/22/15 6:03 PM, Pavel Stehule wrote:

2015-01-22 12:37 GMT+01:00 Marko Tiikkaja <marko@joh.to>:

Or is that a stupid idea? I just think hacking libpq for something like
this is a huge overkill.

I don't think so only plpgsql solution is satisfactory idea. There are
some mix plpgsql / plperl ... application - and it isn't possible to
remove
error context from only one language.

Yeah, not in libpq it isn't. Thing is, PL/PgSQL already is the exception
here, since it's the only language which does this error message
suppression. So if people did think this suppression was a good idea, only
the people using PL/PgSQL were vocal enough to get the behavior changed.
I'm not looking to change that.

I can see where it's a lot nicer not to have the context visible for
people who only care about the contents of the message, but the way it's
done in PL/PgSQL right now is just not good enough. On the other hand, the
backwards compatibility breakage of doing this in libpq is quite
extensive. The most simple option seems to be to just allow a GUC to
change PL/PgSQL's behavior to match what all other PLs are doing.

libpq was changed more time - there is still a open task about a protocol
change.

I afraid about some unexpected side effects of your proposal if somebody
mix languages - these side effects should not be critical - but on second
hand current behave is not critical too - we can wait.

Show quoted text

.marko

#32Marko Tiikkaja
marko@joh.to
In reply to: Pavel Stehule (#31)
Re: PL/pgSQL, RAISE and error context

On 1/26/15 1:14 PM, Pavel Stehule wrote:

2015-01-26 13:02 GMT+01:00 Marko Tiikkaja <marko@joh.to>:

I can see where it's a lot nicer not to have the context visible for
people who only care about the contents of the message, but the way it's
done in PL/PgSQL right now is just not good enough. On the other hand, the
backwards compatibility breakage of doing this in libpq is quite
extensive. The most simple option seems to be to just allow a GUC to
change PL/PgSQL's behavior to match what all other PLs are doing.

libpq was changed more time - there is still a open task about a protocol
change.

I afraid about some unexpected side effects of your proposal if somebody
mix languages - these side effects should not be critical

I have no idea what you're talking about. What kind of side effects?

- but on second
hand current behave is not critical too - we can wait.

I think the current behavior is almost unacceptable. It makes debugging
in some cases really, really difficult.

.marko

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#33Pavel Stehule
pavel.stehule@gmail.com
In reply to: Marko Tiikkaja (#32)
Re: PL/pgSQL, RAISE and error context

2015-01-26 13:39 GMT+01:00 Marko Tiikkaja <marko@joh.to>:

On 1/26/15 1:14 PM, Pavel Stehule wrote:

2015-01-26 13:02 GMT+01:00 Marko Tiikkaja <marko@joh.to>:

I can see where it's a lot nicer not to have the context visible for
people who only care about the contents of the message, but the way it's
done in PL/PgSQL right now is just not good enough. On the other hand,
the
backwards compatibility breakage of doing this in libpq is quite
extensive. The most simple option seems to be to just allow a GUC to
change PL/PgSQL's behavior to match what all other PLs are doing.

libpq was changed more time - there is still a open task about a protocol
change.

I afraid about some unexpected side effects of your proposal if somebody
mix languages - these side effects should not be critical

I have no idea what you're talking about. What kind of side effects?

what will be a error context if plpgsql calls a plperl function that raises
a exception
what will be a error context if plperl calls a plpgsql functions that
raises a exception

- but on second

hand current behave is not critical too - we can wait.

I think the current behavior is almost unacceptable. It makes debugging
in some cases really, really difficult.

if it is necessary, then we can modify libpq

Regards

Pavel

Show quoted text

.marko

#34Marko Tiikkaja
marko@joh.to
In reply to: Pavel Stehule (#33)
Re: PL/pgSQL, RAISE and error context

On 1/26/15 1:44 PM, Pavel Stehule wrote:

2015-01-26 13:39 GMT+01:00 Marko Tiikkaja <marko@joh.to>:

On 1/26/15 1:14 PM, Pavel Stehule wrote:

I afraid about some unexpected side effects of your proposal if somebody
mix languages - these side effects should not be critical

I have no idea what you're talking about. What kind of side effects?

what will be a error context if plpgsql calls a plperl function that raises
a exception
what will be a error context if plperl calls a plpgsql functions that
raises a exception

I fail to see the point. How would that be different from what happens
today? Remember, PL/PgSQL only suppresses the *topmost* stack frame,
and only when using RAISE from within a PL/PgSQL function.

.m

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#35Pavel Stehule
pavel.stehule@gmail.com
In reply to: Marko Tiikkaja (#34)
Re: PL/pgSQL, RAISE and error context

2015-01-26 14:02 GMT+01:00 Marko Tiikkaja <marko@joh.to>:

On 1/26/15 1:44 PM, Pavel Stehule wrote:

2015-01-26 13:39 GMT+01:00 Marko Tiikkaja <marko@joh.to>:

On 1/26/15 1:14 PM, Pavel Stehule wrote:

I afraid about some unexpected side effects of your proposal if somebody
mix languages - these side effects should not be critical

I have no idea what you're talking about. What kind of side effects?

what will be a error context if plpgsql calls a plperl function that
raises
a exception
what will be a error context if plperl calls a plpgsql functions that
raises a exception

I fail to see the point. How would that be different from what happens
today? Remember, PL/PgSQL only suppresses the *topmost* stack frame, and
only when using RAISE from within a PL/PgSQL function.

I had to though little bit more - and I am thinking so we should to return
back to start of this thread.

Current state:

1. RAISE in plpgsql doesn't show a context - what we want in RAISE NOTICE
and we don't want in RAISE EXCEPTION

I am thinking, so solution

/* if we are doing RAISE, don't report its location */
if (estate->err_text == raise_skip_msg)
return;

is too simple, and this part should be fixed. This change can be done by on
plpgsql or libpq side. This is bug, and it should be fixed.

2. Personally I prefer a little bit conceptual solution, that needs a libpq
change because I wish some mode between terse and verbose mode - I would
not to see context for NOTICEs, but I would to see context for errors. This
request is generic - independent on used PL. @2 is my feature request and
it is possible independent on @1.

3. your proposal plpgsql.suppress_simple_error_context fix the @2 partially
- just I prefer a generic solution that will be available for all PL -
exception processing is same for all PL, so filtering should be common too.

Regards

Pavel

Show quoted text

.m

#36Tom Lane
tgl@sss.pgh.pa.us
In reply to: Pavel Stehule (#35)
Re: PL/pgSQL, RAISE and error context

Pavel Stehule <pavel.stehule@gmail.com> writes:

2015-01-26 14:02 GMT+01:00 Marko Tiikkaja <marko@joh.to>:
I am thinking, so solution

/* if we are doing RAISE, don't report its location */
if (estate->err_text == raise_skip_msg)
return;

is too simple, and this part should be fixed. This change can be done by on
plpgsql or libpq side. This is bug, and it should be fixed.

Doing this in libpq is utterly insane. It has not got sufficient context
to do anything intelligent. The fact that it's not intelligent is exposed
by the regression test changes that the proposed patch causes, most of
which do not look like improvements.

Another problem is that past requests to change this behavior have
generally been to the effect that people wanted *more* context suppressed
not less, ie they didn't want any CONTEXT lines at all on certain
messages. So the proposed patch seems to me to be going in exactly the
wrong direction.

The design I thought had been agreed on was to add some new option to
plpgsql's RAISE command which would cause suppression of all CONTEXT lines
not just the most closely nested one. You could argue about whether the
behavior needs to be 100% backwards compatible or not --- if so, perhaps
it could be a three-way option all, none, or one line, defaulting to the
last for backwards compatibility.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#37Pavel Stehule
pavel.stehule@gmail.com
In reply to: Tom Lane (#36)
Re: PL/pgSQL, RAISE and error context

2015-01-26 16:14 GMT+01:00 Tom Lane <tgl@sss.pgh.pa.us>:

Pavel Stehule <pavel.stehule@gmail.com> writes:

2015-01-26 14:02 GMT+01:00 Marko Tiikkaja <marko@joh.to>:
I am thinking, so solution

/* if we are doing RAISE, don't report its location */
if (estate->err_text == raise_skip_msg)
return;

is too simple, and this part should be fixed. This change can be done by

on

plpgsql or libpq side. This is bug, and it should be fixed.

Doing this in libpq is utterly insane. It has not got sufficient context
to do anything intelligent. The fact that it's not intelligent is exposed
by the regression test changes that the proposed patch causes, most of
which do not look like improvements.

I don't understand. There can be a overhead due useless transformation some
data to client side. But all what it need - errcontext and errlevel is
possible.

Another problem is that past requests to change this behavior have
generally been to the effect that people wanted *more* context suppressed
not less, ie they didn't want any CONTEXT lines at all on certain
messages. So the proposed patch seems to me to be going in exactly the
wrong direction.

The design I thought had been agreed on was to add some new option to
plpgsql's RAISE command which would cause suppression of all CONTEXT lines
not just the most closely nested one. You could argue about whether the
behavior needs to be 100% backwards compatible or not --- if so, perhaps
it could be a three-way option all, none, or one line, defaulting to the
last for backwards compatibility.

I see a problem what should be default behave. When I raise NOTICE, then I
don't need (don't would) to see CONTEXT lines, When I raise EXCEPTION, then
I usually would to see CONTEXT lines.

Cannot be solution?

estate->err_text = stmt->elog_level == ERROR ? estate->err_text :
raise_skip_msg ;

Regards

Pavel

Show quoted text

regards, tom lane

#38Jim Nasby
Jim.Nasby@BlueTreble.com
In reply to: Pavel Stehule (#37)
Re: PL/pgSQL, RAISE and error context

On 1/26/15 9:46 AM, Pavel Stehule wrote:

The design I thought had been agreed on was to add some new option to
plpgsql's RAISE command which would cause suppression of all CONTEXT lines
not just the most closely nested one. You could argue about whether the
behavior needs to be 100% backwards compatible or not --- if so, perhaps
it could be a three-way option all, none, or one line, defaulting to the
last for backwards compatibility.

I see a problem what should be default behave. When I raise NOTICE, then I don't need (don't would) to see CONTEXT lines, When I raise EXCEPTION, then I usually would to see CONTEXT lines.

FWIW, that's the case I almost always run into: I turn on some debugging which means I know where the RAISE is coming from, but now I'm flooded with CONTEXT lines. You could do that with an option to RAISE, but that seems like a lot of extra coding work for little gain. Perhaps it'd be worth creating client_min_context and log_min_context GUCs...

Another option that I think would work well is that you only provide context for the first call within a "block" of code. For plpgsql that would be a function, but maybe it'd be better to just do this per-subtransaction.

I do agree that this needs to work across the board, not just for plpgsql.
--
Jim Nasby, Data Architect, Blue Treble Consulting
Data in Trouble? Get it in Treble! http://BlueTreble.com

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#39Pavel Stehule
pavel.stehule@gmail.com
In reply to: Pavel Stehule (#37)
Re: PL/pgSQL, RAISE and error context

2015-01-26 16:46 GMT+01:00 Pavel Stehule <pavel.stehule@gmail.com>:

2015-01-26 16:14 GMT+01:00 Tom Lane <tgl@sss.pgh.pa.us>:

Pavel Stehule <pavel.stehule@gmail.com> writes:

2015-01-26 14:02 GMT+01:00 Marko Tiikkaja <marko@joh.to>:
I am thinking, so solution

/* if we are doing RAISE, don't report its location */
if (estate->err_text == raise_skip_msg)
return;

is too simple, and this part should be fixed. This change can be done

by on

plpgsql or libpq side. This is bug, and it should be fixed.

Doing this in libpq is utterly insane. It has not got sufficient context
to do anything intelligent. The fact that it's not intelligent is exposed
by the regression test changes that the proposed patch causes, most of
which do not look like improvements.

I don't understand. There can be a overhead due useless transformation
some data to client side. But all what it need - errcontext and errlevel is
possible.

Another problem is that past requests to change this behavior have
generally been to the effect that people wanted *more* context suppressed
not less, ie they didn't want any CONTEXT lines at all on certain
messages. So the proposed patch seems to me to be going in exactly the
wrong direction.

The design I thought had been agreed on was to add some new option to
plpgsql's RAISE command which would cause suppression of all CONTEXT lines
not just the most closely nested one. You could argue about whether the
behavior needs to be 100% backwards compatible or not --- if so, perhaps
it could be a three-way option all, none, or one line, defaulting to the
last for backwards compatibility.

I see a problem what should be default behave. When I raise NOTICE, then
I don't need (don't would) to see CONTEXT lines, When I raise EXCEPTION,
then I usually would to see CONTEXT lines.

Cannot be solution?

I would to wakeup this thread.

estate->err_text = stmt->elog_level == ERROR ? estate->err_text :
raise_skip_msg ;

Can we do this simple change? It will produce a stackinfo for exceptions
and it will not to make mad developers by lot of useless content.

Regards

Pavel

Show quoted text

Regards

Pavel

regards, tom lane

#40Marko Tiikkaja
marko@joh.to
In reply to: Pavel Stehule (#39)
Re: PL/pgSQL, RAISE and error context

On 4/2/15 9:37 AM, Pavel Stehule wrote:

estate->err_text = stmt->elog_level == ERROR ? estate->err_text :
raise_skip_msg ;

Can we do this simple change? It will produce a stackinfo for exceptions
and it will not to make mad developers by lot of useless content.

I'm not sure everyone agrees with this to be honest, myself included.

I think the best way to do this would be to have an option for RAISE to
suppress the context *regardless of nesting depth*, but show the full
context by default for ERRORs. For NOTICEs and WARNINGs I don't care
much what the default will be; perhaps just full backwards compatibility
could work there.

.m

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#41Pavel Stehule
pavel.stehule@gmail.com
In reply to: Marko Tiikkaja (#40)
Re: PL/pgSQL, RAISE and error context

2015-04-23 9:53 GMT+02:00 Marko Tiikkaja <marko@joh.to>:

On 4/2/15 9:37 AM, Pavel Stehule wrote:

estate->err_text = stmt->elog_level == ERROR ? estate->err_text :

raise_skip_msg ;

Can we do this simple change? It will produce a stackinfo for exceptions
and it will not to make mad developers by lot of useless content.

I'm not sure everyone agrees with this to be honest, myself included.

I think the best way to do this would be to have an option for RAISE to
suppress the context *regardless of nesting depth*, but show the full
context by default for ERRORs. For NOTICEs and WARNINGs I don't care much
what the default will be; perhaps just full backwards compatibility could
work there.

I don't see a contradiction. There is clean agreement, so ERROR level
should to show the context. NOTICE and WARNINGs doesn't need it - and there
is a backward compatibility and usability reasons don't do it.

I am not to against to any special option to RAISE statement. Have you some
idea?

What about a enhancing a USING clause?

example:

RAISE NOTICE USING message = '', with_context = true
RAISE EXCEPTION USING message = '', with_context = false

Regards

Pavel

Show quoted text

.m

#42Robert Haas
robertmhaas@gmail.com
In reply to: Pavel Stehule (#41)
Re: PL/pgSQL, RAISE and error context

On Thu, Apr 23, 2015 at 4:56 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

I don't see a contradiction. There is clean agreement, so ERROR level should
to show the context. NOTICE and WARNINGs doesn't need it - and there is a
backward compatibility and usability reasons don't do it.

Whether notices and warnings need it is a matter of opinion. I don't
think your idea is bad, and it might be a good rule of thumb in many
cases, but I slightly prefer Marko's approach of adding a new option.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#43Pavel Stehule
pavel.stehule@gmail.com
In reply to: Robert Haas (#42)
Re: PL/pgSQL, RAISE and error context

2015-04-23 15:47 GMT+02:00 Robert Haas <robertmhaas@gmail.com>:

On Thu, Apr 23, 2015 at 4:56 AM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

I don't see a contradiction. There is clean agreement, so ERROR level

should

to show the context. NOTICE and WARNINGs doesn't need it - and there is a
backward compatibility and usability reasons don't do it.

Whether notices and warnings need it is a matter of opinion. I don't
think your idea is bad, and it might be a good rule of thumb in many
cases, but I slightly prefer Marko's approach of adding a new option.

I am not sure if I understand to you.

please, can you write more about your idea?

Show quoted text

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#44Robert Haas
robertmhaas@gmail.com
In reply to: Pavel Stehule (#43)
Re: PL/pgSQL, RAISE and error context

On Thu, Apr 23, 2015 at 9:55 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

On Thu, Apr 23, 2015 at 4:56 AM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

I don't see a contradiction. There is clean agreement, so ERROR level
should
to show the context. NOTICE and WARNINGs doesn't need it - and there is
a
backward compatibility and usability reasons don't do it.

Whether notices and warnings need it is a matter of opinion. I don't
think your idea is bad, and it might be a good rule of thumb in many
cases, but I slightly prefer Marko's approach of adding a new option.

I am not sure if I understand to you.

please, can you write more about your idea?

Your idea, as I understand it, is that for logs at severity levels
lower than ERROR, we can always emit the context, because it's not
necessary. But I'm not sure that's right: some people might find that
context helpful. If, as Marko proposes, we add an explicit option,
then everyone can choose the behavior that is right for them.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#45Pavel Stehule
pavel.stehule@gmail.com
In reply to: Robert Haas (#44)
Re: PL/pgSQL, RAISE and error context

2015-04-23 16:12 GMT+02:00 Robert Haas <robertmhaas@gmail.com>:

On Thu, Apr 23, 2015 at 9:55 AM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

On Thu, Apr 23, 2015 at 4:56 AM, Pavel Stehule <pavel.stehule@gmail.com

wrote:

I don't see a contradiction. There is clean agreement, so ERROR level
should
to show the context. NOTICE and WARNINGs doesn't need it - and there

is

a
backward compatibility and usability reasons don't do it.

Whether notices and warnings need it is a matter of opinion. I don't
think your idea is bad, and it might be a good rule of thumb in many
cases, but I slightly prefer Marko's approach of adding a new option.

I am not sure if I understand to you.

please, can you write more about your idea?

Your idea, as I understand it, is that for logs at severity levels
lower than ERROR, we can always emit the context, because it's not
necessary. But I'm not sure that's right: some people might find that
context helpful. If, as Marko proposes, we add an explicit option,
then everyone can choose the behavior that is right for them.

I am not sure, if explained it well. I would to emit context for ERROR and
higher by default. And I would not to emit context for any less than ERROR
by default (I am not sure about WARNING level).

But it can be changed by some option in RAISE statement like Marko proposes
- possible to change by GUC globally, because it doesn't change a behave of
application.

For current behave I have a problem with ERROR level in plpgsql where the
context is missing now. On second hand I am thinking so current behave is
ok for NOTICE level .

I am not against to any new option in RAISE statement.

If there is some collision between me and Marko, then it is in opinion what
have to be default behave for NOTICE level. I strongly prefer don't show
context there. But I can accept some global switch too.

Regards

Pavel

Show quoted text

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#46Joel Jacobson
joel@trustly.com
In reply to: Pavel Stehule (#45)
Re: PL/pgSQL, RAISE and error context

Entering the discussion because this is a huge pain for me in my daily
work as well.

This is not a reply to any specific post in this thread, but my first
message in the thread.

I see a great value in providing both a GUC and a new RAISE syntax.
The different benefits of the two are maybe obvious, but perhaps worth
pointing out:
GUC: Good because you don't have to change any existing code.
RAISE syntax: Good because you can control exactly what message should
be emitted or not be emitted at that line of code.

I think preserving backwards compatibility is very important.
Not changing the default is not a problem for me, as long as it can be
overridden.

Whatever the default behaviour is, I think the need expressed by all
users in this thread boils down to any of these two sentences:

"I want CONTEXT to be (DISPLAYED|SUPPRESSED) for (ALL|ONLY THIS LINE)
RAISE (NOTICE|WARNING|ERROR)"
OR
"I don't want to change the default current behaviour of CONTEXT"

So we basically need a boolean setting value, where:
NULL means the default behaviour
TRUE means DISPLAY CONTEXT
FALSE means SUPPRESS CONTEXT

And the (ALL|ONLY THIS) part translates into using,
* a GUC to change behaviour for ALL lines of code,
* or using the RAISE syntax to change the behaviour of ONLY THIS line of code.

And then we have the different message levels, for which CONTEXT is
sometimes desirable in some situations:
* The RAISE syntax allows controlling any message level in a natural
way, as the message level is part of the syntax.
* Allowing the same control using GUC would mean the message level
would need to be part of the GUC key name, which means either add
multiple GUCs, one for each message level, or only allow controlling
the most important one and ignore the possibly need to control the
other message levels.

If it would be possible to somehow combine multiple message levels in
the same GUC, that would solve the latter problem.

We already have comma separated values for many GUCs, so maybe we
could use that approach here as well.

It looks like adding these two GUCs would meet the demands of all users:

suppress_context_messages (enum)
display_context_messages (enum)

This would allow doing something crazy as:

suppress_context_messages = warning,error
display_context_messages = notice

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#47Pavel Stehule
pavel.stehule@gmail.com
In reply to: Joel Jacobson (#46)
Re: PL/pgSQL, RAISE and error context

2015-04-24 12:11 GMT+02:00 Joel Jacobson <joel@trustly.com>:

Entering the discussion because this is a huge pain for me in my daily
work as well.

This is not a reply to any specific post in this thread, but my first
message in the thread.

I see a great value in providing both a GUC and a new RAISE syntax.
The different benefits of the two are maybe obvious, but perhaps worth
pointing out:
GUC: Good because you don't have to change any existing code.
RAISE syntax: Good because you can control exactly what message should
be emitted or not be emitted at that line of code.

I think preserving backwards compatibility is very important.
Not changing the default is not a problem for me, as long as it can be
overridden.

Whatever the default behaviour is, I think the need expressed by all
users in this thread boils down to any of these two sentences:

"I want CONTEXT to be (DISPLAYED|SUPPRESSED) for (ALL|ONLY THIS LINE)
RAISE (NOTICE|WARNING|ERROR)"
OR
"I don't want to change the default current behaviour of CONTEXT"

So we basically need a boolean setting value, where:
NULL means the default behaviour
TRUE means DISPLAY CONTEXT
FALSE means SUPPRESS CONTEXT

And the (ALL|ONLY THIS) part translates into using,
* a GUC to change behaviour for ALL lines of code,
* or using the RAISE syntax to change the behaviour of ONLY THIS line of
code.

And then we have the different message levels, for which CONTEXT is
sometimes desirable in some situations:
* The RAISE syntax allows controlling any message level in a natural
way, as the message level is part of the syntax.
* Allowing the same control using GUC would mean the message level
would need to be part of the GUC key name, which means either add
multiple GUCs, one for each message level, or only allow controlling
the most important one and ignore the possibly need to control the
other message levels.

If it would be possible to somehow combine multiple message levels in
the same GUC, that would solve the latter problem.

We already have comma separated values for many GUCs, so maybe we
could use that approach here as well.

It looks like adding these two GUCs would meet the demands of all users:

suppress_context_messages (enum)
display_context_messages (enum)

<<<<<

This proposal looks very practical - it can be very good start point - and
it doesn't block any next discuss about enhancing RAISE statement, what I
would to have too (bat can be separate issue). I like it.

Regards

Pavel

Show quoted text

This would allow doing something crazy as:

suppress_context_messages = warning,error
display_context_messages = notice

#48Robert Haas
robertmhaas@gmail.com
In reply to: Joel Jacobson (#46)
Re: PL/pgSQL, RAISE and error context

On Fri, Apr 24, 2015 at 6:11 AM, Joel Jacobson <joel@trustly.com> wrote:

Entering the discussion because this is a huge pain for me in my daily
work as well.

This is not a reply to any specific post in this thread, but my first
message in the thread.

I see a great value in providing both a GUC and a new RAISE syntax.
The different benefits of the two are maybe obvious, but perhaps worth
pointing out:
GUC: Good because you don't have to change any existing code.
RAISE syntax: Good because you can control exactly what message should
be emitted or not be emitted at that line of code.

I think preserving backwards compatibility is very important.
Not changing the default is not a problem for me, as long as it can be
overridden.

Whatever the default behaviour is, I think the need expressed by all
users in this thread boils down to any of these two sentences:

"I want CONTEXT to be (DISPLAYED|SUPPRESSED) for (ALL|ONLY THIS LINE)
RAISE (NOTICE|WARNING|ERROR)"
OR
"I don't want to change the default current behaviour of CONTEXT"

So we basically need a boolean setting value, where:
NULL means the default behaviour
TRUE means DISPLAY CONTEXT
FALSE means SUPPRESS CONTEXT

And the (ALL|ONLY THIS) part translates into using,
* a GUC to change behaviour for ALL lines of code,
* or using the RAISE syntax to change the behaviour of ONLY THIS line of code.

And then we have the different message levels, for which CONTEXT is
sometimes desirable in some situations:
* The RAISE syntax allows controlling any message level in a natural
way, as the message level is part of the syntax.
* Allowing the same control using GUC would mean the message level
would need to be part of the GUC key name, which means either add
multiple GUCs, one for each message level, or only allow controlling
the most important one and ignore the possibly need to control the
other message levels.

If it would be possible to somehow combine multiple message levels in
the same GUC, that would solve the latter problem.

We already have comma separated values for many GUCs, so maybe we
could use that approach here as well.

It looks like adding these two GUCs would meet the demands of all users:

suppress_context_messages (enum)
display_context_messages (enum)

This would allow doing something crazy as:

suppress_context_messages = warning,error
display_context_messages = notice

This is a very flexible proposal, but it's a tremendous amount of
machinery for what's really a very minor issue. If we added two GUCs
for every comparably important issue, we'd have about 40,000 of them.

I suggest we add the RAISE syntax first, because everybody agrees on
that. Then, we can argue about the other stuff.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#49Pavel Stehule
pavel.stehule@gmail.com
In reply to: Robert Haas (#48)
Re: PL/pgSQL, RAISE and error context

2015-04-24 13:16 GMT+02:00 Robert Haas <robertmhaas@gmail.com>:

On Fri, Apr 24, 2015 at 6:11 AM, Joel Jacobson <joel@trustly.com> wrote:

Entering the discussion because this is a huge pain for me in my daily
work as well.

This is not a reply to any specific post in this thread, but my first
message in the thread.

I see a great value in providing both a GUC and a new RAISE syntax.
The different benefits of the two are maybe obvious, but perhaps worth
pointing out:
GUC: Good because you don't have to change any existing code.
RAISE syntax: Good because you can control exactly what message should
be emitted or not be emitted at that line of code.

I think preserving backwards compatibility is very important.
Not changing the default is not a problem for me, as long as it can be
overridden.

Whatever the default behaviour is, I think the need expressed by all
users in this thread boils down to any of these two sentences:

"I want CONTEXT to be (DISPLAYED|SUPPRESSED) for (ALL|ONLY THIS LINE)
RAISE (NOTICE|WARNING|ERROR)"
OR
"I don't want to change the default current behaviour of CONTEXT"

So we basically need a boolean setting value, where:
NULL means the default behaviour
TRUE means DISPLAY CONTEXT
FALSE means SUPPRESS CONTEXT

And the (ALL|ONLY THIS) part translates into using,
* a GUC to change behaviour for ALL lines of code,
* or using the RAISE syntax to change the behaviour of ONLY THIS line of

code.

And then we have the different message levels, for which CONTEXT is
sometimes desirable in some situations:
* The RAISE syntax allows controlling any message level in a natural
way, as the message level is part of the syntax.
* Allowing the same control using GUC would mean the message level
would need to be part of the GUC key name, which means either add
multiple GUCs, one for each message level, or only allow controlling
the most important one and ignore the possibly need to control the
other message levels.

If it would be possible to somehow combine multiple message levels in
the same GUC, that would solve the latter problem.

We already have comma separated values for many GUCs, so maybe we
could use that approach here as well.

It looks like adding these two GUCs would meet the demands of all users:

suppress_context_messages (enum)
display_context_messages (enum)

This would allow doing something crazy as:

suppress_context_messages = warning,error
display_context_messages = notice

This is a very flexible proposal, but it's a tremendous amount of
machinery for what's really a very minor issue. If we added two GUCs
for every comparably important issue, we'd have about 40,000 of them.

It can be PLpgSQL only GUC. Probably it is a most problematic case.

I suggest we add the RAISE syntax first, because everybody agrees on
that. Then, we can argue about the other stuff.

There is a agreement about it - but I am expecting a harder discussion
about what will be default, and the discussion about syntax should not be
simple too.

Show quoted text

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#50Joel Jacobson
joel@trustly.com
In reply to: Robert Haas (#48)
Re: PL/pgSQL, RAISE and error context

On Fri, Apr 24, 2015 at 1:16 PM, Robert Haas <robertmhaas@gmail.com> wrote:

This would allow doing something crazy as:

suppress_context_messages = warning,error
display_context_messages = notice

This is a very flexible proposal, but it's a tremendous amount of
machinery for what's really a very minor issue. If we added two GUCs
for every comparably important issue, we'd have about 40,000 of them.

I agree. The one-dimensional GUC syntax is not well suited for
multi-dimensional config settings. And that's a good thing mostly I
think. It would be a nightmare if the config file values could in JSON
format, it's good they are simple.

But I'm thinking maybe we could improve the config file syntax for the
general case when you have multiple things you want to control, in
this case the message levels, and for each such thing, you want to
turn something on/off, in this case the CONTEXT. Maybe we could simply
use plus "+" and minus "-" to mean "on" and "off"?

Example:

context_messages = -warning, -error, +notice

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#51Pavel Stehule
pavel.stehule@gmail.com
In reply to: Joel Jacobson (#50)
Re: PL/pgSQL, RAISE and error context

2015-04-24 16:02 GMT+02:00 Joel Jacobson <joel@trustly.com>:

On Fri, Apr 24, 2015 at 1:16 PM, Robert Haas <robertmhaas@gmail.com>
wrote:

This would allow doing something crazy as:

suppress_context_messages = warning,error
display_context_messages = notice

This is a very flexible proposal, but it's a tremendous amount of
machinery for what's really a very minor issue. If we added two GUCs
for every comparably important issue, we'd have about 40,000 of them.

I agree. The one-dimensional GUC syntax is not well suited for
multi-dimensional config settings. And that's a good thing mostly I
think. It would be a nightmare if the config file values could in JSON
format, it's good they are simple.

But I'm thinking maybe we could improve the config file syntax for the
general case when you have multiple things you want to control, in
this case the message levels, and for each such thing, you want to
turn something on/off, in this case the CONTEXT. Maybe we could simply
use plus "+" and minus "-" to mean "on" and "off"?

Example:

context_messages = -warning, -error, +notice

I prefer your first proposal - and there is a precedent for plpgsql -
plpgsql_extra_checks

It is clean for anybody. +-identifiers looks like horrible httpd config. :)

Regards

Pavel

#52Joel Jacobson
joel@trustly.com
In reply to: Pavel Stehule (#51)
Re: PL/pgSQL, RAISE and error context

On Fri, Apr 24, 2015 at 6:07 PM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

Example:

context_messages = -warning, -error, +notice

I prefer your first proposal - and there is a precedent for plpgsql -
plpgsql_extra_checks

It is clean for anybody. +-identifiers looks like horrible httpd config. :)

I have to agree on that :) Just thought this is the best we can do if
we want to reduce the number of GUCs to a minimum.

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#53Pavel Stehule
pavel.stehule@gmail.com
In reply to: Joel Jacobson (#52)
Re: PL/pgSQL, RAISE and error context

2015-04-24 19:16 GMT+02:00 Joel Jacobson <joel@trustly.com>:

On Fri, Apr 24, 2015 at 6:07 PM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

Example:

context_messages = -warning, -error, +notice

I prefer your first proposal - and there is a precedent for plpgsql -
plpgsql_extra_checks

It is clean for anybody. +-identifiers looks like horrible httpd config.

:)

I have to agree on that :) Just thought this is the best we can do if
we want to reduce the number of GUCs to a minimum.

It looks like discussion KDE x GNOME.

GUC that has simply effect on behave without performance impact should not
be problem - like log_lock_wait, log_min_duration and similar. I am sure so
we would it.

The problematic GUC are a performance, planner, bgwriter, checkpoint
related.

#54Pavel Stehule
pavel.stehule@gmail.com
In reply to: Joel Jacobson (#52)
1 attachment(s)
Re: PL/pgSQL, RAISE and error context

Hi

2015-04-24 19:16 GMT+02:00 Joel Jacobson <joel@trustly.com>:

On Fri, Apr 24, 2015 at 6:07 PM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

Example:

context_messages = -warning, -error, +notice

I prefer your first proposal - and there is a precedent for plpgsql -
plpgsql_extra_checks

It is clean for anybody. +-identifiers looks like horrible httpd config.

:)

I have to agree on that :) Just thought this is the best we can do if
we want to reduce the number of GUCs to a minimum.

I played with some prototype and I am thinking so we need only one GUC

plpgsql.display_context_messages = 'none'; -- compatible with current
plpgsql.display_context_messages = 'all';
plpgsql.display_context_messages = 'exception, log'; -- what I prefer

I implemented [ (WITH|WITHOUT) CONTEXT ] clause for RAISE statement

RAISE NOTICE WITH CONTEXT 'some message';
RAISE NOTICE WITH CONTEXT USING message = 'some message';
RAISE EXCEPTION WITHOUT CONTEXT 'other message';

The patch is very small with full functionality (without documentation) - I
am thinking so it can work. This patch is back compatible - and allow to
change default behave simply.

plpgsql.display_context_messages can be simplified to some like
plpgsql.display_context_min_messages

What do you think about it?

Regards

Pavel

Attachments:

plpgsql-raise-context.patchtext/x-patch; charset=US-ASCII; name=plpgsql-raise-context.patchDownload
commit cf9e23a29162ac55fcab1ac4d9e7a24492de0736
Author: Pavel Stehule <pavel.stehule@gooddata.com>
Date:   Sat Apr 25 22:09:28 2015 +0200

    initial implementation of (WITH|WITHOUT) CONTEXT clause to plpgsql RAISE statement.
    
    initial implementation of plpgsql GUC plpgsql.display_context_messages

diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index deefb1f..ea0dac5 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -2921,6 +2921,7 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
 	char	   *err_table = NULL;
 	char	   *err_schema = NULL;
 	ListCell   *lc;
+	bool			hide_ctx;
 
 	/* RAISE with no parameters: re-throw current exception */
 	if (stmt->condname == NULL && stmt->message == NULL &&
@@ -3080,10 +3081,42 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
 			err_message = pstrdup(unpack_sql_state(err_code));
 	}
 
-	/*
-	 * Throw the error (may or may not come back)
-	 */
-	estate->err_text = raise_skip_msg;	/* suppress traceback of raise */
+	if (stmt->context_info == PLPGSQL_CONTEXT_DISPLAY)
+		hide_ctx = false;
+	else if (stmt->context_info == PLPGSQL_CONTEXT_SUPPRESS)
+	{
+		hide_ctx = true;
+	}
+	else
+	{
+		/* we display a messages via plpgsql_display_context_messages */
+		switch (stmt->elog_level)
+		{
+			case ERROR:
+				hide_ctx = !(plpgsql_display_context_messages & PLPGSQL_DISPLAY_CONTEXT_ERROR);
+				break;
+			case WARNING:
+				hide_ctx = !(plpgsql_display_context_messages & PLPGSQL_DISPLAY_CONTEXT_WARNING);
+				break;
+			case NOTICE:
+				hide_ctx = !(plpgsql_display_context_messages & PLPGSQL_DISPLAY_CONTEXT_NOTICE);
+				break;
+			case INFO:
+				hide_ctx = !(plpgsql_display_context_messages & PLPGSQL_DISPLAY_CONTEXT_INFO);
+				break;
+			case LOG:
+				hide_ctx = !(plpgsql_display_context_messages & PLPGSQL_DISPLAY_CONTEXT_LOG);
+				break;
+			case DEBUG1:
+				hide_ctx = !(plpgsql_display_context_messages & PLPGSQL_DISPLAY_CONTEXT_DEBUG);
+				break;
+			default:
+				elog(ERROR, "unexpected RAISE statement level");
+		}
+	}
+
+	if (hide_ctx)
+		estate->err_text = raise_skip_msg;
 
 	ereport(stmt->elog_level,
 			(err_code ? errcode(err_code) : 0,
@@ -3099,7 +3132,8 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
 			 (err_table != NULL) ?
 			 err_generic_string(PG_DIAG_TABLE_NAME, err_table) : 0,
 			 (err_schema != NULL) ?
-			 err_generic_string(PG_DIAG_SCHEMA_NAME, err_schema) : 0));
+			 err_generic_string(PG_DIAG_SCHEMA_NAME, err_schema) : 0,
+			 errhidecontext(hide_ctx)));
 
 	estate->err_text = NULL;	/* un-suppress... */
 
diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y
index 4026e41..48914a7 100644
--- a/src/pl/plpgsql/src/pl_gram.y
+++ b/src/pl/plpgsql/src/pl_gram.y
@@ -259,6 +259,7 @@ static	void			check_raise_parameters(PLpgSQL_stmt_raise *stmt);
 %token <keyword>	K_CONSTANT
 %token <keyword>	K_CONSTRAINT
 %token <keyword>	K_CONSTRAINT_NAME
+%token <keyword>	K_CONTEXT
 %token <keyword>	K_CONTINUE
 %token <keyword>	K_CURRENT
 %token <keyword>	K_CURSOR
@@ -341,6 +342,8 @@ static	void			check_raise_parameters(PLpgSQL_stmt_raise *stmt);
 %token <keyword>	K_WARNING
 %token <keyword>	K_WHEN
 %token <keyword>	K_WHILE
+%token <keyword>	K_WITH
+%token <keyword>	K_WITHOUT
 
 %%
 
@@ -1716,6 +1719,7 @@ stmt_raise		: K_RAISE
 						new->cmd_type	= PLPGSQL_STMT_RAISE;
 						new->lineno		= plpgsql_location_to_lineno(@1);
 						new->elog_level = ERROR;	/* default */
+						new->context_info = PLPGSQL_CONTEXT_DEFAULT;
 						new->condname	= NULL;
 						new->message	= NULL;
 						new->params		= NIL;
@@ -1773,6 +1777,21 @@ stmt_raise		: K_RAISE
 							if (tok == 0)
 								yyerror("unexpected end of function definition");
 
+							/* Optional choose about including context */
+							if (tok == K_WITH || tok == K_WITHOUT)
+							{
+								if (tok == K_WITH)
+									new->context_info = PLPGSQL_CONTEXT_DISPLAY;
+								else
+									new->context_info = PLPGSQL_CONTEXT_SUPPRESS;
+							
+								/* keyword CONTEXT is required */
+								if (yylex() != K_CONTEXT)
+									yyerror("expected CONTEXT");
+
+								tok = yylex();
+							}
+
 							/*
 							 * Next we can have a condition name, or
 							 * equivalently SQLSTATE 'xxxxx', or a string
@@ -2350,6 +2369,7 @@ unreserved_keyword	:
 				| K_CONSTANT
 				| K_CONSTRAINT
 				| K_CONSTRAINT_NAME
+				| K_CONTEXT
 				| K_CONTINUE
 				| K_CURRENT
 				| K_CURSOR
@@ -2412,6 +2432,8 @@ unreserved_keyword	:
 				| K_USE_VARIABLE
 				| K_VARIABLE_CONFLICT
 				| K_WARNING
+				| K_WITH
+				| K_WITHOUT
 				;
 
 %%
diff --git a/src/pl/plpgsql/src/pl_handler.c b/src/pl/plpgsql/src/pl_handler.c
index 266c314..c47365b 100644
--- a/src/pl/plpgsql/src/pl_handler.c
+++ b/src/pl/plpgsql/src/pl_handler.c
@@ -30,6 +30,9 @@ static bool plpgsql_extra_checks_check_hook(char **newvalue, void **extra, GucSo
 static void plpgsql_extra_warnings_assign_hook(const char *newvalue, void *extra);
 static void plpgsql_extra_errors_assign_hook(const char *newvalue, void *extra);
 
+static bool plpgsql_display_context_messages_check_hook(char **newvalue, void **extra, GucSource source);
+static void plpgsql_display_context_messages_assign_hook(const char *newvalue, void *extra);
+
 PG_MODULE_MAGIC;
 
 /* Custom GUC variable */
@@ -51,9 +54,12 @@ char	   *plpgsql_extra_errors_string = NULL;
 int			plpgsql_extra_warnings;
 int			plpgsql_extra_errors;
 
+char	   *plpgsql_display_context_messages_string = NULL;
+
 /* Hook for plugins */
 PLpgSQL_plugin **plugin_ptr = NULL;
 
+int	plpgsql_display_context_messages;
 
 static bool
 plpgsql_extra_checks_check_hook(char **newvalue, void **extra, GucSource source)
@@ -128,6 +134,87 @@ plpgsql_extra_errors_assign_hook(const char *newvalue, void *extra)
 	plpgsql_extra_errors = *((int *) extra);
 }
 
+static bool 
+plpgsql_display_context_messages_check_hook(char **newvalue, void **extra, GucSource source)
+{
+	int		display_context_messages = 0;
+	char	   *rawstring;
+	List	   *elemlist;
+	ListCell   *l;
+	int		*myextra;
+
+	if (pg_strcasecmp(*newvalue, "all") == 0)
+	{
+		display_context_messages = PLPGSQL_DISPLAY_CONTEXT_ALL;
+	}
+	else if (pg_strcasecmp(*newvalue, "none") == 0)
+	{
+		display_context_messages = PLPGSQL_DISPLAY_CONTEXT_NONE;
+	}
+	else
+	{
+		/* Need a modifiable copy of string */
+		rawstring = pstrdup(*newvalue);
+
+		/* Parse string into list of identifiers */
+		if (!SplitIdentifierString(rawstring, ',', &elemlist))
+		{
+			/* syntax error in list */
+			GUC_check_errdetail("List syntax is invalid.");
+			pfree(rawstring);
+			list_free(elemlist);
+			return false;
+		}
+
+		foreach(l, elemlist)
+		{
+			char	   *tok = (char *) lfirst(l);
+
+			if (pg_strcasecmp(tok, "exception") == 0)
+				display_context_messages |= PLPGSQL_DISPLAY_CONTEXT_ERROR;
+			else if (pg_strcasecmp(tok, "warning") == 0)
+				display_context_messages |= PLPGSQL_DISPLAY_CONTEXT_WARNING;
+			else if (pg_strcasecmp(tok, "notice") == 0)
+				display_context_messages |= PLPGSQL_DISPLAY_CONTEXT_NOTICE;
+			else if (pg_strcasecmp(tok, "info") == 0)
+				display_context_messages |= PLPGSQL_DISPLAY_CONTEXT_INFO;
+			else if (pg_strcasecmp(tok, "log") == 0)
+				display_context_messages |= PLPGSQL_DISPLAY_CONTEXT_LOG;
+			else if (pg_strcasecmp(tok, "debug") == 0)
+				display_context_messages |= PLPGSQL_DISPLAY_CONTEXT_DEBUG;
+			else if (pg_strcasecmp(tok, "all") == 0 || pg_strcasecmp(tok, "none") == 0)
+			{
+				GUC_check_errdetail("Key word \"%s\" cannot be combined with other key words.", tok);
+				pfree(rawstring);
+				list_free(elemlist);
+				return false;
+			}
+			else
+			{
+				GUC_check_errdetail("Unrecognized key word: \"%s\".", tok);
+				pfree(rawstring);
+				list_free(elemlist);
+				return false;
+			}
+		}
+
+		pfree(rawstring);
+		list_free(elemlist);
+	}
+
+	myextra = (int *) malloc(sizeof(int));
+	*myextra = display_context_messages;
+	*extra = (void *) myextra;
+
+	return true;
+
+}
+
+static void plpgsql_display_context_messages_assign_hook(const char *newvalue, void *extra)
+{
+	plpgsql_display_context_messages = *((int *) extra);
+}
+
 
 /*
  * _PG_init()			- library load-time initialization
@@ -190,6 +277,16 @@ _PG_init(void)
 							   plpgsql_extra_errors_assign_hook,
 							   NULL);
 
+	DefineCustomStringVariable("plpgsql.display_context_messages",
+							   gettext_noop(""),
+							   NULL,
+							   &plpgsql_display_context_messages_string,
+							   "none",
+							   PGC_USERSET, GUC_LIST_INPUT,
+							   plpgsql_display_context_messages_check_hook,
+							   plpgsql_display_context_messages_assign_hook,
+							   NULL);
+
 	EmitWarningsOnPlaceholders("plpgsql");
 
 	plpgsql_HashTableInit();
diff --git a/src/pl/plpgsql/src/pl_scanner.c b/src/pl/plpgsql/src/pl_scanner.c
index 683fdab..973cab8 100644
--- a/src/pl/plpgsql/src/pl_scanner.c
+++ b/src/pl/plpgsql/src/pl_scanner.c
@@ -107,6 +107,7 @@ static const ScanKeyword unreserved_keywords[] = {
 	PG_KEYWORD("constant", K_CONSTANT, UNRESERVED_KEYWORD)
 	PG_KEYWORD("constraint", K_CONSTRAINT, UNRESERVED_KEYWORD)
 	PG_KEYWORD("constraint_name", K_CONSTRAINT_NAME, UNRESERVED_KEYWORD)
+	PG_KEYWORD("context", K_CONTEXT, UNRESERVED_KEYWORD)
 	PG_KEYWORD("continue", K_CONTINUE, UNRESERVED_KEYWORD)
 	PG_KEYWORD("current", K_CURRENT, UNRESERVED_KEYWORD)
 	PG_KEYWORD("cursor", K_CURSOR, UNRESERVED_KEYWORD)
@@ -170,6 +171,8 @@ static const ScanKeyword unreserved_keywords[] = {
 	PG_KEYWORD("use_variable", K_USE_VARIABLE, UNRESERVED_KEYWORD)
 	PG_KEYWORD("variable_conflict", K_VARIABLE_CONFLICT, UNRESERVED_KEYWORD)
 	PG_KEYWORD("warning", K_WARNING, UNRESERVED_KEYWORD)
+	PG_KEYWORD("with", K_WITH, UNRESERVED_KEYWORD)
+	PG_KEYWORD("without", K_WITHOUT, UNRESERVED_KEYWORD)
 };
 
 static const int num_unreserved_keywords = lengthof(unreserved_keywords);
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index bec773a..cac3833 100644
--- a/src/pl/plpgsql/src/plpgsql.h
+++ b/src/pl/plpgsql/src/plpgsql.h
@@ -168,6 +168,18 @@ typedef enum
 } PLpgSQL_resolve_option;
 
 
+/* --------
+ * Manipulation with context of exception
+ * --------
+ */
+enum
+{
+	PLPGSQL_CONTEXT_DISPLAY,
+	PLPGSQL_CONTEXT_SUPPRESS,
+	PLPGSQL_CONTEXT_DEFAULT
+};
+
+
 /**********************************************************************
  * Node and structure definitions
  **********************************************************************/
@@ -619,6 +631,7 @@ typedef struct
 	int			cmd_type;
 	int			lineno;
 	int			elog_level;
+	int			context_info;
 	char	   *condname;		/* condition name, SQLSTATE, or NULL */
 	char	   *message;		/* old-style message format literal, or NULL */
 	List	   *params;			/* list of expressions for old-style message */
@@ -922,6 +935,18 @@ extern MemoryContext compile_tmp_cxt;
 
 extern PLpgSQL_plugin **plugin_ptr;
 
+/* display context messages */
+#define PLPGSQL_DISPLAY_CONTEXT_NONE		0
+#define PLPGSQL_DISPLAY_CONTEXT_ALL		((int) ~0)
+#define PLPGSQL_DISPLAY_CONTEXT_ERROR		2
+#define PLPGSQL_DISPLAY_CONTEXT_WARNING		4
+#define PLPGSQL_DISPLAY_CONTEXT_NOTICE		8
+#define PLPGSQL_DISPLAY_CONTEXT_INFO		16
+#define PLPGSQL_DISPLAY_CONTEXT_LOG		32
+#define PLPGSQL_DISPLAY_CONTEXT_DEBUG		64
+
+extern int plpgsql_display_context_messages;
+
 /**********************************************************************
  * Function declarations
  **********************************************************************/
diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out
index 78e5a85..6e75185 100644
--- a/src/test/regress/expected/plpgsql.out
+++ b/src/test/regress/expected/plpgsql.out
@@ -5426,3 +5426,38 @@ end;
 $$;
 ERROR:  unhandled assertion
 CONTEXT:  PL/pgSQL function inline_code_block line 3 at ASSERT
+--possibility to enforce context message displaying
+do $$
+begin
+  raise notice with context 'hello';
+end;
+$$;
+NOTICE:  hello
+CONTEXT:  PL/pgSQL function inline_code_block line 3 at RAISE
+do $$
+begin
+  raise exception with context 'hello';
+end;
+$$;
+ERROR:  hello
+CONTEXT:  PL/pgSQL function inline_code_block line 3 at RAISE
+set plpgsql.display_context_messages = 'notice, exception';
+do $$
+begin
+  raise notice 'some notice';
+  raise exception 'some exception';
+end;
+$$;
+NOTICE:  some notice
+CONTEXT:  PL/pgSQL function inline_code_block line 3 at RAISE
+ERROR:  some exception
+CONTEXT:  PL/pgSQL function inline_code_block line 4 at RAISE
+-- possibility to suppress default
+do $$
+begin
+  raise notice without context 'some notice';
+  raise exception without context 'some exception';
+end;
+$$;
+NOTICE:  some notice
+ERROR:  some exception
diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql
index e19e415..927da16 100644
--- a/src/test/regress/sql/plpgsql.sql
+++ b/src/test/regress/sql/plpgsql.sql
@@ -4265,3 +4265,35 @@ exception when others then
   null; -- do nothing
 end;
 $$;
+
+
+--possibility to enforce context message displaying
+do $$
+begin
+  raise notice with context 'hello';
+end;
+$$;
+
+do $$
+begin
+  raise exception with context 'hello';
+end;
+$$;
+
+set plpgsql.display_context_messages = 'notice, exception';
+do $$
+begin
+  raise notice 'some notice';
+  raise exception 'some exception';
+end;
+$$;
+
+-- possibility to suppress default
+do $$
+begin
+  raise notice without context 'some notice';
+  raise exception without context 'some exception';
+end;
+$$;
+
+
#55Joel Jacobson
joel@trustly.com
In reply to: Pavel Stehule (#54)
Re: PL/pgSQL, RAISE and error context

+1

On Sat, Apr 25, 2015 at 10:23 PM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

Show quoted text

Hi

2015-04-24 19:16 GMT+02:00 Joel Jacobson <joel@trustly.com>:

On Fri, Apr 24, 2015 at 6:07 PM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

Example:

context_messages = -warning, -error, +notice

I prefer your first proposal - and there is a precedent for plpgsql -
plpgsql_extra_checks

It is clean for anybody. +-identifiers looks like horrible httpd

config. :)

I have to agree on that :) Just thought this is the best we can do if
we want to reduce the number of GUCs to a minimum.

I played with some prototype and I am thinking so we need only one GUC

plpgsql.display_context_messages = 'none'; -- compatible with current
plpgsql.display_context_messages = 'all';
plpgsql.display_context_messages = 'exception, log'; -- what I prefer

I implemented [ (WITH|WITHOUT) CONTEXT ] clause for RAISE statement

RAISE NOTICE WITH CONTEXT 'some message';
RAISE NOTICE WITH CONTEXT USING message = 'some message';
RAISE EXCEPTION WITHOUT CONTEXT 'other message';

The patch is very small with full functionality (without documentation) -
I am thinking so it can work. This patch is back compatible - and allow to
change default behave simply.

plpgsql.display_context_messages can be simplified to some like
plpgsql.display_context_min_messages

What do you think about it?

Regards

Pavel

#56Pavel Stehule
pavel.stehule@gmail.com
In reply to: Pavel Stehule (#54)
1 attachment(s)
Re: PL/pgSQL, RAISE and error context

Hi

I reduced this patch, little bit cleaned - now it is based on plpgsql GUC
display_context_min_messages - like client_min_messages, log_min_messages.

Documentation added.

Regards

Pavel

2015-04-25 22:23 GMT+02:00 Pavel Stehule <pavel.stehule@gmail.com>:

Show quoted text

Hi

2015-04-24 19:16 GMT+02:00 Joel Jacobson <joel@trustly.com>:

On Fri, Apr 24, 2015 at 6:07 PM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

Example:

context_messages = -warning, -error, +notice

I prefer your first proposal - and there is a precedent for plpgsql -
plpgsql_extra_checks

It is clean for anybody. +-identifiers looks like horrible httpd

config. :)

I have to agree on that :) Just thought this is the best we can do if
we want to reduce the number of GUCs to a minimum.

I played with some prototype and I am thinking so we need only one GUC

plpgsql.display_context_messages = 'none'; -- compatible with current
plpgsql.display_context_messages = 'all';
plpgsql.display_context_messages = 'exception, log'; -- what I prefer

I implemented [ (WITH|WITHOUT) CONTEXT ] clause for RAISE statement

RAISE NOTICE WITH CONTEXT 'some message';
RAISE NOTICE WITH CONTEXT USING message = 'some message';
RAISE EXCEPTION WITHOUT CONTEXT 'other message';

The patch is very small with full functionality (without documentation) -
I am thinking so it can work. This patch is back compatible - and allow to
change default behave simply.

plpgsql.display_context_messages can be simplified to some like
plpgsql.display_context_min_messages

What do you think about it?

Regards

Pavel

Attachments:

plpgsql-raise-context-01.patchtext/x-patch; charset=US-ASCII; name=plpgsql-raise-context-01.patchDownload
commit 33951bc23365029ee94af5ec43e90893dcd737a8
Author: Pavel Stehule <pavel.stehule@gooddata.com>
Date:   Sat Apr 25 22:09:28 2015 +0200

    initial implementation of (WITH|WITHOUT) CONTEXT clause to plpgsql RAISE statement.
    
    initial implementation of plpgsql GUC plpgsql.display_context_messages

diff --git a/doc/src/sgml/plpgsql.sgml b/doc/src/sgml/plpgsql.sgml
index d36acf6..8aebb87 100644
--- a/doc/src/sgml/plpgsql.sgml
+++ b/doc/src/sgml/plpgsql.sgml
@@ -3406,10 +3406,10 @@ END LOOP <optional> <replaceable>label</replaceable> </optional>;
     raise errors.
 
 <synopsis>
-RAISE <optional> <replaceable class="parameter">level</replaceable> </optional> '<replaceable class="parameter">format</replaceable>' <optional>, <replaceable class="parameter">expression</replaceable> <optional>, ... </optional></optional> <optional> USING <replaceable class="parameter">option</replaceable> = <replaceable class="parameter">expression</replaceable> <optional>, ... </optional> </optional>;
-RAISE <optional> <replaceable class="parameter">level</replaceable> </optional> <replaceable class="parameter">condition_name</> <optional> USING <replaceable class="parameter">option</replaceable> = <replaceable class="parameter">expression</replaceable> <optional>, ... </optional> </optional>;
-RAISE <optional> <replaceable class="parameter">level</replaceable> </optional> SQLSTATE '<replaceable class="parameter">sqlstate</>' <optional> USING <replaceable class="parameter">option</replaceable> = <replaceable class="parameter">expression</replaceable> <optional>, ... </optional> </optional>;
-RAISE <optional> <replaceable class="parameter">level</replaceable> </optional> USING <replaceable class="parameter">option</replaceable> = <replaceable class="parameter">expression</replaceable> <optional>, ... </optional>;
+RAISE <optional> <replaceable class="parameter">level</replaceable> </optional> <optional> ( WITH | WITHOUT ) CONTEXT </optional> '<replaceable class="parameter">format</replaceable>' <optional>, <replaceable class="parameter">expression</replaceable> <optional>, ... </optional></optional> <optional> USING <replaceable class="parameter">option</replaceable> = <replaceable class="parameter">expression</replaceable> <optional>, ... </optional> </optional>;
+RAISE <optional> <replaceable class="parameter">level</replaceable> </optional> <optional> ( WITH | WITHOUT ) CONTEXT </optional> <replaceable class="parameter">condition_name</> <optional> USING <replaceable class="parameter">option</replaceable> = <replaceable class="parameter">expression</replaceable> <optional>, ... </optional> </optional>;
+RAISE <optional> <replaceable class="parameter">level</replaceable> </optional> <optional> ( WITH | WITHOUT ) CONTEXT </optional> SQLSTATE '<replaceable class="parameter">sqlstate</>' <optional> USING <replaceable class="parameter">option</replaceable> = <replaceable class="parameter">expression</replaceable> <optional>, ... </optional> </optional>;
+RAISE <optional> <replaceable class="parameter">level</replaceable> </optional> <optional> ( WITH | WITHOUT ) CONTEXT </optional> USING <replaceable class="parameter">option</replaceable> = <replaceable class="parameter">expression</replaceable> <optional>, ... </optional>;
 RAISE ;
 </synopsis>
 
@@ -3431,6 +3431,18 @@ RAISE ;
    </para>
 
    <para>
+    The options <literal>WITH CONTEXT</literal> or <literal>WITHOUT CONTEXT</literal>
+    can enforce or suppress context information related to error or notice. This possibility
+    can be forced by settings of configuration parameter <literal>plpgsql.display_context_min_messages</>.
+    This allows same values like <replaceable class="parameter">level</replaceable> option plus
+    value <literal>none</literal> that is a default. When it is changed, then all errors and notices
+    with higher than specified severity are raised with context info.
+<programlisting>
+RAISE NOTICE WITH CONTEXT 'This message will have a context';
+</programlisting>
+   </para>
+
+   <para>
     After <replaceable class="parameter">level</replaceable> if any,
     you can write a <replaceable class="parameter">format</replaceable>
     (which must be a simple string literal, not an expression).  The
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index deefb1f..6d1e791 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -2921,6 +2921,7 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
 	char	   *err_table = NULL;
 	char	   *err_schema = NULL;
 	ListCell   *lc;
+	bool			hide_ctx = true;		/* suppress context by default */
 
 	/* RAISE with no parameters: re-throw current exception */
 	if (stmt->condname == NULL && stmt->message == NULL &&
@@ -3080,10 +3081,16 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
 			err_message = pstrdup(unpack_sql_state(err_code));
 	}
 
-	/*
-	 * Throw the error (may or may not come back)
-	 */
-	estate->err_text = raise_skip_msg;	/* suppress traceback of raise */
+	if (stmt->context_info == PLPGSQL_CONTEXT_DISPLAY)
+		hide_ctx = false;
+	else if (stmt->context_info == PLPGSQL_CONTEXT_DEFAULT)
+	{
+		if (plpgsql_display_context_min_messages != PLPGSQL_DISPLAY_CONTEXT_SUPPRESS)
+			hide_ctx = stmt->elog_level < plpgsql_display_context_min_messages;
+	}
+
+	if (hide_ctx)
+		estate->err_text = raise_skip_msg;
 
 	ereport(stmt->elog_level,
 			(err_code ? errcode(err_code) : 0,
@@ -3099,7 +3106,8 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
 			 (err_table != NULL) ?
 			 err_generic_string(PG_DIAG_TABLE_NAME, err_table) : 0,
 			 (err_schema != NULL) ?
-			 err_generic_string(PG_DIAG_SCHEMA_NAME, err_schema) : 0));
+			 err_generic_string(PG_DIAG_SCHEMA_NAME, err_schema) : 0,
+			 errhidecontext(hide_ctx)));
 
 	estate->err_text = NULL;	/* un-suppress... */
 
diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y
index 4026e41..48914a7 100644
--- a/src/pl/plpgsql/src/pl_gram.y
+++ b/src/pl/plpgsql/src/pl_gram.y
@@ -259,6 +259,7 @@ static	void			check_raise_parameters(PLpgSQL_stmt_raise *stmt);
 %token <keyword>	K_CONSTANT
 %token <keyword>	K_CONSTRAINT
 %token <keyword>	K_CONSTRAINT_NAME
+%token <keyword>	K_CONTEXT
 %token <keyword>	K_CONTINUE
 %token <keyword>	K_CURRENT
 %token <keyword>	K_CURSOR
@@ -341,6 +342,8 @@ static	void			check_raise_parameters(PLpgSQL_stmt_raise *stmt);
 %token <keyword>	K_WARNING
 %token <keyword>	K_WHEN
 %token <keyword>	K_WHILE
+%token <keyword>	K_WITH
+%token <keyword>	K_WITHOUT
 
 %%
 
@@ -1716,6 +1719,7 @@ stmt_raise		: K_RAISE
 						new->cmd_type	= PLPGSQL_STMT_RAISE;
 						new->lineno		= plpgsql_location_to_lineno(@1);
 						new->elog_level = ERROR;	/* default */
+						new->context_info = PLPGSQL_CONTEXT_DEFAULT;
 						new->condname	= NULL;
 						new->message	= NULL;
 						new->params		= NIL;
@@ -1773,6 +1777,21 @@ stmt_raise		: K_RAISE
 							if (tok == 0)
 								yyerror("unexpected end of function definition");
 
+							/* Optional choose about including context */
+							if (tok == K_WITH || tok == K_WITHOUT)
+							{
+								if (tok == K_WITH)
+									new->context_info = PLPGSQL_CONTEXT_DISPLAY;
+								else
+									new->context_info = PLPGSQL_CONTEXT_SUPPRESS;
+							
+								/* keyword CONTEXT is required */
+								if (yylex() != K_CONTEXT)
+									yyerror("expected CONTEXT");
+
+								tok = yylex();
+							}
+
 							/*
 							 * Next we can have a condition name, or
 							 * equivalently SQLSTATE 'xxxxx', or a string
@@ -2350,6 +2369,7 @@ unreserved_keyword	:
 				| K_CONSTANT
 				| K_CONSTRAINT
 				| K_CONSTRAINT_NAME
+				| K_CONTEXT
 				| K_CONTINUE
 				| K_CURRENT
 				| K_CURSOR
@@ -2412,6 +2432,8 @@ unreserved_keyword	:
 				| K_USE_VARIABLE
 				| K_VARIABLE_CONFLICT
 				| K_WARNING
+				| K_WITH
+				| K_WITHOUT
 				;
 
 %%
diff --git a/src/pl/plpgsql/src/pl_handler.c b/src/pl/plpgsql/src/pl_handler.c
index 266c314..e9f9029 100644
--- a/src/pl/plpgsql/src/pl_handler.c
+++ b/src/pl/plpgsql/src/pl_handler.c
@@ -40,6 +40,17 @@ static const struct config_enum_entry variable_conflict_options[] = {
 	{NULL, 0, false}
 };
 
+static const struct config_enum_entry display_context_min_messages_options[] = {
+	{"none", PLPGSQL_DISPLAY_CONTEXT_SUPPRESS},
+	{"exception", ERROR},
+	{"warning", WARNING},
+	{"notice", NOTICE},
+	{"info", INFO},
+	{"log", LOG},
+	{"debug", DEBUG1},
+	{NULL, 0, false}
+};
+
 int			plpgsql_variable_conflict = PLPGSQL_RESOLVE_ERROR;
 
 bool		plpgsql_print_strict_params = false;
@@ -51,6 +62,8 @@ char	   *plpgsql_extra_errors_string = NULL;
 int			plpgsql_extra_warnings;
 int			plpgsql_extra_errors;
 
+int			plpgsql_display_context_min_messages = PLPGSQL_DISPLAY_CONTEXT_SUPPRESS;
+
 /* Hook for plugins */
 PLpgSQL_plugin **plugin_ptr = NULL;
 
@@ -154,6 +167,15 @@ _PG_init(void)
 							 PGC_SUSET, 0,
 							 NULL, NULL, NULL);
 
+	DefineCustomEnumVariable("plpgsql.display_context_min_messages",
+							 gettext_noop("Sets minimal level of messages with context information."),
+							 NULL,
+							 &plpgsql_display_context_min_messages,
+							 PLPGSQL_DISPLAY_CONTEXT_SUPPRESS,
+							 display_context_min_messages_options,
+							 PGC_SUSET, 0,
+							 NULL, NULL, NULL);
+
 	DefineCustomBoolVariable("plpgsql.print_strict_params",
 							 gettext_noop("Print information about parameters in the DETAIL part of the error messages generated on INTO ... STRICT failures."),
 							 NULL,
diff --git a/src/pl/plpgsql/src/pl_scanner.c b/src/pl/plpgsql/src/pl_scanner.c
index 683fdab..973cab8 100644
--- a/src/pl/plpgsql/src/pl_scanner.c
+++ b/src/pl/plpgsql/src/pl_scanner.c
@@ -107,6 +107,7 @@ static const ScanKeyword unreserved_keywords[] = {
 	PG_KEYWORD("constant", K_CONSTANT, UNRESERVED_KEYWORD)
 	PG_KEYWORD("constraint", K_CONSTRAINT, UNRESERVED_KEYWORD)
 	PG_KEYWORD("constraint_name", K_CONSTRAINT_NAME, UNRESERVED_KEYWORD)
+	PG_KEYWORD("context", K_CONTEXT, UNRESERVED_KEYWORD)
 	PG_KEYWORD("continue", K_CONTINUE, UNRESERVED_KEYWORD)
 	PG_KEYWORD("current", K_CURRENT, UNRESERVED_KEYWORD)
 	PG_KEYWORD("cursor", K_CURSOR, UNRESERVED_KEYWORD)
@@ -170,6 +171,8 @@ static const ScanKeyword unreserved_keywords[] = {
 	PG_KEYWORD("use_variable", K_USE_VARIABLE, UNRESERVED_KEYWORD)
 	PG_KEYWORD("variable_conflict", K_VARIABLE_CONFLICT, UNRESERVED_KEYWORD)
 	PG_KEYWORD("warning", K_WARNING, UNRESERVED_KEYWORD)
+	PG_KEYWORD("with", K_WITH, UNRESERVED_KEYWORD)
+	PG_KEYWORD("without", K_WITHOUT, UNRESERVED_KEYWORD)
 };
 
 static const int num_unreserved_keywords = lengthof(unreserved_keywords);
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index bec773a..73d3238 100644
--- a/src/pl/plpgsql/src/plpgsql.h
+++ b/src/pl/plpgsql/src/plpgsql.h
@@ -168,6 +168,18 @@ typedef enum
 } PLpgSQL_resolve_option;
 
 
+/* --------
+ * Manipulation with context of exception
+ * --------
+ */
+enum
+{
+	PLPGSQL_CONTEXT_DISPLAY,
+	PLPGSQL_CONTEXT_SUPPRESS,
+	PLPGSQL_CONTEXT_DEFAULT
+};
+
+
 /**********************************************************************
  * Node and structure definitions
  **********************************************************************/
@@ -619,6 +631,7 @@ typedef struct
 	int			cmd_type;
 	int			lineno;
 	int			elog_level;
+	int			context_info;
 	char	   *condname;		/* condition name, SQLSTATE, or NULL */
 	char	   *message;		/* old-style message format literal, or NULL */
 	List	   *params;			/* list of expressions for old-style message */
@@ -922,6 +935,10 @@ extern MemoryContext compile_tmp_cxt;
 
 extern PLpgSQL_plugin **plugin_ptr;
 
+#define PLPGSQL_DISPLAY_CONTEXT_SUPPRESS		0
+
+extern int plpgsql_display_context_min_messages;
+
 /**********************************************************************
  * Function declarations
  **********************************************************************/
diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out
index 78e5a85..4726df8 100644
--- a/src/test/regress/expected/plpgsql.out
+++ b/src/test/regress/expected/plpgsql.out
@@ -5426,3 +5426,38 @@ end;
 $$;
 ERROR:  unhandled assertion
 CONTEXT:  PL/pgSQL function inline_code_block line 3 at ASSERT
+--possibility to enforce context message displaying
+do $$
+begin
+  raise notice with context 'hello';
+end;
+$$;
+NOTICE:  hello
+CONTEXT:  PL/pgSQL function inline_code_block line 3 at RAISE
+do $$
+begin
+  raise exception with context 'hello';
+end;
+$$;
+ERROR:  hello
+CONTEXT:  PL/pgSQL function inline_code_block line 3 at RAISE
+set plpgsql.display_context_min_messages = 'notice';
+do $$
+begin
+  raise notice 'some notice';
+  raise exception 'some exception';
+end;
+$$;
+NOTICE:  some notice
+CONTEXT:  PL/pgSQL function inline_code_block line 3 at RAISE
+ERROR:  some exception
+CONTEXT:  PL/pgSQL function inline_code_block line 4 at RAISE
+-- possibility to suppress default
+do $$
+begin
+  raise notice without context 'some notice';
+  raise exception without context 'some exception';
+end;
+$$;
+NOTICE:  some notice
+ERROR:  some exception
diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql
index e19e415..fdb8e49 100644
--- a/src/test/regress/sql/plpgsql.sql
+++ b/src/test/regress/sql/plpgsql.sql
@@ -4265,3 +4265,35 @@ exception when others then
   null; -- do nothing
 end;
 $$;
+
+
+--possibility to enforce context message displaying
+do $$
+begin
+  raise notice with context 'hello';
+end;
+$$;
+
+do $$
+begin
+  raise exception with context 'hello';
+end;
+$$;
+
+set plpgsql.display_context_min_messages = 'notice';
+do $$
+begin
+  raise notice 'some notice';
+  raise exception 'some exception';
+end;
+$$;
+
+-- possibility to suppress default
+do $$
+begin
+  raise notice without context 'some notice';
+  raise exception without context 'some exception';
+end;
+$$;
+
+
#57Joel Jacobson
joel@trustly.com
In reply to: Pavel Stehule (#56)
Re: PL/pgSQL, RAISE and error context

Looks good Pavel!

May I just suggest you add the default case
to src/test/regress/sql/plpgsql.sql
and src/test/regress/expected/plpgsql.out, to make it easier for the
reviewer to compare the difference between what happens in the default
case, when not using the raise-syntax and not using the GUCs?

Suggested addition to the beginning of src/test/regress/sql/plpgsql.sql:
+do $$
+begin
+  raise notice 'hello';
+end;
+$$;
+
+do $$
+begin
+  raise exception 'hello';
+end;
+$$;

Many thanks for this patch! I will pray to the PL/pgSQL God it will be
accepted. :)

Best regards,

Joel

On Sun, Apr 26, 2015 at 9:19 AM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

Show quoted text

Hi

I reduced this patch, little bit cleaned - now it is based on plpgsql GUC
display_context_min_messages - like client_min_messages, log_min_messages.

Documentation added.

Regards

Pavel

2015-04-25 22:23 GMT+02:00 Pavel Stehule <pavel.stehule@gmail.com>:

Hi

2015-04-24 19:16 GMT+02:00 Joel Jacobson <joel@trustly.com>:

On Fri, Apr 24, 2015 at 6:07 PM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

Example:

context_messages = -warning, -error, +notice

I prefer your first proposal - and there is a precedent for plpgsql -
plpgsql_extra_checks

It is clean for anybody. +-identifiers looks like horrible httpd

config. :)

I have to agree on that :) Just thought this is the best we can do if
we want to reduce the number of GUCs to a minimum.

I played with some prototype and I am thinking so we need only one GUC

plpgsql.display_context_messages = 'none'; -- compatible with current
plpgsql.display_context_messages = 'all';
plpgsql.display_context_messages = 'exception, log'; -- what I prefer

I implemented [ (WITH|WITHOUT) CONTEXT ] clause for RAISE statement

RAISE NOTICE WITH CONTEXT 'some message';
RAISE NOTICE WITH CONTEXT USING message = 'some message';
RAISE EXCEPTION WITHOUT CONTEXT 'other message';

The patch is very small with full functionality (without documentation) -
I am thinking so it can work. This patch is back compatible - and allow to
change default behave simply.

plpgsql.display_context_messages can be simplified to some like
plpgsql.display_context_min_messages

What do you think about it?

Regards

Pavel

#58Pavel Stehule
pavel.stehule@gmail.com
In reply to: Joel Jacobson (#57)
1 attachment(s)
Re: PL/pgSQL, RAISE and error context

2015-04-27 16:05 GMT+02:00 Joel Jacobson <joel@trustly.com>:

Looks good Pavel!

May I just suggest you add the default case
to src/test/regress/sql/plpgsql.sql
and src/test/regress/expected/plpgsql.out, to make it easier for the
reviewer to compare the difference between what happens in the default
case, when not using the raise-syntax and not using the GUCs?

Suggested addition to the beginning of src/test/regress/sql/plpgsql.sql:
+do $$
+begin
+  raise notice 'hello';
+end;
+$$;
+
+do $$
+begin
+  raise exception 'hello';
+end;
+$$;

done

Many thanks for this patch! I will pray to the PL/pgSQL God it will be
accepted. :)

:) -- please, do review, or fix documentation in this patch.

I hope, so it will be merged early in 9.6 cycle. It is relatively simple.

Pavel

Show quoted text

Best regards,

Joel

On Sun, Apr 26, 2015 at 9:19 AM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

Hi

I reduced this patch, little bit cleaned - now it is based on plpgsql GUC
display_context_min_messages - like client_min_messages, log_min_messages.

Documentation added.

Regards

Pavel

2015-04-25 22:23 GMT+02:00 Pavel Stehule <pavel.stehule@gmail.com>:

Hi

2015-04-24 19:16 GMT+02:00 Joel Jacobson <joel@trustly.com>:

On Fri, Apr 24, 2015 at 6:07 PM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

Example:

context_messages = -warning, -error, +notice

I prefer your first proposal - and there is a precedent for plpgsql -
plpgsql_extra_checks

It is clean for anybody. +-identifiers looks like horrible httpd

config. :)

I have to agree on that :) Just thought this is the best we can do if
we want to reduce the number of GUCs to a minimum.

I played with some prototype and I am thinking so we need only one GUC

plpgsql.display_context_messages = 'none'; -- compatible with current
plpgsql.display_context_messages = 'all';
plpgsql.display_context_messages = 'exception, log'; -- what I prefer

I implemented [ (WITH|WITHOUT) CONTEXT ] clause for RAISE statement

RAISE NOTICE WITH CONTEXT 'some message';
RAISE NOTICE WITH CONTEXT USING message = 'some message';
RAISE EXCEPTION WITHOUT CONTEXT 'other message';

The patch is very small with full functionality (without documentation)
- I am thinking so it can work. This patch is back compatible - and allow
to change default behave simply.

plpgsql.display_context_messages can be simplified to some like
plpgsql.display_context_min_messages

What do you think about it?

Regards

Pavel

Attachments:

plpgsql-raise-context-02.patchtext/x-patch; charset=US-ASCII; name=plpgsql-raise-context-02.patchDownload
commit d60c21fb798cf25609dc37a4bda3ec7822f790e1
Author: Pavel Stehule <pavel.stehule@gooddata.com>
Date:   Sat Apr 25 22:09:28 2015 +0200

    initial implementation of (WITH|WITHOUT) CONTEXT clause to plpgsql RAISE statement.
    
    initial implementation of plpgsql GUC plpgsql.display_context_messages

diff --git a/doc/src/sgml/plpgsql.sgml b/doc/src/sgml/plpgsql.sgml
index d36acf6..8aebb87 100644
--- a/doc/src/sgml/plpgsql.sgml
+++ b/doc/src/sgml/plpgsql.sgml
@@ -3406,10 +3406,10 @@ END LOOP <optional> <replaceable>label</replaceable> </optional>;
     raise errors.
 
 <synopsis>
-RAISE <optional> <replaceable class="parameter">level</replaceable> </optional> '<replaceable class="parameter">format</replaceable>' <optional>, <replaceable class="parameter">expression</replaceable> <optional>, ... </optional></optional> <optional> USING <replaceable class="parameter">option</replaceable> = <replaceable class="parameter">expression</replaceable> <optional>, ... </optional> </optional>;
-RAISE <optional> <replaceable class="parameter">level</replaceable> </optional> <replaceable class="parameter">condition_name</> <optional> USING <replaceable class="parameter">option</replaceable> = <replaceable class="parameter">expression</replaceable> <optional>, ... </optional> </optional>;
-RAISE <optional> <replaceable class="parameter">level</replaceable> </optional> SQLSTATE '<replaceable class="parameter">sqlstate</>' <optional> USING <replaceable class="parameter">option</replaceable> = <replaceable class="parameter">expression</replaceable> <optional>, ... </optional> </optional>;
-RAISE <optional> <replaceable class="parameter">level</replaceable> </optional> USING <replaceable class="parameter">option</replaceable> = <replaceable class="parameter">expression</replaceable> <optional>, ... </optional>;
+RAISE <optional> <replaceable class="parameter">level</replaceable> </optional> <optional> ( WITH | WITHOUT ) CONTEXT </optional> '<replaceable class="parameter">format</replaceable>' <optional>, <replaceable class="parameter">expression</replaceable> <optional>, ... </optional></optional> <optional> USING <replaceable class="parameter">option</replaceable> = <replaceable class="parameter">expression</replaceable> <optional>, ... </optional> </optional>;
+RAISE <optional> <replaceable class="parameter">level</replaceable> </optional> <optional> ( WITH | WITHOUT ) CONTEXT </optional> <replaceable class="parameter">condition_name</> <optional> USING <replaceable class="parameter">option</replaceable> = <replaceable class="parameter">expression</replaceable> <optional>, ... </optional> </optional>;
+RAISE <optional> <replaceable class="parameter">level</replaceable> </optional> <optional> ( WITH | WITHOUT ) CONTEXT </optional> SQLSTATE '<replaceable class="parameter">sqlstate</>' <optional> USING <replaceable class="parameter">option</replaceable> = <replaceable class="parameter">expression</replaceable> <optional>, ... </optional> </optional>;
+RAISE <optional> <replaceable class="parameter">level</replaceable> </optional> <optional> ( WITH | WITHOUT ) CONTEXT </optional> USING <replaceable class="parameter">option</replaceable> = <replaceable class="parameter">expression</replaceable> <optional>, ... </optional>;
 RAISE ;
 </synopsis>
 
@@ -3431,6 +3431,18 @@ RAISE ;
    </para>
 
    <para>
+    The options <literal>WITH CONTEXT</literal> or <literal>WITHOUT CONTEXT</literal>
+    can enforce or suppress context information related to error or notice. This possibility
+    can be forced by settings of configuration parameter <literal>plpgsql.display_context_min_messages</>.
+    This allows same values like <replaceable class="parameter">level</replaceable> option plus
+    value <literal>none</literal> that is a default. When it is changed, then all errors and notices
+    with higher than specified severity are raised with context info.
+<programlisting>
+RAISE NOTICE WITH CONTEXT 'This message will have a context';
+</programlisting>
+   </para>
+
+   <para>
     After <replaceable class="parameter">level</replaceable> if any,
     you can write a <replaceable class="parameter">format</replaceable>
     (which must be a simple string literal, not an expression).  The
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index deefb1f..6d1e791 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -2921,6 +2921,7 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
 	char	   *err_table = NULL;
 	char	   *err_schema = NULL;
 	ListCell   *lc;
+	bool			hide_ctx = true;		/* suppress context by default */
 
 	/* RAISE with no parameters: re-throw current exception */
 	if (stmt->condname == NULL && stmt->message == NULL &&
@@ -3080,10 +3081,16 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
 			err_message = pstrdup(unpack_sql_state(err_code));
 	}
 
-	/*
-	 * Throw the error (may or may not come back)
-	 */
-	estate->err_text = raise_skip_msg;	/* suppress traceback of raise */
+	if (stmt->context_info == PLPGSQL_CONTEXT_DISPLAY)
+		hide_ctx = false;
+	else if (stmt->context_info == PLPGSQL_CONTEXT_DEFAULT)
+	{
+		if (plpgsql_display_context_min_messages != PLPGSQL_DISPLAY_CONTEXT_SUPPRESS)
+			hide_ctx = stmt->elog_level < plpgsql_display_context_min_messages;
+	}
+
+	if (hide_ctx)
+		estate->err_text = raise_skip_msg;
 
 	ereport(stmt->elog_level,
 			(err_code ? errcode(err_code) : 0,
@@ -3099,7 +3106,8 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
 			 (err_table != NULL) ?
 			 err_generic_string(PG_DIAG_TABLE_NAME, err_table) : 0,
 			 (err_schema != NULL) ?
-			 err_generic_string(PG_DIAG_SCHEMA_NAME, err_schema) : 0));
+			 err_generic_string(PG_DIAG_SCHEMA_NAME, err_schema) : 0,
+			 errhidecontext(hide_ctx)));
 
 	estate->err_text = NULL;	/* un-suppress... */
 
diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y
index 4026e41..48914a7 100644
--- a/src/pl/plpgsql/src/pl_gram.y
+++ b/src/pl/plpgsql/src/pl_gram.y
@@ -259,6 +259,7 @@ static	void			check_raise_parameters(PLpgSQL_stmt_raise *stmt);
 %token <keyword>	K_CONSTANT
 %token <keyword>	K_CONSTRAINT
 %token <keyword>	K_CONSTRAINT_NAME
+%token <keyword>	K_CONTEXT
 %token <keyword>	K_CONTINUE
 %token <keyword>	K_CURRENT
 %token <keyword>	K_CURSOR
@@ -341,6 +342,8 @@ static	void			check_raise_parameters(PLpgSQL_stmt_raise *stmt);
 %token <keyword>	K_WARNING
 %token <keyword>	K_WHEN
 %token <keyword>	K_WHILE
+%token <keyword>	K_WITH
+%token <keyword>	K_WITHOUT
 
 %%
 
@@ -1716,6 +1719,7 @@ stmt_raise		: K_RAISE
 						new->cmd_type	= PLPGSQL_STMT_RAISE;
 						new->lineno		= plpgsql_location_to_lineno(@1);
 						new->elog_level = ERROR;	/* default */
+						new->context_info = PLPGSQL_CONTEXT_DEFAULT;
 						new->condname	= NULL;
 						new->message	= NULL;
 						new->params		= NIL;
@@ -1773,6 +1777,21 @@ stmt_raise		: K_RAISE
 							if (tok == 0)
 								yyerror("unexpected end of function definition");
 
+							/* Optional choose about including context */
+							if (tok == K_WITH || tok == K_WITHOUT)
+							{
+								if (tok == K_WITH)
+									new->context_info = PLPGSQL_CONTEXT_DISPLAY;
+								else
+									new->context_info = PLPGSQL_CONTEXT_SUPPRESS;
+							
+								/* keyword CONTEXT is required */
+								if (yylex() != K_CONTEXT)
+									yyerror("expected CONTEXT");
+
+								tok = yylex();
+							}
+
 							/*
 							 * Next we can have a condition name, or
 							 * equivalently SQLSTATE 'xxxxx', or a string
@@ -2350,6 +2369,7 @@ unreserved_keyword	:
 				| K_CONSTANT
 				| K_CONSTRAINT
 				| K_CONSTRAINT_NAME
+				| K_CONTEXT
 				| K_CONTINUE
 				| K_CURRENT
 				| K_CURSOR
@@ -2412,6 +2432,8 @@ unreserved_keyword	:
 				| K_USE_VARIABLE
 				| K_VARIABLE_CONFLICT
 				| K_WARNING
+				| K_WITH
+				| K_WITHOUT
 				;
 
 %%
diff --git a/src/pl/plpgsql/src/pl_handler.c b/src/pl/plpgsql/src/pl_handler.c
index 266c314..e9f9029 100644
--- a/src/pl/plpgsql/src/pl_handler.c
+++ b/src/pl/plpgsql/src/pl_handler.c
@@ -40,6 +40,17 @@ static const struct config_enum_entry variable_conflict_options[] = {
 	{NULL, 0, false}
 };
 
+static const struct config_enum_entry display_context_min_messages_options[] = {
+	{"none", PLPGSQL_DISPLAY_CONTEXT_SUPPRESS},
+	{"exception", ERROR},
+	{"warning", WARNING},
+	{"notice", NOTICE},
+	{"info", INFO},
+	{"log", LOG},
+	{"debug", DEBUG1},
+	{NULL, 0, false}
+};
+
 int			plpgsql_variable_conflict = PLPGSQL_RESOLVE_ERROR;
 
 bool		plpgsql_print_strict_params = false;
@@ -51,6 +62,8 @@ char	   *plpgsql_extra_errors_string = NULL;
 int			plpgsql_extra_warnings;
 int			plpgsql_extra_errors;
 
+int			plpgsql_display_context_min_messages = PLPGSQL_DISPLAY_CONTEXT_SUPPRESS;
+
 /* Hook for plugins */
 PLpgSQL_plugin **plugin_ptr = NULL;
 
@@ -154,6 +167,15 @@ _PG_init(void)
 							 PGC_SUSET, 0,
 							 NULL, NULL, NULL);
 
+	DefineCustomEnumVariable("plpgsql.display_context_min_messages",
+							 gettext_noop("Sets minimal level of messages with context information."),
+							 NULL,
+							 &plpgsql_display_context_min_messages,
+							 PLPGSQL_DISPLAY_CONTEXT_SUPPRESS,
+							 display_context_min_messages_options,
+							 PGC_SUSET, 0,
+							 NULL, NULL, NULL);
+
 	DefineCustomBoolVariable("plpgsql.print_strict_params",
 							 gettext_noop("Print information about parameters in the DETAIL part of the error messages generated on INTO ... STRICT failures."),
 							 NULL,
diff --git a/src/pl/plpgsql/src/pl_scanner.c b/src/pl/plpgsql/src/pl_scanner.c
index 683fdab..973cab8 100644
--- a/src/pl/plpgsql/src/pl_scanner.c
+++ b/src/pl/plpgsql/src/pl_scanner.c
@@ -107,6 +107,7 @@ static const ScanKeyword unreserved_keywords[] = {
 	PG_KEYWORD("constant", K_CONSTANT, UNRESERVED_KEYWORD)
 	PG_KEYWORD("constraint", K_CONSTRAINT, UNRESERVED_KEYWORD)
 	PG_KEYWORD("constraint_name", K_CONSTRAINT_NAME, UNRESERVED_KEYWORD)
+	PG_KEYWORD("context", K_CONTEXT, UNRESERVED_KEYWORD)
 	PG_KEYWORD("continue", K_CONTINUE, UNRESERVED_KEYWORD)
 	PG_KEYWORD("current", K_CURRENT, UNRESERVED_KEYWORD)
 	PG_KEYWORD("cursor", K_CURSOR, UNRESERVED_KEYWORD)
@@ -170,6 +171,8 @@ static const ScanKeyword unreserved_keywords[] = {
 	PG_KEYWORD("use_variable", K_USE_VARIABLE, UNRESERVED_KEYWORD)
 	PG_KEYWORD("variable_conflict", K_VARIABLE_CONFLICT, UNRESERVED_KEYWORD)
 	PG_KEYWORD("warning", K_WARNING, UNRESERVED_KEYWORD)
+	PG_KEYWORD("with", K_WITH, UNRESERVED_KEYWORD)
+	PG_KEYWORD("without", K_WITHOUT, UNRESERVED_KEYWORD)
 };
 
 static const int num_unreserved_keywords = lengthof(unreserved_keywords);
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index bec773a..73d3238 100644
--- a/src/pl/plpgsql/src/plpgsql.h
+++ b/src/pl/plpgsql/src/plpgsql.h
@@ -168,6 +168,18 @@ typedef enum
 } PLpgSQL_resolve_option;
 
 
+/* --------
+ * Manipulation with context of exception
+ * --------
+ */
+enum
+{
+	PLPGSQL_CONTEXT_DISPLAY,
+	PLPGSQL_CONTEXT_SUPPRESS,
+	PLPGSQL_CONTEXT_DEFAULT
+};
+
+
 /**********************************************************************
  * Node and structure definitions
  **********************************************************************/
@@ -619,6 +631,7 @@ typedef struct
 	int			cmd_type;
 	int			lineno;
 	int			elog_level;
+	int			context_info;
 	char	   *condname;		/* condition name, SQLSTATE, or NULL */
 	char	   *message;		/* old-style message format literal, or NULL */
 	List	   *params;			/* list of expressions for old-style message */
@@ -922,6 +935,10 @@ extern MemoryContext compile_tmp_cxt;
 
 extern PLpgSQL_plugin **plugin_ptr;
 
+#define PLPGSQL_DISPLAY_CONTEXT_SUPPRESS		0
+
+extern int plpgsql_display_context_min_messages;
+
 /**********************************************************************
  * Function declarations
  **********************************************************************/
diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out
index 78e5a85..b8dd2b1 100644
--- a/src/test/regress/expected/plpgsql.out
+++ b/src/test/regress/expected/plpgsql.out
@@ -5426,3 +5426,51 @@ end;
 $$;
 ERROR:  unhandled assertion
 CONTEXT:  PL/pgSQL function inline_code_block line 3 at ASSERT
+-- context is not displayed by default
+do $$
+begin
+  raise notice 'hello';
+end;
+$$;
+NOTICE:  hello
+do $$
+begin
+  raise exception 'hello';
+end;
+$$;
+ERROR:  hello
+--possibility to enforce context message displaying
+do $$
+begin
+  raise notice with context 'hello';
+end;
+$$;
+NOTICE:  hello
+CONTEXT:  PL/pgSQL function inline_code_block line 3 at RAISE
+do $$
+begin
+  raise exception with context 'hello';
+end;
+$$;
+ERROR:  hello
+CONTEXT:  PL/pgSQL function inline_code_block line 3 at RAISE
+set plpgsql.display_context_min_messages = 'notice';
+do $$
+begin
+  raise notice 'some notice';
+  raise exception 'some exception';
+end;
+$$;
+NOTICE:  some notice
+CONTEXT:  PL/pgSQL function inline_code_block line 3 at RAISE
+ERROR:  some exception
+CONTEXT:  PL/pgSQL function inline_code_block line 4 at RAISE
+-- possibility to suppress default
+do $$
+begin
+  raise notice without context 'some notice';
+  raise exception without context 'some exception';
+end;
+$$;
+NOTICE:  some notice
+ERROR:  some exception
diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql
index e19e415..725ce58 100644
--- a/src/test/regress/sql/plpgsql.sql
+++ b/src/test/regress/sql/plpgsql.sql
@@ -4265,3 +4265,47 @@ exception when others then
   null; -- do nothing
 end;
 $$;
+
+-- context is not displayed by default
+do $$
+begin
+  raise notice 'hello';
+end;
+$$;
+
+do $$
+begin
+  raise exception 'hello';
+end;
+$$;
+
+--possibility to enforce context message displaying
+do $$
+begin
+  raise notice with context 'hello';
+end;
+$$;
+
+do $$
+begin
+  raise exception with context 'hello';
+end;
+$$;
+
+set plpgsql.display_context_min_messages = 'notice';
+do $$
+begin
+  raise notice 'some notice';
+  raise exception 'some exception';
+end;
+$$;
+
+-- possibility to suppress default
+do $$
+begin
+  raise notice without context 'some notice';
+  raise exception without context 'some exception';
+end;
+$$;
+
+
#59Fabrízio de Royes Mello
fabriziomello@gmail.com
In reply to: Pavel Stehule (#56)
Re: PL/pgSQL, RAISE and error context

On Sun, Apr 26, 2015 at 4:19 AM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

Hi

I reduced this patch, little bit cleaned - now it is based on plpgsql GUC

display_context_min_messages - like client_min_messages, log_min_messages.

What you think just "context_min_messages" ?

Regards,

--
Fabrízio de Royes Mello
Consultoria/Coaching PostgreSQL

Show quoted text

Timbira: http://www.timbira.com.br
Blog: http://fabriziomello.github.io
Linkedin: http://br.linkedin.com/in/fabriziomello
Twitter: http://twitter.com/fabriziomello
Github: http://github.com/fabriziomello

#60Marko Tiikkaja
marko@joh.to
In reply to: Fabrízio de Royes Mello (#59)
Re: PL/pgSQL, RAISE and error context

On 4/27/15 6:08 PM, Fabrízio de Royes Mello wrote:

On Sun, Apr 26, 2015 at 4:19 AM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

I reduced this patch, little bit cleaned - now it is based on plpgsql GUC

display_context_min_messages - like client_min_messages, log_min_messages.

What you think just "context_min_messages" ?

That sounds weird. log_min_messages are the messages sent to the log;
client_min_messages are sent to the client. context_min_messages are
not sent to a "context", whatever that would mean.

.m

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#61Joel Jacobson
joel@trustly.com
In reply to: Marko Tiikkaja (#60)
Re: PL/pgSQL, RAISE and error context

On Mon, Apr 27, 2015 at 6:14 PM, Marko Tiikkaja <marko@joh.to> wrote:

That sounds weird. log_min_messages are the messages sent to the log;
client_min_messages are sent to the client. context_min_messages are not
sent to a "context", whatever that would mean.

Good point.

I think it can't be any clearer than the proposed
"plpgsql.display_context_min_messages"

#62Jim Nasby
Jim.Nasby@BlueTreble.com
In reply to: Joel Jacobson (#61)
Re: PL/pgSQL, RAISE and error context

On 4/27/15 11:47 AM, Joel Jacobson wrote:

On Mon, Apr 27, 2015 at 6:14 PM, Marko Tiikkaja <marko@joh.to
<mailto:marko@joh.to>> wrote:

That sounds weird. log_min_messages are the messages sent to the
log; client_min_messages are sent to the client.
context_min_messages are not sent to a "context", whatever that
would mean.

Good point.

I think it can't be any clearer than the proposed
"plpgsql.display_context_min_messages"

client_min_context. It's doing the same thing as min_messages does, just
for context instead of the message.

Or does this affect client and log the same way?
--
Jim Nasby, Data Architect, Blue Treble Consulting
Data in Trouble? Get it in Treble! http://BlueTreble.com

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#63Pavel Stehule
pavel.stehule@gmail.com
In reply to: Jim Nasby (#62)
Re: PL/pgSQL, RAISE and error context

2015-04-27 22:53 GMT+02:00 Jim Nasby <Jim.Nasby@bluetreble.com>:

On 4/27/15 11:47 AM, Joel Jacobson wrote:

On Mon, Apr 27, 2015 at 6:14 PM, Marko Tiikkaja <marko@joh.to
<mailto:marko@joh.to>> wrote:

That sounds weird. log_min_messages are the messages sent to the
log; client_min_messages are sent to the client.
context_min_messages are not sent to a "context", whatever that
would mean.

Good point.

I think it can't be any clearer than the proposed
"plpgsql.display_context_min_messages"

client_min_context. It's doing the same thing as min_messages does, just
for context instead of the message.

Or does this affect client and log the same way?

it affect client and log together

maybe "min_context"

Pavel

Show quoted text

--
Jim Nasby, Data Architect, Blue Treble Consulting
Data in Trouble? Get it in Treble! http://BlueTreble.com

#64Jim Nasby
Jim.Nasby@BlueTreble.com
In reply to: Pavel Stehule (#63)
Re: PL/pgSQL, RAISE and error context

On 4/28/15 1:16 AM, Pavel Stehule wrote:

I think it can't be any clearer than the proposed
"plpgsql.display_context_min_messages"

client_min_context. It's doing the same thing as min_messages does,
just for context instead of the message.

Or does this affect client and log the same way?

it affect client and log together

maybe "min_context"

+1
-- 
Jim Nasby, Data Architect, Blue Treble Consulting
Data in Trouble? Get it in Treble! http://BlueTreble.com

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#65Pavel Stehule
pavel.stehule@gmail.com
In reply to: Jim Nasby (#64)
1 attachment(s)
Re: PL/pgSQL, RAISE and error context

2015-04-28 19:44 GMT+02:00 Jim Nasby <Jim.Nasby@bluetreble.com>:

On 4/28/15 1:16 AM, Pavel Stehule wrote:

I think it can't be any clearer than the proposed
"plpgsql.display_context_min_messages"

client_min_context. It's doing the same thing as min_messages does,
just for context instead of the message.

Or does this affect client and log the same way?

it affect client and log together

maybe "min_context"

+1

third variant with GUC plpgsql.min_context

Regards

Pavel

Show quoted text

--
Jim Nasby, Data Architect, Blue Treble Consulting
Data in Trouble? Get it in Treble! http://BlueTreble.com

Attachments:

plpgsql-raise-context-03.patchtext/x-patch; charset=US-ASCII; name=plpgsql-raise-context-03.patchDownload
commit c2f49938f636864234d03994d2f64f8095392d11
Author: Pavel Stehule <pavel.stehule@gooddata.com>
Date:   Sat Apr 25 22:09:28 2015 +0200

    initial implementation of (WITH|WITHOUT) CONTEXT clause to plpgsql RAISE statement.
    
    initial implementation of plpgsql GUC plpgsql.min_context

diff --git a/doc/src/sgml/plpgsql.sgml b/doc/src/sgml/plpgsql.sgml
index d36acf6..ffc3eb8 100644
--- a/doc/src/sgml/plpgsql.sgml
+++ b/doc/src/sgml/plpgsql.sgml
@@ -3406,10 +3406,10 @@ END LOOP <optional> <replaceable>label</replaceable> </optional>;
     raise errors.
 
 <synopsis>
-RAISE <optional> <replaceable class="parameter">level</replaceable> </optional> '<replaceable class="parameter">format</replaceable>' <optional>, <replaceable class="parameter">expression</replaceable> <optional>, ... </optional></optional> <optional> USING <replaceable class="parameter">option</replaceable> = <replaceable class="parameter">expression</replaceable> <optional>, ... </optional> </optional>;
-RAISE <optional> <replaceable class="parameter">level</replaceable> </optional> <replaceable class="parameter">condition_name</> <optional> USING <replaceable class="parameter">option</replaceable> = <replaceable class="parameter">expression</replaceable> <optional>, ... </optional> </optional>;
-RAISE <optional> <replaceable class="parameter">level</replaceable> </optional> SQLSTATE '<replaceable class="parameter">sqlstate</>' <optional> USING <replaceable class="parameter">option</replaceable> = <replaceable class="parameter">expression</replaceable> <optional>, ... </optional> </optional>;
-RAISE <optional> <replaceable class="parameter">level</replaceable> </optional> USING <replaceable class="parameter">option</replaceable> = <replaceable class="parameter">expression</replaceable> <optional>, ... </optional>;
+RAISE <optional> <replaceable class="parameter">level</replaceable> </optional> <optional> ( WITH | WITHOUT ) CONTEXT </optional> '<replaceable class="parameter">format</replaceable>' <optional>, <replaceable class="parameter">expression</replaceable> <optional>, ... </optional></optional> <optional> USING <replaceable class="parameter">option</replaceable> = <replaceable class="parameter">expression</replaceable> <optional>, ... </optional> </optional>;
+RAISE <optional> <replaceable class="parameter">level</replaceable> </optional> <optional> ( WITH | WITHOUT ) CONTEXT </optional> <replaceable class="parameter">condition_name</> <optional> USING <replaceable class="parameter">option</replaceable> = <replaceable class="parameter">expression</replaceable> <optional>, ... </optional> </optional>;
+RAISE <optional> <replaceable class="parameter">level</replaceable> </optional> <optional> ( WITH | WITHOUT ) CONTEXT </optional> SQLSTATE '<replaceable class="parameter">sqlstate</>' <optional> USING <replaceable class="parameter">option</replaceable> = <replaceable class="parameter">expression</replaceable> <optional>, ... </optional> </optional>;
+RAISE <optional> <replaceable class="parameter">level</replaceable> </optional> <optional> ( WITH | WITHOUT ) CONTEXT </optional> USING <replaceable class="parameter">option</replaceable> = <replaceable class="parameter">expression</replaceable> <optional>, ... </optional>;
 RAISE ;
 </synopsis>
 
@@ -3431,6 +3431,18 @@ RAISE ;
    </para>
 
    <para>
+    The options <literal>WITH CONTEXT</literal> or <literal>WITHOUT CONTEXT</literal>
+    can enforce or suppress context information related to error or notice. This possibility
+    can be forced by settings of configuration parameter <literal>plpgsql.min_context</>.
+    This allows same values like <replaceable class="parameter">level</replaceable> option plus
+    value <literal>none</literal> that is a default. When it is changed, then all errors and notices
+    with higher than specified severity are raised with context info.
+<programlisting>
+RAISE NOTICE WITH CONTEXT 'This message will have a context';
+</programlisting>
+   </para>
+
+   <para>
     After <replaceable class="parameter">level</replaceable> if any,
     you can write a <replaceable class="parameter">format</replaceable>
     (which must be a simple string literal, not an expression).  The
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index deefb1f..eaee5a7 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -2921,6 +2921,7 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
 	char	   *err_table = NULL;
 	char	   *err_schema = NULL;
 	ListCell   *lc;
+	bool			hide_ctx = true;		/* suppress context by default */
 
 	/* RAISE with no parameters: re-throw current exception */
 	if (stmt->condname == NULL && stmt->message == NULL &&
@@ -3080,10 +3081,16 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
 			err_message = pstrdup(unpack_sql_state(err_code));
 	}
 
-	/*
-	 * Throw the error (may or may not come back)
-	 */
-	estate->err_text = raise_skip_msg;	/* suppress traceback of raise */
+	if (stmt->context_info == PLPGSQL_CONTEXT_DISPLAY)
+		hide_ctx = false;
+	else if (stmt->context_info == PLPGSQL_CONTEXT_DEFAULT)
+	{
+		if (plpgsql_min_context != PLPGSQL_MIN_CONTEXT_SUPPRESS)
+			hide_ctx = stmt->elog_level < plpgsql_min_context;
+	}
+
+	if (hide_ctx)
+		estate->err_text = raise_skip_msg;
 
 	ereport(stmt->elog_level,
 			(err_code ? errcode(err_code) : 0,
@@ -3099,7 +3106,8 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
 			 (err_table != NULL) ?
 			 err_generic_string(PG_DIAG_TABLE_NAME, err_table) : 0,
 			 (err_schema != NULL) ?
-			 err_generic_string(PG_DIAG_SCHEMA_NAME, err_schema) : 0));
+			 err_generic_string(PG_DIAG_SCHEMA_NAME, err_schema) : 0,
+			 errhidecontext(hide_ctx)));
 
 	estate->err_text = NULL;	/* un-suppress... */
 
diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y
index 4026e41..48914a7 100644
--- a/src/pl/plpgsql/src/pl_gram.y
+++ b/src/pl/plpgsql/src/pl_gram.y
@@ -259,6 +259,7 @@ static	void			check_raise_parameters(PLpgSQL_stmt_raise *stmt);
 %token <keyword>	K_CONSTANT
 %token <keyword>	K_CONSTRAINT
 %token <keyword>	K_CONSTRAINT_NAME
+%token <keyword>	K_CONTEXT
 %token <keyword>	K_CONTINUE
 %token <keyword>	K_CURRENT
 %token <keyword>	K_CURSOR
@@ -341,6 +342,8 @@ static	void			check_raise_parameters(PLpgSQL_stmt_raise *stmt);
 %token <keyword>	K_WARNING
 %token <keyword>	K_WHEN
 %token <keyword>	K_WHILE
+%token <keyword>	K_WITH
+%token <keyword>	K_WITHOUT
 
 %%
 
@@ -1716,6 +1719,7 @@ stmt_raise		: K_RAISE
 						new->cmd_type	= PLPGSQL_STMT_RAISE;
 						new->lineno		= plpgsql_location_to_lineno(@1);
 						new->elog_level = ERROR;	/* default */
+						new->context_info = PLPGSQL_CONTEXT_DEFAULT;
 						new->condname	= NULL;
 						new->message	= NULL;
 						new->params		= NIL;
@@ -1773,6 +1777,21 @@ stmt_raise		: K_RAISE
 							if (tok == 0)
 								yyerror("unexpected end of function definition");
 
+							/* Optional choose about including context */
+							if (tok == K_WITH || tok == K_WITHOUT)
+							{
+								if (tok == K_WITH)
+									new->context_info = PLPGSQL_CONTEXT_DISPLAY;
+								else
+									new->context_info = PLPGSQL_CONTEXT_SUPPRESS;
+							
+								/* keyword CONTEXT is required */
+								if (yylex() != K_CONTEXT)
+									yyerror("expected CONTEXT");
+
+								tok = yylex();
+							}
+
 							/*
 							 * Next we can have a condition name, or
 							 * equivalently SQLSTATE 'xxxxx', or a string
@@ -2350,6 +2369,7 @@ unreserved_keyword	:
 				| K_CONSTANT
 				| K_CONSTRAINT
 				| K_CONSTRAINT_NAME
+				| K_CONTEXT
 				| K_CONTINUE
 				| K_CURRENT
 				| K_CURSOR
@@ -2412,6 +2432,8 @@ unreserved_keyword	:
 				| K_USE_VARIABLE
 				| K_VARIABLE_CONFLICT
 				| K_WARNING
+				| K_WITH
+				| K_WITHOUT
 				;
 
 %%
diff --git a/src/pl/plpgsql/src/pl_handler.c b/src/pl/plpgsql/src/pl_handler.c
index 266c314..2d05cf6 100644
--- a/src/pl/plpgsql/src/pl_handler.c
+++ b/src/pl/plpgsql/src/pl_handler.c
@@ -40,6 +40,17 @@ static const struct config_enum_entry variable_conflict_options[] = {
 	{NULL, 0, false}
 };
 
+static const struct config_enum_entry min_context_options[] = {
+	{"none", PLPGSQL_MIN_CONTEXT_SUPPRESS},
+	{"exception", ERROR},
+	{"warning", WARNING},
+	{"notice", NOTICE},
+	{"info", INFO},
+	{"log", LOG},
+	{"debug", DEBUG1},
+	{NULL, 0, false}
+};
+
 int			plpgsql_variable_conflict = PLPGSQL_RESOLVE_ERROR;
 
 bool		plpgsql_print_strict_params = false;
@@ -51,6 +62,8 @@ char	   *plpgsql_extra_errors_string = NULL;
 int			plpgsql_extra_warnings;
 int			plpgsql_extra_errors;
 
+int			plpgsql_min_context = PLPGSQL_MIN_CONTEXT_SUPPRESS;
+
 /* Hook for plugins */
 PLpgSQL_plugin **plugin_ptr = NULL;
 
@@ -154,6 +167,15 @@ _PG_init(void)
 							 PGC_SUSET, 0,
 							 NULL, NULL, NULL);
 
+	DefineCustomEnumVariable("plpgsql.min_context",
+							 gettext_noop("Sets minimal level of messages with context information."),
+							 NULL,
+							 &plpgsql_min_context,
+							 PLPGSQL_MIN_CONTEXT_SUPPRESS,
+							 min_context_options,
+							 PGC_SUSET, 0,
+							 NULL, NULL, NULL);
+
 	DefineCustomBoolVariable("plpgsql.print_strict_params",
 							 gettext_noop("Print information about parameters in the DETAIL part of the error messages generated on INTO ... STRICT failures."),
 							 NULL,
diff --git a/src/pl/plpgsql/src/pl_scanner.c b/src/pl/plpgsql/src/pl_scanner.c
index 683fdab..973cab8 100644
--- a/src/pl/plpgsql/src/pl_scanner.c
+++ b/src/pl/plpgsql/src/pl_scanner.c
@@ -107,6 +107,7 @@ static const ScanKeyword unreserved_keywords[] = {
 	PG_KEYWORD("constant", K_CONSTANT, UNRESERVED_KEYWORD)
 	PG_KEYWORD("constraint", K_CONSTRAINT, UNRESERVED_KEYWORD)
 	PG_KEYWORD("constraint_name", K_CONSTRAINT_NAME, UNRESERVED_KEYWORD)
+	PG_KEYWORD("context", K_CONTEXT, UNRESERVED_KEYWORD)
 	PG_KEYWORD("continue", K_CONTINUE, UNRESERVED_KEYWORD)
 	PG_KEYWORD("current", K_CURRENT, UNRESERVED_KEYWORD)
 	PG_KEYWORD("cursor", K_CURSOR, UNRESERVED_KEYWORD)
@@ -170,6 +171,8 @@ static const ScanKeyword unreserved_keywords[] = {
 	PG_KEYWORD("use_variable", K_USE_VARIABLE, UNRESERVED_KEYWORD)
 	PG_KEYWORD("variable_conflict", K_VARIABLE_CONFLICT, UNRESERVED_KEYWORD)
 	PG_KEYWORD("warning", K_WARNING, UNRESERVED_KEYWORD)
+	PG_KEYWORD("with", K_WITH, UNRESERVED_KEYWORD)
+	PG_KEYWORD("without", K_WITHOUT, UNRESERVED_KEYWORD)
 };
 
 static const int num_unreserved_keywords = lengthof(unreserved_keywords);
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index bec773a..269fec3 100644
--- a/src/pl/plpgsql/src/plpgsql.h
+++ b/src/pl/plpgsql/src/plpgsql.h
@@ -168,6 +168,18 @@ typedef enum
 } PLpgSQL_resolve_option;
 
 
+/* --------
+ * Manipulation with context of exception
+ * --------
+ */
+enum
+{
+	PLPGSQL_CONTEXT_DISPLAY,
+	PLPGSQL_CONTEXT_SUPPRESS,
+	PLPGSQL_CONTEXT_DEFAULT
+};
+
+
 /**********************************************************************
  * Node and structure definitions
  **********************************************************************/
@@ -619,6 +631,7 @@ typedef struct
 	int			cmd_type;
 	int			lineno;
 	int			elog_level;
+	int			context_info;
 	char	   *condname;		/* condition name, SQLSTATE, or NULL */
 	char	   *message;		/* old-style message format literal, or NULL */
 	List	   *params;			/* list of expressions for old-style message */
@@ -922,6 +935,10 @@ extern MemoryContext compile_tmp_cxt;
 
 extern PLpgSQL_plugin **plugin_ptr;
 
+#define PLPGSQL_MIN_CONTEXT_SUPPRESS		0
+
+extern int plpgsql_min_context;
+
 /**********************************************************************
  * Function declarations
  **********************************************************************/
diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out
index 78e5a85..4f74f9f 100644
--- a/src/test/regress/expected/plpgsql.out
+++ b/src/test/regress/expected/plpgsql.out
@@ -5426,3 +5426,51 @@ end;
 $$;
 ERROR:  unhandled assertion
 CONTEXT:  PL/pgSQL function inline_code_block line 3 at ASSERT
+-- context is not displayed by default
+do $$
+begin
+  raise notice 'hello';
+end;
+$$;
+NOTICE:  hello
+do $$
+begin
+  raise exception 'hello';
+end;
+$$;
+ERROR:  hello
+--possibility to enforce context message displaying
+do $$
+begin
+  raise notice with context 'hello';
+end;
+$$;
+NOTICE:  hello
+CONTEXT:  PL/pgSQL function inline_code_block line 3 at RAISE
+do $$
+begin
+  raise exception with context 'hello';
+end;
+$$;
+ERROR:  hello
+CONTEXT:  PL/pgSQL function inline_code_block line 3 at RAISE
+set plpgsql.min_context = 'notice';
+do $$
+begin
+  raise notice 'some notice';
+  raise exception 'some exception';
+end;
+$$;
+NOTICE:  some notice
+CONTEXT:  PL/pgSQL function inline_code_block line 3 at RAISE
+ERROR:  some exception
+CONTEXT:  PL/pgSQL function inline_code_block line 4 at RAISE
+-- possibility to suppress default
+do $$
+begin
+  raise notice without context 'some notice';
+  raise exception without context 'some exception';
+end;
+$$;
+NOTICE:  some notice
+ERROR:  some exception
diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql
index e19e415..e23a74a 100644
--- a/src/test/regress/sql/plpgsql.sql
+++ b/src/test/regress/sql/plpgsql.sql
@@ -4265,3 +4265,47 @@ exception when others then
   null; -- do nothing
 end;
 $$;
+
+-- context is not displayed by default
+do $$
+begin
+  raise notice 'hello';
+end;
+$$;
+
+do $$
+begin
+  raise exception 'hello';
+end;
+$$;
+
+--possibility to enforce context message displaying
+do $$
+begin
+  raise notice with context 'hello';
+end;
+$$;
+
+do $$
+begin
+  raise exception with context 'hello';
+end;
+$$;
+
+set plpgsql.min_context = 'notice';
+do $$
+begin
+  raise notice 'some notice';
+  raise exception 'some exception';
+end;
+$$;
+
+-- possibility to suppress default
+do $$
+begin
+  raise notice without context 'some notice';
+  raise exception without context 'some exception';
+end;
+$$;
+
+
#66Marko Tiikkaja
marko@joh.to
In reply to: Pavel Stehule (#65)
Re: PL/pgSQL, RAISE and error context

Hi Pavel,

This doesn't seem to be what I thought we had agreed on. For example:

=# create function barf() returns void as $$ begin raise notice without
context 'hello world'; end $$ language plpgsql;
CREATE FUNCTION
=# create function foof() returns void as $$ begin perform barf(); end
$$ language plpgsql;
CREATE FUNCTION
=# select foof();
NOTICE: hello world
CONTEXT: SQL statement "SELECT barf()"
PL/pgSQL function foof() line 1 at PERFORM

It's not only clear that WITHOUT CONTEXT didn't really work here, but it
also had absolutely no effect since the context within barf() is also
displayed.

.m

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#67Pavel Stehule
pavel.stehule@gmail.com
In reply to: Marko Tiikkaja (#66)
Re: PL/pgSQL, RAISE and error context

2015-04-30 10:24 GMT+02:00 Marko Tiikkaja <marko@joh.to>:

Hi Pavel,

This doesn't seem to be what I thought we had agreed on. For example:

=# create function barf() returns void as $$ begin raise notice without
context 'hello world'; end $$ language plpgsql;
CREATE FUNCTION
=# create function foof() returns void as $$ begin perform barf(); end $$
language plpgsql;
CREATE FUNCTION
=# select foof();
NOTICE: hello world
CONTEXT: SQL statement "SELECT barf()"
PL/pgSQL function foof() line 1 at PERFORM

It's not only clear that WITHOUT CONTEXT didn't really work here, but it
also had absolutely no effect since the context within barf() is also
displayed.

It doesn't look well - because it should be solve by errhidecontext(true)

yes, there is a issue in send_message_to_frontend - this ignore
edata->hide_ctx field. After fixing, it working as expected - so this is a
bug in implementation of errhidecontext()

should be

if (edata->context && !edata->hide_ctx)
{
pq_sendbyte(&msgbuf, PG_DIAG_CONTEXT);
err_sendstring(&msgbuf, edata->context);
}

and probably getting stack in err_finish should be fixed too:

if (!edata->hide_ctx)
for (econtext = error_context_stack;
econtext != NULL;
econtext = econtext->previous)
(*econtext->callback) (econtext->arg);

Regards

Pavel

I'll look on this issue.

Regards

Pavel

Show quoted text

.m

#68Pavel Stehule
pavel.stehule@gmail.com
In reply to: Pavel Stehule (#67)
Re: PL/pgSQL, RAISE and error context

2015-04-30 10:50 GMT+02:00 Pavel Stehule <pavel.stehule@gmail.com>:

2015-04-30 10:24 GMT+02:00 Marko Tiikkaja <marko@joh.to>:

Hi Pavel,

This doesn't seem to be what I thought we had agreed on. For example:

=# create function barf() returns void as $$ begin raise notice without
context 'hello world'; end $$ language plpgsql;
CREATE FUNCTION
=# create function foof() returns void as $$ begin perform barf(); end $$
language plpgsql;
CREATE FUNCTION
=# select foof();
NOTICE: hello world
CONTEXT: SQL statement "SELECT barf()"
PL/pgSQL function foof() line 1 at PERFORM

It's not only clear that WITHOUT CONTEXT didn't really work here, but it
also had absolutely no effect since the context within barf() is also
displayed.

It doesn't look well - because it should be solve by errhidecontext(true)

yes, there is a issue in send_message_to_frontend - this ignore
edata->hide_ctx field. After fixing, it working as expected - so this is a
bug in implementation of errhidecontext()

should be

if (edata->context && !edata->hide_ctx)
{
pq_sendbyte(&msgbuf, PG_DIAG_CONTEXT);
err_sendstring(&msgbuf, edata->context);
}

and probably getting stack in err_finish should be fixed too:

if (!edata->hide_ctx)
for (econtext = error_context_stack;
econtext != NULL;
econtext = econtext->previous)
(*econtext->callback) (econtext->arg);

Regards

Pavel

I am sending patch

Show quoted text

I'll look on this issue.

Regards

Pavel

.m

#69Heikki Linnakangas
hlinnaka@iki.fi
In reply to: Tom Lane (#36)
1 attachment(s)
Re: PL/pgSQL, RAISE and error context

On 01/26/2015 05:14 PM, Tom Lane wrote:

Pavel Stehule <pavel.stehule@gmail.com> writes:

2015-01-26 14:02 GMT+01:00 Marko Tiikkaja <marko@joh.to>:
I am thinking, so solution

/* if we are doing RAISE, don't report its location */
if (estate->err_text == raise_skip_msg)
return;

is too simple, and this part should be fixed. This change can be done by on
plpgsql or libpq side. This is bug, and it should be fixed.

Doing this in libpq is utterly insane. It has not got sufficient context
to do anything intelligent. The fact that it's not intelligent is exposed
by the regression test changes that the proposed patch causes, most of
which do not look like improvements.

I think doing this in libpq (or psql) is the way to go. How can the
server know if the client wants to display context information? We just
have to make sure the client has enough information to make a smart
decision. If the client doesn't have enough information today, then
let's work on that.

Note that Marko's patch didn't change libpq's default printing mode,
which is why you got all the extra CONTEXT lines in the regression tests
that were not there before. Just as if we just removed the suppression
from PL/pgSQL and did nothing else. I think we need to also change the
default behaviour to not print CONTEXT lines for NOTICE-level messages,
getting us closer to the current behaviour again.

If you run the regression tests in the "compact" verbosity, the
regression test output changes look quite sensible to me. See attached.

Another problem is that past requests to change this behavior have
generally been to the effect that people wanted *more* context suppressed
not less, ie they didn't want any CONTEXT lines at all on certain
messages. So the proposed patch seems to me to be going in exactly the
wrong direction.

After changing the default to "compact", it prints less CONTEXT lines.

The design I thought had been agreed on was to add some new option to
plpgsql's RAISE command which would cause suppression of all CONTEXT lines
not just the most closely nested one.

I don't understand how you came to that conclusion. In particular, see
/messages/by-id/6656.1377100039@sss.pgh.pa.us. If
you changed your mind, you forgot to tell why.

- Heikki

Attachments:

regression.diffstext/plain; charset=UTF-8; name=regression.diffsDownload
*** /home/heikki/git-sandbox-pgsql/master/src/test/regress/expected/triggers.out	2015-07-07 15:40:38.697861317 +0300
--- /home/heikki/git-sandbox-pgsql/master/src/test/regress/results/triggers.out	2015-07-07 15:50:34.885805473 +0300
***************
*** 958,968 ****
  NOTICE:  main_view INSTEAD OF INSERT ROW (instead_of_ins)
  NOTICE:  NEW: (20,30)
  NOTICE:  trigger_func(before_ins_stmt) called: action = INSERT, when = BEFORE, level = STATEMENT
- CONTEXT:  SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
- PL/pgSQL function view_trigger() line 17 at SQL statement
  NOTICE:  trigger_func(after_ins_stmt) called: action = INSERT, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
- PL/pgSQL function view_trigger() line 17 at SQL statement
  NOTICE:  main_view AFTER INSERT STATEMENT (after_view_ins_stmt)
  INSERT 0 1
  INSERT INTO main_view VALUES (21, 31) RETURNING a, b;
--- 958,964 ----
***************
*** 970,980 ****
  NOTICE:  main_view INSTEAD OF INSERT ROW (instead_of_ins)
  NOTICE:  NEW: (21,31)
  NOTICE:  trigger_func(before_ins_stmt) called: action = INSERT, when = BEFORE, level = STATEMENT
- CONTEXT:  SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
- PL/pgSQL function view_trigger() line 17 at SQL statement
  NOTICE:  trigger_func(after_ins_stmt) called: action = INSERT, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
- PL/pgSQL function view_trigger() line 17 at SQL statement
  NOTICE:  main_view AFTER INSERT STATEMENT (after_view_ins_stmt)
   a  | b  
  ----+----
--- 966,972 ----
***************
*** 988,1004 ****
  NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
  NOTICE:  OLD: (20,30), NEW: (20,31)
  NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
  UPDATE 0
  UPDATE main_view SET b = 32 WHERE a = 21 AND b = 31 RETURNING a, b;
--- 980,988 ----
***************
*** 1006,1022 ****
  NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
  NOTICE:  OLD: (21,31), NEW: (21,32)
  NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
   a | b 
  ---+---
--- 990,998 ----
***************
*** 1031,1050 ****
  NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
  NOTICE:  OLD: (20,30), NEW: (20,31)
  NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
  UPDATE 1
  UPDATE main_view SET b = 32 WHERE a = 21 AND b = 31 RETURNING a, b;
--- 1007,1016 ----
***************
*** 1052,1071 ****
  NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
  NOTICE:  OLD: (21,31), NEW: (21,32)
  NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
   a  | b  
  ----+----
--- 1018,1027 ----
***************
*** 1277,1282 ****
--- 1233,1239 ----
  -- UPDATE .. RETURNING
  UPDATE city_view SET country_name = 'Japon' WHERE city_name = 'Tokyo'; -- error
  ERROR:  No such country: "Japon"
+ CONTEXT:  PL/pgSQL function city_update() line 9 at RAISE
  UPDATE city_view SET country_name = 'Japan' WHERE city_name = 'Takyo'; -- no match
  UPDATE 0
  UPDATE city_view SET country_name = 'Japan' WHERE city_name = 'Tokyo' RETURNING *; -- OK
***************
*** 1489,1514 ****
  insert into depth_a values (1);
  NOTICE:  depth_a_tr: depth = 1
  NOTICE:  depth_b_tr: depth = 2
- CONTEXT:  SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_c_tr: depth = 3
- CONTEXT:  SQL statement "insert into depth_c values (1)"
- PL/pgSQL function depth_b_tf() line 5 at EXECUTE statement
- SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  SQLSTATE = U9999: depth = 2
- CONTEXT:  SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_b_tr: depth = 2
- CONTEXT:  SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_c_tr: depth = 3
- CONTEXT:  SQL statement "insert into depth_c values (1)"
- PL/pgSQL function depth_b_tf() line 12 at EXECUTE statement
- SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  ERROR:  U9999
! CONTEXT:  SQL statement "insert into depth_c values (1)"
  PL/pgSQL function depth_b_tf() line 12 at EXECUTE statement
  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
--- 1446,1458 ----
  insert into depth_a values (1);
  NOTICE:  depth_a_tr: depth = 1
  NOTICE:  depth_b_tr: depth = 2
  NOTICE:  depth_c_tr: depth = 3
  NOTICE:  SQLSTATE = U9999: depth = 2
  NOTICE:  depth_b_tr: depth = 2
  NOTICE:  depth_c_tr: depth = 3
  ERROR:  U9999
! CONTEXT:  PL/pgSQL function depth_c_tf() line 5 at RAISE
! SQL statement "insert into depth_c values (1)"
  PL/pgSQL function depth_b_tf() line 12 at EXECUTE statement
  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
***************
*** 1521,1541 ****
  insert into depth_a values (2);
  NOTICE:  depth_a_tr: depth = 1
  NOTICE:  depth_b_tr: depth = 2
- CONTEXT:  SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_c_tr: depth = 3
- CONTEXT:  SQL statement "insert into depth_c values (2)"
- PL/pgSQL function depth_b_tf() line 5 at EXECUTE statement
- SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_c_tr: depth = 3
- CONTEXT:  SQL statement "insert into depth_c values (2)"
- PL/pgSQL function depth_b_tf() line 5 at EXECUTE statement
- SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_b_tr: depth = 2
- CONTEXT:  SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_a_tr: depth = 1
  select pg_trigger_depth();
   pg_trigger_depth 
--- 1465,1473 ----

======================================================================

*** /home/heikki/git-sandbox-pgsql/master/src/test/regress/expected/privileges.out	2015-07-07 15:40:38.689861374 +0300
--- /home/heikki/git-sandbox-pgsql/master/src/test/regress/results/privileges.out	2015-07-07 15:50:39.833771884 +0300
***************
*** 1023,1029 ****
  ERROR:  must have admin option on role "regressgroup2"
  SELECT dogrant_ok();			-- ok: SECURITY DEFINER conveys ADMIN
  NOTICE:  role "regressuser5" is already a member of role "regressgroup2"
- CONTEXT:  SQL function "dogrant_ok" statement 1
   dogrant_ok 
  ------------
   
--- 1023,1028 ----

======================================================================

*** /home/heikki/git-sandbox-pgsql/master/src/test/regress/expected/plancache.out	2015-07-07 15:40:38.689861374 +0300
--- /home/heikki/git-sandbox-pgsql/master/src/test/regress/results/plancache.out	2015-07-07 15:50:42.433754234 +0300
***************
*** 234,241 ****
  end$$ language plpgsql;
  select cachebug();
  NOTICE:  table "temptable" does not exist, skipping
- CONTEXT:  SQL statement "drop table if exists temptable cascade"
- PL/pgSQL function cachebug() line 4 at SQL statement
  NOTICE:  1
  NOTICE:  2
  NOTICE:  3
--- 234,239 ----
***************
*** 246,253 ****
  
  select cachebug();
  NOTICE:  drop cascades to view vv
- CONTEXT:  SQL statement "drop table if exists temptable cascade"
- PL/pgSQL function cachebug() line 4 at SQL statement
  NOTICE:  1
  NOTICE:  2
  NOTICE:  3
--- 244,249 ----

======================================================================

*** /home/heikki/git-sandbox-pgsql/master/src/test/regress/expected/plpgsql.out	2015-07-07 15:40:38.689861374 +0300
--- /home/heikki/git-sandbox-pgsql/master/src/test/regress/results/plpgsql.out	2015-07-07 15:50:45.549733081 +0300
***************
*** 1518,1544 ****
  DETAIL:  Key (name)=(PF1_1) already exists.
  update PSlot set backlink = 'WS.not.there' where slotname = 'PS.base.a1';
  ERROR:  WS.not.there         does not exist
! CONTEXT:  PL/pgSQL function tg_backlink_a() line 17 at assignment
  update PSlot set backlink = 'XX.illegal' where slotname = 'PS.base.a1';
  ERROR:  illegal backlink beginning with XX
! CONTEXT:  PL/pgSQL function tg_backlink_a() line 17 at assignment
  update PSlot set slotlink = 'PS.not.there' where slotname = 'PS.base.a1';
  ERROR:  PS.not.there         does not exist
! CONTEXT:  PL/pgSQL function tg_slotlink_a() line 17 at assignment
  update PSlot set slotlink = 'XX.illegal' where slotname = 'PS.base.a1';
  ERROR:  illegal slotlink beginning with XX
! CONTEXT:  PL/pgSQL function tg_slotlink_a() line 17 at assignment
  insert into HSlot values ('HS', 'base.hub1', 1, '');
  ERROR:  duplicate key value violates unique constraint "hslot_name"
  DETAIL:  Key (slotname)=(HS.base.hub1.1      ) already exists.
  insert into HSlot values ('HS', 'base.hub1', 20, '');
  ERROR:  no manual manipulation of HSlot
  delete from HSlot;
  ERROR:  no manual manipulation of HSlot
  insert into IFace values ('IF', 'notthere', 'eth0', '');
  ERROR:  system "notthere" does not exist
  insert into IFace values ('IF', 'orion', 'ethernet_interface_name_too_long', '');
  ERROR:  IFace slotname "IF.orion.ethernet_interface_name_too_long" too long (20 char max)
  --
  -- The following tests are unrelated to the scenario outlined above;
  -- they merely exercise specific parts of PL/pgSQL
--- 1518,1552 ----
  DETAIL:  Key (name)=(PF1_1) already exists.
  update PSlot set backlink = 'WS.not.there' where slotname = 'PS.base.a1';
  ERROR:  WS.not.there         does not exist
! CONTEXT:  PL/pgSQL function tg_backlink_set(character,character) line 30 at RAISE
! PL/pgSQL function tg_backlink_a() line 17 at assignment
  update PSlot set backlink = 'XX.illegal' where slotname = 'PS.base.a1';
  ERROR:  illegal backlink beginning with XX
! CONTEXT:  PL/pgSQL function tg_backlink_set(character,character) line 47 at RAISE
! PL/pgSQL function tg_backlink_a() line 17 at assignment
  update PSlot set slotlink = 'PS.not.there' where slotname = 'PS.base.a1';
  ERROR:  PS.not.there         does not exist
! CONTEXT:  PL/pgSQL function tg_slotlink_set(character,character) line 30 at RAISE
! PL/pgSQL function tg_slotlink_a() line 17 at assignment
  update PSlot set slotlink = 'XX.illegal' where slotname = 'PS.base.a1';
  ERROR:  illegal slotlink beginning with XX
! CONTEXT:  PL/pgSQL function tg_slotlink_set(character,character) line 77 at RAISE
! PL/pgSQL function tg_slotlink_a() line 17 at assignment
  insert into HSlot values ('HS', 'base.hub1', 1, '');
  ERROR:  duplicate key value violates unique constraint "hslot_name"
  DETAIL:  Key (slotname)=(HS.base.hub1.1      ) already exists.
  insert into HSlot values ('HS', 'base.hub1', 20, '');
  ERROR:  no manual manipulation of HSlot
+ CONTEXT:  PL/pgSQL function tg_hslot_biu() line 12 at RAISE
  delete from HSlot;
  ERROR:  no manual manipulation of HSlot
+ CONTEXT:  PL/pgSQL function tg_hslot_bd() line 12 at RAISE
  insert into IFace values ('IF', 'notthere', 'eth0', '');
  ERROR:  system "notthere" does not exist
+ CONTEXT:  PL/pgSQL function tg_iface_biu() line 8 at RAISE
  insert into IFace values ('IF', 'orion', 'ethernet_interface_name_too_long', '');
  ERROR:  IFace slotname "IF.orion.ethernet_interface_name_too_long" too long (20 char max)
+ CONTEXT:  PL/pgSQL function tg_iface_biu() line 14 at RAISE
  --
  -- The following tests are unrelated to the scenario outlined above;
  -- they merely exercise specific parts of PL/pgSQL
***************
*** 1963,1968 ****
--- 1971,1977 ----
  NOTICE:  should see this only if -100 <> 0
  NOTICE:  should see this only if -100 fits in smallint
  ERROR:  -100 is less than zero
+ CONTEXT:  PL/pgSQL function trap_zero_divide(integer) line 12 at RAISE
  create function trap_matching_test(int) returns int as $$
  declare x int;
  	sx smallint;
***************
*** 2066,2079 ****
  end$$ language plpgsql;
  select test_variable_storage();
  NOTICE:  should see this
- CONTEXT:  SQL statement "SELECT trap_zero_divide(-100)"
- PL/pgSQL function test_variable_storage() line 8 at PERFORM
  NOTICE:  should see this only if -100 <> 0
- CONTEXT:  SQL statement "SELECT trap_zero_divide(-100)"
- PL/pgSQL function test_variable_storage() line 8 at PERFORM
  NOTICE:  should see this only if -100 fits in smallint
- CONTEXT:  SQL statement "SELECT trap_zero_divide(-100)"
- PL/pgSQL function test_variable_storage() line 8 at PERFORM
   test_variable_storage 
  -----------------------
   123456789012
--- 2075,2082 ----
***************
*** 4052,4057 ****
--- 4055,4061 ----
  HINT:  some hint
  ERROR:  1 2 3
  DETAIL:  some detail info
+ CONTEXT:  PL/pgSQL function raise_test() line 5 at RAISE
  -- Since we can't actually see the thrown SQLSTATE in default psql output,
  -- test it like this; this also tests re-RAISE
  create or replace function raise_test() returns void as $$
***************
*** 4068,4073 ****
--- 4072,4078 ----
  NOTICE:  SQLSTATE: 22012 SQLERRM: check me
  ERROR:  check me
  DETAIL:  some detail info
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise 'check me'
***************
*** 4082,4087 ****
--- 4087,4093 ----
  NOTICE:  SQLSTATE: 1234F SQLERRM: check me
  ERROR:  check me
  DETAIL:  some detail info
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  -- SQLSTATE specification in WHEN
  create or replace function raise_test() returns void as $$
  begin
***************
*** 4097,4102 ****
--- 4103,4109 ----
  NOTICE:  SQLSTATE: 1234F SQLERRM: check me
  ERROR:  check me
  DETAIL:  some detail info
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise division_by_zero using detail = 'some detail info';
***************
*** 4110,4115 ****
--- 4117,4123 ----
  NOTICE:  SQLSTATE: 22012 SQLERRM: division_by_zero
  ERROR:  division_by_zero
  DETAIL:  some detail info
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise division_by_zero;
***************
*** 4117,4122 ****
--- 4125,4131 ----
  $$ language plpgsql;
  select raise_test();
  ERROR:  division_by_zero
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise sqlstate '1234F';
***************
*** 4124,4129 ****
--- 4133,4139 ----
  $$ language plpgsql;
  select raise_test();
  ERROR:  1234F
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise division_by_zero using message = 'custom' || ' message';
***************
*** 4131,4136 ****
--- 4141,4147 ----
  $$ language plpgsql;
  select raise_test();
  ERROR:  custom message
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise using message = 'custom' || ' message', errcode = '22012';
***************
*** 4138,4143 ****
--- 4149,4155 ----
  $$ language plpgsql;
  select raise_test();
  ERROR:  custom message
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  -- conflict on message
  create or replace function raise_test() returns void as $$
  begin
***************
*** 4254,4259 ****
--- 4266,4272 ----
  select raise_test();
  NOTICE:  22012
  ERROR:  substitute message
+ CONTEXT:  PL/pgSQL function raise_test() line 7 at RAISE
  drop function raise_test();
  -- test passing column_name, constraint_name, datatype_name, table_name
  -- and schema_name error fields
***************
*** 4744,4750 ****
                 ^
  HINT:  Use the escape string syntax for backslashes, e.g., E'\\'.
  QUERY:  SELECT 'foo\\bar\041baz'
- CONTEXT:  PL/pgSQL function strtest() line 4 at RETURN
     strtest   
  -------------
   foo\bar!baz
--- 4757,4762 ----
***************
*** 5260,5281 ****
  select outer_outer_func(10);
  NOTICE:  calling down into outer_func()
  NOTICE:  calling down into inner_func()
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 4 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 7 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  lets make sure we didnt break anything
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  inner_func() done
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  outer_func() done
   outer_outer_func 
  ------------------
--- 5272,5285 ----
***************
*** 5286,5307 ****
  select outer_outer_func(20);
  NOTICE:  calling down into outer_func()
  NOTICE:  calling down into inner_func()
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 4 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 7 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  lets make sure we didnt break anything
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  inner_func() done
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  outer_func() done
   outer_outer_func 
  ------------------
--- 5290,5303 ----
***************
*** 5358,5379 ****
  select outer_outer_func(10);
  NOTICE:  calling down into outer_func()
  NOTICE:  calling down into inner_func()
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 10 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 15 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  lets make sure we didnt break anything
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  inner_func() done
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  outer_func() done
   outer_outer_func 
  ------------------
--- 5354,5367 ----
***************
*** 5384,5405 ****
  select outer_outer_func(20);
  NOTICE:  calling down into outer_func()
  NOTICE:  calling down into inner_func()
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 10 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 15 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  lets make sure we didnt break anything
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  inner_func() done
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  outer_func() done
   outer_outer_func 
  ------------------
--- 5372,5385 ----

======================================================================

*** /home/heikki/git-sandbox-pgsql/master/src/test/regress/expected/copy2.out	2015-07-07 15:40:38.677861460 +0300
--- /home/heikki/git-sandbox-pgsql/master/src/test/regress/results/copy2.out	2015-07-07 15:50:42.577753257 +0300
***************
*** 447,458 ****
  
  copy check_con_tbl from stdin;
  NOTICE:  input = {"f1":1}
- CONTEXT:  COPY check_con_tbl, line 1: "1"
  NOTICE:  input = {"f1":null}
- CONTEXT:  COPY check_con_tbl, line 2: "\N"
  copy check_con_tbl from stdin;
  NOTICE:  input = {"f1":0}
- CONTEXT:  COPY check_con_tbl, line 1: "0"
  ERROR:  new row for relation "check_con_tbl" violates check constraint "check_con_tbl_check"
  DETAIL:  Failing row contains (0).
  CONTEXT:  COPY check_con_tbl, line 1: "0"
--- 447,455 ----

======================================================================

*** /home/heikki/git-sandbox-pgsql/master/src/test/regress/expected/rangefuncs.out	2015-07-07 15:40:38.689861374 +0300
--- /home/heikki/git-sandbox-pgsql/master/src/test/regress/results/rangefuncs.out	2015-07-07 15:50:42.745752116 +0300
***************
*** 1704,1712 ****
  execute procedure noticetrigger();
  select insert_tt2('foolme','barme') limit 1;
  NOTICE:  noticetrigger 11 foolme
- CONTEXT:  SQL function "insert_tt2" statement 1
  NOTICE:  noticetrigger 12 barme
- CONTEXT:  SQL function "insert_tt2" statement 1
   insert_tt2 
  ------------
           11
--- 1704,1710 ----
***************
*** 1735,1743 ****
    insert into tt_log values(new.*);
  select insert_tt2('foollog','barlog') limit 1;
  NOTICE:  noticetrigger 13 foollog
- CONTEXT:  SQL function "insert_tt2" statement 1
  NOTICE:  noticetrigger 14 barlog
- CONTEXT:  SQL function "insert_tt2" statement 1
   insert_tt2 
  ------------
           13
--- 1733,1739 ----

======================================================================

*** /home/heikki/git-sandbox-pgsql/master/src/test/regress/expected/xml.out	2015-07-07 15:40:38.697861317 +0300
--- /home/heikki/git-sandbox-pgsql/master/src/test/regress/results/xml.out	2015-07-07 15:50:42.425754288 +0300
***************
*** 934,940 ****
  WARNING:  line 1: xmlns: URI relative is not absolute
  <relativens xmlns='relative'/>
                              ^
- CONTEXT:  SQL function "xpath" statement 1
                  xpath                 
  --------------------------------------
   {"<relativens xmlns=\"relative\"/>"}
--- 934,939 ----

======================================================================

*** /home/heikki/git-sandbox-pgsql/master/src/test/regress/expected/event_trigger.out	2015-07-07 15:40:38.681861432 +0300
--- /home/heikki/git-sandbox-pgsql/master/src/test/regress/results/event_trigger.out	2015-07-07 15:50:45.665732294 +0300
***************
*** 234,248 ****
  drop cascades to table schema_one."table two"
  drop cascades to table schema_one.table_three
  NOTICE:  table "schema_two_table_two" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_two"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "audit_tbls_schema_two_table_three" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.audit_tbls_schema_two_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
- SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  ERROR:  object audit_tbls.schema_two_table_three of type table cannot be dropped
! CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three"
  PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  DELETE FROM undroppable_objs WHERE object_identity = 'audit_tbls.schema_two_table_three';
  DROP SCHEMA schema_one, schema_two CASCADE;
--- 234,243 ----
  drop cascades to table schema_one."table two"
  drop cascades to table schema_one.table_three
  NOTICE:  table "schema_two_table_two" does not exist, skipping
  NOTICE:  table "audit_tbls_schema_two_table_three" does not exist, skipping
  ERROR:  object audit_tbls.schema_two_table_three of type table cannot be dropped
! CONTEXT:  PL/pgSQL function undroppable() line 14 at RAISE
! SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three"
  PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  DELETE FROM undroppable_objs WHERE object_identity = 'audit_tbls.schema_two_table_three';
  DROP SCHEMA schema_one, schema_two CASCADE;
***************
*** 255,277 ****
  drop cascades to table schema_one."table two"
  drop cascades to table schema_one.table_three
  NOTICE:  table "schema_two_table_two" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_two"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "audit_tbls_schema_two_table_three" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.audit_tbls_schema_two_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
- SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "schema_one_table_one" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_one_table_one"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "schema_one_table two" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls."schema_one_table two""
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "schema_one_table_three" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_one_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  ERROR:  object schema_one.table_three of type table cannot be dropped
  DELETE FROM undroppable_objs WHERE object_identity = 'schema_one.table_three';
  DROP SCHEMA schema_one, schema_two CASCADE;
  NOTICE:  drop cascades to 7 other objects
--- 250,261 ----
  drop cascades to table schema_one."table two"
  drop cascades to table schema_one.table_three
  NOTICE:  table "schema_two_table_two" does not exist, skipping
  NOTICE:  table "audit_tbls_schema_two_table_three" does not exist, skipping
  NOTICE:  table "schema_one_table_one" does not exist, skipping
  NOTICE:  table "schema_one_table two" does not exist, skipping
  NOTICE:  table "schema_one_table_three" does not exist, skipping
  ERROR:  object schema_one.table_three of type table cannot be dropped
+ CONTEXT:  PL/pgSQL function undroppable() line 14 at RAISE
  DELETE FROM undroppable_objs WHERE object_identity = 'schema_one.table_three';
  DROP SCHEMA schema_one, schema_two CASCADE;
  NOTICE:  drop cascades to 7 other objects
***************
*** 283,304 ****
  drop cascades to table schema_one."table two"
  drop cascades to table schema_one.table_three
  NOTICE:  table "schema_two_table_two" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_two"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "audit_tbls_schema_two_table_three" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.audit_tbls_schema_two_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
- SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "schema_one_table_one" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_one_table_one"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "schema_one_table two" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls."schema_one_table two""
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "schema_one_table_three" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_one_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  SELECT * FROM dropped_objects WHERE schema IS NULL OR schema <> 'pg_toast';
       type     |   schema   |               object                
  --------------+------------+-------------------------------------
--- 267,276 ----
***************
*** 329,336 ****
  
  DROP OWNED BY regression_bob;
  NOTICE:  schema "audit_tbls" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.audit_tbls_schema_one_table_two"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  SELECT * FROM dropped_objects WHERE type = 'schema';
    type  | schema |   object   
  --------+--------+------------
--- 301,306 ----
***************
*** 402,409 ****
--- 372,381 ----
       select x * 1.001 from generate_series(1, 500) as t(x);
  alter table rewriteme alter column foo type numeric;
  ERROR:  I'm sorry Sir, No Rewrite Allowed.
+ CONTEXT:  PL/pgSQL function test_evtrig_no_rewrite() line 3 at RAISE
  alter table rewriteme add column baz int default 0;
  ERROR:  I'm sorry Sir, No Rewrite Allowed.
+ CONTEXT:  PL/pgSQL function test_evtrig_no_rewrite() line 3 at RAISE
  -- test with more than one reason to rewrite a single table
  CREATE OR REPLACE FUNCTION test_evtrig_no_rewrite() RETURNS event_trigger
  LANGUAGE plpgsql AS $$

======================================================================

#70Merlin Moncure
mmoncure@gmail.com
In reply to: Heikki Linnakangas (#69)
Re: PL/pgSQL, RAISE and error context

On Tue, Jul 7, 2015 at 8:13 AM, Heikki Linnakangas <hlinnaka@iki.fi> wrote:

On 01/26/2015 05:14 PM, Tom Lane wrote:

Pavel Stehule <pavel.stehule@gmail.com> writes:

2015-01-26 14:02 GMT+01:00 Marko Tiikkaja <marko@joh.to>:
I am thinking, so solution

/* if we are doing RAISE, don't report its location */
if (estate->err_text == raise_skip_msg)
return;

is too simple, and this part should be fixed. This change can be done by
on
plpgsql or libpq side. This is bug, and it should be fixed.

Doing this in libpq is utterly insane. It has not got sufficient context
to do anything intelligent. The fact that it's not intelligent is exposed
by the regression test changes that the proposed patch causes, most of
which do not look like improvements.

How can the server know if the client wants to display context information?

It doesn't have to if the behavior is guarded with a GUC. I just
don't understand what all the fuss is about. The default behavior of
logging that is well established by other languages (for example java)
that manage error stack for you should be to:

*) Give stack trace when an uncaught exception is thrown
*) Do not give stack trace in all other logging cases unless asked for

I would be happy to show you the psql redirected output logs from my
nightly server processes that spew into the megabytes because of
logging various high level steps (did this, did that). I can't throw
the verbose switch to terse because if the error happens to be
'Division by Zero', or some other difficult to trace problem then I'm
sunk. I believe the protocol decision to 'always send context' needs
to be revisited; if your server-side codebase is large and heavily
nested it makes logging an expensive operation even if the client
strips off the log.

plpgsql.min_context seems like the ideal solution to this problem; it
can be managed on the server or the client and does not require new
syntax. If we require syntax to slip and and out of debugging type
operations the solution has missed the mark IMNSHO.

merlin

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#71Pavel Stehule
pavel.stehule@gmail.com
In reply to: Merlin Moncure (#70)
Re: PL/pgSQL, RAISE and error context

2015-07-07 15:56 GMT+02:00 Merlin Moncure <mmoncure@gmail.com>:

On Tue, Jul 7, 2015 at 8:13 AM, Heikki Linnakangas <hlinnaka@iki.fi>
wrote:

On 01/26/2015 05:14 PM, Tom Lane wrote:

Pavel Stehule <pavel.stehule@gmail.com> writes:

2015-01-26 14:02 GMT+01:00 Marko Tiikkaja <marko@joh.to>:
I am thinking, so solution

/* if we are doing RAISE, don't report its location */
if (estate->err_text == raise_skip_msg)
return;

is too simple, and this part should be fixed. This change can be done

by

on
plpgsql or libpq side. This is bug, and it should be fixed.

Doing this in libpq is utterly insane. It has not got sufficient

context

to do anything intelligent. The fact that it's not intelligent is

exposed

by the regression test changes that the proposed patch causes, most of
which do not look like improvements.

How can the server know if the client wants to display context

information?

It doesn't have to if the behavior is guarded with a GUC. I just
don't understand what all the fuss is about. The default behavior of
logging that is well established by other languages (for example java)
that manage error stack for you should be to:

*) Give stack trace when an uncaught exception is thrown
*) Do not give stack trace in all other logging cases unless asked for

what is RAISE EXCEPTION - first or second case?

Show quoted text

I would be happy to show you the psql redirected output logs from my
nightly server processes that spew into the megabytes because of
logging various high level steps (did this, did that). I can't throw
the verbose switch to terse because if the error happens to be
'Division by Zero', or some other difficult to trace problem then I'm
sunk. I believe the protocol decision to 'always send context' needs
to be revisited; if your server-side codebase is large and heavily
nested it makes logging an expensive operation even if the client
strips off the log.

plpgsql.min_context seems like the ideal solution to this problem; it
can be managed on the server or the client and does not require new
syntax. If we require syntax to slip and and out of debugging type
operations the solution has missed the mark IMNSHO.

merlin

#72Heikki Linnakangas
hlinnaka@iki.fi
In reply to: Merlin Moncure (#70)
Re: PL/pgSQL, RAISE and error context

On 07/07/2015 04:56 PM, Merlin Moncure wrote:

On Tue, Jul 7, 2015 at 8:13 AM, Heikki Linnakangas <hlinnaka@iki.fi> wrote:

On 01/26/2015 05:14 PM, Tom Lane wrote:

Pavel Stehule <pavel.stehule@gmail.com> writes:

2015-01-26 14:02 GMT+01:00 Marko Tiikkaja <marko@joh.to>:
I am thinking, so solution

/* if we are doing RAISE, don't report its location */
if (estate->err_text == raise_skip_msg)
return;

is too simple, and this part should be fixed. This change can be done by
on
plpgsql or libpq side. This is bug, and it should be fixed.

Doing this in libpq is utterly insane. It has not got sufficient context
to do anything intelligent. The fact that it's not intelligent is exposed
by the regression test changes that the proposed patch causes, most of
which do not look like improvements.

How can the server know if the client wants to display context information?

It doesn't have to if the behavior is guarded with a GUC. I just
don't understand what all the fuss is about. The default behavior of
logging that is well established by other languages (for example java)
that manage error stack for you should be to:

*) Give stack trace when an uncaught exception is thrown
*) Do not give stack trace in all other logging cases unless asked for

Java's exception handling is so different from PostgreSQL's errors that
I don't think there's much to be learned from that. But I'll bite:

First of all, Java's exceptions always contain a stack trace. It's up to
you when you catch an exception to decide whether to print it or not.
"try { ... } catch (Exception e) { e.printStackTrace() }" is fairly
common, actually. There is nothing like a NOTICE in Java, i.e. an
exception that's thrown but doesn't affect the control flow. The best I
can think of is System.out.println(), which of course has no stack trace
attached to it.

Perhaps you're arguing that NOTICE is more like printing to stderr, and
should never contain any context information. I don't think that would
be an improvement. It's very handy to have the context information
available if don't know where a NOTICE is coming from, even if in most
cases you're not interested in it.

This is really quite different from a programming language's exception
handling. First, there's a server, which produces the errors, and a
separate client, which displays them. You cannot catch an exception in
the client.

BTW, let me throw in one use case to consider. We've been talking about
psql, and what to print, but imagine a more sophisticated client like
pgAdmin. It's not limited to either printing the context or not. It
could e.g. hide the context information of all messages when they occur,
but if you double-click on it, it's expanded to show all the context,
location and all. You can't do that if the server doesn't send the
context information in the first place.

I would be happy to show you the psql redirected output logs from my
nightly server processes that spew into the megabytes because of
logging various high level steps (did this, did that).

Oh, I believe you. I understand what the problem is, we're only talking
about how best to address it.
- Heikki

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#73Merlin Moncure
mmoncure@gmail.com
In reply to: Pavel Stehule (#71)
Re: PL/pgSQL, RAISE and error context

On Tue, Jul 7, 2015 at 9:04 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

It doesn't have to if the behavior is guarded with a GUC. I just
don't understand what all the fuss is about. The default behavior of
logging that is well established by other languages (for example java)
that manage error stack for you should be to:

*) Give stack trace when an uncaught exception is thrown
*) Do not give stack trace in all other logging cases unless asked for

what is RAISE EXCEPTION - first or second case?

First: RAISE (unless caught) is no different than any other kind of error.

On Tue, Jul 7, 2015 at 9:42 AM, Heikki Linnakangas <hlinnaka@iki.fi> wrote:

On 07/07/2015 04:56 PM, Merlin Moncure wrote:

It doesn't have to if the behavior is guarded with a GUC. I just
don't understand what all the fuss is about. The default behavior of
logging that is well established by other languages (for example java)
that manage error stack for you should be to:

*) Give stack trace when an uncaught exception is thrown
*) Do not give stack trace in all other logging cases unless asked for

Java's exception handling is so different from PostgreSQL's errors that I
don't think there's much to be learned from that. But I'll bite:

First of all, Java's exceptions always contain a stack trace. It's up to you
when you catch an exception to decide whether to print it or not. "try { ...
} catch (Exception e) { e.printStackTrace() }" is fairly common, actually.
There is nothing like a NOTICE in Java, i.e. an exception that's thrown but
doesn't affect the control flow. The best I can think of is
System.out.println(), which of course has no stack trace attached to it.

exactly.

Perhaps you're arguing that NOTICE is more like printing to stderr, and
should never contain any context information. I don't think that would be an
improvement. It's very handy to have the context information available if
don't know where a NOTICE is coming from, even if in most cases you're not
interested in it.

That's exactly what I'm arguing. NOTICE (and WARNING) are for
printing out information to client side logging; it's really the only
tool we have for that purpose and it fits that role perfectly. Of
course, you may want to have NOTICE print context, especially when
debugging, but some control over that would be nice and in most cases
it's really not necessary. I really don't understand the objection to
offering control over that behavior although I certainly understand
wanting to keep the default behavior as it currently is.

This is really quite different from a programming language's exception
handling. First, there's a server, which produces the errors, and a separate
client, which displays them. You cannot catch an exception in the client.

BTW, let me throw in one use case to consider. We've been talking about
psql, and what to print, but imagine a more sophisticated client like
pgAdmin. It's not limited to either printing the context or not. It could
e.g. hide the context information of all messages when they occur, but if
you double-click on it, it's expanded to show all the context, location and
all. You can't do that if the server doesn't send the context information in
the first place.

I would be happy to show you the psql redirected output logs from my
nightly server processes that spew into the megabytes because of
logging various high level steps (did this, did that).

Oh, I believe you. I understand what the problem is, we're only talking
about how best to address it.

Yeah. For posterity, a psql based solution would work fine for me,
but a server side solution has a lot of advantages (less protocol
chatter, more configurability, keeping libpq/psql light).

merlin

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#74Pavel Stehule
pavel.stehule@gmail.com
In reply to: Merlin Moncure (#73)
Re: PL/pgSQL, RAISE and error context

2015-07-07 18:15 GMT+02:00 Merlin Moncure <mmoncure@gmail.com>:

On Tue, Jul 7, 2015 at 9:04 AM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

It doesn't have to if the behavior is guarded with a GUC. I just
don't understand what all the fuss is about. The default behavior of
logging that is well established by other languages (for example java)
that manage error stack for you should be to:

*) Give stack trace when an uncaught exception is thrown
*) Do not give stack trace in all other logging cases unless asked for

what is RAISE EXCEPTION - first or second case?

First: RAISE (unless caught) is no different than any other kind of error.

On Tue, Jul 7, 2015 at 9:42 AM, Heikki Linnakangas <hlinnaka@iki.fi>
wrote:

On 07/07/2015 04:56 PM, Merlin Moncure wrote:

It doesn't have to if the behavior is guarded with a GUC. I just
don't understand what all the fuss is about. The default behavior of
logging that is well established by other languages (for example java)
that manage error stack for you should be to:

*) Give stack trace when an uncaught exception is thrown
*) Do not give stack trace in all other logging cases unless asked for

Java's exception handling is so different from PostgreSQL's errors that I
don't think there's much to be learned from that. But I'll bite:

First of all, Java's exceptions always contain a stack trace. It's up to

you

when you catch an exception to decide whether to print it or not. "try {

...

} catch (Exception e) { e.printStackTrace() }" is fairly common,

actually.

There is nothing like a NOTICE in Java, i.e. an exception that's thrown

but

doesn't affect the control flow. The best I can think of is
System.out.println(), which of course has no stack trace attached to it.

exactly.

Perhaps you're arguing that NOTICE is more like printing to stderr, and
should never contain any context information. I don't think that would

be an

improvement. It's very handy to have the context information available if
don't know where a NOTICE is coming from, even if in most cases you're

not

interested in it.

That's exactly what I'm arguing. NOTICE (and WARNING) are for
printing out information to client side logging; it's really the only
tool we have for that purpose and it fits that role perfectly. Of
course, you may want to have NOTICE print context, especially when
debugging, but some control over that would be nice and in most cases
it's really not necessary. I really don't understand the objection to
offering control over that behavior although I certainly understand
wanting to keep the default behavior as it currently is.

This is really quite different from a programming language's exception
handling. First, there's a server, which produces the errors, and a

separate

client, which displays them. You cannot catch an exception in the client.

BTW, let me throw in one use case to consider. We've been talking about
psql, and what to print, but imagine a more sophisticated client like
pgAdmin. It's not limited to either printing the context or not. It could
e.g. hide the context information of all messages when they occur, but if
you double-click on it, it's expanded to show all the context, location

and

all. You can't do that if the server doesn't send the context

information in

the first place.

I would be happy to show you the psql redirected output logs from my
nightly server processes that spew into the megabytes because of
logging various high level steps (did this, did that).

Oh, I believe you. I understand what the problem is, we're only talking
about how best to address it.

Yeah. For posterity, a psql based solution would work fine for me,
but a server side solution has a lot of advantages (less protocol
chatter, more configurability, keeping libpq/psql light).

I prefer a server side solution too. With it I can have (as plpgsql
developer) bigger control of expected output.

Client can change this behave on global (min_context) or on language level
(plpgsql.min_context). If somebody afraid about security, we can to enforce
rule so min_context <= error always.

The possibility to enable or disable context per any RAISE statement is
nice to have, but it is not fundamental.

Other variant is a implementation of min_context on client side - but then
we cannot to ensure current behave and fix plpgsql raise exception issue
together.

Pavel

Show quoted text

merlin

#75Pavel Stehule
pavel.stehule@gmail.com
In reply to: Merlin Moncure (#73)
Re: PL/pgSQL, RAISE and error context

2015-07-07 18:15 GMT+02:00 Merlin Moncure <mmoncure@gmail.com>:

On Tue, Jul 7, 2015 at 9:04 AM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

It doesn't have to if the behavior is guarded with a GUC. I just
don't understand what all the fuss is about. The default behavior of
logging that is well established by other languages (for example java)
that manage error stack for you should be to:

*) Give stack trace when an uncaught exception is thrown
*) Do not give stack trace in all other logging cases unless asked for

what is RAISE EXCEPTION - first or second case?

First: RAISE (unless caught) is no different than any other kind of error.

On Tue, Jul 7, 2015 at 9:42 AM, Heikki Linnakangas <hlinnaka@iki.fi>
wrote:

On 07/07/2015 04:56 PM, Merlin Moncure wrote:

It doesn't have to if the behavior is guarded with a GUC. I just
don't understand what all the fuss is about. The default behavior of
logging that is well established by other languages (for example java)
that manage error stack for you should be to:

*) Give stack trace when an uncaught exception is thrown
*) Do not give stack trace in all other logging cases unless asked for

Java's exception handling is so different from PostgreSQL's errors that I
don't think there's much to be learned from that. But I'll bite:

First of all, Java's exceptions always contain a stack trace. It's up to

you

when you catch an exception to decide whether to print it or not. "try {

...

} catch (Exception e) { e.printStackTrace() }" is fairly common,

actually.

There is nothing like a NOTICE in Java, i.e. an exception that's thrown

but

doesn't affect the control flow. The best I can think of is
System.out.println(), which of course has no stack trace attached to it.

exactly.

Perhaps you're arguing that NOTICE is more like printing to stderr, and
should never contain any context information. I don't think that would

be an

improvement. It's very handy to have the context information available if
don't know where a NOTICE is coming from, even if in most cases you're

not

interested in it.

That's exactly what I'm arguing. NOTICE (and WARNING) are for
printing out information to client side logging; it's really the only
tool we have for that purpose and it fits that role perfectly. Of
course, you may want to have NOTICE print context, especially when
debugging, but some control over that would be nice and in most cases
it's really not necessary. I really don't understand the objection to
offering control over that behavior although I certainly understand
wanting to keep the default behavior as it currently is.

This is really quite different from a programming language's exception
handling. First, there's a server, which produces the errors, and a

separate

client, which displays them. You cannot catch an exception in the client.

BTW, let me throw in one use case to consider. We've been talking about
psql, and what to print, but imagine a more sophisticated client like
pgAdmin. It's not limited to either printing the context or not. It could
e.g. hide the context information of all messages when they occur, but if
you double-click on it, it's expanded to show all the context, location

and

all. You can't do that if the server doesn't send the context

information in

the first place.

I would be happy to show you the psql redirected output logs from my
nightly server processes that spew into the megabytes because of
logging various high level steps (did this, did that).

Oh, I believe you. I understand what the problem is, we're only talking
about how best to address it.

Yeah. For posterity, a psql based solution would work fine for me,
but a server side solution has a lot of advantages (less protocol
chatter, more configurability, keeping libpq/psql light).

After some work on reduced version of "plpgsql.min_context" patch I am
inclining to think so ideal solution needs more steps - because this issue
has more than one dimension.

There are two independent issues:

1. old plpgsql workaround that reduced the unwanted call stack info for
RAISE NOTICE. Negative side effect of this workaround is missing context
info about the RAISE command that raises the exception. We know a function,
but we don't know a line of related RAISE statement. The important is fact,
so NOTICE doesn't bubble to up. So this workaround was relative successful
without to implement some filtering on client or log side.

2. second issue is general suppressing context info for interactive client
or for log.

These issues should be solved separately, because solution for @2 doesn't
fix @1, and @1 is too local for @2.

So what we can do?

1. remove current plpgsql workaround - and implement client_min_context and
log_min_context
2. implement plpgsql.min_context, and client_min_context and log_min_context

@1 is consistent, but isn't possible to configure same behave as was before

@2 is difficult in definition what plpgsql.min_context should to really do
- and what is relation to client_min_context and log_min_context, but I can
prepare configuration, that is fully compatible.

Comments, any other ideas?

Personally, I prefer @1 as general solution, that will work for all PL

Regards

Pavel

Show quoted text

merlin

#76Merlin Moncure
mmoncure@gmail.com
In reply to: Pavel Stehule (#75)
Re: PL/pgSQL, RAISE and error context

On Wed, Jul 8, 2015 at 1:35 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

2015-07-07 18:15 GMT+02:00 Merlin Moncure <mmoncure@gmail.com>:

On Tue, Jul 7, 2015 at 9:04 AM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

It doesn't have to if the behavior is guarded with a GUC. I just
don't understand what all the fuss is about. The default behavior of
logging that is well established by other languages (for example java)
that manage error stack for you should be to:

*) Give stack trace when an uncaught exception is thrown
*) Do not give stack trace in all other logging cases unless asked for

what is RAISE EXCEPTION - first or second case?

First: RAISE (unless caught) is no different than any other kind of error.

On Tue, Jul 7, 2015 at 9:42 AM, Heikki Linnakangas <hlinnaka@iki.fi>
wrote:

On 07/07/2015 04:56 PM, Merlin Moncure wrote:

It doesn't have to if the behavior is guarded with a GUC. I just
don't understand what all the fuss is about. The default behavior of
logging that is well established by other languages (for example java)
that manage error stack for you should be to:

*) Give stack trace when an uncaught exception is thrown
*) Do not give stack trace in all other logging cases unless asked for

Java's exception handling is so different from PostgreSQL's errors that
I
don't think there's much to be learned from that. But I'll bite:

First of all, Java's exceptions always contain a stack trace. It's up to
you
when you catch an exception to decide whether to print it or not. "try {
...
} catch (Exception e) { e.printStackTrace() }" is fairly common,
actually.
There is nothing like a NOTICE in Java, i.e. an exception that's thrown
but
doesn't affect the control flow. The best I can think of is
System.out.println(), which of course has no stack trace attached to it.

exactly.

Perhaps you're arguing that NOTICE is more like printing to stderr, and
should never contain any context information. I don't think that would
be an
improvement. It's very handy to have the context information available
if
don't know where a NOTICE is coming from, even if in most cases you're
not
interested in it.

That's exactly what I'm arguing. NOTICE (and WARNING) are for
printing out information to client side logging; it's really the only
tool we have for that purpose and it fits that role perfectly. Of
course, you may want to have NOTICE print context, especially when
debugging, but some control over that would be nice and in most cases
it's really not necessary. I really don't understand the objection to
offering control over that behavior although I certainly understand
wanting to keep the default behavior as it currently is.

This is really quite different from a programming language's exception
handling. First, there's a server, which produces the errors, and a
separate
client, which displays them. You cannot catch an exception in the
client.

BTW, let me throw in one use case to consider. We've been talking about
psql, and what to print, but imagine a more sophisticated client like
pgAdmin. It's not limited to either printing the context or not. It
could
e.g. hide the context information of all messages when they occur, but
if
you double-click on it, it's expanded to show all the context, location
and
all. You can't do that if the server doesn't send the context
information in
the first place.

I would be happy to show you the psql redirected output logs from my
nightly server processes that spew into the megabytes because of
logging various high level steps (did this, did that).

Oh, I believe you. I understand what the problem is, we're only talking
about how best to address it.

Yeah. For posterity, a psql based solution would work fine for me,
but a server side solution has a lot of advantages (less protocol
chatter, more configurability, keeping libpq/psql light).

After some work on reduced version of "plpgsql.min_context" patch I am
inclining to think so ideal solution needs more steps - because this issue
has more than one dimension.

There are two independent issues:

1. old plpgsql workaround that reduced the unwanted call stack info for
RAISE NOTICE. Negative side effect of this workaround is missing context
info about the RAISE command that raises the exception. We know a function,
but we don't know a line of related RAISE statement. The important is fact,
so NOTICE doesn't bubble to up. So this workaround was relative successful
without to implement some filtering on client or log side.

2. second issue is general suppressing context info for interactive client
or for log.

These issues should be solved separately, because solution for @2 doesn't
fix @1, and @1 is too local for @2.

So what we can do?

1. remove current plpgsql workaround - and implement client_min_context and
log_min_context
2. implement plpgsql.min_context, and client_min_context and log_min_context

@1 is consistent, but isn't possible to configure same behave as was before

@2 is difficult in definition what plpgsql.min_context should to really do
- and what is relation to client_min_context and log_min_context, but I can
prepare configuration, that is fully compatible.

Comments, any other ideas?

Personally, I prefer @1 as general solution, that will work for all PL

+1

merlin

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#77Pavel Stehule
pavel.stehule@gmail.com
In reply to: Merlin Moncure (#76)
1 attachment(s)
Re: PL/pgSQL, RAISE and error context

Hi

here is initial version of reduced patch. It is small code, but relative
big (although I expected bigger) change in tests.

if these changes are too big, then we have to introduce a plpgsql GUC
plpgsql.client_min_context and plpgsql.log_min_client. These GUC overwrite
global setting for plpgsql functions. I'll be more happy without these
variables. It decrease a impact of changes, but there is not clean what
behave is expected when PL are used together - and when fails PLpgSQL
function called from PLPerl. The context filtering should be really solved
on TOP level.

Regards

Pavel

2015-07-08 14:09 GMT+02:00 Merlin Moncure <mmoncure@gmail.com>:

Show quoted text

On Wed, Jul 8, 2015 at 1:35 AM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

2015-07-07 18:15 GMT+02:00 Merlin Moncure <mmoncure@gmail.com>:

On Tue, Jul 7, 2015 at 9:04 AM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

It doesn't have to if the behavior is guarded with a GUC. I just
don't understand what all the fuss is about. The default behavior of
logging that is well established by other languages (for example

java)

that manage error stack for you should be to:

*) Give stack trace when an uncaught exception is thrown
*) Do not give stack trace in all other logging cases unless asked

for

what is RAISE EXCEPTION - first or second case?

First: RAISE (unless caught) is no different than any other kind of

error.

On Tue, Jul 7, 2015 at 9:42 AM, Heikki Linnakangas <hlinnaka@iki.fi>
wrote:

On 07/07/2015 04:56 PM, Merlin Moncure wrote:

It doesn't have to if the behavior is guarded with a GUC. I just
don't understand what all the fuss is about. The default behavior of
logging that is well established by other languages (for example

java)

that manage error stack for you should be to:

*) Give stack trace when an uncaught exception is thrown
*) Do not give stack trace in all other logging cases unless asked

for

Java's exception handling is so different from PostgreSQL's errors

that

I
don't think there's much to be learned from that. But I'll bite:

First of all, Java's exceptions always contain a stack trace. It's up

to

you
when you catch an exception to decide whether to print it or not.

"try {

...
} catch (Exception e) { e.printStackTrace() }" is fairly common,
actually.
There is nothing like a NOTICE in Java, i.e. an exception that's

thrown

but
doesn't affect the control flow. The best I can think of is
System.out.println(), which of course has no stack trace attached to

it.

exactly.

Perhaps you're arguing that NOTICE is more like printing to stderr,

and

should never contain any context information. I don't think that would
be an
improvement. It's very handy to have the context information available
if
don't know where a NOTICE is coming from, even if in most cases you're
not
interested in it.

That's exactly what I'm arguing. NOTICE (and WARNING) are for
printing out information to client side logging; it's really the only
tool we have for that purpose and it fits that role perfectly. Of
course, you may want to have NOTICE print context, especially when
debugging, but some control over that would be nice and in most cases
it's really not necessary. I really don't understand the objection to
offering control over that behavior although I certainly understand
wanting to keep the default behavior as it currently is.

This is really quite different from a programming language's exception
handling. First, there's a server, which produces the errors, and a
separate
client, which displays them. You cannot catch an exception in the
client.

BTW, let me throw in one use case to consider. We've been talking

about

psql, and what to print, but imagine a more sophisticated client like
pgAdmin. It's not limited to either printing the context or not. It
could
e.g. hide the context information of all messages when they occur, but
if
you double-click on it, it's expanded to show all the context,

location

and
all. You can't do that if the server doesn't send the context
information in
the first place.

I would be happy to show you the psql redirected output logs from my
nightly server processes that spew into the megabytes because of
logging various high level steps (did this, did that).

Oh, I believe you. I understand what the problem is, we're only

talking

about how best to address it.

Yeah. For posterity, a psql based solution would work fine for me,
but a server side solution has a lot of advantages (less protocol
chatter, more configurability, keeping libpq/psql light).

After some work on reduced version of "plpgsql.min_context" patch I am
inclining to think so ideal solution needs more steps - because this

issue

has more than one dimension.

There are two independent issues:

1. old plpgsql workaround that reduced the unwanted call stack info for
RAISE NOTICE. Negative side effect of this workaround is missing context
info about the RAISE command that raises the exception. We know a

function,

but we don't know a line of related RAISE statement. The important is

fact,

so NOTICE doesn't bubble to up. So this workaround was relative

successful

without to implement some filtering on client or log side.

2. second issue is general suppressing context info for interactive

client

or for log.

These issues should be solved separately, because solution for @2 doesn't
fix @1, and @1 is too local for @2.

So what we can do?

1. remove current plpgsql workaround - and implement client_min_context

and

log_min_context
2. implement plpgsql.min_context, and client_min_context and

log_min_context

@1 is consistent, but isn't possible to configure same behave as was

before

@2 is difficult in definition what plpgsql.min_context should to really

do

- and what is relation to client_min_context and log_min_context, but I

can

prepare configuration, that is fully compatible.

Comments, any other ideas?

Personally, I prefer @1 as general solution, that will work for all PL

+1

merlin

Attachments:

min_context.patchtext/x-patch; charset=US-ASCII; name=min_context.patchDownload
commit e3053e47ab7a9735aeda24995501c7b74042e7c6
Author: Pavel Stehule <pavel.stehule@gooddata.com>
Date:   Wed Jul 8 22:12:30 2015 +0200

    initial

diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 088c714..9445230 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -2730,7 +2730,7 @@ write_csvlog(ErrorData *edata)
 	appendStringInfoChar(&buf, ',');
 
 	/* errcontext */
-	if (!edata->hide_ctx)
+	if (!edata->hide_ctx && edata->elevel >= log_min_context)
 		appendCSVLiteral(&buf, edata->context);
 	appendStringInfoChar(&buf, ',');
 
@@ -2863,7 +2863,7 @@ send_message_to_server_log(ErrorData *edata)
 			append_with_tabs(&buf, edata->internalquery);
 			appendStringInfoChar(&buf, '\n');
 		}
-		if (edata->context && !edata->hide_ctx)
+		if (edata->context && !edata->hide_ctx && edata->elevel >= log_min_context)
 		{
 			log_line_prefix(&buf, edata);
 			appendStringInfoString(&buf, _("CONTEXT:  "));
@@ -3137,7 +3137,7 @@ send_message_to_frontend(ErrorData *edata)
 			err_sendstring(&msgbuf, edata->hint);
 		}
 
-		if (edata->context)
+		if (edata->context && edata->elevel >= client_min_context)
 		{
 			pq_sendbyte(&msgbuf, PG_DIAG_CONTEXT);
 			err_sendstring(&msgbuf, edata->context);
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 595a609..ca63bf5 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -430,6 +430,8 @@ bool		Password_encryption = true;
 int			log_min_error_statement = ERROR;
 int			log_min_messages = WARNING;
 int			client_min_messages = NOTICE;
+int			log_min_context = ERROR;
+int			client_min_context = ERROR;
 int			log_min_duration_statement = -1;
 int			log_temp_files = -1;
 int			trace_recovery_messages = LOG;
@@ -3426,6 +3428,17 @@ static struct config_enum ConfigureNamesEnum[] =
 	},
 
 	{
+		{"client_min_context", PGC_USERSET, LOGGING_WHEN,
+			gettext_noop("Sets the message levels when the context is send to the client."),
+			gettext_noop("Each level includes all the levels that follow it. The later"
+						 " the level, the less content are sent.")
+		},
+		&client_min_context,
+		ERROR, client_message_level_options,
+		NULL, NULL, NULL
+	},
+
+	{
 		{"client_min_messages", PGC_USERSET, LOGGING_WHEN,
 			gettext_noop("Sets the message levels that are sent to the client."),
 			gettext_noop("Each level includes all the levels that follow it. The later"
@@ -3479,6 +3492,17 @@ static struct config_enum ConfigureNamesEnum[] =
 	},
 
 	{
+		{"log_min_context", PGC_SUSET, LOGGING_WHEN,
+			gettext_noop("Sets the message levels that has context logged."),
+			gettext_noop("Each level includes all the levels that follow it. The later"
+						 " the level, the less content are sent.")
+		},
+		&log_min_context,
+		WARNING, server_message_level_options,
+		NULL, NULL, NULL
+	},
+
+	{
 		{"log_min_messages", PGC_SUSET, LOGGING_WHEN,
 			gettext_noop("Sets the message levels that are logged."),
 			gettext_noop("Each level includes all the levels that follow it. The later"
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 06dfc06..8695e8b 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -360,6 +360,31 @@
 
 # - When to Log -
 
+#client_min_context = error		# values in order of decreasing detail:
+					#   debug5
+					#   debug4
+					#   debug3
+					#   debug2
+					#   debug1
+					#   log
+					#   notice
+					#   warning
+					#   error
+
+#log_min_context = warning		# values in order of decreasing detail:
+					#   debug5
+					#   debug4
+					#   debug3
+					#   debug2
+					#   debug1
+					#   info
+					#   notice
+					#   warning
+					#   error
+					#   log
+					#   fatal
+					#   panic
+
 #client_min_messages = notice		# values in order of decreasing detail:
 					#   debug5
 					#   debug4
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index dc167f9..f03a5e1 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -246,6 +246,8 @@ extern PGDLLIMPORT bool check_function_bodies;
 extern bool default_with_oids;
 extern bool SQL_inheritance;
 
+extern int	log_min_context;
+extern int	client_min_context;
 extern int	log_min_error_statement;
 extern int	log_min_messages;
 extern int	client_min_messages;
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 7d4001c..e1a6b7d 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -42,8 +42,6 @@
 #include "utils/typcache.h"
 
 
-static const char *const raise_skip_msg = "RAISE";
-
 typedef struct
 {
 	int			nargs;			/* number of arguments */
@@ -939,10 +937,6 @@ plpgsql_exec_error_callback(void *arg)
 {
 	PLpgSQL_execstate *estate = (PLpgSQL_execstate *) arg;
 
-	/* if we are doing RAISE, don't report its location */
-	if (estate->err_text == raise_skip_msg)
-		return;
-
 	if (estate->err_text != NULL)
 	{
 		/*
@@ -3158,8 +3152,6 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
 	/*
 	 * Throw the error (may or may not come back)
 	 */
-	estate->err_text = raise_skip_msg;	/* suppress traceback of raise */
-
 	ereport(stmt->elog_level,
 			(err_code ? errcode(err_code) : 0,
 			 errmsg_internal("%s", err_message),
diff --git a/src/test/regress/expected/copy2.out b/src/test/regress/expected/copy2.out
index 5e31737..72ada21 100644
--- a/src/test/regress/expected/copy2.out
+++ b/src/test/regress/expected/copy2.out
@@ -447,12 +447,9 @@ Check constraints:
 
 copy check_con_tbl from stdin;
 NOTICE:  input = {"f1":1}
-CONTEXT:  COPY check_con_tbl, line 1: "1"
 NOTICE:  input = {"f1":null}
-CONTEXT:  COPY check_con_tbl, line 2: "\N"
 copy check_con_tbl from stdin;
 NOTICE:  input = {"f1":0}
-CONTEXT:  COPY check_con_tbl, line 1: "0"
 ERROR:  new row for relation "check_con_tbl" violates check constraint "check_con_tbl_check"
 DETAIL:  Failing row contains (0).
 CONTEXT:  COPY check_con_tbl, line 1: "0"
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index e70c315..05ac0ad 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -234,15 +234,10 @@ drop cascades to table schema_one.table_one
 drop cascades to table schema_one."table two"
 drop cascades to table schema_one.table_three
 NOTICE:  table "schema_two_table_two" does not exist, skipping
-CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_two"
-PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
 NOTICE:  table "audit_tbls_schema_two_table_three" does not exist, skipping
-CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.audit_tbls_schema_two_table_three"
-PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
-SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three"
-PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
 ERROR:  object audit_tbls.schema_two_table_three of type table cannot be dropped
-CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three"
+CONTEXT:  PL/pgSQL function undroppable() line 14 at RAISE
+SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three"
 PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
 DELETE FROM undroppable_objs WHERE object_identity = 'audit_tbls.schema_two_table_three';
 DROP SCHEMA schema_one, schema_two CASCADE;
@@ -255,23 +250,12 @@ drop cascades to table schema_one.table_one
 drop cascades to table schema_one."table two"
 drop cascades to table schema_one.table_three
 NOTICE:  table "schema_two_table_two" does not exist, skipping
-CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_two"
-PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
 NOTICE:  table "audit_tbls_schema_two_table_three" does not exist, skipping
-CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.audit_tbls_schema_two_table_three"
-PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
-SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three"
-PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
 NOTICE:  table "schema_one_table_one" does not exist, skipping
-CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_one_table_one"
-PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
 NOTICE:  table "schema_one_table two" does not exist, skipping
-CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls."schema_one_table two""
-PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
 NOTICE:  table "schema_one_table_three" does not exist, skipping
-CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_one_table_three"
-PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
 ERROR:  object schema_one.table_three of type table cannot be dropped
+CONTEXT:  PL/pgSQL function undroppable() line 14 at RAISE
 DELETE FROM undroppable_objs WHERE object_identity = 'schema_one.table_three';
 DROP SCHEMA schema_one, schema_two CASCADE;
 NOTICE:  drop cascades to 7 other objects
@@ -283,22 +267,10 @@ drop cascades to table schema_one.table_one
 drop cascades to table schema_one."table two"
 drop cascades to table schema_one.table_three
 NOTICE:  table "schema_two_table_two" does not exist, skipping
-CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_two"
-PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
 NOTICE:  table "audit_tbls_schema_two_table_three" does not exist, skipping
-CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.audit_tbls_schema_two_table_three"
-PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
-SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three"
-PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
 NOTICE:  table "schema_one_table_one" does not exist, skipping
-CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_one_table_one"
-PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
 NOTICE:  table "schema_one_table two" does not exist, skipping
-CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls."schema_one_table two""
-PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
 NOTICE:  table "schema_one_table_three" does not exist, skipping
-CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_one_table_three"
-PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
 SELECT * FROM dropped_objects WHERE schema IS NULL OR schema <> 'pg_toast';
      type     |   schema   |               object                
 --------------+------------+-------------------------------------
@@ -329,8 +301,6 @@ SELECT * FROM dropped_objects WHERE schema IS NULL OR schema <> 'pg_toast';
 
 DROP OWNED BY regression_bob;
 NOTICE:  schema "audit_tbls" does not exist, skipping
-CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.audit_tbls_schema_one_table_two"
-PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
 SELECT * FROM dropped_objects WHERE type = 'schema';
   type  | schema |   object   
 --------+--------+------------
@@ -402,8 +372,10 @@ insert into rewriteme
      select x * 1.001 from generate_series(1, 500) as t(x);
 alter table rewriteme alter column foo type numeric;
 ERROR:  I'm sorry Sir, No Rewrite Allowed.
+CONTEXT:  PL/pgSQL function test_evtrig_no_rewrite() line 3 at RAISE
 alter table rewriteme add column baz int default 0;
 ERROR:  I'm sorry Sir, No Rewrite Allowed.
+CONTEXT:  PL/pgSQL function test_evtrig_no_rewrite() line 3 at RAISE
 -- test with more than one reason to rewrite a single table
 CREATE OR REPLACE FUNCTION test_evtrig_no_rewrite() RETURNS event_trigger
 LANGUAGE plpgsql AS $$
diff --git a/src/test/regress/expected/plancache.out b/src/test/regress/expected/plancache.out
index 864f70f..3f3db33 100644
--- a/src/test/regress/expected/plancache.out
+++ b/src/test/regress/expected/plancache.out
@@ -234,8 +234,6 @@ begin
 end$$ language plpgsql;
 select cachebug();
 NOTICE:  table "temptable" does not exist, skipping
-CONTEXT:  SQL statement "drop table if exists temptable cascade"
-PL/pgSQL function cachebug() line 4 at SQL statement
 NOTICE:  1
 NOTICE:  2
 NOTICE:  3
@@ -246,8 +244,6 @@ NOTICE:  3
 
 select cachebug();
 NOTICE:  drop cascades to view vv
-CONTEXT:  SQL statement "drop table if exists temptable cascade"
-PL/pgSQL function cachebug() line 4 at SQL statement
 NOTICE:  1
 NOTICE:  2
 NOTICE:  3
diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out
index 7ce5415..a19424d 100644
--- a/src/test/regress/expected/plpgsql.out
+++ b/src/test/regress/expected/plpgsql.out
@@ -1518,27 +1518,35 @@ ERROR:  duplicate key value violates unique constraint "pfield_name"
 DETAIL:  Key (name)=(PF1_1) already exists.
 update PSlot set backlink = 'WS.not.there' where slotname = 'PS.base.a1';
 ERROR:  WS.not.there         does not exist
-CONTEXT:  PL/pgSQL function tg_backlink_a() line 17 at assignment
+CONTEXT:  PL/pgSQL function tg_backlink_set(character,character) line 30 at RAISE
+PL/pgSQL function tg_backlink_a() line 17 at assignment
 update PSlot set backlink = 'XX.illegal' where slotname = 'PS.base.a1';
 ERROR:  illegal backlink beginning with XX
-CONTEXT:  PL/pgSQL function tg_backlink_a() line 17 at assignment
+CONTEXT:  PL/pgSQL function tg_backlink_set(character,character) line 47 at RAISE
+PL/pgSQL function tg_backlink_a() line 17 at assignment
 update PSlot set slotlink = 'PS.not.there' where slotname = 'PS.base.a1';
 ERROR:  PS.not.there         does not exist
-CONTEXT:  PL/pgSQL function tg_slotlink_a() line 17 at assignment
+CONTEXT:  PL/pgSQL function tg_slotlink_set(character,character) line 30 at RAISE
+PL/pgSQL function tg_slotlink_a() line 17 at assignment
 update PSlot set slotlink = 'XX.illegal' where slotname = 'PS.base.a1';
 ERROR:  illegal slotlink beginning with XX
-CONTEXT:  PL/pgSQL function tg_slotlink_a() line 17 at assignment
+CONTEXT:  PL/pgSQL function tg_slotlink_set(character,character) line 77 at RAISE
+PL/pgSQL function tg_slotlink_a() line 17 at assignment
 insert into HSlot values ('HS', 'base.hub1', 1, '');
 ERROR:  duplicate key value violates unique constraint "hslot_name"
 DETAIL:  Key (slotname)=(HS.base.hub1.1      ) already exists.
 insert into HSlot values ('HS', 'base.hub1', 20, '');
 ERROR:  no manual manipulation of HSlot
+CONTEXT:  PL/pgSQL function tg_hslot_biu() line 12 at RAISE
 delete from HSlot;
 ERROR:  no manual manipulation of HSlot
+CONTEXT:  PL/pgSQL function tg_hslot_bd() line 12 at RAISE
 insert into IFace values ('IF', 'notthere', 'eth0', '');
 ERROR:  system "notthere" does not exist
+CONTEXT:  PL/pgSQL function tg_iface_biu() line 8 at RAISE
 insert into IFace values ('IF', 'orion', 'ethernet_interface_name_too_long', '');
 ERROR:  IFace slotname "IF.orion.ethernet_interface_name_too_long" too long (20 char max)
+CONTEXT:  PL/pgSQL function tg_iface_biu() line 14 at RAISE
 --
 -- The following tests are unrelated to the scenario outlined above;
 -- they merely exercise specific parts of PL/pgSQL
@@ -1963,6 +1971,7 @@ NOTICE:  should see this
 NOTICE:  should see this only if -100 <> 0
 NOTICE:  should see this only if -100 fits in smallint
 ERROR:  -100 is less than zero
+CONTEXT:  PL/pgSQL function trap_zero_divide(integer) line 12 at RAISE
 create function trap_matching_test(int) returns int as $$
 declare x int;
 	sx smallint;
@@ -2066,14 +2075,8 @@ begin
 end$$ language plpgsql;
 select test_variable_storage();
 NOTICE:  should see this
-CONTEXT:  SQL statement "SELECT trap_zero_divide(-100)"
-PL/pgSQL function test_variable_storage() line 8 at PERFORM
 NOTICE:  should see this only if -100 <> 0
-CONTEXT:  SQL statement "SELECT trap_zero_divide(-100)"
-PL/pgSQL function test_variable_storage() line 8 at PERFORM
 NOTICE:  should see this only if -100 fits in smallint
-CONTEXT:  SQL statement "SELECT trap_zero_divide(-100)"
-PL/pgSQL function test_variable_storage() line 8 at PERFORM
  test_variable_storage 
 -----------------------
  123456789012
@@ -4052,6 +4055,7 @@ DETAIL:  some detail info
 HINT:  some hint
 ERROR:  1 2 3
 DETAIL:  some detail info
+CONTEXT:  PL/pgSQL function raise_test() line 5 at RAISE
 -- Since we can't actually see the thrown SQLSTATE in default psql output,
 -- test it like this; this also tests re-RAISE
 create or replace function raise_test() returns void as $$
@@ -4068,6 +4072,7 @@ select raise_test();
 NOTICE:  SQLSTATE: 22012 SQLERRM: check me
 ERROR:  check me
 DETAIL:  some detail info
+CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
 create or replace function raise_test() returns void as $$
 begin
   raise 'check me'
@@ -4082,6 +4087,7 @@ select raise_test();
 NOTICE:  SQLSTATE: 1234F SQLERRM: check me
 ERROR:  check me
 DETAIL:  some detail info
+CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
 -- SQLSTATE specification in WHEN
 create or replace function raise_test() returns void as $$
 begin
@@ -4097,6 +4103,7 @@ select raise_test();
 NOTICE:  SQLSTATE: 1234F SQLERRM: check me
 ERROR:  check me
 DETAIL:  some detail info
+CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
 create or replace function raise_test() returns void as $$
 begin
   raise division_by_zero using detail = 'some detail info';
@@ -4110,6 +4117,7 @@ select raise_test();
 NOTICE:  SQLSTATE: 22012 SQLERRM: division_by_zero
 ERROR:  division_by_zero
 DETAIL:  some detail info
+CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
 create or replace function raise_test() returns void as $$
 begin
   raise division_by_zero;
@@ -4117,6 +4125,7 @@ end;
 $$ language plpgsql;
 select raise_test();
 ERROR:  division_by_zero
+CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
 create or replace function raise_test() returns void as $$
 begin
   raise sqlstate '1234F';
@@ -4124,6 +4133,7 @@ end;
 $$ language plpgsql;
 select raise_test();
 ERROR:  1234F
+CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
 create or replace function raise_test() returns void as $$
 begin
   raise division_by_zero using message = 'custom' || ' message';
@@ -4131,6 +4141,7 @@ end;
 $$ language plpgsql;
 select raise_test();
 ERROR:  custom message
+CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
 create or replace function raise_test() returns void as $$
 begin
   raise using message = 'custom' || ' message', errcode = '22012';
@@ -4138,6 +4149,7 @@ end;
 $$ language plpgsql;
 select raise_test();
 ERROR:  custom message
+CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
 -- conflict on message
 create or replace function raise_test() returns void as $$
 begin
@@ -4254,6 +4266,7 @@ $$ language plpgsql;
 select raise_test();
 NOTICE:  22012
 ERROR:  substitute message
+CONTEXT:  PL/pgSQL function raise_test() line 7 at RAISE
 drop function raise_test();
 -- test passing column_name, constraint_name, datatype_name, table_name
 -- and schema_name error fields
@@ -4744,7 +4757,6 @@ LINE 1: SELECT 'foo\\bar\041baz'
                ^
 HINT:  Use the escape string syntax for backslashes, e.g., E'\\'.
 QUERY:  SELECT 'foo\\bar\041baz'
-CONTEXT:  PL/pgSQL function strtest() line 4 at RETURN
    strtest   
 -------------
  foo\bar!baz
@@ -5260,22 +5272,14 @@ $$ language plpgsql;
 select outer_outer_func(10);
 NOTICE:  calling down into outer_func()
 NOTICE:  calling down into inner_func()
-CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
 NOTICE:  ***PL/pgSQL function inner_func(integer) line 4 at GET DIAGNOSTICS
 PL/pgSQL function outer_func(integer) line 6 at assignment
 PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
-CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
-PL/pgSQL function outer_outer_func(integer) line 6 at assignment
 NOTICE:  ***PL/pgSQL function inner_func(integer) line 7 at GET DIAGNOSTICS
 PL/pgSQL function outer_func(integer) line 6 at assignment
 PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
-CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
-PL/pgSQL function outer_outer_func(integer) line 6 at assignment
 NOTICE:  lets make sure we didnt break anything
-CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
-PL/pgSQL function outer_outer_func(integer) line 6 at assignment
 NOTICE:  inner_func() done
-CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
 NOTICE:  outer_func() done
  outer_outer_func 
 ------------------
@@ -5286,22 +5290,14 @@ NOTICE:  outer_func() done
 select outer_outer_func(20);
 NOTICE:  calling down into outer_func()
 NOTICE:  calling down into inner_func()
-CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
 NOTICE:  ***PL/pgSQL function inner_func(integer) line 4 at GET DIAGNOSTICS
 PL/pgSQL function outer_func(integer) line 6 at assignment
 PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
-CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
-PL/pgSQL function outer_outer_func(integer) line 6 at assignment
 NOTICE:  ***PL/pgSQL function inner_func(integer) line 7 at GET DIAGNOSTICS
 PL/pgSQL function outer_func(integer) line 6 at assignment
 PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
-CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
-PL/pgSQL function outer_outer_func(integer) line 6 at assignment
 NOTICE:  lets make sure we didnt break anything
-CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
-PL/pgSQL function outer_outer_func(integer) line 6 at assignment
 NOTICE:  inner_func() done
-CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
 NOTICE:  outer_func() done
  outer_outer_func 
 ------------------
@@ -5358,22 +5354,14 @@ $$ language plpgsql;
 select outer_outer_func(10);
 NOTICE:  calling down into outer_func()
 NOTICE:  calling down into inner_func()
-CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
 NOTICE:  ***PL/pgSQL function inner_func(integer) line 10 at GET DIAGNOSTICS
 PL/pgSQL function outer_func(integer) line 6 at assignment
 PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
-CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
-PL/pgSQL function outer_outer_func(integer) line 6 at assignment
 NOTICE:  ***PL/pgSQL function inner_func(integer) line 15 at GET DIAGNOSTICS
 PL/pgSQL function outer_func(integer) line 6 at assignment
 PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
-CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
-PL/pgSQL function outer_outer_func(integer) line 6 at assignment
 NOTICE:  lets make sure we didnt break anything
-CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
-PL/pgSQL function outer_outer_func(integer) line 6 at assignment
 NOTICE:  inner_func() done
-CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
 NOTICE:  outer_func() done
  outer_outer_func 
 ------------------
@@ -5384,22 +5372,14 @@ NOTICE:  outer_func() done
 select outer_outer_func(20);
 NOTICE:  calling down into outer_func()
 NOTICE:  calling down into inner_func()
-CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
 NOTICE:  ***PL/pgSQL function inner_func(integer) line 10 at GET DIAGNOSTICS
 PL/pgSQL function outer_func(integer) line 6 at assignment
 PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
-CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
-PL/pgSQL function outer_outer_func(integer) line 6 at assignment
 NOTICE:  ***PL/pgSQL function inner_func(integer) line 15 at GET DIAGNOSTICS
 PL/pgSQL function outer_func(integer) line 6 at assignment
 PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
-CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
-PL/pgSQL function outer_outer_func(integer) line 6 at assignment
 NOTICE:  lets make sure we didnt break anything
-CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
-PL/pgSQL function outer_outer_func(integer) line 6 at assignment
 NOTICE:  inner_func() done
-CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
 NOTICE:  outer_func() done
  outer_outer_func 
 ------------------
diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out
index c0cd9fa..88bdc2c 100644
--- a/src/test/regress/expected/privileges.out
+++ b/src/test/regress/expected/privileges.out
@@ -1023,7 +1023,6 @@ GRANT regressgroup2 TO regressuser5; -- fails: no ADMIN OPTION
 ERROR:  must have admin option on role "regressgroup2"
 SELECT dogrant_ok();			-- ok: SECURITY DEFINER conveys ADMIN
 NOTICE:  role "regressuser5" is already a member of role "regressgroup2"
-CONTEXT:  SQL function "dogrant_ok" statement 1
  dogrant_ok 
 ------------
  
diff --git a/src/test/regress/expected/rangefuncs.out b/src/test/regress/expected/rangefuncs.out
index 6dabe50..00ef421 100644
--- a/src/test/regress/expected/rangefuncs.out
+++ b/src/test/regress/expected/rangefuncs.out
@@ -1704,9 +1704,7 @@ create trigger tnoticetrigger after insert on tt for each row
 execute procedure noticetrigger();
 select insert_tt2('foolme','barme') limit 1;
 NOTICE:  noticetrigger 11 foolme
-CONTEXT:  SQL function "insert_tt2" statement 1
 NOTICE:  noticetrigger 12 barme
-CONTEXT:  SQL function "insert_tt2" statement 1
  insert_tt2 
 ------------
          11
@@ -1735,9 +1733,7 @@ create rule insert_tt_rule as on insert to tt do also
   insert into tt_log values(new.*);
 select insert_tt2('foollog','barlog') limit 1;
 NOTICE:  noticetrigger 13 foollog
-CONTEXT:  SQL function "insert_tt2" statement 1
 NOTICE:  noticetrigger 14 barlog
-CONTEXT:  SQL function "insert_tt2" statement 1
  insert_tt2 
 ------------
          13
diff --git a/src/test/regress/expected/triggers.out b/src/test/regress/expected/triggers.out
index 3b32e8f..cd43e46 100644
--- a/src/test/regress/expected/triggers.out
+++ b/src/test/regress/expected/triggers.out
@@ -958,11 +958,7 @@ NOTICE:  main_view BEFORE INSERT STATEMENT (before_view_ins_stmt)
 NOTICE:  main_view INSTEAD OF INSERT ROW (instead_of_ins)
 NOTICE:  NEW: (20,30)
 NOTICE:  trigger_func(before_ins_stmt) called: action = INSERT, when = BEFORE, level = STATEMENT
-CONTEXT:  SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
-PL/pgSQL function view_trigger() line 17 at SQL statement
 NOTICE:  trigger_func(after_ins_stmt) called: action = INSERT, when = AFTER, level = STATEMENT
-CONTEXT:  SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
-PL/pgSQL function view_trigger() line 17 at SQL statement
 NOTICE:  main_view AFTER INSERT STATEMENT (after_view_ins_stmt)
 INSERT 0 1
 INSERT INTO main_view VALUES (21, 31) RETURNING a, b;
@@ -970,11 +966,7 @@ NOTICE:  main_view BEFORE INSERT STATEMENT (before_view_ins_stmt)
 NOTICE:  main_view INSTEAD OF INSERT ROW (instead_of_ins)
 NOTICE:  NEW: (21,31)
 NOTICE:  trigger_func(before_ins_stmt) called: action = INSERT, when = BEFORE, level = STATEMENT
-CONTEXT:  SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
-PL/pgSQL function view_trigger() line 17 at SQL statement
 NOTICE:  trigger_func(after_ins_stmt) called: action = INSERT, when = AFTER, level = STATEMENT
-CONTEXT:  SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
-PL/pgSQL function view_trigger() line 17 at SQL statement
 NOTICE:  main_view AFTER INSERT STATEMENT (after_view_ins_stmt)
  a  | b  
 ----+----
@@ -988,17 +980,9 @@ NOTICE:  main_view BEFORE UPDATE STATEMENT (before_view_upd_stmt)
 NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
 NOTICE:  OLD: (20,30), NEW: (20,31)
 NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
-CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
-PL/pgSQL function view_trigger() line 23 at SQL statement
 NOTICE:  trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW
-CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
-PL/pgSQL function view_trigger() line 23 at SQL statement
 NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
-CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
-PL/pgSQL function view_trigger() line 23 at SQL statement
 NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
-CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
-PL/pgSQL function view_trigger() line 23 at SQL statement
 NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
 UPDATE 0
 UPDATE main_view SET b = 32 WHERE a = 21 AND b = 31 RETURNING a, b;
@@ -1006,17 +990,9 @@ NOTICE:  main_view BEFORE UPDATE STATEMENT (before_view_upd_stmt)
 NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
 NOTICE:  OLD: (21,31), NEW: (21,32)
 NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
-CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
-PL/pgSQL function view_trigger() line 23 at SQL statement
 NOTICE:  trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW
-CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
-PL/pgSQL function view_trigger() line 23 at SQL statement
 NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
-CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
-PL/pgSQL function view_trigger() line 23 at SQL statement
 NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
-CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
-PL/pgSQL function view_trigger() line 23 at SQL statement
 NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
  a | b 
 ---+---
@@ -1031,20 +1007,10 @@ NOTICE:  main_view BEFORE UPDATE STATEMENT (before_view_upd_stmt)
 NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
 NOTICE:  OLD: (20,30), NEW: (20,31)
 NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
-CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
-PL/pgSQL function view_trigger() line 23 at SQL statement
 NOTICE:  trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW
-CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
-PL/pgSQL function view_trigger() line 23 at SQL statement
 NOTICE:  trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW
-CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
-PL/pgSQL function view_trigger() line 23 at SQL statement
 NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
-CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
-PL/pgSQL function view_trigger() line 23 at SQL statement
 NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
-CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
-PL/pgSQL function view_trigger() line 23 at SQL statement
 NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
 UPDATE 1
 UPDATE main_view SET b = 32 WHERE a = 21 AND b = 31 RETURNING a, b;
@@ -1052,20 +1018,10 @@ NOTICE:  main_view BEFORE UPDATE STATEMENT (before_view_upd_stmt)
 NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
 NOTICE:  OLD: (21,31), NEW: (21,32)
 NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
-CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
-PL/pgSQL function view_trigger() line 23 at SQL statement
 NOTICE:  trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW
-CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
-PL/pgSQL function view_trigger() line 23 at SQL statement
 NOTICE:  trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW
-CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
-PL/pgSQL function view_trigger() line 23 at SQL statement
 NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
-CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
-PL/pgSQL function view_trigger() line 23 at SQL statement
 NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
-CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
-PL/pgSQL function view_trigger() line 23 at SQL statement
 NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
  a  | b  
 ----+----
@@ -1277,6 +1233,7 @@ INSERT 0 1
 -- UPDATE .. RETURNING
 UPDATE city_view SET country_name = 'Japon' WHERE city_name = 'Tokyo'; -- error
 ERROR:  No such country: "Japon"
+CONTEXT:  PL/pgSQL function city_update() line 9 at RAISE
 UPDATE city_view SET country_name = 'Japan' WHERE city_name = 'Takyo'; -- no match
 UPDATE 0
 UPDATE city_view SET country_name = 'Japan' WHERE city_name = 'Tokyo' RETURNING *; -- OK
@@ -1489,26 +1446,13 @@ select pg_trigger_depth();
 insert into depth_a values (1);
 NOTICE:  depth_a_tr: depth = 1
 NOTICE:  depth_b_tr: depth = 2
-CONTEXT:  SQL statement "insert into depth_b values (new.id)"
-PL/pgSQL function depth_a_tf() line 4 at SQL statement
 NOTICE:  depth_c_tr: depth = 3
-CONTEXT:  SQL statement "insert into depth_c values (1)"
-PL/pgSQL function depth_b_tf() line 5 at EXECUTE statement
-SQL statement "insert into depth_b values (new.id)"
-PL/pgSQL function depth_a_tf() line 4 at SQL statement
 NOTICE:  SQLSTATE = U9999: depth = 2
-CONTEXT:  SQL statement "insert into depth_b values (new.id)"
-PL/pgSQL function depth_a_tf() line 4 at SQL statement
 NOTICE:  depth_b_tr: depth = 2
-CONTEXT:  SQL statement "insert into depth_b values (new.id)"
-PL/pgSQL function depth_a_tf() line 4 at SQL statement
 NOTICE:  depth_c_tr: depth = 3
-CONTEXT:  SQL statement "insert into depth_c values (1)"
-PL/pgSQL function depth_b_tf() line 12 at EXECUTE statement
-SQL statement "insert into depth_b values (new.id)"
-PL/pgSQL function depth_a_tf() line 4 at SQL statement
 ERROR:  U9999
-CONTEXT:  SQL statement "insert into depth_c values (1)"
+CONTEXT:  PL/pgSQL function depth_c_tf() line 5 at RAISE
+SQL statement "insert into depth_c values (1)"
 PL/pgSQL function depth_b_tf() line 12 at EXECUTE statement
 SQL statement "insert into depth_b values (new.id)"
 PL/pgSQL function depth_a_tf() line 4 at SQL statement
@@ -1521,21 +1465,9 @@ select pg_trigger_depth();
 insert into depth_a values (2);
 NOTICE:  depth_a_tr: depth = 1
 NOTICE:  depth_b_tr: depth = 2
-CONTEXT:  SQL statement "insert into depth_b values (new.id)"
-PL/pgSQL function depth_a_tf() line 4 at SQL statement
 NOTICE:  depth_c_tr: depth = 3
-CONTEXT:  SQL statement "insert into depth_c values (2)"
-PL/pgSQL function depth_b_tf() line 5 at EXECUTE statement
-SQL statement "insert into depth_b values (new.id)"
-PL/pgSQL function depth_a_tf() line 4 at SQL statement
 NOTICE:  depth_c_tr: depth = 3
-CONTEXT:  SQL statement "insert into depth_c values (2)"
-PL/pgSQL function depth_b_tf() line 5 at EXECUTE statement
-SQL statement "insert into depth_b values (new.id)"
-PL/pgSQL function depth_a_tf() line 4 at SQL statement
 NOTICE:  depth_b_tr: depth = 2
-CONTEXT:  SQL statement "insert into depth_b values (new.id)"
-PL/pgSQL function depth_a_tf() line 4 at SQL statement
 NOTICE:  depth_a_tr: depth = 1
 select pg_trigger_depth();
  pg_trigger_depth 
diff --git a/src/test/regress/expected/xml.out b/src/test/regress/expected/xml.out
index 9b2d264..5691e47 100644
--- a/src/test/regress/expected/xml.out
+++ b/src/test/regress/expected/xml.out
@@ -934,7 +934,6 @@ SELECT xpath('/*', '<relativens xmlns=''relative''/>');
 WARNING:  line 1: xmlns: URI relative is not absolute
 <relativens xmlns='relative'/>
                             ^
-CONTEXT:  SQL function "xpath" statement 1
                 xpath                 
 --------------------------------------
  {"<relativens xmlns=\"relative\"/>"}
#78Pavel Stehule
pavel.stehule@gmail.com
In reply to: Pavel Stehule (#75)
Re: PL/pgSQL, RAISE and error context

2015-07-08 8:35 GMT+02:00 Pavel Stehule <pavel.stehule@gmail.com>:

2015-07-07 18:15 GMT+02:00 Merlin Moncure <mmoncure@gmail.com>:

On Tue, Jul 7, 2015 at 9:04 AM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

It doesn't have to if the behavior is guarded with a GUC. I just
don't understand what all the fuss is about. The default behavior of
logging that is well established by other languages (for example java)
that manage error stack for you should be to:

*) Give stack trace when an uncaught exception is thrown
*) Do not give stack trace in all other logging cases unless asked for

what is RAISE EXCEPTION - first or second case?

First: RAISE (unless caught) is no different than any other kind of error.

On Tue, Jul 7, 2015 at 9:42 AM, Heikki Linnakangas <hlinnaka@iki.fi>
wrote:

On 07/07/2015 04:56 PM, Merlin Moncure wrote:

It doesn't have to if the behavior is guarded with a GUC. I just
don't understand what all the fuss is about. The default behavior of
logging that is well established by other languages (for example java)
that manage error stack for you should be to:

*) Give stack trace when an uncaught exception is thrown
*) Do not give stack trace in all other logging cases unless asked for

Java's exception handling is so different from PostgreSQL's errors that

I

don't think there's much to be learned from that. But I'll bite:

First of all, Java's exceptions always contain a stack trace. It's up

to you

when you catch an exception to decide whether to print it or not. "try

{ ...

} catch (Exception e) { e.printStackTrace() }" is fairly common,

actually.

There is nothing like a NOTICE in Java, i.e. an exception that's thrown

but

doesn't affect the control flow. The best I can think of is
System.out.println(), which of course has no stack trace attached to it.

exactly.

Perhaps you're arguing that NOTICE is more like printing to stderr, and
should never contain any context information. I don't think that would

be an

improvement. It's very handy to have the context information available

if

don't know where a NOTICE is coming from, even if in most cases you're

not

interested in it.

That's exactly what I'm arguing. NOTICE (and WARNING) are for
printing out information to client side logging; it's really the only
tool we have for that purpose and it fits that role perfectly. Of
course, you may want to have NOTICE print context, especially when
debugging, but some control over that would be nice and in most cases
it's really not necessary. I really don't understand the objection to
offering control over that behavior although I certainly understand
wanting to keep the default behavior as it currently is.

This is really quite different from a programming language's exception
handling. First, there's a server, which produces the errors, and a

separate

client, which displays them. You cannot catch an exception in the

client.

BTW, let me throw in one use case to consider. We've been talking about
psql, and what to print, but imagine a more sophisticated client like
pgAdmin. It's not limited to either printing the context or not. It

could

e.g. hide the context information of all messages when they occur, but

if

you double-click on it, it's expanded to show all the context, location

and

all. You can't do that if the server doesn't send the context

information in

the first place.

I would be happy to show you the psql redirected output logs from my
nightly server processes that spew into the megabytes because of
logging various high level steps (did this, did that).

Oh, I believe you. I understand what the problem is, we're only talking
about how best to address it.

Yeah. For posterity, a psql based solution would work fine for me,
but a server side solution has a lot of advantages (less protocol
chatter, more configurability, keeping libpq/psql light).

After some work on reduced version of "plpgsql.min_context" patch I am
inclining to think so ideal solution needs more steps - because this issue
has more than one dimension.

There are two independent issues:

1. old plpgsql workaround that reduced the unwanted call stack info for
RAISE NOTICE. Negative side effect of this workaround is missing context
info about the RAISE command that raises the exception. We know a function,
but we don't know a line of related RAISE statement. The important is fact,
so NOTICE doesn't bubble to up. So this workaround was relative successful
without to implement some filtering on client or log side.

I found a other issue of this workaround - it doesn't work well for nested
SQL statement call, when inner statement invoke RAISE NOTICE. In this case
a context is showed too.

postgres=# insert into xx values(60);
NOTICE: <<<<<>>>>>>
NOTICE: trigger_func(before_ins_stmt) called: action = INSERT, when =
BEFORE, level = STATEMENT
CONTEXT: SQL statement "INSERT INTO boo VALUES(30)"
PL/pgSQL function hh() line 1 at SQL statement

So filtering context for selected environment is not good idea. The result
is fragmented context, where is not clear, what is missing.

Pavel

Show quoted text

2. second issue is general suppressing context info for interactive client
or for log.

These issues should be solved separately, because solution for @2 doesn't
fix @1, and @1 is too local for @2.

So what we can do?

1. remove current plpgsql workaround - and implement client_min_context
and log_min_context
2. implement plpgsql.min_context, and client_min_context and
log_min_context

@1 is consistent, but isn't possible to configure same behave as was before

@2 is difficult in definition what plpgsql.min_context should to really
do - and what is relation to client_min_context and log_min_context, but I
can prepare configuration, that is fully compatible.

Comments, any other ideas?

Personally, I prefer @1 as general solution, that will work for all PL

Regards

Pavel

merlin

#79Merlin Moncure
mmoncure@gmail.com
In reply to: Pavel Stehule (#78)
Re: PL/pgSQL, RAISE and error context

On Wed, Jul 8, 2015 at 4:39 PM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

2015-07-08 8:35 GMT+02:00 Pavel Stehule <pavel.stehule@gmail.com>:

2015-07-07 18:15 GMT+02:00 Merlin Moncure <mmoncure@gmail.com>:

On Tue, Jul 7, 2015 at 9:04 AM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

It doesn't have to if the behavior is guarded with a GUC. I just
don't understand what all the fuss is about. The default behavior of
logging that is well established by other languages (for example java)
that manage error stack for you should be to:

*) Give stack trace when an uncaught exception is thrown
*) Do not give stack trace in all other logging cases unless asked for

what is RAISE EXCEPTION - first or second case?

First: RAISE (unless caught) is no different than any other kind of
error.

On Tue, Jul 7, 2015 at 9:42 AM, Heikki Linnakangas <hlinnaka@iki.fi>
wrote:

On 07/07/2015 04:56 PM, Merlin Moncure wrote:

It doesn't have to if the behavior is guarded with a GUC. I just
don't understand what all the fuss is about. The default behavior of
logging that is well established by other languages (for example java)
that manage error stack for you should be to:

*) Give stack trace when an uncaught exception is thrown
*) Do not give stack trace in all other logging cases unless asked for

Java's exception handling is so different from PostgreSQL's errors that
I
don't think there's much to be learned from that. But I'll bite:

First of all, Java's exceptions always contain a stack trace. It's up
to you
when you catch an exception to decide whether to print it or not. "try
{ ...
} catch (Exception e) { e.printStackTrace() }" is fairly common,
actually.
There is nothing like a NOTICE in Java, i.e. an exception that's thrown
but
doesn't affect the control flow. The best I can think of is
System.out.println(), which of course has no stack trace attached to
it.

exactly.

Perhaps you're arguing that NOTICE is more like printing to stderr, and
should never contain any context information. I don't think that would
be an
improvement. It's very handy to have the context information available
if
don't know where a NOTICE is coming from, even if in most cases you're
not
interested in it.

That's exactly what I'm arguing. NOTICE (and WARNING) are for
printing out information to client side logging; it's really the only
tool we have for that purpose and it fits that role perfectly. Of
course, you may want to have NOTICE print context, especially when
debugging, but some control over that would be nice and in most cases
it's really not necessary. I really don't understand the objection to
offering control over that behavior although I certainly understand
wanting to keep the default behavior as it currently is.

This is really quite different from a programming language's exception
handling. First, there's a server, which produces the errors, and a
separate
client, which displays them. You cannot catch an exception in the
client.

BTW, let me throw in one use case to consider. We've been talking about
psql, and what to print, but imagine a more sophisticated client like
pgAdmin. It's not limited to either printing the context or not. It
could
e.g. hide the context information of all messages when they occur, but
if
you double-click on it, it's expanded to show all the context, location
and
all. You can't do that if the server doesn't send the context
information in
the first place.

I would be happy to show you the psql redirected output logs from my
nightly server processes that spew into the megabytes because of
logging various high level steps (did this, did that).

Oh, I believe you. I understand what the problem is, we're only talking
about how best to address it.

Yeah. For posterity, a psql based solution would work fine for me,
but a server side solution has a lot of advantages (less protocol
chatter, more configurability, keeping libpq/psql light).

After some work on reduced version of "plpgsql.min_context" patch I am
inclining to think so ideal solution needs more steps - because this issue
has more than one dimension.

There are two independent issues:

1. old plpgsql workaround that reduced the unwanted call stack info for
RAISE NOTICE. Negative side effect of this workaround is missing context
info about the RAISE command that raises the exception. We know a function,
but we don't know a line of related RAISE statement. The important is fact,
so NOTICE doesn't bubble to up. So this workaround was relative successful
without to implement some filtering on client or log side.

I found a other issue of this workaround - it doesn't work well for nested
SQL statement call, when inner statement invoke RAISE NOTICE. In this case a
context is showed too.

postgres=# insert into xx values(60);
NOTICE: <<<<<>>>>>>
NOTICE: trigger_func(before_ins_stmt) called: action = INSERT, when =
BEFORE, level = STATEMENT
CONTEXT: SQL statement "INSERT INTO boo VALUES(30)"
PL/pgSQL function hh() line 1 at SQL statement

So filtering context for selected environment is not good idea. The result
is fragmented context, where is not clear, what is missing.

not quite following you. Is this a problem with your proposed patch,
or a reason why your patch is the 'right' implementation?

merlin

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#80Pavel Stehule
pavel.stehule@gmail.com
In reply to: Merlin Moncure (#79)
Re: PL/pgSQL, RAISE and error context

2015-07-08 23:46 GMT+02:00 Merlin Moncure <mmoncure@gmail.com>:

On Wed, Jul 8, 2015 at 4:39 PM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

2015-07-08 8:35 GMT+02:00 Pavel Stehule <pavel.stehule@gmail.com>:

2015-07-07 18:15 GMT+02:00 Merlin Moncure <mmoncure@gmail.com>:

On Tue, Jul 7, 2015 at 9:04 AM, Pavel Stehule <pavel.stehule@gmail.com

wrote:

It doesn't have to if the behavior is guarded with a GUC. I just
don't understand what all the fuss is about. The default behavior

of

logging that is well established by other languages (for example

java)

that manage error stack for you should be to:

*) Give stack trace when an uncaught exception is thrown
*) Do not give stack trace in all other logging cases unless asked

for

what is RAISE EXCEPTION - first or second case?

First: RAISE (unless caught) is no different than any other kind of
error.

On Tue, Jul 7, 2015 at 9:42 AM, Heikki Linnakangas <hlinnaka@iki.fi>
wrote:

On 07/07/2015 04:56 PM, Merlin Moncure wrote:

It doesn't have to if the behavior is guarded with a GUC. I just
don't understand what all the fuss is about. The default behavior

of

logging that is well established by other languages (for example

java)

that manage error stack for you should be to:

*) Give stack trace when an uncaught exception is thrown
*) Do not give stack trace in all other logging cases unless asked

for

Java's exception handling is so different from PostgreSQL's errors

that

I
don't think there's much to be learned from that. But I'll bite:

First of all, Java's exceptions always contain a stack trace. It's up
to you
when you catch an exception to decide whether to print it or not.

"try

{ ...
} catch (Exception e) { e.printStackTrace() }" is fairly common,
actually.
There is nothing like a NOTICE in Java, i.e. an exception that's

thrown

but
doesn't affect the control flow. The best I can think of is
System.out.println(), which of course has no stack trace attached to
it.

exactly.

Perhaps you're arguing that NOTICE is more like printing to stderr,

and

should never contain any context information. I don't think that

would

be an
improvement. It's very handy to have the context information

available

if
don't know where a NOTICE is coming from, even if in most cases

you're

not
interested in it.

That's exactly what I'm arguing. NOTICE (and WARNING) are for
printing out information to client side logging; it's really the only
tool we have for that purpose and it fits that role perfectly. Of
course, you may want to have NOTICE print context, especially when
debugging, but some control over that would be nice and in most cases
it's really not necessary. I really don't understand the objection to
offering control over that behavior although I certainly understand
wanting to keep the default behavior as it currently is.

This is really quite different from a programming language's

exception

handling. First, there's a server, which produces the errors, and a
separate
client, which displays them. You cannot catch an exception in the
client.

BTW, let me throw in one use case to consider. We've been talking

about

psql, and what to print, but imagine a more sophisticated client like
pgAdmin. It's not limited to either printing the context or not. It
could
e.g. hide the context information of all messages when they occur,

but

if
you double-click on it, it's expanded to show all the context,

location

and
all. You can't do that if the server doesn't send the context
information in
the first place.

I would be happy to show you the psql redirected output logs from my
nightly server processes that spew into the megabytes because of
logging various high level steps (did this, did that).

Oh, I believe you. I understand what the problem is, we're only

talking

about how best to address it.

Yeah. For posterity, a psql based solution would work fine for me,
but a server side solution has a lot of advantages (less protocol
chatter, more configurability, keeping libpq/psql light).

After some work on reduced version of "plpgsql.min_context" patch I am
inclining to think so ideal solution needs more steps - because this

issue

has more than one dimension.

There are two independent issues:

1. old plpgsql workaround that reduced the unwanted call stack info for
RAISE NOTICE. Negative side effect of this workaround is missing context
info about the RAISE command that raises the exception. We know a

function,

but we don't know a line of related RAISE statement. The important is

fact,

so NOTICE doesn't bubble to up. So this workaround was relative

successful

without to implement some filtering on client or log side.

I found a other issue of this workaround - it doesn't work well for

nested

SQL statement call, when inner statement invoke RAISE NOTICE. In this

case a

context is showed too.

postgres=# insert into xx values(60);
NOTICE: <<<<<>>>>>>
NOTICE: trigger_func(before_ins_stmt) called: action = INSERT, when =
BEFORE, level = STATEMENT
CONTEXT: SQL statement "INSERT INTO boo VALUES(30)"
PL/pgSQL function hh() line 1 at SQL statement

So filtering context for selected environment is not good idea. The

result

is fragmented context, where is not clear, what is missing.

not quite following you. Is this a problem with your proposed patch,
or a reason why your patch is the 'right' implementation?

My patch fixes it. The current design is not consistent.

Pavel

Show quoted text

merlin

#81Pavel Stehule
pavel.stehule@gmail.com
In reply to: Pavel Stehule (#77)
1 attachment(s)
Re: PL/pgSQL, RAISE and error context

Hi

second version of this patch

make check-world passed

Regards

Pavel

2015-07-08 23:05 GMT+02:00 Pavel Stehule <pavel.stehule@gmail.com>:

Show quoted text

Hi

here is initial version of reduced patch. It is small code, but relative
big (although I expected bigger) change in tests.

if these changes are too big, then we have to introduce a plpgsql GUC
plpgsql.client_min_context and plpgsql.log_min_client. These GUC overwrite
global setting for plpgsql functions. I'll be more happy without these
variables. It decrease a impact of changes, but there is not clean what
behave is expected when PL are used together - and when fails PLpgSQL
function called from PLPerl. The context filtering should be really solved
on TOP level.

Regards

Pavel

2015-07-08 14:09 GMT+02:00 Merlin Moncure <mmoncure@gmail.com>:

On Wed, Jul 8, 2015 at 1:35 AM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

2015-07-07 18:15 GMT+02:00 Merlin Moncure <mmoncure@gmail.com>:

On Tue, Jul 7, 2015 at 9:04 AM, Pavel Stehule <pavel.stehule@gmail.com

wrote:

It doesn't have to if the behavior is guarded with a GUC. I just
don't understand what all the fuss is about. The default behavior

of

logging that is well established by other languages (for example

java)

that manage error stack for you should be to:

*) Give stack trace when an uncaught exception is thrown
*) Do not give stack trace in all other logging cases unless asked

for

what is RAISE EXCEPTION - first or second case?

First: RAISE (unless caught) is no different than any other kind of

error.

On Tue, Jul 7, 2015 at 9:42 AM, Heikki Linnakangas <hlinnaka@iki.fi>
wrote:

On 07/07/2015 04:56 PM, Merlin Moncure wrote:

It doesn't have to if the behavior is guarded with a GUC. I just
don't understand what all the fuss is about. The default behavior

of

logging that is well established by other languages (for example

java)

that manage error stack for you should be to:

*) Give stack trace when an uncaught exception is thrown
*) Do not give stack trace in all other logging cases unless asked

for

Java's exception handling is so different from PostgreSQL's errors

that

I
don't think there's much to be learned from that. But I'll bite:

First of all, Java's exceptions always contain a stack trace. It's

up to

you
when you catch an exception to decide whether to print it or not.

"try {

...
} catch (Exception e) { e.printStackTrace() }" is fairly common,
actually.
There is nothing like a NOTICE in Java, i.e. an exception that's

thrown

but
doesn't affect the control flow. The best I can think of is
System.out.println(), which of course has no stack trace attached to

it.

exactly.

Perhaps you're arguing that NOTICE is more like printing to stderr,

and

should never contain any context information. I don't think that

would

be an
improvement. It's very handy to have the context information

available

if
don't know where a NOTICE is coming from, even if in most cases

you're

not
interested in it.

That's exactly what I'm arguing. NOTICE (and WARNING) are for
printing out information to client side logging; it's really the only
tool we have for that purpose and it fits that role perfectly. Of
course, you may want to have NOTICE print context, especially when
debugging, but some control over that would be nice and in most cases
it's really not necessary. I really don't understand the objection to
offering control over that behavior although I certainly understand
wanting to keep the default behavior as it currently is.

This is really quite different from a programming language's

exception

handling. First, there's a server, which produces the errors, and a
separate
client, which displays them. You cannot catch an exception in the
client.

BTW, let me throw in one use case to consider. We've been talking

about

psql, and what to print, but imagine a more sophisticated client like
pgAdmin. It's not limited to either printing the context or not. It
could
e.g. hide the context information of all messages when they occur,

but

if
you double-click on it, it's expanded to show all the context,

location

and
all. You can't do that if the server doesn't send the context
information in
the first place.

I would be happy to show you the psql redirected output logs from my
nightly server processes that spew into the megabytes because of
logging various high level steps (did this, did that).

Oh, I believe you. I understand what the problem is, we're only

talking

about how best to address it.

Yeah. For posterity, a psql based solution would work fine for me,
but a server side solution has a lot of advantages (less protocol
chatter, more configurability, keeping libpq/psql light).

After some work on reduced version of "plpgsql.min_context" patch I am
inclining to think so ideal solution needs more steps - because this

issue

has more than one dimension.

There are two independent issues:

1. old plpgsql workaround that reduced the unwanted call stack info for
RAISE NOTICE. Negative side effect of this workaround is missing context
info about the RAISE command that raises the exception. We know a

function,

but we don't know a line of related RAISE statement. The important is

fact,

so NOTICE doesn't bubble to up. So this workaround was relative

successful

without to implement some filtering on client or log side.

2. second issue is general suppressing context info for interactive

client

or for log.

These issues should be solved separately, because solution for @2

doesn't

fix @1, and @1 is too local for @2.

So what we can do?

1. remove current plpgsql workaround - and implement client_min_context

and

log_min_context
2. implement plpgsql.min_context, and client_min_context and

log_min_context

@1 is consistent, but isn't possible to configure same behave as was

before

@2 is difficult in definition what plpgsql.min_context should to

really do

- and what is relation to client_min_context and log_min_context, but I

can

prepare configuration, that is fully compatible.

Comments, any other ideas?

Personally, I prefer @1 as general solution, that will work for all PL

+1

merlin

Attachments:

min_context-20150709-01.patchtext/x-patch; charset=US-ASCII; name=min_context-20150709-01.patchDownload
diff --git a/contrib/dblink/expected/dblink.out b/contrib/dblink/expected/dblink.out
new file mode 100644
index a49b562..a268fc7
*** a/contrib/dblink/expected/dblink.out
--- b/contrib/dblink/expected/dblink.out
***************
*** 1,3 ****
--- 1,4 ----
+ set client_min_context TO notice;
  CREATE EXTENSION dblink;
  CREATE TABLE foo(f1 int, f2 text, f3 text[], primary key (f1,f2));
  INSERT INTO foo VALUES (0,'a','{"a0","b0","c0"}');
diff --git a/contrib/dblink/sql/dblink.sql b/contrib/dblink/sql/dblink.sql
new file mode 100644
index ea78cc2..cf7e57e
*** a/contrib/dblink/sql/dblink.sql
--- b/contrib/dblink/sql/dblink.sql
***************
*** 1,3 ****
--- 1,5 ----
+ set client_min_context TO notice;
+ 
  CREATE EXTENSION dblink;
  
  CREATE TABLE foo(f1 int, f2 text, f3 text[], primary key (f1,f2));
diff --git a/contrib/hstore_plperl/expected/hstore_plperlu.out b/contrib/hstore_plperl/expected/hstore_plperlu.out
new file mode 100644
index 8c689ad..c97fd3f
*** a/contrib/hstore_plperl/expected/hstore_plperlu.out
--- b/contrib/hstore_plperl/expected/hstore_plperlu.out
*************** INFO:  $VAR1 = {
*** 29,35 ****
            'cc' => undef
          };
  
- CONTEXT:  PL/Perl function "test1"
   test1 
  -------
       2
--- 29,34 ----
*************** $$;
*** 46,52 ****
  SELECT test1none('aa=>bb, cc=>NULL'::hstore);
  INFO:  $VAR1 = '"aa"=>"bb", "cc"=>NULL';
  
- CONTEXT:  PL/Perl function "test1none"
   test1none 
  -----------
           0
--- 45,50 ----
*************** INFO:  $VAR1 = {
*** 67,73 ****
            'cc' => undef
          };
  
- CONTEXT:  PL/Perl function "test1list"
   test1list 
  -----------
           2
--- 65,70 ----
*************** $VAR2 = {
*** 92,98 ****
            'dd' => 'ee'
          };
  
- CONTEXT:  PL/Perl function "test1arr"
   test1arr 
  ----------
          2
--- 89,94 ----
*************** INFO:  $VAR1 = {
*** 120,129 ****
            'cc' => undef
          };
  
- CONTEXT:  PL/Perl function "test3"
  INFO:  $VAR1 = '"a"=>"1", "b"=>"boo", "c"=>NULL';
  
- CONTEXT:  PL/Perl function "test3"
   test3 
  -------
   
--- 116,123 ----
*************** INFO:  $VAR1 = {
*** 161,167 ****
                 }
          };
  
- CONTEXT:  PL/Perl function "test4"
  SELECT * FROM test1;
   a |                b                
  ---+---------------------------------
--- 155,160 ----
diff --git a/contrib/hstore_plpython/expected/hstore_plpython.out b/contrib/hstore_plpython/expected/hstore_plpython.out
new file mode 100644
index b7a6a92..23091d3
*** a/contrib/hstore_plpython/expected/hstore_plpython.out
--- b/contrib/hstore_plpython/expected/hstore_plpython.out
*************** return len(val)
*** 13,19 ****
  $$;
  SELECT test1('aa=>bb, cc=>NULL'::hstore);
  INFO:  [('aa', 'bb'), ('cc', None)]
- CONTEXT:  PL/Python function "test1"
   test1 
  -------
       2
--- 13,18 ----
*************** return len(val)
*** 32,38 ****
  $$;
  SELECT test1n('aa=>bb, cc=>NULL'::hstore);
  INFO:  [('aa', 'bb'), ('cc', None)]
- CONTEXT:  PL/Python function "test1n"
   test1n 
  --------
        2
--- 31,36 ----
diff --git a/contrib/ltree_plpython/expected/ltree_plpython.out b/contrib/ltree_plpython/expected/ltree_plpython.out
new file mode 100644
index 934529e..c6e8a7c
*** a/contrib/ltree_plpython/expected/ltree_plpython.out
--- b/contrib/ltree_plpython/expected/ltree_plpython.out
*************** return len(val)
*** 9,15 ****
  $$;
  SELECT test1('aa.bb.cc'::ltree);
  INFO:  ['aa', 'bb', 'cc']
- CONTEXT:  PL/Python function "test1"
   test1 
  -------
       3
--- 9,14 ----
*************** return len(val)
*** 24,30 ****
  $$;
  SELECT test1n('aa.bb.cc'::ltree);
  INFO:  ['aa', 'bb', 'cc']
- CONTEXT:  PL/Python function "test1n"
   test1n 
  --------
        3
--- 23,28 ----
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
new file mode 100644
index 088c714..9445230
*** a/src/backend/utils/error/elog.c
--- b/src/backend/utils/error/elog.c
*************** write_csvlog(ErrorData *edata)
*** 2730,2736 ****
  	appendStringInfoChar(&buf, ',');
  
  	/* errcontext */
! 	if (!edata->hide_ctx)
  		appendCSVLiteral(&buf, edata->context);
  	appendStringInfoChar(&buf, ',');
  
--- 2730,2736 ----
  	appendStringInfoChar(&buf, ',');
  
  	/* errcontext */
! 	if (!edata->hide_ctx && edata->elevel >= log_min_context)
  		appendCSVLiteral(&buf, edata->context);
  	appendStringInfoChar(&buf, ',');
  
*************** send_message_to_server_log(ErrorData *ed
*** 2863,2869 ****
  			append_with_tabs(&buf, edata->internalquery);
  			appendStringInfoChar(&buf, '\n');
  		}
! 		if (edata->context && !edata->hide_ctx)
  		{
  			log_line_prefix(&buf, edata);
  			appendStringInfoString(&buf, _("CONTEXT:  "));
--- 2863,2869 ----
  			append_with_tabs(&buf, edata->internalquery);
  			appendStringInfoChar(&buf, '\n');
  		}
! 		if (edata->context && !edata->hide_ctx && edata->elevel >= log_min_context)
  		{
  			log_line_prefix(&buf, edata);
  			appendStringInfoString(&buf, _("CONTEXT:  "));
*************** send_message_to_frontend(ErrorData *edat
*** 3137,3143 ****
  			err_sendstring(&msgbuf, edata->hint);
  		}
  
! 		if (edata->context)
  		{
  			pq_sendbyte(&msgbuf, PG_DIAG_CONTEXT);
  			err_sendstring(&msgbuf, edata->context);
--- 3137,3143 ----
  			err_sendstring(&msgbuf, edata->hint);
  		}
  
! 		if (edata->context && edata->elevel >= client_min_context)
  		{
  			pq_sendbyte(&msgbuf, PG_DIAG_CONTEXT);
  			err_sendstring(&msgbuf, edata->context);
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
new file mode 100644
index 595a609..e2fae21
*** a/src/backend/utils/misc/guc.c
--- b/src/backend/utils/misc/guc.c
*************** bool		Password_encryption = true;
*** 430,435 ****
--- 430,437 ----
  int			log_min_error_statement = ERROR;
  int			log_min_messages = WARNING;
  int			client_min_messages = NOTICE;
+ int			log_min_context = WARNING;
+ int			client_min_context = ERROR;
  int			log_min_duration_statement = -1;
  int			log_temp_files = -1;
  int			trace_recovery_messages = LOG;
*************** static struct config_enum ConfigureNames
*** 3426,3431 ****
--- 3428,3444 ----
  	},
  
  	{
+ 		{"client_min_context", PGC_USERSET, LOGGING_WHEN,
+ 			gettext_noop("Sets the message levels when the context is send to the client."),
+ 			gettext_noop("Each level includes all the levels that follow it. The later"
+ 						 " the level, the less content are sent.")
+ 		},
+ 		&client_min_context,
+ 		ERROR, client_message_level_options,
+ 		NULL, NULL, NULL
+ 	},
+ 
+ 	{
  		{"client_min_messages", PGC_USERSET, LOGGING_WHEN,
  			gettext_noop("Sets the message levels that are sent to the client."),
  			gettext_noop("Each level includes all the levels that follow it. The later"
*************** static struct config_enum ConfigureNames
*** 3478,3483 ****
--- 3491,3507 ----
  		NULL, NULL, NULL
  	},
  
+ 	{
+ 		{"log_min_context", PGC_SUSET, LOGGING_WHEN,
+ 			gettext_noop("Sets the message levels that has context logged."),
+ 			gettext_noop("Each level includes all the levels that follow it. The later"
+ 						 " the level, the less content are sent.")
+ 		},
+ 		&log_min_context,
+ 		WARNING, server_message_level_options,
+ 		NULL, NULL, NULL
+ 	},
+ 
  	{
  		{"log_min_messages", PGC_SUSET, LOGGING_WHEN,
  			gettext_noop("Sets the message levels that are logged."),
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
new file mode 100644
index 06dfc06..8695e8b
*** a/src/backend/utils/misc/postgresql.conf.sample
--- b/src/backend/utils/misc/postgresql.conf.sample
***************
*** 360,365 ****
--- 360,390 ----
  
  # - When to Log -
  
+ #client_min_context = error		# values in order of decreasing detail:
+ 					#   debug5
+ 					#   debug4
+ 					#   debug3
+ 					#   debug2
+ 					#   debug1
+ 					#   log
+ 					#   notice
+ 					#   warning
+ 					#   error
+ 
+ #log_min_context = warning		# values in order of decreasing detail:
+ 					#   debug5
+ 					#   debug4
+ 					#   debug3
+ 					#   debug2
+ 					#   debug1
+ 					#   info
+ 					#   notice
+ 					#   warning
+ 					#   error
+ 					#   log
+ 					#   fatal
+ 					#   panic
+ 
  #client_min_messages = notice		# values in order of decreasing detail:
  					#   debug5
  					#   debug4
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
new file mode 100644
index dc167f9..f03a5e1
*** a/src/include/utils/guc.h
--- b/src/include/utils/guc.h
*************** extern PGDLLIMPORT bool check_function_b
*** 246,251 ****
--- 246,253 ----
  extern bool default_with_oids;
  extern bool SQL_inheritance;
  
+ extern int	log_min_context;
+ extern int	client_min_context;
  extern int	log_min_error_statement;
  extern int	log_min_messages;
  extern int	client_min_messages;
diff --git a/src/pl/plperl/expected/plperl.out b/src/pl/plperl/expected/plperl.out
new file mode 100644
index d23a302..14df5f4
*** a/src/pl/plperl/expected/plperl.out
--- b/src/pl/plperl/expected/plperl.out
*************** DO $$
*** 614,620 ****
    elog(NOTICE, $a);
  $$ LANGUAGE plperl;
  NOTICE:  This is a test
- CONTEXT:  PL/Perl anonymous code block
  -- check that restricted operations are rejected in a plperl DO block
  DO $$ system("/nonesuch"); $$ LANGUAGE plperl;
  ERROR:  'system' trapped by operation mask at line 1.
--- 614,619 ----
*************** CONTEXT:  PL/Perl anonymous code block
*** 628,634 ****
  -- check that eval is allowed and eval'd restricted ops are caught
  DO $$ eval q{chdir '.';}; warn "Caught: $@"; $$ LANGUAGE plperl;
  WARNING:  Caught: 'chdir' trapped by operation mask at line 1.
- CONTEXT:  PL/Perl anonymous code block
  -- check that compiling do (dofile opcode) is allowed
  -- but that executing it for a file not already loaded (via require) dies
  DO $$ warn do "/dev/null"; $$ LANGUAGE plperl;
--- 627,632 ----
diff --git a/src/pl/plperl/expected/plperl_elog.out b/src/pl/plperl/expected/plperl_elog.out
new file mode 100644
index c447fa2..3f9449a
*** a/src/pl/plperl/expected/plperl_elog.out
--- b/src/pl/plperl/expected/plperl_elog.out
*************** create or replace function perl_elog(tex
*** 7,13 ****
  $$;
  select perl_elog('explicit elog');
  NOTICE:  explicit elog
- CONTEXT:  PL/Perl function "perl_elog"
   perl_elog 
  -----------
   
--- 7,12 ----
*************** create or replace function perl_warn(tex
*** 21,27 ****
  $$;
  select perl_warn('implicit elog via warn');
  WARNING:  implicit elog via warn at line 4.
- CONTEXT:  PL/Perl function "perl_warn"
   perl_warn 
  -----------
   
--- 20,25 ----
*************** select uses_global();
*** 61,67 ****
  -- make sure we don't choke on readonly values
  do language plperl $$ elog(NOTICE, ${^TAINT}); $$;
  NOTICE:  0
- CONTEXT:  PL/Perl anonymous code block
  -- test recovery after "die"
  create or replace function just_die() returns void language plperl AS $$
  die "just die";
--- 59,64 ----
*************** return $a + $b;
*** 94,104 ****
  $$;
  select indirect_die_caller();
  NOTICE:  caught die
- CONTEXT:  SQL statement "SELECT die_caller() AS fx"
- PL/Perl function "indirect_die_caller"
  NOTICE:  caught die
- CONTEXT:  SQL statement "SELECT die_caller() AS fx"
- PL/Perl function "indirect_die_caller"
   indirect_die_caller 
  ---------------------
                     2
--- 91,97 ----
diff --git a/src/pl/plperl/expected/plperl_trigger.out b/src/pl/plperl/expected/plperl_trigger.out
new file mode 100644
index 36ecb92..5e3860e
*** a/src/pl/plperl/expected/plperl_trigger.out
--- b/src/pl/plperl/expected/plperl_trigger.out
*************** BEFORE INSERT OR UPDATE OR DELETE ON tri
*** 62,136 ****
  FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
  insert into trigger_test values(1,'insert', '("(1)")');
  NOTICE:  $_TD->{argc} = '2'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{args} = ['23', 'skidoo']
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{event} = 'INSERT'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{level} = 'ROW'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{name} = 'show_trigger_data_trig'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{new} = {'foo' => {'rfoo' => {'i' => '1'}}, 'i' => '1', 'v' => 'insert'}
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{relid} = 'bogus:12345'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{relname} = 'trigger_test'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{table_name} = 'trigger_test'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{table_schema} = 'public'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{when} = 'BEFORE'
- CONTEXT:  PL/Perl function "trigger_data"
  update trigger_test set v = 'update' where i = 1;
  NOTICE:  $_TD->{argc} = '2'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{args} = ['23', 'skidoo']
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{event} = 'UPDATE'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{level} = 'ROW'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{name} = 'show_trigger_data_trig'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{new} = {'foo' => {'rfoo' => {'i' => '1'}}, 'i' => '1', 'v' => 'update'}
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{old} = {'foo' => {'rfoo' => {'i' => '1'}}, 'i' => '1', 'v' => 'insert'}
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{relid} = 'bogus:12345'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{relname} = 'trigger_test'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{table_name} = 'trigger_test'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{table_schema} = 'public'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{when} = 'BEFORE'
- CONTEXT:  PL/Perl function "trigger_data"
  delete from trigger_test;
  NOTICE:  $_TD->{argc} = '2'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{args} = ['23', 'skidoo']
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{event} = 'DELETE'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{level} = 'ROW'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{name} = 'show_trigger_data_trig'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{old} = {'foo' => {'rfoo' => {'i' => '1'}}, 'i' => '1', 'v' => 'update'}
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{relid} = 'bogus:12345'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{relname} = 'trigger_test'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{table_name} = 'trigger_test'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{table_schema} = 'public'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{when} = 'BEFORE'
- CONTEXT:  PL/Perl function "trigger_data"
  DROP TRIGGER show_trigger_data_trig on trigger_test;
  insert into trigger_test values(1,'insert', '("(1)")');
  CREATE VIEW trigger_test_view AS SELECT * FROM trigger_test;
--- 62,102 ----
*************** INSTEAD OF INSERT OR UPDATE OR DELETE ON
*** 139,213 ****
  FOR EACH ROW EXECUTE PROCEDURE trigger_data(24,'skidoo view');
  insert into trigger_test_view values(2,'insert', '("(2)")');
  NOTICE:  $_TD->{argc} = '2'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{args} = ['24', 'skidoo view']
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{event} = 'INSERT'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{level} = 'ROW'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{name} = 'show_trigger_data_trig'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{new} = {'foo' => {'rfoo' => {'i' => '2'}}, 'i' => '2', 'v' => 'insert'}
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{relid} = 'bogus:12345'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{relname} = 'trigger_test_view'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{table_name} = 'trigger_test_view'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{table_schema} = 'public'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{when} = 'INSTEAD OF'
- CONTEXT:  PL/Perl function "trigger_data"
  update trigger_test_view set v = 'update', foo = '("(3)")' where i = 1;
  NOTICE:  $_TD->{argc} = '2'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{args} = ['24', 'skidoo view']
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{event} = 'UPDATE'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{level} = 'ROW'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{name} = 'show_trigger_data_trig'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{new} = {'foo' => {'rfoo' => {'i' => '3'}}, 'i' => '1', 'v' => 'update'}
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{old} = {'foo' => {'rfoo' => {'i' => '1'}}, 'i' => '1', 'v' => 'insert'}
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{relid} = 'bogus:12345'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{relname} = 'trigger_test_view'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{table_name} = 'trigger_test_view'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{table_schema} = 'public'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{when} = 'INSTEAD OF'
- CONTEXT:  PL/Perl function "trigger_data"
  delete from trigger_test_view;
  NOTICE:  $_TD->{argc} = '2'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{args} = ['24', 'skidoo view']
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{event} = 'DELETE'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{level} = 'ROW'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{name} = 'show_trigger_data_trig'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{old} = {'foo' => {'rfoo' => {'i' => '1'}}, 'i' => '1', 'v' => 'insert'}
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{relid} = 'bogus:12345'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{relname} = 'trigger_test_view'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{table_name} = 'trigger_test_view'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{table_schema} = 'public'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{when} = 'INSTEAD OF'
- CONTEXT:  PL/Perl function "trigger_data"
  DROP VIEW trigger_test_view;
  delete from trigger_test;
  DROP FUNCTION trigger_data();
--- 105,145 ----
*************** create event trigger perl_b_snitch on dd
*** 319,346 ****
     execute procedure perlsnitch();
  create or replace function foobar() returns int language sql as $$select 1;$$;
  NOTICE:  perlsnitch: ddl_command_start CREATE FUNCTION 
- CONTEXT:  PL/Perl function "perlsnitch"
  NOTICE:  perlsnitch: ddl_command_end CREATE FUNCTION 
- CONTEXT:  PL/Perl function "perlsnitch"
  alter function foobar() cost 77;
  NOTICE:  perlsnitch: ddl_command_start ALTER FUNCTION 
- CONTEXT:  PL/Perl function "perlsnitch"
  NOTICE:  perlsnitch: ddl_command_end ALTER FUNCTION 
- CONTEXT:  PL/Perl function "perlsnitch"
  drop function foobar();
  NOTICE:  perlsnitch: ddl_command_start DROP FUNCTION 
- CONTEXT:  PL/Perl function "perlsnitch"
  NOTICE:  perlsnitch: ddl_command_end DROP FUNCTION 
- CONTEXT:  PL/Perl function "perlsnitch"
  create table foo();
  NOTICE:  perlsnitch: ddl_command_start CREATE TABLE 
- CONTEXT:  PL/Perl function "perlsnitch"
  NOTICE:  perlsnitch: ddl_command_end CREATE TABLE 
- CONTEXT:  PL/Perl function "perlsnitch"
  drop table foo;
  NOTICE:  perlsnitch: ddl_command_start DROP TABLE 
- CONTEXT:  PL/Perl function "perlsnitch"
  NOTICE:  perlsnitch: ddl_command_end DROP TABLE 
- CONTEXT:  PL/Perl function "perlsnitch"
  drop event trigger perl_a_snitch;
  drop event trigger perl_b_snitch;
--- 251,268 ----
diff --git a/src/pl/plperl/expected/plperlu.out b/src/pl/plperl/expected/plperlu.out
new file mode 100644
index 3daf4ce..a3edb38
*** a/src/pl/plperl/expected/plperlu.out
--- b/src/pl/plperl/expected/plperlu.out
*************** LOAD 'plperl';
*** 6,12 ****
  SET plperl.on_plperlu_init = '$_SHARED{init} = 42';
  DO $$ warn $_SHARED{init} $$ language plperlu;
  WARNING:  42 at line 1.
- CONTEXT:  PL/Perl anonymous code block
  --
  -- Test compilation of unicode regex - regardless of locale.
  -- This code fails in plain plperl in a non-UTF8 database.
--- 6,11 ----
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
new file mode 100644
index 7d4001c..e1a6b7d
*** a/src/pl/plpgsql/src/pl_exec.c
--- b/src/pl/plpgsql/src/pl_exec.c
***************
*** 42,49 ****
  #include "utils/typcache.h"
  
  
- static const char *const raise_skip_msg = "RAISE";
- 
  typedef struct
  {
  	int			nargs;			/* number of arguments */
--- 42,47 ----
*************** plpgsql_exec_error_callback(void *arg)
*** 939,948 ****
  {
  	PLpgSQL_execstate *estate = (PLpgSQL_execstate *) arg;
  
- 	/* if we are doing RAISE, don't report its location */
- 	if (estate->err_text == raise_skip_msg)
- 		return;
- 
  	if (estate->err_text != NULL)
  	{
  		/*
--- 937,942 ----
*************** exec_stmt_raise(PLpgSQL_execstate *estat
*** 3158,3165 ****
  	/*
  	 * Throw the error (may or may not come back)
  	 */
- 	estate->err_text = raise_skip_msg;	/* suppress traceback of raise */
- 
  	ereport(stmt->elog_level,
  			(err_code ? errcode(err_code) : 0,
  			 errmsg_internal("%s", err_message),
--- 3152,3157 ----
diff --git a/src/pl/plpython/expected/plpython_do.out b/src/pl/plpython/expected/plpython_do.out
new file mode 100644
index 0977812..e300530
*** a/src/pl/plpython/expected/plpython_do.out
--- b/src/pl/plpython/expected/plpython_do.out
***************
*** 1,9 ****
  DO $$ plpy.notice("This is plpythonu.") $$ LANGUAGE plpythonu;
  NOTICE:  This is plpythonu.
- CONTEXT:  PL/Python anonymous code block
  DO $$ plpy.notice("This is plpython2u.") $$ LANGUAGE plpython2u;
  NOTICE:  This is plpython2u.
- CONTEXT:  PL/Python anonymous code block
  DO $$ raise Exception("error test") $$ LANGUAGE plpythonu;
  ERROR:  Exception: error test
  CONTEXT:  Traceback (most recent call last):
--- 1,7 ----
diff --git a/src/pl/plpython/expected/plpython_error.out b/src/pl/plpython/expected/plpython_error.out
new file mode 100644
index be2ec97..1f52af7
*** a/src/pl/plpython/expected/plpython_error.out
--- b/src/pl/plpython/expected/plpython_error.out
*************** return None
*** 108,114 ****
  	LANGUAGE plpythonu;
  SELECT invalid_type_caught('rick');
  NOTICE:  type "test" does not exist
- CONTEXT:  PL/Python function "invalid_type_caught"
   invalid_type_caught 
  ---------------------
   
--- 108,113 ----
*************** return "you''ve been warned"
*** 232,238 ****
  	LANGUAGE plpythonu;
  SELECT nested_warning();
  WARNING:  boom
- CONTEXT:  PL/Python function "nested_warning"
     nested_warning   
  --------------------
   you've been warned
--- 231,236 ----
*************** SELECT specific_exception(2);
*** 336,342 ****
  
  SELECT specific_exception(NULL);
  NOTICE:  Violated the NOT NULL constraint, sqlstate 23502
- CONTEXT:  PL/Python function "specific_exception"
   specific_exception 
  --------------------
   
--- 334,339 ----
*************** CONTEXT:  PL/Python function "specific_e
*** 344,350 ****
  
  SELECT specific_exception(2);
  NOTICE:  Violated the UNIQUE constraint, sqlstate 23505
- CONTEXT:  PL/Python function "specific_exception"
   specific_exception 
  --------------------
   
--- 341,346 ----
diff --git a/src/pl/plpython/expected/plpython_spi.out b/src/pl/plpython/expected/plpython_spi.out
new file mode 100644
index e2861df..e715ee5
*** a/src/pl/plpython/expected/plpython_spi.out
--- b/src/pl/plpython/expected/plpython_spi.out
*************** else:
*** 130,142 ****
  $$ LANGUAGE plpythonu;
  SELECT result_metadata_test($$SELECT 1 AS foo, '11'::text AS bar UNION SELECT 2, '22'$$);
  INFO:  True
- CONTEXT:  PL/Python function "result_metadata_test"
  INFO:  ['foo', 'bar']
- CONTEXT:  PL/Python function "result_metadata_test"
  INFO:  [23, 25]
- CONTEXT:  PL/Python function "result_metadata_test"
  INFO:  [-1, -1]
- CONTEXT:  PL/Python function "result_metadata_test"
   result_metadata_test 
  ----------------------
                      2
--- 130,138 ----
*************** CONTEXT:  PL/Python function "result_met
*** 144,150 ****
  
  SELECT result_metadata_test($$CREATE TEMPORARY TABLE foo1 (a int, b text)$$);
  INFO:  True
- CONTEXT:  PL/Python function "result_metadata_test"
  ERROR:  plpy.Error: command did not produce a result set
  CONTEXT:  Traceback (most recent call last):
    PL/Python function "result_metadata_test", line 6, in <module>
--- 140,145 ----
*************** else:
*** 234,248 ****
  $$ LANGUAGE plpythonu;
  SELECT result_subscript_test();
  INFO:  2
- CONTEXT:  PL/Python function "result_subscript_test"
  INFO:  4
- CONTEXT:  PL/Python function "result_subscript_test"
  INFO:  [2, 3]
- CONTEXT:  PL/Python function "result_subscript_test"
  INFO:  [1, 3]
- CONTEXT:  PL/Python function "result_subscript_test"
  INFO:  [10, 100, 3, 1000]
- CONTEXT:  PL/Python function "result_subscript_test"
   result_subscript_test 
  -----------------------
   
--- 229,238 ----
*************** plpy.info(result[:])
*** 257,263 ****
  $$ LANGUAGE plpythonu;
  SELECT result_empty_test();
  INFO:  []
- CONTEXT:  PL/Python function "result_empty_test"
   result_empty_test 
  -------------------
   
--- 247,252 ----
diff --git a/src/pl/plpython/expected/plpython_subtransaction.out b/src/pl/plpython/expected/plpython_subtransaction.out
new file mode 100644
index ced4682..635bac6
*** a/src/pl/plpython/expected/plpython_subtransaction.out
--- b/src/pl/plpython/expected/plpython_subtransaction.out
*************** SELECT * FROM subtransaction_tbl;
*** 154,160 ****
  TRUNCATE subtransaction_tbl;
  SELECT subtransaction_nested_test('t');
  NOTICE:  Swallowed SyntaxError('syntax error at or near "error"',)
- CONTEXT:  PL/Python function "subtransaction_nested_test"
   subtransaction_nested_test 
  ----------------------------
   ok
--- 154,159 ----
*************** return "ok"
*** 180,188 ****
  $$ LANGUAGE plpythonu;
  SELECT subtransaction_deeply_nested_test();
  NOTICE:  Swallowed SyntaxError('syntax error at or near "error"',)
- CONTEXT:  PL/Python function "subtransaction_nested_test"
- SQL statement "SELECT subtransaction_nested_test('t')"
- PL/Python function "subtransaction_nested_test"
   subtransaction_deeply_nested_test 
  -----------------------------------
   ok
--- 179,184 ----
*************** CONTEXT:  Traceback (most recent call la
*** 251,257 ****
  PL/Python function "subtransaction_exit_without_enter"
  SELECT subtransaction_enter_without_exit();
  WARNING:  forcibly aborting a subtransaction that has not been exited
- CONTEXT:  PL/Python function "subtransaction_enter_without_exit"
   subtransaction_enter_without_exit 
  -----------------------------------
   
--- 247,252 ----
*************** CONTEXT:  PL/Python function "subtransac
*** 259,265 ****
  
  SELECT subtransaction_exit_twice();
  WARNING:  forcibly aborting a subtransaction that has not been exited
- CONTEXT:  PL/Python function "subtransaction_exit_twice"
  ERROR:  ValueError: this subtransaction has not been entered
  CONTEXT:  Traceback (most recent call last):
    PL/Python function "subtransaction_exit_twice", line 3, in <module>
--- 254,259 ----
*************** CONTEXT:  Traceback (most recent call la
*** 267,275 ****
  PL/Python function "subtransaction_exit_twice"
  SELECT subtransaction_enter_twice();
  WARNING:  forcibly aborting a subtransaction that has not been exited
- CONTEXT:  PL/Python function "subtransaction_enter_twice"
  WARNING:  forcibly aborting a subtransaction that has not been exited
- CONTEXT:  PL/Python function "subtransaction_enter_twice"
   subtransaction_enter_twice 
  ----------------------------
   
--- 261,267 ----
*************** CONTEXT:  Traceback (most recent call la
*** 283,289 ****
  PL/Python function "subtransaction_exit_same_subtransaction_twice"
  SELECT subtransaction_enter_same_subtransaction_twice();
  WARNING:  forcibly aborting a subtransaction that has not been exited
- CONTEXT:  PL/Python function "subtransaction_enter_same_subtransaction_twice"
  ERROR:  ValueError: this subtransaction has already been entered
  CONTEXT:  Traceback (most recent call last):
    PL/Python function "subtransaction_enter_same_subtransaction_twice", line 4, in <module>
--- 275,280 ----
*************** except plpy.SPIError:
*** 329,337 ****
  $$ LANGUAGE plpythonu;
  SELECT subtransaction_mix_explicit_and_implicit();
  WARNING:  Caught a SPI error from an explicit subtransaction
- CONTEXT:  PL/Python function "subtransaction_mix_explicit_and_implicit"
  WARNING:  Caught a SPI error
- CONTEXT:  PL/Python function "subtransaction_mix_explicit_and_implicit"
   subtransaction_mix_explicit_and_implicit 
  ------------------------------------------
   
--- 320,326 ----
*************** with plpy.subtransaction():
*** 370,376 ****
  $$ LANGUAGE plpythonu;
  SELECT try_catch_inside_subtransaction();
  NOTICE:  caught
- CONTEXT:  PL/Python function "try_catch_inside_subtransaction"
   try_catch_inside_subtransaction 
  ---------------------------------
   
--- 359,364 ----
*************** with plpy.subtransaction():
*** 395,401 ****
  $$ LANGUAGE plpythonu;
  SELECT pk_violation_inside_subtransaction();
  NOTICE:  caught
- CONTEXT:  PL/Python function "pk_violation_inside_subtransaction"
   pk_violation_inside_subtransaction 
  ------------------------------------
   
--- 383,388 ----
diff --git a/src/pl/plpython/expected/plpython_test.out b/src/pl/plpython/expected/plpython_test.out
new file mode 100644
index a884fc0..7b76faf
*** a/src/pl/plpython/expected/plpython_test.out
--- b/src/pl/plpython/expected/plpython_test.out
*************** plpy.error('error')
*** 62,78 ****
  $$ LANGUAGE plpythonu;
  SELECT elog_test();
  INFO:  info
- CONTEXT:  PL/Python function "elog_test"
  INFO:  37
- CONTEXT:  PL/Python function "elog_test"
  INFO:  ()
- CONTEXT:  PL/Python function "elog_test"
  INFO:  ('info', 37, [1, 2, 3])
- CONTEXT:  PL/Python function "elog_test"
  NOTICE:  notice
- CONTEXT:  PL/Python function "elog_test"
  WARNING:  warning
- CONTEXT:  PL/Python function "elog_test"
  ERROR:  plpy.Error: error
  CONTEXT:  Traceback (most recent call last):
    PL/Python function "elog_test", line 10, in <module>
--- 62,72 ----
diff --git a/src/pl/plpython/expected/plpython_trigger.out b/src/pl/plpython/expected/plpython_trigger.out
new file mode 100644
index 80e478b..4148963
*** a/src/pl/plpython/expected/plpython_trigger.out
--- b/src/pl/plpython/expected/plpython_trigger.out
*************** BEFORE INSERT OR UPDATE OR DELETE OR TRU
*** 98,305 ****
  FOR EACH STATEMENT EXECUTE PROCEDURE trigger_data(23,'skidoo');
  insert into trigger_test values(1,'insert');
  NOTICE:  TD[args] => ['23', 'skidoo']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => INSERT
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => STATEMENT
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig_stmt
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => BEFORE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[args] => ['23', 'skidoo']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => INSERT
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => ROW
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig_before
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => {'i': 1, 'v': 'insert'}
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => BEFORE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[args] => ['23', 'skidoo']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => INSERT
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => ROW
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig_after
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => {'i': 1, 'v': 'insert'}
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => AFTER
- CONTEXT:  PL/Python function "trigger_data"
  update trigger_test set v = 'update' where i = 1;
  NOTICE:  TD[args] => ['23', 'skidoo']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => UPDATE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => STATEMENT
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig_stmt
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => BEFORE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[args] => ['23', 'skidoo']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => UPDATE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => ROW
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig_before
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => {'i': 1, 'v': 'update'}
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => {'i': 1, 'v': 'insert'}
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => BEFORE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[args] => ['23', 'skidoo']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => UPDATE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => ROW
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig_after
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => {'i': 1, 'v': 'update'}
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => {'i': 1, 'v': 'insert'}
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => AFTER
- CONTEXT:  PL/Python function "trigger_data"
  delete from trigger_test;
  NOTICE:  TD[args] => ['23', 'skidoo']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => DELETE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => STATEMENT
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig_stmt
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => BEFORE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[args] => ['23', 'skidoo']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => DELETE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => ROW
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig_before
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => {'i': 1, 'v': 'update'}
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => BEFORE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[args] => ['23', 'skidoo']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => DELETE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => ROW
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig_after
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => {'i': 1, 'v': 'update'}
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => AFTER
- CONTEXT:  PL/Python function "trigger_data"
  truncate table trigger_test;
  NOTICE:  TD[args] => ['23', 'skidoo']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => TRUNCATE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => STATEMENT
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig_stmt
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => BEFORE
- CONTEXT:  PL/Python function "trigger_data"
  DROP TRIGGER show_trigger_data_trig_stmt on trigger_test;
  DROP TRIGGER show_trigger_data_trig_before on trigger_test;
  DROP TRIGGER show_trigger_data_trig_after on trigger_test;
--- 98,205 ----
*************** INSTEAD OF INSERT OR UPDATE OR DELETE ON
*** 310,376 ****
  FOR EACH ROW EXECUTE PROCEDURE trigger_data(24,'skidoo view');
  insert into trigger_test_view values(2,'insert');
  NOTICE:  TD[args] => ['24', 'skidoo view']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => INSERT
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => ROW
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => {'i': 2, 'v': 'insert'}
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test_view
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => INSTEAD OF
- CONTEXT:  PL/Python function "trigger_data"
  update trigger_test_view set v = 'update' where i = 1;
  NOTICE:  TD[args] => ['24', 'skidoo view']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => UPDATE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => ROW
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => {'i': 1, 'v': 'update'}
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => {'i': 1, 'v': 'insert'}
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test_view
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => INSTEAD OF
- CONTEXT:  PL/Python function "trigger_data"
  delete from trigger_test_view;
  NOTICE:  TD[args] => ['24', 'skidoo view']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => DELETE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => ROW
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => {'i': 1, 'v': 'insert'}
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test_view
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => INSTEAD OF
- CONTEXT:  PL/Python function "trigger_data"
  DROP FUNCTION trigger_data() CASCADE;
  NOTICE:  drop cascades to trigger show_trigger_data_trig on view trigger_test_view
  DROP VIEW trigger_test_view;
--- 210,246 ----
*************** BEFORE DELETE ON trigger_test
*** 402,408 ****
  FOR EACH ROW EXECUTE PROCEDURE stupid2();
  DELETE FROM trigger_test WHERE i = 0;
  WARNING:  PL/Python trigger function returned "MODIFY" in a DELETE trigger -- ignored
- CONTEXT:  PL/Python function "stupid2"
  DROP TRIGGER stupid_trigger2 ON trigger_test;
  INSERT INTO trigger_test VALUES (0, 'zero');
  -- returning unrecognized string from trigger function
--- 272,277 ----
diff --git a/src/pl/plpython/expected/plpython_types.out b/src/pl/plpython/expected/plpython_types.out
new file mode 100644
index 17057a5..f0b6abd
*** a/src/pl/plpython/expected/plpython_types.out
--- b/src/pl/plpython/expected/plpython_types.out
*************** return x
*** 10,16 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_bool(true);
  INFO:  (True, <type 'bool'>)
- CONTEXT:  PL/Python function "test_type_conversion_bool"
   test_type_conversion_bool 
  ---------------------------
   t
--- 10,15 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 18,24 ****
  
  SELECT * FROM test_type_conversion_bool(false);
  INFO:  (False, <type 'bool'>)
- CONTEXT:  PL/Python function "test_type_conversion_bool"
   test_type_conversion_bool 
  ---------------------------
   f
--- 17,22 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 26,32 ****
  
  SELECT * FROM test_type_conversion_bool(null);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_bool"
   test_type_conversion_bool 
  ---------------------------
   
--- 24,29 ----
*************** return ret
*** 54,60 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_bool_other(0);
  INFO:  (0, False)
- CONTEXT:  PL/Python function "test_type_conversion_bool_other"
   test_type_conversion_bool_other 
  ---------------------------------
   f
--- 51,56 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 62,68 ****
  
  SELECT * FROM test_type_conversion_bool_other(1);
  INFO:  (5, True)
- CONTEXT:  PL/Python function "test_type_conversion_bool_other"
   test_type_conversion_bool_other 
  ---------------------------------
   t
--- 58,63 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 70,76 ****
  
  SELECT * FROM test_type_conversion_bool_other(2);
  INFO:  ('', False)
- CONTEXT:  PL/Python function "test_type_conversion_bool_other"
   test_type_conversion_bool_other 
  ---------------------------------
   f
--- 65,70 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 78,84 ****
  
  SELECT * FROM test_type_conversion_bool_other(3);
  INFO:  ('fa', True)
- CONTEXT:  PL/Python function "test_type_conversion_bool_other"
   test_type_conversion_bool_other 
  ---------------------------------
   t
--- 72,77 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 86,92 ****
  
  SELECT * FROM test_type_conversion_bool_other(4);
  INFO:  ([], False)
- CONTEXT:  PL/Python function "test_type_conversion_bool_other"
   test_type_conversion_bool_other 
  ---------------------------------
   f
--- 79,84 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 94,100 ****
  
  SELECT * FROM test_type_conversion_bool_other(5);
  INFO:  ([0], True)
- CONTEXT:  PL/Python function "test_type_conversion_bool_other"
   test_type_conversion_bool_other 
  ---------------------------------
   t
--- 86,91 ----
*************** return x
*** 106,112 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_char('a');
  INFO:  ('a', <type 'str'>)
- CONTEXT:  PL/Python function "test_type_conversion_char"
   test_type_conversion_char 
  ---------------------------
   a
--- 97,102 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 114,120 ****
  
  SELECT * FROM test_type_conversion_char(null);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_char"
   test_type_conversion_char 
  ---------------------------
   
--- 104,109 ----
*************** return x
*** 126,132 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_int2(100::int2);
  INFO:  (100, <type 'int'>)
- CONTEXT:  PL/Python function "test_type_conversion_int2"
   test_type_conversion_int2 
  ---------------------------
                         100
--- 115,120 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 134,140 ****
  
  SELECT * FROM test_type_conversion_int2(-100::int2);
  INFO:  (-100, <type 'int'>)
- CONTEXT:  PL/Python function "test_type_conversion_int2"
   test_type_conversion_int2 
  ---------------------------
                        -100
--- 122,127 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 142,148 ****
  
  SELECT * FROM test_type_conversion_int2(null);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_int2"
   test_type_conversion_int2 
  ---------------------------
                            
--- 129,134 ----
*************** return x
*** 154,160 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_int4(100);
  INFO:  (100, <type 'int'>)
- CONTEXT:  PL/Python function "test_type_conversion_int4"
   test_type_conversion_int4 
  ---------------------------
                         100
--- 140,145 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 162,168 ****
  
  SELECT * FROM test_type_conversion_int4(-100);
  INFO:  (-100, <type 'int'>)
- CONTEXT:  PL/Python function "test_type_conversion_int4"
   test_type_conversion_int4 
  ---------------------------
                        -100
--- 147,152 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 170,176 ****
  
  SELECT * FROM test_type_conversion_int4(null);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_int4"
   test_type_conversion_int4 
  ---------------------------
                            
--- 154,159 ----
*************** return x
*** 182,188 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_int8(100);
  INFO:  (100L, <type 'long'>)
- CONTEXT:  PL/Python function "test_type_conversion_int8"
   test_type_conversion_int8 
  ---------------------------
                         100
--- 165,170 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 190,196 ****
  
  SELECT * FROM test_type_conversion_int8(-100);
  INFO:  (-100L, <type 'long'>)
- CONTEXT:  PL/Python function "test_type_conversion_int8"
   test_type_conversion_int8 
  ---------------------------
                        -100
--- 172,177 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 198,204 ****
  
  SELECT * FROM test_type_conversion_int8(5000000000);
  INFO:  (5000000000L, <type 'long'>)
- CONTEXT:  PL/Python function "test_type_conversion_int8"
   test_type_conversion_int8 
  ---------------------------
                  5000000000
--- 179,184 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 206,212 ****
  
  SELECT * FROM test_type_conversion_int8(null);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_int8"
   test_type_conversion_int8 
  ---------------------------
                            
--- 186,191 ----
*************** return x
*** 220,226 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_numeric(100);
  INFO:  ('100', 'Decimal')
- CONTEXT:  PL/Python function "test_type_conversion_numeric"
   test_type_conversion_numeric 
  ------------------------------
                            100
--- 199,204 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 228,234 ****
  
  SELECT * FROM test_type_conversion_numeric(-100);
  INFO:  ('-100', 'Decimal')
- CONTEXT:  PL/Python function "test_type_conversion_numeric"
   test_type_conversion_numeric 
  ------------------------------
                           -100
--- 206,211 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 236,242 ****
  
  SELECT * FROM test_type_conversion_numeric(100.0);
  INFO:  ('100.0', 'Decimal')
- CONTEXT:  PL/Python function "test_type_conversion_numeric"
   test_type_conversion_numeric 
  ------------------------------
                          100.0
--- 213,218 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 244,250 ****
  
  SELECT * FROM test_type_conversion_numeric(100.00);
  INFO:  ('100.00', 'Decimal')
- CONTEXT:  PL/Python function "test_type_conversion_numeric"
   test_type_conversion_numeric 
  ------------------------------
                         100.00
--- 220,225 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 252,258 ****
  
  SELECT * FROM test_type_conversion_numeric(5000000000.5);
  INFO:  ('5000000000.5', 'Decimal')
- CONTEXT:  PL/Python function "test_type_conversion_numeric"
   test_type_conversion_numeric 
  ------------------------------
                   5000000000.5
--- 227,232 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 260,266 ****
  
  SELECT * FROM test_type_conversion_numeric(1234567890.0987654321);
  INFO:  ('1234567890.0987654321', 'Decimal')
- CONTEXT:  PL/Python function "test_type_conversion_numeric"
   test_type_conversion_numeric 
  ------------------------------
          1234567890.0987654321
--- 234,239 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 268,274 ****
  
  SELECT * FROM test_type_conversion_numeric(-1234567890.0987654321);
  INFO:  ('-1234567890.0987654321', 'Decimal')
- CONTEXT:  PL/Python function "test_type_conversion_numeric"
   test_type_conversion_numeric 
  ------------------------------
         -1234567890.0987654321
--- 241,246 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 276,282 ****
  
  SELECT * FROM test_type_conversion_numeric(null);
  INFO:  ('None', 'NoneType')
- CONTEXT:  PL/Python function "test_type_conversion_numeric"
   test_type_conversion_numeric 
  ------------------------------
                               
--- 248,253 ----
*************** return x
*** 288,294 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_float4(100);
  INFO:  (100.0, <type 'float'>)
- CONTEXT:  PL/Python function "test_type_conversion_float4"
   test_type_conversion_float4 
  -----------------------------
                           100
--- 259,264 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 296,302 ****
  
  SELECT * FROM test_type_conversion_float4(-100);
  INFO:  (-100.0, <type 'float'>)
- CONTEXT:  PL/Python function "test_type_conversion_float4"
   test_type_conversion_float4 
  -----------------------------
                          -100
--- 266,271 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 304,310 ****
  
  SELECT * FROM test_type_conversion_float4(5000.5);
  INFO:  (5000.5, <type 'float'>)
- CONTEXT:  PL/Python function "test_type_conversion_float4"
   test_type_conversion_float4 
  -----------------------------
                        5000.5
--- 273,278 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 312,318 ****
  
  SELECT * FROM test_type_conversion_float4(null);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_float4"
   test_type_conversion_float4 
  -----------------------------
                              
--- 280,285 ----
*************** return x
*** 324,330 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_float8(100);
  INFO:  (100.0, <type 'float'>)
- CONTEXT:  PL/Python function "test_type_conversion_float8"
   test_type_conversion_float8 
  -----------------------------
                           100
--- 291,296 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 332,338 ****
  
  SELECT * FROM test_type_conversion_float8(-100);
  INFO:  (-100.0, <type 'float'>)
- CONTEXT:  PL/Python function "test_type_conversion_float8"
   test_type_conversion_float8 
  -----------------------------
                          -100
--- 298,303 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 340,346 ****
  
  SELECT * FROM test_type_conversion_float8(5000000000.5);
  INFO:  (5000000000.5, <type 'float'>)
- CONTEXT:  PL/Python function "test_type_conversion_float8"
   test_type_conversion_float8 
  -----------------------------
                  5000000000.5
--- 305,310 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 348,354 ****
  
  SELECT * FROM test_type_conversion_float8(null);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_float8"
   test_type_conversion_float8 
  -----------------------------
                              
--- 312,317 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 356,362 ****
  
  SELECT * FROM test_type_conversion_float8(100100100.654321);
  INFO:  (100100100.654321, <type 'float'>)
- CONTEXT:  PL/Python function "test_type_conversion_float8"
   test_type_conversion_float8 
  -----------------------------
              100100100.654321
--- 319,324 ----
*************** return x
*** 368,374 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_oid(100);
  INFO:  (100L, <type 'long'>)
- CONTEXT:  PL/Python function "test_type_conversion_oid"
   test_type_conversion_oid 
  --------------------------
                        100
--- 330,335 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 376,382 ****
  
  SELECT * FROM test_type_conversion_oid(2147483649);
  INFO:  (2147483649L, <type 'long'>)
- CONTEXT:  PL/Python function "test_type_conversion_oid"
   test_type_conversion_oid 
  --------------------------
                 2147483649
--- 337,342 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 384,390 ****
  
  SELECT * FROM test_type_conversion_oid(null);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_oid"
   test_type_conversion_oid 
  --------------------------
                           
--- 344,349 ----
*************** return x
*** 396,402 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_text('hello world');
  INFO:  ('hello world', <type 'str'>)
- CONTEXT:  PL/Python function "test_type_conversion_text"
   test_type_conversion_text 
  ---------------------------
   hello world
--- 355,360 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 404,410 ****
  
  SELECT * FROM test_type_conversion_text(null);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_text"
   test_type_conversion_text 
  ---------------------------
   
--- 362,367 ----
*************** return x
*** 416,422 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_bytea('hello world');
  INFO:  ('hello world', <type 'str'>)
- CONTEXT:  PL/Python function "test_type_conversion_bytea"
   test_type_conversion_bytea 
  ----------------------------
   \x68656c6c6f20776f726c64
--- 373,378 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 424,430 ****
  
  SELECT * FROM test_type_conversion_bytea(E'null\\000byte');
  INFO:  ('null\x00byte', <type 'str'>)
- CONTEXT:  PL/Python function "test_type_conversion_bytea"
   test_type_conversion_bytea 
  ----------------------------
   \x6e756c6c0062797465
--- 380,385 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 432,438 ****
  
  SELECT * FROM test_type_conversion_bytea(null);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_bytea"
   test_type_conversion_bytea 
  ----------------------------
   
--- 387,392 ----
*************** return y
*** 481,487 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_uint2(100::uint2, 50);
  INFO:  (100, <type 'int'>)
- CONTEXT:  PL/Python function "test_type_conversion_uint2"
   test_type_conversion_uint2 
  ----------------------------
                           50
--- 435,440 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 489,501 ****
  
  SELECT * FROM test_type_conversion_uint2(100::uint2, -50);
  INFO:  (100, <type 'int'>)
- CONTEXT:  PL/Python function "test_type_conversion_uint2"
  ERROR:  value for domain uint2 violates check constraint "uint2_check"
  CONTEXT:  while creating return value
  PL/Python function "test_type_conversion_uint2"
  SELECT * FROM test_type_conversion_uint2(null, 1);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_uint2"
   test_type_conversion_uint2 
  ----------------------------
                            1
--- 442,452 ----
*************** return y
*** 524,530 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_bytea10('hello wold', 'hello wold');
  INFO:  ('hello wold', <type 'str'>)
- CONTEXT:  PL/Python function "test_type_conversion_bytea10"
   test_type_conversion_bytea10 
  ------------------------------
   \x68656c6c6f20776f6c64
--- 475,480 ----
*************** SELECT * FROM test_type_conversion_bytea
*** 534,540 ****
  ERROR:  value for domain bytea10 violates check constraint "bytea10_check"
  SELECT * FROM test_type_conversion_bytea10('hello word', 'hello world');
  INFO:  ('hello word', <type 'str'>)
- CONTEXT:  PL/Python function "test_type_conversion_bytea10"
  ERROR:  value for domain bytea10 violates check constraint "bytea10_check"
  CONTEXT:  while creating return value
  PL/Python function "test_type_conversion_bytea10"
--- 484,489 ----
*************** SELECT * FROM test_type_conversion_bytea
*** 542,548 ****
  ERROR:  value for domain bytea10 violates check constraint "bytea10_check"
  SELECT * FROM test_type_conversion_bytea10('hello word', null);
  INFO:  ('hello word', <type 'str'>)
- CONTEXT:  PL/Python function "test_type_conversion_bytea10"
  ERROR:  value for domain bytea10 violates check constraint "bytea10_check"
  CONTEXT:  while creating return value
  PL/Python function "test_type_conversion_bytea10"
--- 491,496 ----
*************** return x
*** 555,561 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_array_int4(ARRAY[0, 100]);
  INFO:  ([0, 100], <type 'list'>)
- CONTEXT:  PL/Python function "test_type_conversion_array_int4"
   test_type_conversion_array_int4 
  ---------------------------------
   {0,100}
--- 503,508 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 563,569 ****
  
  SELECT * FROM test_type_conversion_array_int4(ARRAY[0,-100,55]);
  INFO:  ([0, -100, 55], <type 'list'>)
- CONTEXT:  PL/Python function "test_type_conversion_array_int4"
   test_type_conversion_array_int4 
  ---------------------------------
   {0,-100,55}
--- 510,515 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 571,577 ****
  
  SELECT * FROM test_type_conversion_array_int4(ARRAY[NULL,1]);
  INFO:  ([None, 1], <type 'list'>)
- CONTEXT:  PL/Python function "test_type_conversion_array_int4"
   test_type_conversion_array_int4 
  ---------------------------------
   {NULL,1}
--- 517,522 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 579,585 ****
  
  SELECT * FROM test_type_conversion_array_int4(ARRAY[]::integer[]);
  INFO:  ([], <type 'list'>)
- CONTEXT:  PL/Python function "test_type_conversion_array_int4"
   test_type_conversion_array_int4 
  ---------------------------------
   {}
--- 524,529 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 587,593 ****
  
  SELECT * FROM test_type_conversion_array_int4(NULL);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_array_int4"
   test_type_conversion_array_int4 
  ---------------------------------
   
--- 531,536 ----
*************** return x
*** 603,609 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_array_text(ARRAY['foo', 'bar']);
  INFO:  (['foo', 'bar'], <type 'list'>)
- CONTEXT:  PL/Python function "test_type_conversion_array_text"
   test_type_conversion_array_text 
  ---------------------------------
   {foo,bar}
--- 546,551 ----
*************** return x
*** 615,621 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_array_bytea(ARRAY[E'\\xdeadbeef'::bytea, NULL]);
  INFO:  (['\xde\xad\xbe\xef', None], <type 'list'>)
- CONTEXT:  PL/Python function "test_type_conversion_array_bytea"
   test_type_conversion_array_bytea 
  ----------------------------------
   {"\\xdeadbeef",NULL}
--- 557,562 ----
*************** return x
*** 681,687 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_array_domain(ARRAY[0, 100]::ordered_pair_domain);
  INFO:  ([0, 100], <type 'list'>)
- CONTEXT:  PL/Python function "test_type_conversion_array_domain"
   test_type_conversion_array_domain 
  -----------------------------------
   {0,100}
--- 622,627 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 689,695 ****
  
  SELECT * FROM test_type_conversion_array_domain(NULL::ordered_pair_domain);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_array_domain"
   test_type_conversion_array_domain 
  -----------------------------------
   
--- 629,634 ----
*************** return rv[0]['val']
*** 783,789 ****
  $$;
  SELECT test_prep_bool_output(); -- false
  INFO:  {'val': False}
- CONTEXT:  PL/Python function "test_prep_bool_output"
   test_prep_bool_output 
  -----------------------
   f
--- 722,727 ----
*************** return rv[0]['val']
*** 812,818 ****
  $$;
  SELECT test_prep_bytea_output();
  INFO:  {'val': '\xaa\x00\xbb'}
- CONTEXT:  PL/Python function "test_prep_bytea_output"
   test_prep_bytea_output 
  ------------------------
   \xaa00bb
--- 750,755 ----
diff --git a/src/test/regress/expected/copy2.out b/src/test/regress/expected/copy2.out
new file mode 100644
index 5e31737..72ada21
*** a/src/test/regress/expected/copy2.out
--- b/src/test/regress/expected/copy2.out
*************** Check constraints:
*** 447,458 ****
  
  copy check_con_tbl from stdin;
  NOTICE:  input = {"f1":1}
- CONTEXT:  COPY check_con_tbl, line 1: "1"
  NOTICE:  input = {"f1":null}
- CONTEXT:  COPY check_con_tbl, line 2: "\N"
  copy check_con_tbl from stdin;
  NOTICE:  input = {"f1":0}
- CONTEXT:  COPY check_con_tbl, line 1: "0"
  ERROR:  new row for relation "check_con_tbl" violates check constraint "check_con_tbl_check"
  DETAIL:  Failing row contains (0).
  CONTEXT:  COPY check_con_tbl, line 1: "0"
--- 447,455 ----
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
new file mode 100644
index e70c315..05ac0ad
*** a/src/test/regress/expected/event_trigger.out
--- b/src/test/regress/expected/event_trigger.out
*************** drop cascades to table schema_one.table_
*** 234,248 ****
  drop cascades to table schema_one."table two"
  drop cascades to table schema_one.table_three
  NOTICE:  table "schema_two_table_two" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_two"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "audit_tbls_schema_two_table_three" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.audit_tbls_schema_two_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
- SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  ERROR:  object audit_tbls.schema_two_table_three of type table cannot be dropped
! CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three"
  PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  DELETE FROM undroppable_objs WHERE object_identity = 'audit_tbls.schema_two_table_three';
  DROP SCHEMA schema_one, schema_two CASCADE;
--- 234,243 ----
  drop cascades to table schema_one."table two"
  drop cascades to table schema_one.table_three
  NOTICE:  table "schema_two_table_two" does not exist, skipping
  NOTICE:  table "audit_tbls_schema_two_table_three" does not exist, skipping
  ERROR:  object audit_tbls.schema_two_table_three of type table cannot be dropped
! CONTEXT:  PL/pgSQL function undroppable() line 14 at RAISE
! SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three"
  PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  DELETE FROM undroppable_objs WHERE object_identity = 'audit_tbls.schema_two_table_three';
  DROP SCHEMA schema_one, schema_two CASCADE;
*************** drop cascades to table schema_one.table_
*** 255,277 ****
  drop cascades to table schema_one."table two"
  drop cascades to table schema_one.table_three
  NOTICE:  table "schema_two_table_two" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_two"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "audit_tbls_schema_two_table_three" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.audit_tbls_schema_two_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
- SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "schema_one_table_one" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_one_table_one"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "schema_one_table two" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls."schema_one_table two""
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "schema_one_table_three" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_one_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  ERROR:  object schema_one.table_three of type table cannot be dropped
  DELETE FROM undroppable_objs WHERE object_identity = 'schema_one.table_three';
  DROP SCHEMA schema_one, schema_two CASCADE;
  NOTICE:  drop cascades to 7 other objects
--- 250,261 ----
  drop cascades to table schema_one."table two"
  drop cascades to table schema_one.table_three
  NOTICE:  table "schema_two_table_two" does not exist, skipping
  NOTICE:  table "audit_tbls_schema_two_table_three" does not exist, skipping
  NOTICE:  table "schema_one_table_one" does not exist, skipping
  NOTICE:  table "schema_one_table two" does not exist, skipping
  NOTICE:  table "schema_one_table_three" does not exist, skipping
  ERROR:  object schema_one.table_three of type table cannot be dropped
+ CONTEXT:  PL/pgSQL function undroppable() line 14 at RAISE
  DELETE FROM undroppable_objs WHERE object_identity = 'schema_one.table_three';
  DROP SCHEMA schema_one, schema_two CASCADE;
  NOTICE:  drop cascades to 7 other objects
*************** drop cascades to table schema_one.table_
*** 283,304 ****
  drop cascades to table schema_one."table two"
  drop cascades to table schema_one.table_three
  NOTICE:  table "schema_two_table_two" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_two"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "audit_tbls_schema_two_table_three" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.audit_tbls_schema_two_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
- SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "schema_one_table_one" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_one_table_one"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "schema_one_table two" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls."schema_one_table two""
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "schema_one_table_three" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_one_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  SELECT * FROM dropped_objects WHERE schema IS NULL OR schema <> 'pg_toast';
       type     |   schema   |               object                
  --------------+------------+-------------------------------------
--- 267,276 ----
*************** SELECT * FROM dropped_objects WHERE sche
*** 329,336 ****
  
  DROP OWNED BY regression_bob;
  NOTICE:  schema "audit_tbls" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.audit_tbls_schema_one_table_two"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  SELECT * FROM dropped_objects WHERE type = 'schema';
    type  | schema |   object   
  --------+--------+------------
--- 301,306 ----
*************** insert into rewriteme
*** 402,409 ****
--- 372,381 ----
       select x * 1.001 from generate_series(1, 500) as t(x);
  alter table rewriteme alter column foo type numeric;
  ERROR:  I'm sorry Sir, No Rewrite Allowed.
+ CONTEXT:  PL/pgSQL function test_evtrig_no_rewrite() line 3 at RAISE
  alter table rewriteme add column baz int default 0;
  ERROR:  I'm sorry Sir, No Rewrite Allowed.
+ CONTEXT:  PL/pgSQL function test_evtrig_no_rewrite() line 3 at RAISE
  -- test with more than one reason to rewrite a single table
  CREATE OR REPLACE FUNCTION test_evtrig_no_rewrite() RETURNS event_trigger
  LANGUAGE plpgsql AS $$
diff --git a/src/test/regress/expected/plancache.out b/src/test/regress/expected/plancache.out
new file mode 100644
index 864f70f..3f3db33
*** a/src/test/regress/expected/plancache.out
--- b/src/test/regress/expected/plancache.out
*************** begin
*** 234,241 ****
  end$$ language plpgsql;
  select cachebug();
  NOTICE:  table "temptable" does not exist, skipping
- CONTEXT:  SQL statement "drop table if exists temptable cascade"
- PL/pgSQL function cachebug() line 4 at SQL statement
  NOTICE:  1
  NOTICE:  2
  NOTICE:  3
--- 234,239 ----
*************** NOTICE:  3
*** 246,253 ****
  
  select cachebug();
  NOTICE:  drop cascades to view vv
- CONTEXT:  SQL statement "drop table if exists temptable cascade"
- PL/pgSQL function cachebug() line 4 at SQL statement
  NOTICE:  1
  NOTICE:  2
  NOTICE:  3
--- 244,249 ----
diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out
new file mode 100644
index 7ce5415..a19424d
*** a/src/test/regress/expected/plpgsql.out
--- b/src/test/regress/expected/plpgsql.out
*************** ERROR:  duplicate key value violates uni
*** 1518,1544 ****
  DETAIL:  Key (name)=(PF1_1) already exists.
  update PSlot set backlink = 'WS.not.there' where slotname = 'PS.base.a1';
  ERROR:  WS.not.there         does not exist
! CONTEXT:  PL/pgSQL function tg_backlink_a() line 17 at assignment
  update PSlot set backlink = 'XX.illegal' where slotname = 'PS.base.a1';
  ERROR:  illegal backlink beginning with XX
! CONTEXT:  PL/pgSQL function tg_backlink_a() line 17 at assignment
  update PSlot set slotlink = 'PS.not.there' where slotname = 'PS.base.a1';
  ERROR:  PS.not.there         does not exist
! CONTEXT:  PL/pgSQL function tg_slotlink_a() line 17 at assignment
  update PSlot set slotlink = 'XX.illegal' where slotname = 'PS.base.a1';
  ERROR:  illegal slotlink beginning with XX
! CONTEXT:  PL/pgSQL function tg_slotlink_a() line 17 at assignment
  insert into HSlot values ('HS', 'base.hub1', 1, '');
  ERROR:  duplicate key value violates unique constraint "hslot_name"
  DETAIL:  Key (slotname)=(HS.base.hub1.1      ) already exists.
  insert into HSlot values ('HS', 'base.hub1', 20, '');
  ERROR:  no manual manipulation of HSlot
  delete from HSlot;
  ERROR:  no manual manipulation of HSlot
  insert into IFace values ('IF', 'notthere', 'eth0', '');
  ERROR:  system "notthere" does not exist
  insert into IFace values ('IF', 'orion', 'ethernet_interface_name_too_long', '');
  ERROR:  IFace slotname "IF.orion.ethernet_interface_name_too_long" too long (20 char max)
  --
  -- The following tests are unrelated to the scenario outlined above;
  -- they merely exercise specific parts of PL/pgSQL
--- 1518,1552 ----
  DETAIL:  Key (name)=(PF1_1) already exists.
  update PSlot set backlink = 'WS.not.there' where slotname = 'PS.base.a1';
  ERROR:  WS.not.there         does not exist
! CONTEXT:  PL/pgSQL function tg_backlink_set(character,character) line 30 at RAISE
! PL/pgSQL function tg_backlink_a() line 17 at assignment
  update PSlot set backlink = 'XX.illegal' where slotname = 'PS.base.a1';
  ERROR:  illegal backlink beginning with XX
! CONTEXT:  PL/pgSQL function tg_backlink_set(character,character) line 47 at RAISE
! PL/pgSQL function tg_backlink_a() line 17 at assignment
  update PSlot set slotlink = 'PS.not.there' where slotname = 'PS.base.a1';
  ERROR:  PS.not.there         does not exist
! CONTEXT:  PL/pgSQL function tg_slotlink_set(character,character) line 30 at RAISE
! PL/pgSQL function tg_slotlink_a() line 17 at assignment
  update PSlot set slotlink = 'XX.illegal' where slotname = 'PS.base.a1';
  ERROR:  illegal slotlink beginning with XX
! CONTEXT:  PL/pgSQL function tg_slotlink_set(character,character) line 77 at RAISE
! PL/pgSQL function tg_slotlink_a() line 17 at assignment
  insert into HSlot values ('HS', 'base.hub1', 1, '');
  ERROR:  duplicate key value violates unique constraint "hslot_name"
  DETAIL:  Key (slotname)=(HS.base.hub1.1      ) already exists.
  insert into HSlot values ('HS', 'base.hub1', 20, '');
  ERROR:  no manual manipulation of HSlot
+ CONTEXT:  PL/pgSQL function tg_hslot_biu() line 12 at RAISE
  delete from HSlot;
  ERROR:  no manual manipulation of HSlot
+ CONTEXT:  PL/pgSQL function tg_hslot_bd() line 12 at RAISE
  insert into IFace values ('IF', 'notthere', 'eth0', '');
  ERROR:  system "notthere" does not exist
+ CONTEXT:  PL/pgSQL function tg_iface_biu() line 8 at RAISE
  insert into IFace values ('IF', 'orion', 'ethernet_interface_name_too_long', '');
  ERROR:  IFace slotname "IF.orion.ethernet_interface_name_too_long" too long (20 char max)
+ CONTEXT:  PL/pgSQL function tg_iface_biu() line 14 at RAISE
  --
  -- The following tests are unrelated to the scenario outlined above;
  -- they merely exercise specific parts of PL/pgSQL
*************** NOTICE:  should see this
*** 1963,1968 ****
--- 1971,1977 ----
  NOTICE:  should see this only if -100 <> 0
  NOTICE:  should see this only if -100 fits in smallint
  ERROR:  -100 is less than zero
+ CONTEXT:  PL/pgSQL function trap_zero_divide(integer) line 12 at RAISE
  create function trap_matching_test(int) returns int as $$
  declare x int;
  	sx smallint;
*************** begin
*** 2066,2079 ****
  end$$ language plpgsql;
  select test_variable_storage();
  NOTICE:  should see this
- CONTEXT:  SQL statement "SELECT trap_zero_divide(-100)"
- PL/pgSQL function test_variable_storage() line 8 at PERFORM
  NOTICE:  should see this only if -100 <> 0
- CONTEXT:  SQL statement "SELECT trap_zero_divide(-100)"
- PL/pgSQL function test_variable_storage() line 8 at PERFORM
  NOTICE:  should see this only if -100 fits in smallint
- CONTEXT:  SQL statement "SELECT trap_zero_divide(-100)"
- PL/pgSQL function test_variable_storage() line 8 at PERFORM
   test_variable_storage 
  -----------------------
   123456789012
--- 2075,2082 ----
*************** DETAIL:  some detail info
*** 4052,4057 ****
--- 4055,4061 ----
  HINT:  some hint
  ERROR:  1 2 3
  DETAIL:  some detail info
+ CONTEXT:  PL/pgSQL function raise_test() line 5 at RAISE
  -- Since we can't actually see the thrown SQLSTATE in default psql output,
  -- test it like this; this also tests re-RAISE
  create or replace function raise_test() returns void as $$
*************** select raise_test();
*** 4068,4073 ****
--- 4072,4078 ----
  NOTICE:  SQLSTATE: 22012 SQLERRM: check me
  ERROR:  check me
  DETAIL:  some detail info
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise 'check me'
*************** select raise_test();
*** 4082,4087 ****
--- 4087,4093 ----
  NOTICE:  SQLSTATE: 1234F SQLERRM: check me
  ERROR:  check me
  DETAIL:  some detail info
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  -- SQLSTATE specification in WHEN
  create or replace function raise_test() returns void as $$
  begin
*************** select raise_test();
*** 4097,4102 ****
--- 4103,4109 ----
  NOTICE:  SQLSTATE: 1234F SQLERRM: check me
  ERROR:  check me
  DETAIL:  some detail info
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise division_by_zero using detail = 'some detail info';
*************** select raise_test();
*** 4110,4115 ****
--- 4117,4123 ----
  NOTICE:  SQLSTATE: 22012 SQLERRM: division_by_zero
  ERROR:  division_by_zero
  DETAIL:  some detail info
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise division_by_zero;
*************** end;
*** 4117,4122 ****
--- 4125,4131 ----
  $$ language plpgsql;
  select raise_test();
  ERROR:  division_by_zero
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise sqlstate '1234F';
*************** end;
*** 4124,4129 ****
--- 4133,4139 ----
  $$ language plpgsql;
  select raise_test();
  ERROR:  1234F
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise division_by_zero using message = 'custom' || ' message';
*************** end;
*** 4131,4136 ****
--- 4141,4147 ----
  $$ language plpgsql;
  select raise_test();
  ERROR:  custom message
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise using message = 'custom' || ' message', errcode = '22012';
*************** end;
*** 4138,4143 ****
--- 4149,4155 ----
  $$ language plpgsql;
  select raise_test();
  ERROR:  custom message
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  -- conflict on message
  create or replace function raise_test() returns void as $$
  begin
*************** $$ language plpgsql;
*** 4254,4259 ****
--- 4266,4272 ----
  select raise_test();
  NOTICE:  22012
  ERROR:  substitute message
+ CONTEXT:  PL/pgSQL function raise_test() line 7 at RAISE
  drop function raise_test();
  -- test passing column_name, constraint_name, datatype_name, table_name
  -- and schema_name error fields
*************** LINE 1: SELECT 'foo\\bar\041baz'
*** 4744,4750 ****
                 ^
  HINT:  Use the escape string syntax for backslashes, e.g., E'\\'.
  QUERY:  SELECT 'foo\\bar\041baz'
- CONTEXT:  PL/pgSQL function strtest() line 4 at RETURN
     strtest   
  -------------
   foo\bar!baz
--- 4757,4762 ----
*************** $$ language plpgsql;
*** 5260,5281 ****
  select outer_outer_func(10);
  NOTICE:  calling down into outer_func()
  NOTICE:  calling down into inner_func()
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 4 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 7 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  lets make sure we didnt break anything
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  inner_func() done
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  outer_func() done
   outer_outer_func 
  ------------------
--- 5272,5285 ----
*************** NOTICE:  outer_func() done
*** 5286,5307 ****
  select outer_outer_func(20);
  NOTICE:  calling down into outer_func()
  NOTICE:  calling down into inner_func()
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 4 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 7 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  lets make sure we didnt break anything
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  inner_func() done
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  outer_func() done
   outer_outer_func 
  ------------------
--- 5290,5303 ----
*************** $$ language plpgsql;
*** 5358,5379 ****
  select outer_outer_func(10);
  NOTICE:  calling down into outer_func()
  NOTICE:  calling down into inner_func()
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 10 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 15 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  lets make sure we didnt break anything
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  inner_func() done
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  outer_func() done
   outer_outer_func 
  ------------------
--- 5354,5367 ----
*************** NOTICE:  outer_func() done
*** 5384,5405 ****
  select outer_outer_func(20);
  NOTICE:  calling down into outer_func()
  NOTICE:  calling down into inner_func()
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 10 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 15 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  lets make sure we didnt break anything
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  inner_func() done
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  outer_func() done
   outer_outer_func 
  ------------------
--- 5372,5385 ----
diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out
new file mode 100644
index c0cd9fa..88bdc2c
*** a/src/test/regress/expected/privileges.out
--- b/src/test/regress/expected/privileges.out
*************** GRANT regressgroup2 TO regressuser5; --
*** 1023,1029 ****
  ERROR:  must have admin option on role "regressgroup2"
  SELECT dogrant_ok();			-- ok: SECURITY DEFINER conveys ADMIN
  NOTICE:  role "regressuser5" is already a member of role "regressgroup2"
- CONTEXT:  SQL function "dogrant_ok" statement 1
   dogrant_ok 
  ------------
   
--- 1023,1028 ----
diff --git a/src/test/regress/expected/rangefuncs.out b/src/test/regress/expected/rangefuncs.out
new file mode 100644
index 6dabe50..00ef421
*** a/src/test/regress/expected/rangefuncs.out
--- b/src/test/regress/expected/rangefuncs.out
*************** create trigger tnoticetrigger after inse
*** 1704,1712 ****
  execute procedure noticetrigger();
  select insert_tt2('foolme','barme') limit 1;
  NOTICE:  noticetrigger 11 foolme
- CONTEXT:  SQL function "insert_tt2" statement 1
  NOTICE:  noticetrigger 12 barme
- CONTEXT:  SQL function "insert_tt2" statement 1
   insert_tt2 
  ------------
           11
--- 1704,1710 ----
*************** create rule insert_tt_rule as on insert
*** 1735,1743 ****
    insert into tt_log values(new.*);
  select insert_tt2('foollog','barlog') limit 1;
  NOTICE:  noticetrigger 13 foollog
- CONTEXT:  SQL function "insert_tt2" statement 1
  NOTICE:  noticetrigger 14 barlog
- CONTEXT:  SQL function "insert_tt2" statement 1
   insert_tt2 
  ------------
           13
--- 1733,1739 ----
diff --git a/src/test/regress/expected/triggers.out b/src/test/regress/expected/triggers.out
new file mode 100644
index 3b32e8f..cd43e46
*** a/src/test/regress/expected/triggers.out
--- b/src/test/regress/expected/triggers.out
*************** NOTICE:  main_view BEFORE INSERT STATEME
*** 958,968 ****
  NOTICE:  main_view INSTEAD OF INSERT ROW (instead_of_ins)
  NOTICE:  NEW: (20,30)
  NOTICE:  trigger_func(before_ins_stmt) called: action = INSERT, when = BEFORE, level = STATEMENT
- CONTEXT:  SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
- PL/pgSQL function view_trigger() line 17 at SQL statement
  NOTICE:  trigger_func(after_ins_stmt) called: action = INSERT, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
- PL/pgSQL function view_trigger() line 17 at SQL statement
  NOTICE:  main_view AFTER INSERT STATEMENT (after_view_ins_stmt)
  INSERT 0 1
  INSERT INTO main_view VALUES (21, 31) RETURNING a, b;
--- 958,964 ----
*************** NOTICE:  main_view BEFORE INSERT STATEME
*** 970,980 ****
  NOTICE:  main_view INSTEAD OF INSERT ROW (instead_of_ins)
  NOTICE:  NEW: (21,31)
  NOTICE:  trigger_func(before_ins_stmt) called: action = INSERT, when = BEFORE, level = STATEMENT
- CONTEXT:  SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
- PL/pgSQL function view_trigger() line 17 at SQL statement
  NOTICE:  trigger_func(after_ins_stmt) called: action = INSERT, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
- PL/pgSQL function view_trigger() line 17 at SQL statement
  NOTICE:  main_view AFTER INSERT STATEMENT (after_view_ins_stmt)
   a  | b  
  ----+----
--- 966,972 ----
*************** NOTICE:  main_view BEFORE UPDATE STATEME
*** 988,1004 ****
  NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
  NOTICE:  OLD: (20,30), NEW: (20,31)
  NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
  UPDATE 0
  UPDATE main_view SET b = 32 WHERE a = 21 AND b = 31 RETURNING a, b;
--- 980,988 ----
*************** NOTICE:  main_view BEFORE UPDATE STATEME
*** 1006,1022 ****
  NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
  NOTICE:  OLD: (21,31), NEW: (21,32)
  NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
   a | b 
  ---+---
--- 990,998 ----
*************** NOTICE:  main_view BEFORE UPDATE STATEME
*** 1031,1050 ****
  NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
  NOTICE:  OLD: (20,30), NEW: (20,31)
  NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
  UPDATE 1
  UPDATE main_view SET b = 32 WHERE a = 21 AND b = 31 RETURNING a, b;
--- 1007,1016 ----
*************** NOTICE:  main_view BEFORE UPDATE STATEME
*** 1052,1071 ****
  NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
  NOTICE:  OLD: (21,31), NEW: (21,32)
  NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
   a  | b  
  ----+----
--- 1018,1027 ----
*************** INSERT 0 1
*** 1277,1282 ****
--- 1233,1239 ----
  -- UPDATE .. RETURNING
  UPDATE city_view SET country_name = 'Japon' WHERE city_name = 'Tokyo'; -- error
  ERROR:  No such country: "Japon"
+ CONTEXT:  PL/pgSQL function city_update() line 9 at RAISE
  UPDATE city_view SET country_name = 'Japan' WHERE city_name = 'Takyo'; -- no match
  UPDATE 0
  UPDATE city_view SET country_name = 'Japan' WHERE city_name = 'Tokyo' RETURNING *; -- OK
*************** select pg_trigger_depth();
*** 1489,1514 ****
  insert into depth_a values (1);
  NOTICE:  depth_a_tr: depth = 1
  NOTICE:  depth_b_tr: depth = 2
- CONTEXT:  SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_c_tr: depth = 3
- CONTEXT:  SQL statement "insert into depth_c values (1)"
- PL/pgSQL function depth_b_tf() line 5 at EXECUTE statement
- SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  SQLSTATE = U9999: depth = 2
- CONTEXT:  SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_b_tr: depth = 2
- CONTEXT:  SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_c_tr: depth = 3
- CONTEXT:  SQL statement "insert into depth_c values (1)"
- PL/pgSQL function depth_b_tf() line 12 at EXECUTE statement
- SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  ERROR:  U9999
! CONTEXT:  SQL statement "insert into depth_c values (1)"
  PL/pgSQL function depth_b_tf() line 12 at EXECUTE statement
  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
--- 1446,1458 ----
  insert into depth_a values (1);
  NOTICE:  depth_a_tr: depth = 1
  NOTICE:  depth_b_tr: depth = 2
  NOTICE:  depth_c_tr: depth = 3
  NOTICE:  SQLSTATE = U9999: depth = 2
  NOTICE:  depth_b_tr: depth = 2
  NOTICE:  depth_c_tr: depth = 3
  ERROR:  U9999
! CONTEXT:  PL/pgSQL function depth_c_tf() line 5 at RAISE
! SQL statement "insert into depth_c values (1)"
  PL/pgSQL function depth_b_tf() line 12 at EXECUTE statement
  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
*************** select pg_trigger_depth();
*** 1521,1541 ****
  insert into depth_a values (2);
  NOTICE:  depth_a_tr: depth = 1
  NOTICE:  depth_b_tr: depth = 2
- CONTEXT:  SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_c_tr: depth = 3
- CONTEXT:  SQL statement "insert into depth_c values (2)"
- PL/pgSQL function depth_b_tf() line 5 at EXECUTE statement
- SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_c_tr: depth = 3
- CONTEXT:  SQL statement "insert into depth_c values (2)"
- PL/pgSQL function depth_b_tf() line 5 at EXECUTE statement
- SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_b_tr: depth = 2
- CONTEXT:  SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_a_tr: depth = 1
  select pg_trigger_depth();
   pg_trigger_depth 
--- 1465,1473 ----
diff --git a/src/test/regress/expected/xml.out b/src/test/regress/expected/xml.out
new file mode 100644
index 9b2d264..5691e47
*** a/src/test/regress/expected/xml.out
--- b/src/test/regress/expected/xml.out
*************** SELECT xpath('/*', '<relativens xmlns=''
*** 934,940 ****
  WARNING:  line 1: xmlns: URI relative is not absolute
  <relativens xmlns='relative'/>
                              ^
- CONTEXT:  SQL function "xpath" statement 1
                  xpath                 
  --------------------------------------
   {"<relativens xmlns=\"relative\"/>"}
--- 934,939 ----
#82Merlin Moncure
mmoncure@gmail.com
In reply to: Pavel Stehule (#81)
Re: PL/pgSQL, RAISE and error context

On Wed, Jul 8, 2015 at 11:28 PM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

Hi

second version of this patch

make check-world passed

quickly scanning the patch, the implementation is trivial (minus
regression test adjustments), and is, IMSNSHO, the right solution.

Several of the source level comments need some minor wordsmithing and
the GUCs are missing documentation. If we've got consensus on the
approach, I'll pitch in on that.

merlin

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#83Pavel Stehule
pavel.stehule@gmail.com
In reply to: Merlin Moncure (#82)
Re: PL/pgSQL, RAISE and error context

2015-07-09 15:17 GMT+02:00 Merlin Moncure <mmoncure@gmail.com>:

On Wed, Jul 8, 2015 at 11:28 PM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

Hi

second version of this patch

make check-world passed

quickly scanning the patch, the implementation is trivial (minus
regression test adjustments), and is, IMSNSHO, the right solution.

yes, it is right way - the behave of RAISE statement will be much more
cleaner

Several of the source level comments need some minor wordsmithing and
the GUCs are missing documentation. If we've got consensus on the
approach, I'll pitch in on that.

thank you

Pavel

Show quoted text

merlin

#84Merlin Moncure
mmoncure@gmail.com
In reply to: Pavel Stehule (#83)
1 attachment(s)
Re: PL/pgSQL, RAISE and error context

On Thu, Jul 9, 2015 at 10:48 AM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

2015-07-09 15:17 GMT+02:00 Merlin Moncure <mmoncure@gmail.com>:

On Wed, Jul 8, 2015 at 11:28 PM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

Hi

second version of this patch

make check-world passed

quickly scanning the patch, the implementation is trivial (minus
regression test adjustments), and is, IMSNSHO, the right solution.

yes, it is right way - the behave of RAISE statement will be much more
cleaner

Several of the source level comments need some minor wordsmithing and
the GUCs are missing documentation. If we've got consensus on the
approach, I'll pitch in on that.

thank you

revised patch attached. added GUC docs and cleaned up pg_settings
language. Also tested patch and it works beautifully.

Note, Pavel's patch does adjust default behavior to what we think is
the "right" settings.

merlin

Attachments:

min_context-20150709-02.patchtext/x-patch; charset=US-ASCII; name=min_context-20150709-02.patchDownload
diff --git a/contrib/dblink/expected/dblink.out b/contrib/dblink/expected/dblink.out
new file mode 100644
index a49b562..a268fc7
*** a/contrib/dblink/expected/dblink.out
--- b/contrib/dblink/expected/dblink.out
***************
*** 1,3 ****
--- 1,4 ----
+ set client_min_context TO notice;
  CREATE EXTENSION dblink;
  CREATE TABLE foo(f1 int, f2 text, f3 text[], primary key (f1,f2));
  INSERT INTO foo VALUES (0,'a','{"a0","b0","c0"}');
diff --git a/contrib/dblink/sql/dblink.sql b/contrib/dblink/sql/dblink.sql
new file mode 100644
index ea78cc2..cf7e57e
*** a/contrib/dblink/sql/dblink.sql
--- b/contrib/dblink/sql/dblink.sql
***************
*** 1,3 ****
--- 1,5 ----
+ set client_min_context TO notice;
+ 
  CREATE EXTENSION dblink;
  
  CREATE TABLE foo(f1 int, f2 text, f3 text[], primary key (f1,f2));
diff --git a/contrib/hstore_plperl/expected/hstore_plperlu.out b/contrib/hstore_plperl/expected/hstore_plperlu.out
new file mode 100644
index 8c689ad..c97fd3f
*** a/contrib/hstore_plperl/expected/hstore_plperlu.out
--- b/contrib/hstore_plperl/expected/hstore_plperlu.out
*************** INFO:  $VAR1 = {
*** 29,35 ****
            'cc' => undef
          };
  
- CONTEXT:  PL/Perl function "test1"
   test1 
  -------
       2
--- 29,34 ----
*************** $$;
*** 46,52 ****
  SELECT test1none('aa=>bb, cc=>NULL'::hstore);
  INFO:  $VAR1 = '"aa"=>"bb", "cc"=>NULL';
  
- CONTEXT:  PL/Perl function "test1none"
   test1none 
  -----------
           0
--- 45,50 ----
*************** INFO:  $VAR1 = {
*** 67,73 ****
            'cc' => undef
          };
  
- CONTEXT:  PL/Perl function "test1list"
   test1list 
  -----------
           2
--- 65,70 ----
*************** $VAR2 = {
*** 92,98 ****
            'dd' => 'ee'
          };
  
- CONTEXT:  PL/Perl function "test1arr"
   test1arr 
  ----------
          2
--- 89,94 ----
*************** INFO:  $VAR1 = {
*** 120,129 ****
            'cc' => undef
          };
  
- CONTEXT:  PL/Perl function "test3"
  INFO:  $VAR1 = '"a"=>"1", "b"=>"boo", "c"=>NULL';
  
- CONTEXT:  PL/Perl function "test3"
   test3 
  -------
   
--- 116,123 ----
*************** INFO:  $VAR1 = {
*** 161,167 ****
                 }
          };
  
- CONTEXT:  PL/Perl function "test4"
  SELECT * FROM test1;
   a |                b                
  ---+---------------------------------
--- 155,160 ----
diff --git a/contrib/hstore_plpython/expected/hstore_plpython.out b/contrib/hstore_plpython/expected/hstore_plpython.out
new file mode 100644
index b7a6a92..23091d3
*** a/contrib/hstore_plpython/expected/hstore_plpython.out
--- b/contrib/hstore_plpython/expected/hstore_plpython.out
*************** return len(val)
*** 13,19 ****
  $$;
  SELECT test1('aa=>bb, cc=>NULL'::hstore);
  INFO:  [('aa', 'bb'), ('cc', None)]
- CONTEXT:  PL/Python function "test1"
   test1 
  -------
       2
--- 13,18 ----
*************** return len(val)
*** 32,38 ****
  $$;
  SELECT test1n('aa=>bb, cc=>NULL'::hstore);
  INFO:  [('aa', 'bb'), ('cc', None)]
- CONTEXT:  PL/Python function "test1n"
   test1n 
  --------
        2
--- 31,36 ----
diff --git a/contrib/ltree_plpython/expected/ltree_plpython.out b/contrib/ltree_plpython/expected/ltree_plpython.out
new file mode 100644
index 934529e..c6e8a7c
*** a/contrib/ltree_plpython/expected/ltree_plpython.out
--- b/contrib/ltree_plpython/expected/ltree_plpython.out
*************** return len(val)
*** 9,15 ****
  $$;
  SELECT test1('aa.bb.cc'::ltree);
  INFO:  ['aa', 'bb', 'cc']
- CONTEXT:  PL/Python function "test1"
   test1 
  -------
       3
--- 9,14 ----
*************** return len(val)
*** 24,30 ****
  $$;
  SELECT test1n('aa.bb.cc'::ltree);
  INFO:  ['aa', 'bb', 'cc']
- CONTEXT:  PL/Python function "test1n"
   test1n 
  --------
        3
--- 23,28 ----
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
new file mode 100644
index b91d6c7..38ae0ad
*** a/doc/src/sgml/config.sgml
--- b/doc/src/sgml/config.sgml
*************** local0.*    /var/log/postgresql
*** 4144,4149 ****
--- 4144,4171 ----
  
       <variablelist>
  
+      <varlistentry id="guc-client-min-context" xreflabel="client_min_context">
+       <term><varname>client_min_context</varname> (<type>enum</type>)
+       <indexterm>
+        <primary><varname>client_min_context</> configuration parameter</primary>
+       </indexterm>
+       </term>
+       <listitem>
+        <para>
+         Controls which message levels include context when sent to the client.
+         Valid values are <literal>DEBUG5</>,
+         <literal>DEBUG4</>, <literal>DEBUG3</>, <literal>DEBUG2</>,
+         <literal>DEBUG1</>, <literal>LOG</>, <literal>NOTICE</>,
+         <literal>WARNING</>, <literal>ERROR</>, <literal>FATAL</>,
+         and <literal>PANIC</>.  Each level
+         includes all the levels that follow it.  The later the level,
+         the fewer messages are sent.  The default is
+         <literal>NOTICE</>.  Note that <literal>LOG</> has a different
+         rank here than in <varname>log_min_messages</>.
+        </para>
+       </listitem>
+      </varlistentry>
+ 
       <varlistentry id="guc-client-min-messages" xreflabel="client_min_messages">
        <term><varname>client_min_messages</varname> (<type>enum</type>)
        <indexterm>
*************** local0.*    /var/log/postgresql
*** 4165,4170 ****
--- 4187,4216 ----
         </para>
        </listitem>
       </varlistentry>
+ 
+      <varlistentry id="guc-log-min-context" xreflabel="log_min_context">
+       <term><varname>log_min_context</varname> (<type>enum</type>)
+       <indexterm>
+        <primary><varname>log_min_context</> configuration parameter</primary>
+       </indexterm>
+       </term>
+       <listitem>
+        <para>
+         Controls which message levels include context when written to 
+         the server log.
+         Valid values are <literal>DEBUG5</>, <literal>DEBUG4</>,
+         <literal>DEBUG3</>, <literal>DEBUG2</>, <literal>DEBUG1</>,
+         <literal>INFO</>, <literal>NOTICE</>, <literal>WARNING</>,
+         <literal>ERROR</>, <literal>LOG</>, <literal>FATAL</>, and
+         <literal>PANIC</>.  Each level includes all the levels that
+         follow it.  The later the level, the fewer messages are sent
+         to the log.  The default is <literal>WARNING</>.  Note that
+         <literal>LOG</> has a different rank here than in
+         <varname>client_min_messages</>.
+         Only superusers can change this setting.
+        </para>
+       </listitem>
+      </varlistentry>
  
       <varlistentry id="guc-log-min-messages" xreflabel="log_min_messages">
        <term><varname>log_min_messages</varname> (<type>enum</type>)
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
new file mode 100644
index 088c714..9445230
*** a/src/backend/utils/error/elog.c
--- b/src/backend/utils/error/elog.c
*************** write_csvlog(ErrorData *edata)
*** 2730,2736 ****
  	appendStringInfoChar(&buf, ',');
  
  	/* errcontext */
! 	if (!edata->hide_ctx)
  		appendCSVLiteral(&buf, edata->context);
  	appendStringInfoChar(&buf, ',');
  
--- 2730,2736 ----
  	appendStringInfoChar(&buf, ',');
  
  	/* errcontext */
! 	if (!edata->hide_ctx && edata->elevel >= log_min_context)
  		appendCSVLiteral(&buf, edata->context);
  	appendStringInfoChar(&buf, ',');
  
*************** send_message_to_server_log(ErrorData *ed
*** 2863,2869 ****
  			append_with_tabs(&buf, edata->internalquery);
  			appendStringInfoChar(&buf, '\n');
  		}
! 		if (edata->context && !edata->hide_ctx)
  		{
  			log_line_prefix(&buf, edata);
  			appendStringInfoString(&buf, _("CONTEXT:  "));
--- 2863,2869 ----
  			append_with_tabs(&buf, edata->internalquery);
  			appendStringInfoChar(&buf, '\n');
  		}
! 		if (edata->context && !edata->hide_ctx && edata->elevel >= log_min_context)
  		{
  			log_line_prefix(&buf, edata);
  			appendStringInfoString(&buf, _("CONTEXT:  "));
*************** send_message_to_frontend(ErrorData *edat
*** 3137,3143 ****
  			err_sendstring(&msgbuf, edata->hint);
  		}
  
! 		if (edata->context)
  		{
  			pq_sendbyte(&msgbuf, PG_DIAG_CONTEXT);
  			err_sendstring(&msgbuf, edata->context);
--- 3137,3143 ----
  			err_sendstring(&msgbuf, edata->hint);
  		}
  
! 		if (edata->context && edata->elevel >= client_min_context)
  		{
  			pq_sendbyte(&msgbuf, PG_DIAG_CONTEXT);
  			err_sendstring(&msgbuf, edata->context);
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
new file mode 100644
index 1bed525..cae8094
*** a/src/backend/utils/misc/guc.c
--- b/src/backend/utils/misc/guc.c
*************** bool		Password_encryption = true;
*** 430,435 ****
--- 430,437 ----
  int			log_min_error_statement = ERROR;
  int			log_min_messages = WARNING;
  int			client_min_messages = NOTICE;
+ int			log_min_context = WARNING;
+ int			client_min_context = ERROR;
  int			log_min_duration_statement = -1;
  int			log_temp_files = -1;
  int			trace_recovery_messages = LOG;
*************** static struct config_enum ConfigureNames
*** 3426,3431 ****
--- 3428,3444 ----
  	},
  
  	{
+ 		{"client_min_context", PGC_USERSET, LOGGING_WHEN,
+ 			gettext_noop("Sets the message levels for which context is sent to the client."),
+ 			gettext_noop("Each level includes all the levels that follow it. The later"
+ 						 " the level, the less context is sent.")
+ 		},
+ 		&client_min_context,
+ 		ERROR, client_message_level_options,
+ 		NULL, NULL, NULL
+ 	},
+ 
+ 	{
  		{"client_min_messages", PGC_USERSET, LOGGING_WHEN,
  			gettext_noop("Sets the message levels that are sent to the client."),
  			gettext_noop("Each level includes all the levels that follow it. The later"
*************** static struct config_enum ConfigureNames
*** 3478,3483 ****
--- 3491,3507 ----
  		NULL, NULL, NULL
  	},
  
+ 	{
+ 		{"log_min_context", PGC_SUSET, LOGGING_WHEN,
+ 			gettext_noop("Sets the message levels for which context is logged."),
+ 			gettext_noop("Each level includes all the levels that follow it. The later"
+ 						 " the level, the less context is sent.")
+ 		},
+ 		&log_min_context,
+ 		WARNING, server_message_level_options,
+ 		NULL, NULL, NULL
+ 	},
+ 
  	{
  		{"log_min_messages", PGC_SUSET, LOGGING_WHEN,
  			gettext_noop("Sets the message levels that are logged."),
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
new file mode 100644
index 06dfc06..8695e8b
*** a/src/backend/utils/misc/postgresql.conf.sample
--- b/src/backend/utils/misc/postgresql.conf.sample
***************
*** 360,365 ****
--- 360,390 ----
  
  # - When to Log -
  
+ #client_min_context = error		# values in order of decreasing detail:
+ 					#   debug5
+ 					#   debug4
+ 					#   debug3
+ 					#   debug2
+ 					#   debug1
+ 					#   log
+ 					#   notice
+ 					#   warning
+ 					#   error
+ 
+ #log_min_context = warning		# values in order of decreasing detail:
+ 					#   debug5
+ 					#   debug4
+ 					#   debug3
+ 					#   debug2
+ 					#   debug1
+ 					#   info
+ 					#   notice
+ 					#   warning
+ 					#   error
+ 					#   log
+ 					#   fatal
+ 					#   panic
+ 
  #client_min_messages = notice		# values in order of decreasing detail:
  					#   debug5
  					#   debug4
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
new file mode 100644
index dc167f9..f03a5e1
*** a/src/include/utils/guc.h
--- b/src/include/utils/guc.h
*************** extern PGDLLIMPORT bool check_function_b
*** 246,251 ****
--- 246,253 ----
  extern bool default_with_oids;
  extern bool SQL_inheritance;
  
+ extern int	log_min_context;
+ extern int	client_min_context;
  extern int	log_min_error_statement;
  extern int	log_min_messages;
  extern int	client_min_messages;
diff --git a/src/pl/plperl/expected/plperl.out b/src/pl/plperl/expected/plperl.out
new file mode 100644
index d23a302..14df5f4
*** a/src/pl/plperl/expected/plperl.out
--- b/src/pl/plperl/expected/plperl.out
*************** DO $$
*** 614,620 ****
    elog(NOTICE, $a);
  $$ LANGUAGE plperl;
  NOTICE:  This is a test
- CONTEXT:  PL/Perl anonymous code block
  -- check that restricted operations are rejected in a plperl DO block
  DO $$ system("/nonesuch"); $$ LANGUAGE plperl;
  ERROR:  'system' trapped by operation mask at line 1.
--- 614,619 ----
*************** CONTEXT:  PL/Perl anonymous code block
*** 628,634 ****
  -- check that eval is allowed and eval'd restricted ops are caught
  DO $$ eval q{chdir '.';}; warn "Caught: $@"; $$ LANGUAGE plperl;
  WARNING:  Caught: 'chdir' trapped by operation mask at line 1.
- CONTEXT:  PL/Perl anonymous code block
  -- check that compiling do (dofile opcode) is allowed
  -- but that executing it for a file not already loaded (via require) dies
  DO $$ warn do "/dev/null"; $$ LANGUAGE plperl;
--- 627,632 ----
diff --git a/src/pl/plperl/expected/plperl_elog.out b/src/pl/plperl/expected/plperl_elog.out
new file mode 100644
index c447fa2..3f9449a
*** a/src/pl/plperl/expected/plperl_elog.out
--- b/src/pl/plperl/expected/plperl_elog.out
*************** create or replace function perl_elog(tex
*** 7,13 ****
  $$;
  select perl_elog('explicit elog');
  NOTICE:  explicit elog
- CONTEXT:  PL/Perl function "perl_elog"
   perl_elog 
  -----------
   
--- 7,12 ----
*************** create or replace function perl_warn(tex
*** 21,27 ****
  $$;
  select perl_warn('implicit elog via warn');
  WARNING:  implicit elog via warn at line 4.
- CONTEXT:  PL/Perl function "perl_warn"
   perl_warn 
  -----------
   
--- 20,25 ----
*************** select uses_global();
*** 61,67 ****
  -- make sure we don't choke on readonly values
  do language plperl $$ elog(NOTICE, ${^TAINT}); $$;
  NOTICE:  0
- CONTEXT:  PL/Perl anonymous code block
  -- test recovery after "die"
  create or replace function just_die() returns void language plperl AS $$
  die "just die";
--- 59,64 ----
*************** return $a + $b;
*** 94,104 ****
  $$;
  select indirect_die_caller();
  NOTICE:  caught die
- CONTEXT:  SQL statement "SELECT die_caller() AS fx"
- PL/Perl function "indirect_die_caller"
  NOTICE:  caught die
- CONTEXT:  SQL statement "SELECT die_caller() AS fx"
- PL/Perl function "indirect_die_caller"
   indirect_die_caller 
  ---------------------
                     2
--- 91,97 ----
diff --git a/src/pl/plperl/expected/plperl_trigger.out b/src/pl/plperl/expected/plperl_trigger.out
new file mode 100644
index 36ecb92..5e3860e
*** a/src/pl/plperl/expected/plperl_trigger.out
--- b/src/pl/plperl/expected/plperl_trigger.out
*************** BEFORE INSERT OR UPDATE OR DELETE ON tri
*** 62,136 ****
  FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
  insert into trigger_test values(1,'insert', '("(1)")');
  NOTICE:  $_TD->{argc} = '2'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{args} = ['23', 'skidoo']
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{event} = 'INSERT'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{level} = 'ROW'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{name} = 'show_trigger_data_trig'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{new} = {'foo' => {'rfoo' => {'i' => '1'}}, 'i' => '1', 'v' => 'insert'}
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{relid} = 'bogus:12345'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{relname} = 'trigger_test'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{table_name} = 'trigger_test'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{table_schema} = 'public'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{when} = 'BEFORE'
- CONTEXT:  PL/Perl function "trigger_data"
  update trigger_test set v = 'update' where i = 1;
  NOTICE:  $_TD->{argc} = '2'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{args} = ['23', 'skidoo']
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{event} = 'UPDATE'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{level} = 'ROW'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{name} = 'show_trigger_data_trig'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{new} = {'foo' => {'rfoo' => {'i' => '1'}}, 'i' => '1', 'v' => 'update'}
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{old} = {'foo' => {'rfoo' => {'i' => '1'}}, 'i' => '1', 'v' => 'insert'}
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{relid} = 'bogus:12345'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{relname} = 'trigger_test'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{table_name} = 'trigger_test'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{table_schema} = 'public'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{when} = 'BEFORE'
- CONTEXT:  PL/Perl function "trigger_data"
  delete from trigger_test;
  NOTICE:  $_TD->{argc} = '2'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{args} = ['23', 'skidoo']
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{event} = 'DELETE'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{level} = 'ROW'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{name} = 'show_trigger_data_trig'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{old} = {'foo' => {'rfoo' => {'i' => '1'}}, 'i' => '1', 'v' => 'update'}
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{relid} = 'bogus:12345'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{relname} = 'trigger_test'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{table_name} = 'trigger_test'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{table_schema} = 'public'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{when} = 'BEFORE'
- CONTEXT:  PL/Perl function "trigger_data"
  DROP TRIGGER show_trigger_data_trig on trigger_test;
  insert into trigger_test values(1,'insert', '("(1)")');
  CREATE VIEW trigger_test_view AS SELECT * FROM trigger_test;
--- 62,102 ----
*************** INSTEAD OF INSERT OR UPDATE OR DELETE ON
*** 139,213 ****
  FOR EACH ROW EXECUTE PROCEDURE trigger_data(24,'skidoo view');
  insert into trigger_test_view values(2,'insert', '("(2)")');
  NOTICE:  $_TD->{argc} = '2'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{args} = ['24', 'skidoo view']
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{event} = 'INSERT'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{level} = 'ROW'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{name} = 'show_trigger_data_trig'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{new} = {'foo' => {'rfoo' => {'i' => '2'}}, 'i' => '2', 'v' => 'insert'}
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{relid} = 'bogus:12345'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{relname} = 'trigger_test_view'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{table_name} = 'trigger_test_view'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{table_schema} = 'public'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{when} = 'INSTEAD OF'
- CONTEXT:  PL/Perl function "trigger_data"
  update trigger_test_view set v = 'update', foo = '("(3)")' where i = 1;
  NOTICE:  $_TD->{argc} = '2'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{args} = ['24', 'skidoo view']
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{event} = 'UPDATE'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{level} = 'ROW'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{name} = 'show_trigger_data_trig'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{new} = {'foo' => {'rfoo' => {'i' => '3'}}, 'i' => '1', 'v' => 'update'}
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{old} = {'foo' => {'rfoo' => {'i' => '1'}}, 'i' => '1', 'v' => 'insert'}
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{relid} = 'bogus:12345'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{relname} = 'trigger_test_view'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{table_name} = 'trigger_test_view'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{table_schema} = 'public'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{when} = 'INSTEAD OF'
- CONTEXT:  PL/Perl function "trigger_data"
  delete from trigger_test_view;
  NOTICE:  $_TD->{argc} = '2'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{args} = ['24', 'skidoo view']
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{event} = 'DELETE'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{level} = 'ROW'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{name} = 'show_trigger_data_trig'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{old} = {'foo' => {'rfoo' => {'i' => '1'}}, 'i' => '1', 'v' => 'insert'}
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{relid} = 'bogus:12345'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{relname} = 'trigger_test_view'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{table_name} = 'trigger_test_view'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{table_schema} = 'public'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{when} = 'INSTEAD OF'
- CONTEXT:  PL/Perl function "trigger_data"
  DROP VIEW trigger_test_view;
  delete from trigger_test;
  DROP FUNCTION trigger_data();
--- 105,145 ----
*************** create event trigger perl_b_snitch on dd
*** 319,346 ****
     execute procedure perlsnitch();
  create or replace function foobar() returns int language sql as $$select 1;$$;
  NOTICE:  perlsnitch: ddl_command_start CREATE FUNCTION 
- CONTEXT:  PL/Perl function "perlsnitch"
  NOTICE:  perlsnitch: ddl_command_end CREATE FUNCTION 
- CONTEXT:  PL/Perl function "perlsnitch"
  alter function foobar() cost 77;
  NOTICE:  perlsnitch: ddl_command_start ALTER FUNCTION 
- CONTEXT:  PL/Perl function "perlsnitch"
  NOTICE:  perlsnitch: ddl_command_end ALTER FUNCTION 
- CONTEXT:  PL/Perl function "perlsnitch"
  drop function foobar();
  NOTICE:  perlsnitch: ddl_command_start DROP FUNCTION 
- CONTEXT:  PL/Perl function "perlsnitch"
  NOTICE:  perlsnitch: ddl_command_end DROP FUNCTION 
- CONTEXT:  PL/Perl function "perlsnitch"
  create table foo();
  NOTICE:  perlsnitch: ddl_command_start CREATE TABLE 
- CONTEXT:  PL/Perl function "perlsnitch"
  NOTICE:  perlsnitch: ddl_command_end CREATE TABLE 
- CONTEXT:  PL/Perl function "perlsnitch"
  drop table foo;
  NOTICE:  perlsnitch: ddl_command_start DROP TABLE 
- CONTEXT:  PL/Perl function "perlsnitch"
  NOTICE:  perlsnitch: ddl_command_end DROP TABLE 
- CONTEXT:  PL/Perl function "perlsnitch"
  drop event trigger perl_a_snitch;
  drop event trigger perl_b_snitch;
--- 251,268 ----
diff --git a/src/pl/plperl/expected/plperlu.out b/src/pl/plperl/expected/plperlu.out
new file mode 100644
index 3daf4ce..a3edb38
*** a/src/pl/plperl/expected/plperlu.out
--- b/src/pl/plperl/expected/plperlu.out
*************** LOAD 'plperl';
*** 6,12 ****
  SET plperl.on_plperlu_init = '$_SHARED{init} = 42';
  DO $$ warn $_SHARED{init} $$ language plperlu;
  WARNING:  42 at line 1.
- CONTEXT:  PL/Perl anonymous code block
  --
  -- Test compilation of unicode regex - regardless of locale.
  -- This code fails in plain plperl in a non-UTF8 database.
--- 6,11 ----
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
new file mode 100644
index 7d4001c..e1a6b7d
*** a/src/pl/plpgsql/src/pl_exec.c
--- b/src/pl/plpgsql/src/pl_exec.c
***************
*** 42,49 ****
  #include "utils/typcache.h"
  
  
- static const char *const raise_skip_msg = "RAISE";
- 
  typedef struct
  {
  	int			nargs;			/* number of arguments */
--- 42,47 ----
*************** plpgsql_exec_error_callback(void *arg)
*** 939,948 ****
  {
  	PLpgSQL_execstate *estate = (PLpgSQL_execstate *) arg;
  
- 	/* if we are doing RAISE, don't report its location */
- 	if (estate->err_text == raise_skip_msg)
- 		return;
- 
  	if (estate->err_text != NULL)
  	{
  		/*
--- 937,942 ----
*************** exec_stmt_raise(PLpgSQL_execstate *estat
*** 3158,3165 ****
  	/*
  	 * Throw the error (may or may not come back)
  	 */
- 	estate->err_text = raise_skip_msg;	/* suppress traceback of raise */
- 
  	ereport(stmt->elog_level,
  			(err_code ? errcode(err_code) : 0,
  			 errmsg_internal("%s", err_message),
--- 3152,3157 ----
diff --git a/src/pl/plpython/expected/plpython_do.out b/src/pl/plpython/expected/plpython_do.out
new file mode 100644
index 0977812..e300530
*** a/src/pl/plpython/expected/plpython_do.out
--- b/src/pl/plpython/expected/plpython_do.out
***************
*** 1,9 ****
  DO $$ plpy.notice("This is plpythonu.") $$ LANGUAGE plpythonu;
  NOTICE:  This is plpythonu.
- CONTEXT:  PL/Python anonymous code block
  DO $$ plpy.notice("This is plpython2u.") $$ LANGUAGE plpython2u;
  NOTICE:  This is plpython2u.
- CONTEXT:  PL/Python anonymous code block
  DO $$ raise Exception("error test") $$ LANGUAGE plpythonu;
  ERROR:  Exception: error test
  CONTEXT:  Traceback (most recent call last):
--- 1,7 ----
diff --git a/src/pl/plpython/expected/plpython_error.out b/src/pl/plpython/expected/plpython_error.out
new file mode 100644
index be2ec97..1f52af7
*** a/src/pl/plpython/expected/plpython_error.out
--- b/src/pl/plpython/expected/plpython_error.out
*************** return None
*** 108,114 ****
  	LANGUAGE plpythonu;
  SELECT invalid_type_caught('rick');
  NOTICE:  type "test" does not exist
- CONTEXT:  PL/Python function "invalid_type_caught"
   invalid_type_caught 
  ---------------------
   
--- 108,113 ----
*************** return "you''ve been warned"
*** 232,238 ****
  	LANGUAGE plpythonu;
  SELECT nested_warning();
  WARNING:  boom
- CONTEXT:  PL/Python function "nested_warning"
     nested_warning   
  --------------------
   you've been warned
--- 231,236 ----
*************** SELECT specific_exception(2);
*** 336,342 ****
  
  SELECT specific_exception(NULL);
  NOTICE:  Violated the NOT NULL constraint, sqlstate 23502
- CONTEXT:  PL/Python function "specific_exception"
   specific_exception 
  --------------------
   
--- 334,339 ----
*************** CONTEXT:  PL/Python function "specific_e
*** 344,350 ****
  
  SELECT specific_exception(2);
  NOTICE:  Violated the UNIQUE constraint, sqlstate 23505
- CONTEXT:  PL/Python function "specific_exception"
   specific_exception 
  --------------------
   
--- 341,346 ----
diff --git a/src/pl/plpython/expected/plpython_spi.out b/src/pl/plpython/expected/plpython_spi.out
new file mode 100644
index e2861df..e715ee5
*** a/src/pl/plpython/expected/plpython_spi.out
--- b/src/pl/plpython/expected/plpython_spi.out
*************** else:
*** 130,142 ****
  $$ LANGUAGE plpythonu;
  SELECT result_metadata_test($$SELECT 1 AS foo, '11'::text AS bar UNION SELECT 2, '22'$$);
  INFO:  True
- CONTEXT:  PL/Python function "result_metadata_test"
  INFO:  ['foo', 'bar']
- CONTEXT:  PL/Python function "result_metadata_test"
  INFO:  [23, 25]
- CONTEXT:  PL/Python function "result_metadata_test"
  INFO:  [-1, -1]
- CONTEXT:  PL/Python function "result_metadata_test"
   result_metadata_test 
  ----------------------
                      2
--- 130,138 ----
*************** CONTEXT:  PL/Python function "result_met
*** 144,150 ****
  
  SELECT result_metadata_test($$CREATE TEMPORARY TABLE foo1 (a int, b text)$$);
  INFO:  True
- CONTEXT:  PL/Python function "result_metadata_test"
  ERROR:  plpy.Error: command did not produce a result set
  CONTEXT:  Traceback (most recent call last):
    PL/Python function "result_metadata_test", line 6, in <module>
--- 140,145 ----
*************** else:
*** 234,248 ****
  $$ LANGUAGE plpythonu;
  SELECT result_subscript_test();
  INFO:  2
- CONTEXT:  PL/Python function "result_subscript_test"
  INFO:  4
- CONTEXT:  PL/Python function "result_subscript_test"
  INFO:  [2, 3]
- CONTEXT:  PL/Python function "result_subscript_test"
  INFO:  [1, 3]
- CONTEXT:  PL/Python function "result_subscript_test"
  INFO:  [10, 100, 3, 1000]
- CONTEXT:  PL/Python function "result_subscript_test"
   result_subscript_test 
  -----------------------
   
--- 229,238 ----
*************** plpy.info(result[:])
*** 257,263 ****
  $$ LANGUAGE plpythonu;
  SELECT result_empty_test();
  INFO:  []
- CONTEXT:  PL/Python function "result_empty_test"
   result_empty_test 
  -------------------
   
--- 247,252 ----
diff --git a/src/pl/plpython/expected/plpython_subtransaction.out b/src/pl/plpython/expected/plpython_subtransaction.out
new file mode 100644
index ced4682..635bac6
*** a/src/pl/plpython/expected/plpython_subtransaction.out
--- b/src/pl/plpython/expected/plpython_subtransaction.out
*************** SELECT * FROM subtransaction_tbl;
*** 154,160 ****
  TRUNCATE subtransaction_tbl;
  SELECT subtransaction_nested_test('t');
  NOTICE:  Swallowed SyntaxError('syntax error at or near "error"',)
- CONTEXT:  PL/Python function "subtransaction_nested_test"
   subtransaction_nested_test 
  ----------------------------
   ok
--- 154,159 ----
*************** return "ok"
*** 180,188 ****
  $$ LANGUAGE plpythonu;
  SELECT subtransaction_deeply_nested_test();
  NOTICE:  Swallowed SyntaxError('syntax error at or near "error"',)
- CONTEXT:  PL/Python function "subtransaction_nested_test"
- SQL statement "SELECT subtransaction_nested_test('t')"
- PL/Python function "subtransaction_nested_test"
   subtransaction_deeply_nested_test 
  -----------------------------------
   ok
--- 179,184 ----
*************** CONTEXT:  Traceback (most recent call la
*** 251,257 ****
  PL/Python function "subtransaction_exit_without_enter"
  SELECT subtransaction_enter_without_exit();
  WARNING:  forcibly aborting a subtransaction that has not been exited
- CONTEXT:  PL/Python function "subtransaction_enter_without_exit"
   subtransaction_enter_without_exit 
  -----------------------------------
   
--- 247,252 ----
*************** CONTEXT:  PL/Python function "subtransac
*** 259,265 ****
  
  SELECT subtransaction_exit_twice();
  WARNING:  forcibly aborting a subtransaction that has not been exited
- CONTEXT:  PL/Python function "subtransaction_exit_twice"
  ERROR:  ValueError: this subtransaction has not been entered
  CONTEXT:  Traceback (most recent call last):
    PL/Python function "subtransaction_exit_twice", line 3, in <module>
--- 254,259 ----
*************** CONTEXT:  Traceback (most recent call la
*** 267,275 ****
  PL/Python function "subtransaction_exit_twice"
  SELECT subtransaction_enter_twice();
  WARNING:  forcibly aborting a subtransaction that has not been exited
- CONTEXT:  PL/Python function "subtransaction_enter_twice"
  WARNING:  forcibly aborting a subtransaction that has not been exited
- CONTEXT:  PL/Python function "subtransaction_enter_twice"
   subtransaction_enter_twice 
  ----------------------------
   
--- 261,267 ----
*************** CONTEXT:  Traceback (most recent call la
*** 283,289 ****
  PL/Python function "subtransaction_exit_same_subtransaction_twice"
  SELECT subtransaction_enter_same_subtransaction_twice();
  WARNING:  forcibly aborting a subtransaction that has not been exited
- CONTEXT:  PL/Python function "subtransaction_enter_same_subtransaction_twice"
  ERROR:  ValueError: this subtransaction has already been entered
  CONTEXT:  Traceback (most recent call last):
    PL/Python function "subtransaction_enter_same_subtransaction_twice", line 4, in <module>
--- 275,280 ----
*************** except plpy.SPIError:
*** 329,337 ****
  $$ LANGUAGE plpythonu;
  SELECT subtransaction_mix_explicit_and_implicit();
  WARNING:  Caught a SPI error from an explicit subtransaction
- CONTEXT:  PL/Python function "subtransaction_mix_explicit_and_implicit"
  WARNING:  Caught a SPI error
- CONTEXT:  PL/Python function "subtransaction_mix_explicit_and_implicit"
   subtransaction_mix_explicit_and_implicit 
  ------------------------------------------
   
--- 320,326 ----
*************** with plpy.subtransaction():
*** 370,376 ****
  $$ LANGUAGE plpythonu;
  SELECT try_catch_inside_subtransaction();
  NOTICE:  caught
- CONTEXT:  PL/Python function "try_catch_inside_subtransaction"
   try_catch_inside_subtransaction 
  ---------------------------------
   
--- 359,364 ----
*************** with plpy.subtransaction():
*** 395,401 ****
  $$ LANGUAGE plpythonu;
  SELECT pk_violation_inside_subtransaction();
  NOTICE:  caught
- CONTEXT:  PL/Python function "pk_violation_inside_subtransaction"
   pk_violation_inside_subtransaction 
  ------------------------------------
   
--- 383,388 ----
diff --git a/src/pl/plpython/expected/plpython_test.out b/src/pl/plpython/expected/plpython_test.out
new file mode 100644
index a884fc0..7b76faf
*** a/src/pl/plpython/expected/plpython_test.out
--- b/src/pl/plpython/expected/plpython_test.out
*************** plpy.error('error')
*** 62,78 ****
  $$ LANGUAGE plpythonu;
  SELECT elog_test();
  INFO:  info
- CONTEXT:  PL/Python function "elog_test"
  INFO:  37
- CONTEXT:  PL/Python function "elog_test"
  INFO:  ()
- CONTEXT:  PL/Python function "elog_test"
  INFO:  ('info', 37, [1, 2, 3])
- CONTEXT:  PL/Python function "elog_test"
  NOTICE:  notice
- CONTEXT:  PL/Python function "elog_test"
  WARNING:  warning
- CONTEXT:  PL/Python function "elog_test"
  ERROR:  plpy.Error: error
  CONTEXT:  Traceback (most recent call last):
    PL/Python function "elog_test", line 10, in <module>
--- 62,72 ----
diff --git a/src/pl/plpython/expected/plpython_trigger.out b/src/pl/plpython/expected/plpython_trigger.out
new file mode 100644
index 80e478b..4148963
*** a/src/pl/plpython/expected/plpython_trigger.out
--- b/src/pl/plpython/expected/plpython_trigger.out
*************** BEFORE INSERT OR UPDATE OR DELETE OR TRU
*** 98,305 ****
  FOR EACH STATEMENT EXECUTE PROCEDURE trigger_data(23,'skidoo');
  insert into trigger_test values(1,'insert');
  NOTICE:  TD[args] => ['23', 'skidoo']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => INSERT
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => STATEMENT
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig_stmt
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => BEFORE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[args] => ['23', 'skidoo']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => INSERT
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => ROW
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig_before
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => {'i': 1, 'v': 'insert'}
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => BEFORE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[args] => ['23', 'skidoo']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => INSERT
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => ROW
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig_after
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => {'i': 1, 'v': 'insert'}
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => AFTER
- CONTEXT:  PL/Python function "trigger_data"
  update trigger_test set v = 'update' where i = 1;
  NOTICE:  TD[args] => ['23', 'skidoo']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => UPDATE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => STATEMENT
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig_stmt
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => BEFORE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[args] => ['23', 'skidoo']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => UPDATE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => ROW
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig_before
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => {'i': 1, 'v': 'update'}
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => {'i': 1, 'v': 'insert'}
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => BEFORE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[args] => ['23', 'skidoo']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => UPDATE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => ROW
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig_after
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => {'i': 1, 'v': 'update'}
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => {'i': 1, 'v': 'insert'}
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => AFTER
- CONTEXT:  PL/Python function "trigger_data"
  delete from trigger_test;
  NOTICE:  TD[args] => ['23', 'skidoo']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => DELETE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => STATEMENT
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig_stmt
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => BEFORE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[args] => ['23', 'skidoo']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => DELETE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => ROW
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig_before
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => {'i': 1, 'v': 'update'}
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => BEFORE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[args] => ['23', 'skidoo']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => DELETE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => ROW
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig_after
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => {'i': 1, 'v': 'update'}
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => AFTER
- CONTEXT:  PL/Python function "trigger_data"
  truncate table trigger_test;
  NOTICE:  TD[args] => ['23', 'skidoo']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => TRUNCATE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => STATEMENT
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig_stmt
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => BEFORE
- CONTEXT:  PL/Python function "trigger_data"
  DROP TRIGGER show_trigger_data_trig_stmt on trigger_test;
  DROP TRIGGER show_trigger_data_trig_before on trigger_test;
  DROP TRIGGER show_trigger_data_trig_after on trigger_test;
--- 98,205 ----
*************** INSTEAD OF INSERT OR UPDATE OR DELETE ON
*** 310,376 ****
  FOR EACH ROW EXECUTE PROCEDURE trigger_data(24,'skidoo view');
  insert into trigger_test_view values(2,'insert');
  NOTICE:  TD[args] => ['24', 'skidoo view']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => INSERT
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => ROW
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => {'i': 2, 'v': 'insert'}
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test_view
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => INSTEAD OF
- CONTEXT:  PL/Python function "trigger_data"
  update trigger_test_view set v = 'update' where i = 1;
  NOTICE:  TD[args] => ['24', 'skidoo view']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => UPDATE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => ROW
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => {'i': 1, 'v': 'update'}
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => {'i': 1, 'v': 'insert'}
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test_view
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => INSTEAD OF
- CONTEXT:  PL/Python function "trigger_data"
  delete from trigger_test_view;
  NOTICE:  TD[args] => ['24', 'skidoo view']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => DELETE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => ROW
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => {'i': 1, 'v': 'insert'}
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test_view
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => INSTEAD OF
- CONTEXT:  PL/Python function "trigger_data"
  DROP FUNCTION trigger_data() CASCADE;
  NOTICE:  drop cascades to trigger show_trigger_data_trig on view trigger_test_view
  DROP VIEW trigger_test_view;
--- 210,246 ----
*************** BEFORE DELETE ON trigger_test
*** 402,408 ****
  FOR EACH ROW EXECUTE PROCEDURE stupid2();
  DELETE FROM trigger_test WHERE i = 0;
  WARNING:  PL/Python trigger function returned "MODIFY" in a DELETE trigger -- ignored
- CONTEXT:  PL/Python function "stupid2"
  DROP TRIGGER stupid_trigger2 ON trigger_test;
  INSERT INTO trigger_test VALUES (0, 'zero');
  -- returning unrecognized string from trigger function
--- 272,277 ----
diff --git a/src/pl/plpython/expected/plpython_types.out b/src/pl/plpython/expected/plpython_types.out
new file mode 100644
index 17057a5..f0b6abd
*** a/src/pl/plpython/expected/plpython_types.out
--- b/src/pl/plpython/expected/plpython_types.out
*************** return x
*** 10,16 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_bool(true);
  INFO:  (True, <type 'bool'>)
- CONTEXT:  PL/Python function "test_type_conversion_bool"
   test_type_conversion_bool 
  ---------------------------
   t
--- 10,15 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 18,24 ****
  
  SELECT * FROM test_type_conversion_bool(false);
  INFO:  (False, <type 'bool'>)
- CONTEXT:  PL/Python function "test_type_conversion_bool"
   test_type_conversion_bool 
  ---------------------------
   f
--- 17,22 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 26,32 ****
  
  SELECT * FROM test_type_conversion_bool(null);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_bool"
   test_type_conversion_bool 
  ---------------------------
   
--- 24,29 ----
*************** return ret
*** 54,60 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_bool_other(0);
  INFO:  (0, False)
- CONTEXT:  PL/Python function "test_type_conversion_bool_other"
   test_type_conversion_bool_other 
  ---------------------------------
   f
--- 51,56 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 62,68 ****
  
  SELECT * FROM test_type_conversion_bool_other(1);
  INFO:  (5, True)
- CONTEXT:  PL/Python function "test_type_conversion_bool_other"
   test_type_conversion_bool_other 
  ---------------------------------
   t
--- 58,63 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 70,76 ****
  
  SELECT * FROM test_type_conversion_bool_other(2);
  INFO:  ('', False)
- CONTEXT:  PL/Python function "test_type_conversion_bool_other"
   test_type_conversion_bool_other 
  ---------------------------------
   f
--- 65,70 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 78,84 ****
  
  SELECT * FROM test_type_conversion_bool_other(3);
  INFO:  ('fa', True)
- CONTEXT:  PL/Python function "test_type_conversion_bool_other"
   test_type_conversion_bool_other 
  ---------------------------------
   t
--- 72,77 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 86,92 ****
  
  SELECT * FROM test_type_conversion_bool_other(4);
  INFO:  ([], False)
- CONTEXT:  PL/Python function "test_type_conversion_bool_other"
   test_type_conversion_bool_other 
  ---------------------------------
   f
--- 79,84 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 94,100 ****
  
  SELECT * FROM test_type_conversion_bool_other(5);
  INFO:  ([0], True)
- CONTEXT:  PL/Python function "test_type_conversion_bool_other"
   test_type_conversion_bool_other 
  ---------------------------------
   t
--- 86,91 ----
*************** return x
*** 106,112 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_char('a');
  INFO:  ('a', <type 'str'>)
- CONTEXT:  PL/Python function "test_type_conversion_char"
   test_type_conversion_char 
  ---------------------------
   a
--- 97,102 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 114,120 ****
  
  SELECT * FROM test_type_conversion_char(null);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_char"
   test_type_conversion_char 
  ---------------------------
   
--- 104,109 ----
*************** return x
*** 126,132 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_int2(100::int2);
  INFO:  (100, <type 'int'>)
- CONTEXT:  PL/Python function "test_type_conversion_int2"
   test_type_conversion_int2 
  ---------------------------
                         100
--- 115,120 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 134,140 ****
  
  SELECT * FROM test_type_conversion_int2(-100::int2);
  INFO:  (-100, <type 'int'>)
- CONTEXT:  PL/Python function "test_type_conversion_int2"
   test_type_conversion_int2 
  ---------------------------
                        -100
--- 122,127 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 142,148 ****
  
  SELECT * FROM test_type_conversion_int2(null);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_int2"
   test_type_conversion_int2 
  ---------------------------
                            
--- 129,134 ----
*************** return x
*** 154,160 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_int4(100);
  INFO:  (100, <type 'int'>)
- CONTEXT:  PL/Python function "test_type_conversion_int4"
   test_type_conversion_int4 
  ---------------------------
                         100
--- 140,145 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 162,168 ****
  
  SELECT * FROM test_type_conversion_int4(-100);
  INFO:  (-100, <type 'int'>)
- CONTEXT:  PL/Python function "test_type_conversion_int4"
   test_type_conversion_int4 
  ---------------------------
                        -100
--- 147,152 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 170,176 ****
  
  SELECT * FROM test_type_conversion_int4(null);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_int4"
   test_type_conversion_int4 
  ---------------------------
                            
--- 154,159 ----
*************** return x
*** 182,188 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_int8(100);
  INFO:  (100L, <type 'long'>)
- CONTEXT:  PL/Python function "test_type_conversion_int8"
   test_type_conversion_int8 
  ---------------------------
                         100
--- 165,170 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 190,196 ****
  
  SELECT * FROM test_type_conversion_int8(-100);
  INFO:  (-100L, <type 'long'>)
- CONTEXT:  PL/Python function "test_type_conversion_int8"
   test_type_conversion_int8 
  ---------------------------
                        -100
--- 172,177 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 198,204 ****
  
  SELECT * FROM test_type_conversion_int8(5000000000);
  INFO:  (5000000000L, <type 'long'>)
- CONTEXT:  PL/Python function "test_type_conversion_int8"
   test_type_conversion_int8 
  ---------------------------
                  5000000000
--- 179,184 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 206,212 ****
  
  SELECT * FROM test_type_conversion_int8(null);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_int8"
   test_type_conversion_int8 
  ---------------------------
                            
--- 186,191 ----
*************** return x
*** 220,226 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_numeric(100);
  INFO:  ('100', 'Decimal')
- CONTEXT:  PL/Python function "test_type_conversion_numeric"
   test_type_conversion_numeric 
  ------------------------------
                            100
--- 199,204 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 228,234 ****
  
  SELECT * FROM test_type_conversion_numeric(-100);
  INFO:  ('-100', 'Decimal')
- CONTEXT:  PL/Python function "test_type_conversion_numeric"
   test_type_conversion_numeric 
  ------------------------------
                           -100
--- 206,211 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 236,242 ****
  
  SELECT * FROM test_type_conversion_numeric(100.0);
  INFO:  ('100.0', 'Decimal')
- CONTEXT:  PL/Python function "test_type_conversion_numeric"
   test_type_conversion_numeric 
  ------------------------------
                          100.0
--- 213,218 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 244,250 ****
  
  SELECT * FROM test_type_conversion_numeric(100.00);
  INFO:  ('100.00', 'Decimal')
- CONTEXT:  PL/Python function "test_type_conversion_numeric"
   test_type_conversion_numeric 
  ------------------------------
                         100.00
--- 220,225 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 252,258 ****
  
  SELECT * FROM test_type_conversion_numeric(5000000000.5);
  INFO:  ('5000000000.5', 'Decimal')
- CONTEXT:  PL/Python function "test_type_conversion_numeric"
   test_type_conversion_numeric 
  ------------------------------
                   5000000000.5
--- 227,232 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 260,266 ****
  
  SELECT * FROM test_type_conversion_numeric(1234567890.0987654321);
  INFO:  ('1234567890.0987654321', 'Decimal')
- CONTEXT:  PL/Python function "test_type_conversion_numeric"
   test_type_conversion_numeric 
  ------------------------------
          1234567890.0987654321
--- 234,239 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 268,274 ****
  
  SELECT * FROM test_type_conversion_numeric(-1234567890.0987654321);
  INFO:  ('-1234567890.0987654321', 'Decimal')
- CONTEXT:  PL/Python function "test_type_conversion_numeric"
   test_type_conversion_numeric 
  ------------------------------
         -1234567890.0987654321
--- 241,246 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 276,282 ****
  
  SELECT * FROM test_type_conversion_numeric(null);
  INFO:  ('None', 'NoneType')
- CONTEXT:  PL/Python function "test_type_conversion_numeric"
   test_type_conversion_numeric 
  ------------------------------
                               
--- 248,253 ----
*************** return x
*** 288,294 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_float4(100);
  INFO:  (100.0, <type 'float'>)
- CONTEXT:  PL/Python function "test_type_conversion_float4"
   test_type_conversion_float4 
  -----------------------------
                           100
--- 259,264 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 296,302 ****
  
  SELECT * FROM test_type_conversion_float4(-100);
  INFO:  (-100.0, <type 'float'>)
- CONTEXT:  PL/Python function "test_type_conversion_float4"
   test_type_conversion_float4 
  -----------------------------
                          -100
--- 266,271 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 304,310 ****
  
  SELECT * FROM test_type_conversion_float4(5000.5);
  INFO:  (5000.5, <type 'float'>)
- CONTEXT:  PL/Python function "test_type_conversion_float4"
   test_type_conversion_float4 
  -----------------------------
                        5000.5
--- 273,278 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 312,318 ****
  
  SELECT * FROM test_type_conversion_float4(null);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_float4"
   test_type_conversion_float4 
  -----------------------------
                              
--- 280,285 ----
*************** return x
*** 324,330 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_float8(100);
  INFO:  (100.0, <type 'float'>)
- CONTEXT:  PL/Python function "test_type_conversion_float8"
   test_type_conversion_float8 
  -----------------------------
                           100
--- 291,296 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 332,338 ****
  
  SELECT * FROM test_type_conversion_float8(-100);
  INFO:  (-100.0, <type 'float'>)
- CONTEXT:  PL/Python function "test_type_conversion_float8"
   test_type_conversion_float8 
  -----------------------------
                          -100
--- 298,303 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 340,346 ****
  
  SELECT * FROM test_type_conversion_float8(5000000000.5);
  INFO:  (5000000000.5, <type 'float'>)
- CONTEXT:  PL/Python function "test_type_conversion_float8"
   test_type_conversion_float8 
  -----------------------------
                  5000000000.5
--- 305,310 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 348,354 ****
  
  SELECT * FROM test_type_conversion_float8(null);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_float8"
   test_type_conversion_float8 
  -----------------------------
                              
--- 312,317 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 356,362 ****
  
  SELECT * FROM test_type_conversion_float8(100100100.654321);
  INFO:  (100100100.654321, <type 'float'>)
- CONTEXT:  PL/Python function "test_type_conversion_float8"
   test_type_conversion_float8 
  -----------------------------
              100100100.654321
--- 319,324 ----
*************** return x
*** 368,374 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_oid(100);
  INFO:  (100L, <type 'long'>)
- CONTEXT:  PL/Python function "test_type_conversion_oid"
   test_type_conversion_oid 
  --------------------------
                        100
--- 330,335 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 376,382 ****
  
  SELECT * FROM test_type_conversion_oid(2147483649);
  INFO:  (2147483649L, <type 'long'>)
- CONTEXT:  PL/Python function "test_type_conversion_oid"
   test_type_conversion_oid 
  --------------------------
                 2147483649
--- 337,342 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 384,390 ****
  
  SELECT * FROM test_type_conversion_oid(null);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_oid"
   test_type_conversion_oid 
  --------------------------
                           
--- 344,349 ----
*************** return x
*** 396,402 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_text('hello world');
  INFO:  ('hello world', <type 'str'>)
- CONTEXT:  PL/Python function "test_type_conversion_text"
   test_type_conversion_text 
  ---------------------------
   hello world
--- 355,360 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 404,410 ****
  
  SELECT * FROM test_type_conversion_text(null);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_text"
   test_type_conversion_text 
  ---------------------------
   
--- 362,367 ----
*************** return x
*** 416,422 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_bytea('hello world');
  INFO:  ('hello world', <type 'str'>)
- CONTEXT:  PL/Python function "test_type_conversion_bytea"
   test_type_conversion_bytea 
  ----------------------------
   \x68656c6c6f20776f726c64
--- 373,378 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 424,430 ****
  
  SELECT * FROM test_type_conversion_bytea(E'null\\000byte');
  INFO:  ('null\x00byte', <type 'str'>)
- CONTEXT:  PL/Python function "test_type_conversion_bytea"
   test_type_conversion_bytea 
  ----------------------------
   \x6e756c6c0062797465
--- 380,385 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 432,438 ****
  
  SELECT * FROM test_type_conversion_bytea(null);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_bytea"
   test_type_conversion_bytea 
  ----------------------------
   
--- 387,392 ----
*************** return y
*** 481,487 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_uint2(100::uint2, 50);
  INFO:  (100, <type 'int'>)
- CONTEXT:  PL/Python function "test_type_conversion_uint2"
   test_type_conversion_uint2 
  ----------------------------
                           50
--- 435,440 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 489,501 ****
  
  SELECT * FROM test_type_conversion_uint2(100::uint2, -50);
  INFO:  (100, <type 'int'>)
- CONTEXT:  PL/Python function "test_type_conversion_uint2"
  ERROR:  value for domain uint2 violates check constraint "uint2_check"
  CONTEXT:  while creating return value
  PL/Python function "test_type_conversion_uint2"
  SELECT * FROM test_type_conversion_uint2(null, 1);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_uint2"
   test_type_conversion_uint2 
  ----------------------------
                            1
--- 442,452 ----
*************** return y
*** 524,530 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_bytea10('hello wold', 'hello wold');
  INFO:  ('hello wold', <type 'str'>)
- CONTEXT:  PL/Python function "test_type_conversion_bytea10"
   test_type_conversion_bytea10 
  ------------------------------
   \x68656c6c6f20776f6c64
--- 475,480 ----
*************** SELECT * FROM test_type_conversion_bytea
*** 534,540 ****
  ERROR:  value for domain bytea10 violates check constraint "bytea10_check"
  SELECT * FROM test_type_conversion_bytea10('hello word', 'hello world');
  INFO:  ('hello word', <type 'str'>)
- CONTEXT:  PL/Python function "test_type_conversion_bytea10"
  ERROR:  value for domain bytea10 violates check constraint "bytea10_check"
  CONTEXT:  while creating return value
  PL/Python function "test_type_conversion_bytea10"
--- 484,489 ----
*************** SELECT * FROM test_type_conversion_bytea
*** 542,548 ****
  ERROR:  value for domain bytea10 violates check constraint "bytea10_check"
  SELECT * FROM test_type_conversion_bytea10('hello word', null);
  INFO:  ('hello word', <type 'str'>)
- CONTEXT:  PL/Python function "test_type_conversion_bytea10"
  ERROR:  value for domain bytea10 violates check constraint "bytea10_check"
  CONTEXT:  while creating return value
  PL/Python function "test_type_conversion_bytea10"
--- 491,496 ----
*************** return x
*** 555,561 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_array_int4(ARRAY[0, 100]);
  INFO:  ([0, 100], <type 'list'>)
- CONTEXT:  PL/Python function "test_type_conversion_array_int4"
   test_type_conversion_array_int4 
  ---------------------------------
   {0,100}
--- 503,508 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 563,569 ****
  
  SELECT * FROM test_type_conversion_array_int4(ARRAY[0,-100,55]);
  INFO:  ([0, -100, 55], <type 'list'>)
- CONTEXT:  PL/Python function "test_type_conversion_array_int4"
   test_type_conversion_array_int4 
  ---------------------------------
   {0,-100,55}
--- 510,515 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 571,577 ****
  
  SELECT * FROM test_type_conversion_array_int4(ARRAY[NULL,1]);
  INFO:  ([None, 1], <type 'list'>)
- CONTEXT:  PL/Python function "test_type_conversion_array_int4"
   test_type_conversion_array_int4 
  ---------------------------------
   {NULL,1}
--- 517,522 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 579,585 ****
  
  SELECT * FROM test_type_conversion_array_int4(ARRAY[]::integer[]);
  INFO:  ([], <type 'list'>)
- CONTEXT:  PL/Python function "test_type_conversion_array_int4"
   test_type_conversion_array_int4 
  ---------------------------------
   {}
--- 524,529 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 587,593 ****
  
  SELECT * FROM test_type_conversion_array_int4(NULL);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_array_int4"
   test_type_conversion_array_int4 
  ---------------------------------
   
--- 531,536 ----
*************** return x
*** 603,609 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_array_text(ARRAY['foo', 'bar']);
  INFO:  (['foo', 'bar'], <type 'list'>)
- CONTEXT:  PL/Python function "test_type_conversion_array_text"
   test_type_conversion_array_text 
  ---------------------------------
   {foo,bar}
--- 546,551 ----
*************** return x
*** 615,621 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_array_bytea(ARRAY[E'\\xdeadbeef'::bytea, NULL]);
  INFO:  (['\xde\xad\xbe\xef', None], <type 'list'>)
- CONTEXT:  PL/Python function "test_type_conversion_array_bytea"
   test_type_conversion_array_bytea 
  ----------------------------------
   {"\\xdeadbeef",NULL}
--- 557,562 ----
*************** return x
*** 681,687 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_array_domain(ARRAY[0, 100]::ordered_pair_domain);
  INFO:  ([0, 100], <type 'list'>)
- CONTEXT:  PL/Python function "test_type_conversion_array_domain"
   test_type_conversion_array_domain 
  -----------------------------------
   {0,100}
--- 622,627 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 689,695 ****
  
  SELECT * FROM test_type_conversion_array_domain(NULL::ordered_pair_domain);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_array_domain"
   test_type_conversion_array_domain 
  -----------------------------------
   
--- 629,634 ----
*************** return rv[0]['val']
*** 783,789 ****
  $$;
  SELECT test_prep_bool_output(); -- false
  INFO:  {'val': False}
- CONTEXT:  PL/Python function "test_prep_bool_output"
   test_prep_bool_output 
  -----------------------
   f
--- 722,727 ----
*************** return rv[0]['val']
*** 812,818 ****
  $$;
  SELECT test_prep_bytea_output();
  INFO:  {'val': '\xaa\x00\xbb'}
- CONTEXT:  PL/Python function "test_prep_bytea_output"
   test_prep_bytea_output 
  ------------------------
   \xaa00bb
--- 750,755 ----
diff --git a/src/test/regress/expected/copy2.out b/src/test/regress/expected/copy2.out
new file mode 100644
index 5e31737..72ada21
*** a/src/test/regress/expected/copy2.out
--- b/src/test/regress/expected/copy2.out
*************** Check constraints:
*** 447,458 ****
  
  copy check_con_tbl from stdin;
  NOTICE:  input = {"f1":1}
- CONTEXT:  COPY check_con_tbl, line 1: "1"
  NOTICE:  input = {"f1":null}
- CONTEXT:  COPY check_con_tbl, line 2: "\N"
  copy check_con_tbl from stdin;
  NOTICE:  input = {"f1":0}
- CONTEXT:  COPY check_con_tbl, line 1: "0"
  ERROR:  new row for relation "check_con_tbl" violates check constraint "check_con_tbl_check"
  DETAIL:  Failing row contains (0).
  CONTEXT:  COPY check_con_tbl, line 1: "0"
--- 447,455 ----
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
new file mode 100644
index e70c315..05ac0ad
*** a/src/test/regress/expected/event_trigger.out
--- b/src/test/regress/expected/event_trigger.out
*************** drop cascades to table schema_one.table_
*** 234,248 ****
  drop cascades to table schema_one."table two"
  drop cascades to table schema_one.table_three
  NOTICE:  table "schema_two_table_two" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_two"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "audit_tbls_schema_two_table_three" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.audit_tbls_schema_two_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
- SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  ERROR:  object audit_tbls.schema_two_table_three of type table cannot be dropped
! CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three"
  PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  DELETE FROM undroppable_objs WHERE object_identity = 'audit_tbls.schema_two_table_three';
  DROP SCHEMA schema_one, schema_two CASCADE;
--- 234,243 ----
  drop cascades to table schema_one."table two"
  drop cascades to table schema_one.table_three
  NOTICE:  table "schema_two_table_two" does not exist, skipping
  NOTICE:  table "audit_tbls_schema_two_table_three" does not exist, skipping
  ERROR:  object audit_tbls.schema_two_table_three of type table cannot be dropped
! CONTEXT:  PL/pgSQL function undroppable() line 14 at RAISE
! SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three"
  PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  DELETE FROM undroppable_objs WHERE object_identity = 'audit_tbls.schema_two_table_three';
  DROP SCHEMA schema_one, schema_two CASCADE;
*************** drop cascades to table schema_one.table_
*** 255,277 ****
  drop cascades to table schema_one."table two"
  drop cascades to table schema_one.table_three
  NOTICE:  table "schema_two_table_two" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_two"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "audit_tbls_schema_two_table_three" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.audit_tbls_schema_two_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
- SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "schema_one_table_one" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_one_table_one"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "schema_one_table two" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls."schema_one_table two""
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "schema_one_table_three" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_one_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  ERROR:  object schema_one.table_three of type table cannot be dropped
  DELETE FROM undroppable_objs WHERE object_identity = 'schema_one.table_three';
  DROP SCHEMA schema_one, schema_two CASCADE;
  NOTICE:  drop cascades to 7 other objects
--- 250,261 ----
  drop cascades to table schema_one."table two"
  drop cascades to table schema_one.table_three
  NOTICE:  table "schema_two_table_two" does not exist, skipping
  NOTICE:  table "audit_tbls_schema_two_table_three" does not exist, skipping
  NOTICE:  table "schema_one_table_one" does not exist, skipping
  NOTICE:  table "schema_one_table two" does not exist, skipping
  NOTICE:  table "schema_one_table_three" does not exist, skipping
  ERROR:  object schema_one.table_three of type table cannot be dropped
+ CONTEXT:  PL/pgSQL function undroppable() line 14 at RAISE
  DELETE FROM undroppable_objs WHERE object_identity = 'schema_one.table_three';
  DROP SCHEMA schema_one, schema_two CASCADE;
  NOTICE:  drop cascades to 7 other objects
*************** drop cascades to table schema_one.table_
*** 283,304 ****
  drop cascades to table schema_one."table two"
  drop cascades to table schema_one.table_three
  NOTICE:  table "schema_two_table_two" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_two"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "audit_tbls_schema_two_table_three" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.audit_tbls_schema_two_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
- SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "schema_one_table_one" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_one_table_one"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "schema_one_table two" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls."schema_one_table two""
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "schema_one_table_three" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_one_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  SELECT * FROM dropped_objects WHERE schema IS NULL OR schema <> 'pg_toast';
       type     |   schema   |               object                
  --------------+------------+-------------------------------------
--- 267,276 ----
*************** SELECT * FROM dropped_objects WHERE sche
*** 329,336 ****
  
  DROP OWNED BY regression_bob;
  NOTICE:  schema "audit_tbls" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.audit_tbls_schema_one_table_two"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  SELECT * FROM dropped_objects WHERE type = 'schema';
    type  | schema |   object   
  --------+--------+------------
--- 301,306 ----
*************** insert into rewriteme
*** 402,409 ****
--- 372,381 ----
       select x * 1.001 from generate_series(1, 500) as t(x);
  alter table rewriteme alter column foo type numeric;
  ERROR:  I'm sorry Sir, No Rewrite Allowed.
+ CONTEXT:  PL/pgSQL function test_evtrig_no_rewrite() line 3 at RAISE
  alter table rewriteme add column baz int default 0;
  ERROR:  I'm sorry Sir, No Rewrite Allowed.
+ CONTEXT:  PL/pgSQL function test_evtrig_no_rewrite() line 3 at RAISE
  -- test with more than one reason to rewrite a single table
  CREATE OR REPLACE FUNCTION test_evtrig_no_rewrite() RETURNS event_trigger
  LANGUAGE plpgsql AS $$
diff --git a/src/test/regress/expected/plancache.out b/src/test/regress/expected/plancache.out
new file mode 100644
index 864f70f..3f3db33
*** a/src/test/regress/expected/plancache.out
--- b/src/test/regress/expected/plancache.out
*************** begin
*** 234,241 ****
  end$$ language plpgsql;
  select cachebug();
  NOTICE:  table "temptable" does not exist, skipping
- CONTEXT:  SQL statement "drop table if exists temptable cascade"
- PL/pgSQL function cachebug() line 4 at SQL statement
  NOTICE:  1
  NOTICE:  2
  NOTICE:  3
--- 234,239 ----
*************** NOTICE:  3
*** 246,253 ****
  
  select cachebug();
  NOTICE:  drop cascades to view vv
- CONTEXT:  SQL statement "drop table if exists temptable cascade"
- PL/pgSQL function cachebug() line 4 at SQL statement
  NOTICE:  1
  NOTICE:  2
  NOTICE:  3
--- 244,249 ----
diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out
new file mode 100644
index 7ce5415..a19424d
*** a/src/test/regress/expected/plpgsql.out
--- b/src/test/regress/expected/plpgsql.out
*************** ERROR:  duplicate key value violates uni
*** 1518,1544 ****
  DETAIL:  Key (name)=(PF1_1) already exists.
  update PSlot set backlink = 'WS.not.there' where slotname = 'PS.base.a1';
  ERROR:  WS.not.there         does not exist
! CONTEXT:  PL/pgSQL function tg_backlink_a() line 17 at assignment
  update PSlot set backlink = 'XX.illegal' where slotname = 'PS.base.a1';
  ERROR:  illegal backlink beginning with XX
! CONTEXT:  PL/pgSQL function tg_backlink_a() line 17 at assignment
  update PSlot set slotlink = 'PS.not.there' where slotname = 'PS.base.a1';
  ERROR:  PS.not.there         does not exist
! CONTEXT:  PL/pgSQL function tg_slotlink_a() line 17 at assignment
  update PSlot set slotlink = 'XX.illegal' where slotname = 'PS.base.a1';
  ERROR:  illegal slotlink beginning with XX
! CONTEXT:  PL/pgSQL function tg_slotlink_a() line 17 at assignment
  insert into HSlot values ('HS', 'base.hub1', 1, '');
  ERROR:  duplicate key value violates unique constraint "hslot_name"
  DETAIL:  Key (slotname)=(HS.base.hub1.1      ) already exists.
  insert into HSlot values ('HS', 'base.hub1', 20, '');
  ERROR:  no manual manipulation of HSlot
  delete from HSlot;
  ERROR:  no manual manipulation of HSlot
  insert into IFace values ('IF', 'notthere', 'eth0', '');
  ERROR:  system "notthere" does not exist
  insert into IFace values ('IF', 'orion', 'ethernet_interface_name_too_long', '');
  ERROR:  IFace slotname "IF.orion.ethernet_interface_name_too_long" too long (20 char max)
  --
  -- The following tests are unrelated to the scenario outlined above;
  -- they merely exercise specific parts of PL/pgSQL
--- 1518,1552 ----
  DETAIL:  Key (name)=(PF1_1) already exists.
  update PSlot set backlink = 'WS.not.there' where slotname = 'PS.base.a1';
  ERROR:  WS.not.there         does not exist
! CONTEXT:  PL/pgSQL function tg_backlink_set(character,character) line 30 at RAISE
! PL/pgSQL function tg_backlink_a() line 17 at assignment
  update PSlot set backlink = 'XX.illegal' where slotname = 'PS.base.a1';
  ERROR:  illegal backlink beginning with XX
! CONTEXT:  PL/pgSQL function tg_backlink_set(character,character) line 47 at RAISE
! PL/pgSQL function tg_backlink_a() line 17 at assignment
  update PSlot set slotlink = 'PS.not.there' where slotname = 'PS.base.a1';
  ERROR:  PS.not.there         does not exist
! CONTEXT:  PL/pgSQL function tg_slotlink_set(character,character) line 30 at RAISE
! PL/pgSQL function tg_slotlink_a() line 17 at assignment
  update PSlot set slotlink = 'XX.illegal' where slotname = 'PS.base.a1';
  ERROR:  illegal slotlink beginning with XX
! CONTEXT:  PL/pgSQL function tg_slotlink_set(character,character) line 77 at RAISE
! PL/pgSQL function tg_slotlink_a() line 17 at assignment
  insert into HSlot values ('HS', 'base.hub1', 1, '');
  ERROR:  duplicate key value violates unique constraint "hslot_name"
  DETAIL:  Key (slotname)=(HS.base.hub1.1      ) already exists.
  insert into HSlot values ('HS', 'base.hub1', 20, '');
  ERROR:  no manual manipulation of HSlot
+ CONTEXT:  PL/pgSQL function tg_hslot_biu() line 12 at RAISE
  delete from HSlot;
  ERROR:  no manual manipulation of HSlot
+ CONTEXT:  PL/pgSQL function tg_hslot_bd() line 12 at RAISE
  insert into IFace values ('IF', 'notthere', 'eth0', '');
  ERROR:  system "notthere" does not exist
+ CONTEXT:  PL/pgSQL function tg_iface_biu() line 8 at RAISE
  insert into IFace values ('IF', 'orion', 'ethernet_interface_name_too_long', '');
  ERROR:  IFace slotname "IF.orion.ethernet_interface_name_too_long" too long (20 char max)
+ CONTEXT:  PL/pgSQL function tg_iface_biu() line 14 at RAISE
  --
  -- The following tests are unrelated to the scenario outlined above;
  -- they merely exercise specific parts of PL/pgSQL
*************** NOTICE:  should see this
*** 1963,1968 ****
--- 1971,1977 ----
  NOTICE:  should see this only if -100 <> 0
  NOTICE:  should see this only if -100 fits in smallint
  ERROR:  -100 is less than zero
+ CONTEXT:  PL/pgSQL function trap_zero_divide(integer) line 12 at RAISE
  create function trap_matching_test(int) returns int as $$
  declare x int;
  	sx smallint;
*************** begin
*** 2066,2079 ****
  end$$ language plpgsql;
  select test_variable_storage();
  NOTICE:  should see this
- CONTEXT:  SQL statement "SELECT trap_zero_divide(-100)"
- PL/pgSQL function test_variable_storage() line 8 at PERFORM
  NOTICE:  should see this only if -100 <> 0
- CONTEXT:  SQL statement "SELECT trap_zero_divide(-100)"
- PL/pgSQL function test_variable_storage() line 8 at PERFORM
  NOTICE:  should see this only if -100 fits in smallint
- CONTEXT:  SQL statement "SELECT trap_zero_divide(-100)"
- PL/pgSQL function test_variable_storage() line 8 at PERFORM
   test_variable_storage 
  -----------------------
   123456789012
--- 2075,2082 ----
*************** DETAIL:  some detail info
*** 4052,4057 ****
--- 4055,4061 ----
  HINT:  some hint
  ERROR:  1 2 3
  DETAIL:  some detail info
+ CONTEXT:  PL/pgSQL function raise_test() line 5 at RAISE
  -- Since we can't actually see the thrown SQLSTATE in default psql output,
  -- test it like this; this also tests re-RAISE
  create or replace function raise_test() returns void as $$
*************** select raise_test();
*** 4068,4073 ****
--- 4072,4078 ----
  NOTICE:  SQLSTATE: 22012 SQLERRM: check me
  ERROR:  check me
  DETAIL:  some detail info
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise 'check me'
*************** select raise_test();
*** 4082,4087 ****
--- 4087,4093 ----
  NOTICE:  SQLSTATE: 1234F SQLERRM: check me
  ERROR:  check me
  DETAIL:  some detail info
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  -- SQLSTATE specification in WHEN
  create or replace function raise_test() returns void as $$
  begin
*************** select raise_test();
*** 4097,4102 ****
--- 4103,4109 ----
  NOTICE:  SQLSTATE: 1234F SQLERRM: check me
  ERROR:  check me
  DETAIL:  some detail info
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise division_by_zero using detail = 'some detail info';
*************** select raise_test();
*** 4110,4115 ****
--- 4117,4123 ----
  NOTICE:  SQLSTATE: 22012 SQLERRM: division_by_zero
  ERROR:  division_by_zero
  DETAIL:  some detail info
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise division_by_zero;
*************** end;
*** 4117,4122 ****
--- 4125,4131 ----
  $$ language plpgsql;
  select raise_test();
  ERROR:  division_by_zero
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise sqlstate '1234F';
*************** end;
*** 4124,4129 ****
--- 4133,4139 ----
  $$ language plpgsql;
  select raise_test();
  ERROR:  1234F
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise division_by_zero using message = 'custom' || ' message';
*************** end;
*** 4131,4136 ****
--- 4141,4147 ----
  $$ language plpgsql;
  select raise_test();
  ERROR:  custom message
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise using message = 'custom' || ' message', errcode = '22012';
*************** end;
*** 4138,4143 ****
--- 4149,4155 ----
  $$ language plpgsql;
  select raise_test();
  ERROR:  custom message
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  -- conflict on message
  create or replace function raise_test() returns void as $$
  begin
*************** $$ language plpgsql;
*** 4254,4259 ****
--- 4266,4272 ----
  select raise_test();
  NOTICE:  22012
  ERROR:  substitute message
+ CONTEXT:  PL/pgSQL function raise_test() line 7 at RAISE
  drop function raise_test();
  -- test passing column_name, constraint_name, datatype_name, table_name
  -- and schema_name error fields
*************** LINE 1: SELECT 'foo\\bar\041baz'
*** 4744,4750 ****
                 ^
  HINT:  Use the escape string syntax for backslashes, e.g., E'\\'.
  QUERY:  SELECT 'foo\\bar\041baz'
- CONTEXT:  PL/pgSQL function strtest() line 4 at RETURN
     strtest   
  -------------
   foo\bar!baz
--- 4757,4762 ----
*************** $$ language plpgsql;
*** 5260,5281 ****
  select outer_outer_func(10);
  NOTICE:  calling down into outer_func()
  NOTICE:  calling down into inner_func()
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 4 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 7 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  lets make sure we didnt break anything
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  inner_func() done
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  outer_func() done
   outer_outer_func 
  ------------------
--- 5272,5285 ----
*************** NOTICE:  outer_func() done
*** 5286,5307 ****
  select outer_outer_func(20);
  NOTICE:  calling down into outer_func()
  NOTICE:  calling down into inner_func()
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 4 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 7 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  lets make sure we didnt break anything
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  inner_func() done
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  outer_func() done
   outer_outer_func 
  ------------------
--- 5290,5303 ----
*************** $$ language plpgsql;
*** 5358,5379 ****
  select outer_outer_func(10);
  NOTICE:  calling down into outer_func()
  NOTICE:  calling down into inner_func()
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 10 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 15 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  lets make sure we didnt break anything
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  inner_func() done
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  outer_func() done
   outer_outer_func 
  ------------------
--- 5354,5367 ----
*************** NOTICE:  outer_func() done
*** 5384,5405 ****
  select outer_outer_func(20);
  NOTICE:  calling down into outer_func()
  NOTICE:  calling down into inner_func()
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 10 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 15 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  lets make sure we didnt break anything
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  inner_func() done
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  outer_func() done
   outer_outer_func 
  ------------------
--- 5372,5385 ----
diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out
new file mode 100644
index c0cd9fa..88bdc2c
*** a/src/test/regress/expected/privileges.out
--- b/src/test/regress/expected/privileges.out
*************** GRANT regressgroup2 TO regressuser5; --
*** 1023,1029 ****
  ERROR:  must have admin option on role "regressgroup2"
  SELECT dogrant_ok();			-- ok: SECURITY DEFINER conveys ADMIN
  NOTICE:  role "regressuser5" is already a member of role "regressgroup2"
- CONTEXT:  SQL function "dogrant_ok" statement 1
   dogrant_ok 
  ------------
   
--- 1023,1028 ----
diff --git a/src/test/regress/expected/rangefuncs.out b/src/test/regress/expected/rangefuncs.out
new file mode 100644
index 6dabe50..00ef421
*** a/src/test/regress/expected/rangefuncs.out
--- b/src/test/regress/expected/rangefuncs.out
*************** create trigger tnoticetrigger after inse
*** 1704,1712 ****
  execute procedure noticetrigger();
  select insert_tt2('foolme','barme') limit 1;
  NOTICE:  noticetrigger 11 foolme
- CONTEXT:  SQL function "insert_tt2" statement 1
  NOTICE:  noticetrigger 12 barme
- CONTEXT:  SQL function "insert_tt2" statement 1
   insert_tt2 
  ------------
           11
--- 1704,1710 ----
*************** create rule insert_tt_rule as on insert
*** 1735,1743 ****
    insert into tt_log values(new.*);
  select insert_tt2('foollog','barlog') limit 1;
  NOTICE:  noticetrigger 13 foollog
- CONTEXT:  SQL function "insert_tt2" statement 1
  NOTICE:  noticetrigger 14 barlog
- CONTEXT:  SQL function "insert_tt2" statement 1
   insert_tt2 
  ------------
           13
--- 1733,1739 ----
diff --git a/src/test/regress/expected/triggers.out b/src/test/regress/expected/triggers.out
new file mode 100644
index 3b32e8f..cd43e46
*** a/src/test/regress/expected/triggers.out
--- b/src/test/regress/expected/triggers.out
*************** NOTICE:  main_view BEFORE INSERT STATEME
*** 958,968 ****
  NOTICE:  main_view INSTEAD OF INSERT ROW (instead_of_ins)
  NOTICE:  NEW: (20,30)
  NOTICE:  trigger_func(before_ins_stmt) called: action = INSERT, when = BEFORE, level = STATEMENT
- CONTEXT:  SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
- PL/pgSQL function view_trigger() line 17 at SQL statement
  NOTICE:  trigger_func(after_ins_stmt) called: action = INSERT, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
- PL/pgSQL function view_trigger() line 17 at SQL statement
  NOTICE:  main_view AFTER INSERT STATEMENT (after_view_ins_stmt)
  INSERT 0 1
  INSERT INTO main_view VALUES (21, 31) RETURNING a, b;
--- 958,964 ----
*************** NOTICE:  main_view BEFORE INSERT STATEME
*** 970,980 ****
  NOTICE:  main_view INSTEAD OF INSERT ROW (instead_of_ins)
  NOTICE:  NEW: (21,31)
  NOTICE:  trigger_func(before_ins_stmt) called: action = INSERT, when = BEFORE, level = STATEMENT
- CONTEXT:  SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
- PL/pgSQL function view_trigger() line 17 at SQL statement
  NOTICE:  trigger_func(after_ins_stmt) called: action = INSERT, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
- PL/pgSQL function view_trigger() line 17 at SQL statement
  NOTICE:  main_view AFTER INSERT STATEMENT (after_view_ins_stmt)
   a  | b  
  ----+----
--- 966,972 ----
*************** NOTICE:  main_view BEFORE UPDATE STATEME
*** 988,1004 ****
  NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
  NOTICE:  OLD: (20,30), NEW: (20,31)
  NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
  UPDATE 0
  UPDATE main_view SET b = 32 WHERE a = 21 AND b = 31 RETURNING a, b;
--- 980,988 ----
*************** NOTICE:  main_view BEFORE UPDATE STATEME
*** 1006,1022 ****
  NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
  NOTICE:  OLD: (21,31), NEW: (21,32)
  NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
   a | b 
  ---+---
--- 990,998 ----
*************** NOTICE:  main_view BEFORE UPDATE STATEME
*** 1031,1050 ****
  NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
  NOTICE:  OLD: (20,30), NEW: (20,31)
  NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
  UPDATE 1
  UPDATE main_view SET b = 32 WHERE a = 21 AND b = 31 RETURNING a, b;
--- 1007,1016 ----
*************** NOTICE:  main_view BEFORE UPDATE STATEME
*** 1052,1071 ****
  NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
  NOTICE:  OLD: (21,31), NEW: (21,32)
  NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
   a  | b  
  ----+----
--- 1018,1027 ----
*************** INSERT 0 1
*** 1277,1282 ****
--- 1233,1239 ----
  -- UPDATE .. RETURNING
  UPDATE city_view SET country_name = 'Japon' WHERE city_name = 'Tokyo'; -- error
  ERROR:  No such country: "Japon"
+ CONTEXT:  PL/pgSQL function city_update() line 9 at RAISE
  UPDATE city_view SET country_name = 'Japan' WHERE city_name = 'Takyo'; -- no match
  UPDATE 0
  UPDATE city_view SET country_name = 'Japan' WHERE city_name = 'Tokyo' RETURNING *; -- OK
*************** select pg_trigger_depth();
*** 1489,1514 ****
  insert into depth_a values (1);
  NOTICE:  depth_a_tr: depth = 1
  NOTICE:  depth_b_tr: depth = 2
- CONTEXT:  SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_c_tr: depth = 3
- CONTEXT:  SQL statement "insert into depth_c values (1)"
- PL/pgSQL function depth_b_tf() line 5 at EXECUTE statement
- SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  SQLSTATE = U9999: depth = 2
- CONTEXT:  SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_b_tr: depth = 2
- CONTEXT:  SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_c_tr: depth = 3
- CONTEXT:  SQL statement "insert into depth_c values (1)"
- PL/pgSQL function depth_b_tf() line 12 at EXECUTE statement
- SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  ERROR:  U9999
! CONTEXT:  SQL statement "insert into depth_c values (1)"
  PL/pgSQL function depth_b_tf() line 12 at EXECUTE statement
  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
--- 1446,1458 ----
  insert into depth_a values (1);
  NOTICE:  depth_a_tr: depth = 1
  NOTICE:  depth_b_tr: depth = 2
  NOTICE:  depth_c_tr: depth = 3
  NOTICE:  SQLSTATE = U9999: depth = 2
  NOTICE:  depth_b_tr: depth = 2
  NOTICE:  depth_c_tr: depth = 3
  ERROR:  U9999
! CONTEXT:  PL/pgSQL function depth_c_tf() line 5 at RAISE
! SQL statement "insert into depth_c values (1)"
  PL/pgSQL function depth_b_tf() line 12 at EXECUTE statement
  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
*************** select pg_trigger_depth();
*** 1521,1541 ****
  insert into depth_a values (2);
  NOTICE:  depth_a_tr: depth = 1
  NOTICE:  depth_b_tr: depth = 2
- CONTEXT:  SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_c_tr: depth = 3
- CONTEXT:  SQL statement "insert into depth_c values (2)"
- PL/pgSQL function depth_b_tf() line 5 at EXECUTE statement
- SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_c_tr: depth = 3
- CONTEXT:  SQL statement "insert into depth_c values (2)"
- PL/pgSQL function depth_b_tf() line 5 at EXECUTE statement
- SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_b_tr: depth = 2
- CONTEXT:  SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_a_tr: depth = 1
  select pg_trigger_depth();
   pg_trigger_depth 
--- 1465,1473 ----
diff --git a/src/test/regress/expected/xml.out b/src/test/regress/expected/xml.out
new file mode 100644
index 9b2d264..5691e47
*** a/src/test/regress/expected/xml.out
--- b/src/test/regress/expected/xml.out
*************** SELECT xpath('/*', '<relativens xmlns=''
*** 934,940 ****
  WARNING:  line 1: xmlns: URI relative is not absolute
  <relativens xmlns='relative'/>
                              ^
- CONTEXT:  SQL function "xpath" statement 1
                  xpath                 
  --------------------------------------
   {"<relativens xmlns=\"relative\"/>"}
--- 934,939 ----
#85Pavel Stehule
pavel.stehule@gmail.com
In reply to: Merlin Moncure (#84)
1 attachment(s)
Re: PL/pgSQL, RAISE and error context

2015-07-09 20:08 GMT+02:00 Merlin Moncure <mmoncure@gmail.com>:

On Thu, Jul 9, 2015 at 10:48 AM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

2015-07-09 15:17 GMT+02:00 Merlin Moncure <mmoncure@gmail.com>:

On Wed, Jul 8, 2015 at 11:28 PM, Pavel Stehule <pavel.stehule@gmail.com

wrote:

Hi

second version of this patch

make check-world passed

quickly scanning the patch, the implementation is trivial (minus
regression test adjustments), and is, IMSNSHO, the right solution.

yes, it is right way - the behave of RAISE statement will be much more
cleaner

Several of the source level comments need some minor wordsmithing and
the GUCs are missing documentation. If we've got consensus on the
approach, I'll pitch in on that.

thank you

revised patch attached. added GUC docs and cleaned up pg_settings
language. Also tested patch and it works beautifully.

Note, Pavel's patch does adjust default behavior to what we think is
the "right" settings.

Thank you for documentation.

There is small error - default for client_min_context is error - not
notice. With this level a diff from regress tests is minimal. Default for
log_min_context should be warning.

Regards

Pavel

Show quoted text

merlin

Attachments:

min_context-20150709-02-2.patchtext/x-patch; charset=US-ASCII; name=min_context-20150709-02-2.patchDownload
diff --git a/contrib/dblink/expected/dblink.out b/contrib/dblink/expected/dblink.out
new file mode 100644
index a49b562..a268fc7
*** a/contrib/dblink/expected/dblink.out
--- b/contrib/dblink/expected/dblink.out
***************
*** 1,3 ****
--- 1,4 ----
+ set client_min_context TO notice;
  CREATE EXTENSION dblink;
  CREATE TABLE foo(f1 int, f2 text, f3 text[], primary key (f1,f2));
  INSERT INTO foo VALUES (0,'a','{"a0","b0","c0"}');
diff --git a/contrib/dblink/sql/dblink.sql b/contrib/dblink/sql/dblink.sql
new file mode 100644
index ea78cc2..cf7e57e
*** a/contrib/dblink/sql/dblink.sql
--- b/contrib/dblink/sql/dblink.sql
***************
*** 1,3 ****
--- 1,5 ----
+ set client_min_context TO notice;
+ 
  CREATE EXTENSION dblink;
  
  CREATE TABLE foo(f1 int, f2 text, f3 text[], primary key (f1,f2));
diff --git a/contrib/hstore_plperl/expected/hstore_plperlu.out b/contrib/hstore_plperl/expected/hstore_plperlu.out
new file mode 100644
index 8c689ad..c97fd3f
*** a/contrib/hstore_plperl/expected/hstore_plperlu.out
--- b/contrib/hstore_plperl/expected/hstore_plperlu.out
*************** INFO:  $VAR1 = {
*** 29,35 ****
            'cc' => undef
          };
  
- CONTEXT:  PL/Perl function "test1"
   test1 
  -------
       2
--- 29,34 ----
*************** $$;
*** 46,52 ****
  SELECT test1none('aa=>bb, cc=>NULL'::hstore);
  INFO:  $VAR1 = '"aa"=>"bb", "cc"=>NULL';
  
- CONTEXT:  PL/Perl function "test1none"
   test1none 
  -----------
           0
--- 45,50 ----
*************** INFO:  $VAR1 = {
*** 67,73 ****
            'cc' => undef
          };
  
- CONTEXT:  PL/Perl function "test1list"
   test1list 
  -----------
           2
--- 65,70 ----
*************** $VAR2 = {
*** 92,98 ****
            'dd' => 'ee'
          };
  
- CONTEXT:  PL/Perl function "test1arr"
   test1arr 
  ----------
          2
--- 89,94 ----
*************** INFO:  $VAR1 = {
*** 120,129 ****
            'cc' => undef
          };
  
- CONTEXT:  PL/Perl function "test3"
  INFO:  $VAR1 = '"a"=>"1", "b"=>"boo", "c"=>NULL';
  
- CONTEXT:  PL/Perl function "test3"
   test3 
  -------
   
--- 116,123 ----
*************** INFO:  $VAR1 = {
*** 161,167 ****
                 }
          };
  
- CONTEXT:  PL/Perl function "test4"
  SELECT * FROM test1;
   a |                b                
  ---+---------------------------------
--- 155,160 ----
diff --git a/contrib/hstore_plpython/expected/hstore_plpython.out b/contrib/hstore_plpython/expected/hstore_plpython.out
new file mode 100644
index b7a6a92..23091d3
*** a/contrib/hstore_plpython/expected/hstore_plpython.out
--- b/contrib/hstore_plpython/expected/hstore_plpython.out
*************** return len(val)
*** 13,19 ****
  $$;
  SELECT test1('aa=>bb, cc=>NULL'::hstore);
  INFO:  [('aa', 'bb'), ('cc', None)]
- CONTEXT:  PL/Python function "test1"
   test1 
  -------
       2
--- 13,18 ----
*************** return len(val)
*** 32,38 ****
  $$;
  SELECT test1n('aa=>bb, cc=>NULL'::hstore);
  INFO:  [('aa', 'bb'), ('cc', None)]
- CONTEXT:  PL/Python function "test1n"
   test1n 
  --------
        2
--- 31,36 ----
diff --git a/contrib/ltree_plpython/expected/ltree_plpython.out b/contrib/ltree_plpython/expected/ltree_plpython.out
new file mode 100644
index 934529e..c6e8a7c
*** a/contrib/ltree_plpython/expected/ltree_plpython.out
--- b/contrib/ltree_plpython/expected/ltree_plpython.out
*************** return len(val)
*** 9,15 ****
  $$;
  SELECT test1('aa.bb.cc'::ltree);
  INFO:  ['aa', 'bb', 'cc']
- CONTEXT:  PL/Python function "test1"
   test1 
  -------
       3
--- 9,14 ----
*************** return len(val)
*** 24,30 ****
  $$;
  SELECT test1n('aa.bb.cc'::ltree);
  INFO:  ['aa', 'bb', 'cc']
- CONTEXT:  PL/Python function "test1n"
   test1n 
  --------
        3
--- 23,28 ----
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
new file mode 100644
index b91d6c7..6365d4a
*** a/doc/src/sgml/config.sgml
--- b/doc/src/sgml/config.sgml
*************** local0.*    /var/log/postgresql
*** 4144,4149 ****
--- 4144,4171 ----
  
       <variablelist>
  
+      <varlistentry id="guc-client-min-context" xreflabel="client_min_context">
+       <term><varname>client_min_context</varname> (<type>enum</type>)
+       <indexterm>
+        <primary><varname>client_min_context</> configuration parameter</primary>
+       </indexterm>
+       </term>
+       <listitem>
+        <para>
+         Controls which message levels include context when sent to the client.
+         Valid values are <literal>DEBUG5</>,
+         <literal>DEBUG4</>, <literal>DEBUG3</>, <literal>DEBUG2</>,
+         <literal>DEBUG1</>, <literal>LOG</>, <literal>NOTICE</>,
+         <literal>WARNING</>, <literal>ERROR</>, <literal>FATAL</>,
+         and <literal>PANIC</>.  Each level
+         includes all the levels that follow it.  The later the level,
+         the fewer messages are sent.  The default is
+         <literal>ERROR</>.  Note that <literal>LOG</> has a different
+         rank here than in <varname>log_min_messages</>.
+        </para>
+       </listitem>
+      </varlistentry>
+ 
       <varlistentry id="guc-client-min-messages" xreflabel="client_min_messages">
        <term><varname>client_min_messages</varname> (<type>enum</type>)
        <indexterm>
*************** local0.*    /var/log/postgresql
*** 4165,4170 ****
--- 4187,4216 ----
         </para>
        </listitem>
       </varlistentry>
+ 
+      <varlistentry id="guc-log-min-context" xreflabel="log_min_context">
+       <term><varname>log_min_context</varname> (<type>enum</type>)
+       <indexterm>
+        <primary><varname>log_min_context</> configuration parameter</primary>
+       </indexterm>
+       </term>
+       <listitem>
+        <para>
+         Controls which message levels include context when written to 
+         the server log.
+         Valid values are <literal>DEBUG5</>, <literal>DEBUG4</>,
+         <literal>DEBUG3</>, <literal>DEBUG2</>, <literal>DEBUG1</>,
+         <literal>INFO</>, <literal>NOTICE</>, <literal>WARNING</>,
+         <literal>ERROR</>, <literal>LOG</>, <literal>FATAL</>, and
+         <literal>PANIC</>.  Each level includes all the levels that
+         follow it.  The later the level, the fewer messages are sent
+         to the log.  The default is <literal>WARNING</>.  Note that
+         <literal>LOG</> has a different rank here than in
+         <varname>client_min_messages</>.
+         Only superusers can change this setting.
+        </para>
+       </listitem>
+      </varlistentry>
  
       <varlistentry id="guc-log-min-messages" xreflabel="log_min_messages">
        <term><varname>log_min_messages</varname> (<type>enum</type>)
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
new file mode 100644
index 088c714..9445230
*** a/src/backend/utils/error/elog.c
--- b/src/backend/utils/error/elog.c
*************** write_csvlog(ErrorData *edata)
*** 2730,2736 ****
  	appendStringInfoChar(&buf, ',');
  
  	/* errcontext */
! 	if (!edata->hide_ctx)
  		appendCSVLiteral(&buf, edata->context);
  	appendStringInfoChar(&buf, ',');
  
--- 2730,2736 ----
  	appendStringInfoChar(&buf, ',');
  
  	/* errcontext */
! 	if (!edata->hide_ctx && edata->elevel >= log_min_context)
  		appendCSVLiteral(&buf, edata->context);
  	appendStringInfoChar(&buf, ',');
  
*************** send_message_to_server_log(ErrorData *ed
*** 2863,2869 ****
  			append_with_tabs(&buf, edata->internalquery);
  			appendStringInfoChar(&buf, '\n');
  		}
! 		if (edata->context && !edata->hide_ctx)
  		{
  			log_line_prefix(&buf, edata);
  			appendStringInfoString(&buf, _("CONTEXT:  "));
--- 2863,2869 ----
  			append_with_tabs(&buf, edata->internalquery);
  			appendStringInfoChar(&buf, '\n');
  		}
! 		if (edata->context && !edata->hide_ctx && edata->elevel >= log_min_context)
  		{
  			log_line_prefix(&buf, edata);
  			appendStringInfoString(&buf, _("CONTEXT:  "));
*************** send_message_to_frontend(ErrorData *edat
*** 3137,3143 ****
  			err_sendstring(&msgbuf, edata->hint);
  		}
  
! 		if (edata->context)
  		{
  			pq_sendbyte(&msgbuf, PG_DIAG_CONTEXT);
  			err_sendstring(&msgbuf, edata->context);
--- 3137,3143 ----
  			err_sendstring(&msgbuf, edata->hint);
  		}
  
! 		if (edata->context && edata->elevel >= client_min_context)
  		{
  			pq_sendbyte(&msgbuf, PG_DIAG_CONTEXT);
  			err_sendstring(&msgbuf, edata->context);
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
new file mode 100644
index 1bed525..cae8094
*** a/src/backend/utils/misc/guc.c
--- b/src/backend/utils/misc/guc.c
*************** bool		Password_encryption = true;
*** 430,435 ****
--- 430,437 ----
  int			log_min_error_statement = ERROR;
  int			log_min_messages = WARNING;
  int			client_min_messages = NOTICE;
+ int			log_min_context = WARNING;
+ int			client_min_context = ERROR;
  int			log_min_duration_statement = -1;
  int			log_temp_files = -1;
  int			trace_recovery_messages = LOG;
*************** static struct config_enum ConfigureNames
*** 3426,3431 ****
--- 3428,3444 ----
  	},
  
  	{
+ 		{"client_min_context", PGC_USERSET, LOGGING_WHEN,
+ 			gettext_noop("Sets the message levels for which context is sent to the client."),
+ 			gettext_noop("Each level includes all the levels that follow it. The later"
+ 						 " the level, the less context is sent.")
+ 		},
+ 		&client_min_context,
+ 		ERROR, client_message_level_options,
+ 		NULL, NULL, NULL
+ 	},
+ 
+ 	{
  		{"client_min_messages", PGC_USERSET, LOGGING_WHEN,
  			gettext_noop("Sets the message levels that are sent to the client."),
  			gettext_noop("Each level includes all the levels that follow it. The later"
*************** static struct config_enum ConfigureNames
*** 3478,3483 ****
--- 3491,3507 ----
  		NULL, NULL, NULL
  	},
  
+ 	{
+ 		{"log_min_context", PGC_SUSET, LOGGING_WHEN,
+ 			gettext_noop("Sets the message levels for which context is logged."),
+ 			gettext_noop("Each level includes all the levels that follow it. The later"
+ 						 " the level, the less context is sent.")
+ 		},
+ 		&log_min_context,
+ 		WARNING, server_message_level_options,
+ 		NULL, NULL, NULL
+ 	},
+ 
  	{
  		{"log_min_messages", PGC_SUSET, LOGGING_WHEN,
  			gettext_noop("Sets the message levels that are logged."),
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
new file mode 100644
index 06dfc06..8695e8b
*** a/src/backend/utils/misc/postgresql.conf.sample
--- b/src/backend/utils/misc/postgresql.conf.sample
***************
*** 360,365 ****
--- 360,390 ----
  
  # - When to Log -
  
+ #client_min_context = error		# values in order of decreasing detail:
+ 					#   debug5
+ 					#   debug4
+ 					#   debug3
+ 					#   debug2
+ 					#   debug1
+ 					#   log
+ 					#   notice
+ 					#   warning
+ 					#   error
+ 
+ #log_min_context = warning		# values in order of decreasing detail:
+ 					#   debug5
+ 					#   debug4
+ 					#   debug3
+ 					#   debug2
+ 					#   debug1
+ 					#   info
+ 					#   notice
+ 					#   warning
+ 					#   error
+ 					#   log
+ 					#   fatal
+ 					#   panic
+ 
  #client_min_messages = notice		# values in order of decreasing detail:
  					#   debug5
  					#   debug4
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
new file mode 100644
index dc167f9..f03a5e1
*** a/src/include/utils/guc.h
--- b/src/include/utils/guc.h
*************** extern PGDLLIMPORT bool check_function_b
*** 246,251 ****
--- 246,253 ----
  extern bool default_with_oids;
  extern bool SQL_inheritance;
  
+ extern int	log_min_context;
+ extern int	client_min_context;
  extern int	log_min_error_statement;
  extern int	log_min_messages;
  extern int	client_min_messages;
diff --git a/src/pl/plperl/expected/plperl.out b/src/pl/plperl/expected/plperl.out
new file mode 100644
index d23a302..14df5f4
*** a/src/pl/plperl/expected/plperl.out
--- b/src/pl/plperl/expected/plperl.out
*************** DO $$
*** 614,620 ****
    elog(NOTICE, $a);
  $$ LANGUAGE plperl;
  NOTICE:  This is a test
- CONTEXT:  PL/Perl anonymous code block
  -- check that restricted operations are rejected in a plperl DO block
  DO $$ system("/nonesuch"); $$ LANGUAGE plperl;
  ERROR:  'system' trapped by operation mask at line 1.
--- 614,619 ----
*************** CONTEXT:  PL/Perl anonymous code block
*** 628,634 ****
  -- check that eval is allowed and eval'd restricted ops are caught
  DO $$ eval q{chdir '.';}; warn "Caught: $@"; $$ LANGUAGE plperl;
  WARNING:  Caught: 'chdir' trapped by operation mask at line 1.
- CONTEXT:  PL/Perl anonymous code block
  -- check that compiling do (dofile opcode) is allowed
  -- but that executing it for a file not already loaded (via require) dies
  DO $$ warn do "/dev/null"; $$ LANGUAGE plperl;
--- 627,632 ----
diff --git a/src/pl/plperl/expected/plperl_elog.out b/src/pl/plperl/expected/plperl_elog.out
new file mode 100644
index c447fa2..3f9449a
*** a/src/pl/plperl/expected/plperl_elog.out
--- b/src/pl/plperl/expected/plperl_elog.out
*************** create or replace function perl_elog(tex
*** 7,13 ****
  $$;
  select perl_elog('explicit elog');
  NOTICE:  explicit elog
- CONTEXT:  PL/Perl function "perl_elog"
   perl_elog 
  -----------
   
--- 7,12 ----
*************** create or replace function perl_warn(tex
*** 21,27 ****
  $$;
  select perl_warn('implicit elog via warn');
  WARNING:  implicit elog via warn at line 4.
- CONTEXT:  PL/Perl function "perl_warn"
   perl_warn 
  -----------
   
--- 20,25 ----
*************** select uses_global();
*** 61,67 ****
  -- make sure we don't choke on readonly values
  do language plperl $$ elog(NOTICE, ${^TAINT}); $$;
  NOTICE:  0
- CONTEXT:  PL/Perl anonymous code block
  -- test recovery after "die"
  create or replace function just_die() returns void language plperl AS $$
  die "just die";
--- 59,64 ----
*************** return $a + $b;
*** 94,104 ****
  $$;
  select indirect_die_caller();
  NOTICE:  caught die
- CONTEXT:  SQL statement "SELECT die_caller() AS fx"
- PL/Perl function "indirect_die_caller"
  NOTICE:  caught die
- CONTEXT:  SQL statement "SELECT die_caller() AS fx"
- PL/Perl function "indirect_die_caller"
   indirect_die_caller 
  ---------------------
                     2
--- 91,97 ----
diff --git a/src/pl/plperl/expected/plperl_trigger.out b/src/pl/plperl/expected/plperl_trigger.out
new file mode 100644
index 36ecb92..5e3860e
*** a/src/pl/plperl/expected/plperl_trigger.out
--- b/src/pl/plperl/expected/plperl_trigger.out
*************** BEFORE INSERT OR UPDATE OR DELETE ON tri
*** 62,136 ****
  FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
  insert into trigger_test values(1,'insert', '("(1)")');
  NOTICE:  $_TD->{argc} = '2'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{args} = ['23', 'skidoo']
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{event} = 'INSERT'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{level} = 'ROW'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{name} = 'show_trigger_data_trig'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{new} = {'foo' => {'rfoo' => {'i' => '1'}}, 'i' => '1', 'v' => 'insert'}
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{relid} = 'bogus:12345'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{relname} = 'trigger_test'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{table_name} = 'trigger_test'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{table_schema} = 'public'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{when} = 'BEFORE'
- CONTEXT:  PL/Perl function "trigger_data"
  update trigger_test set v = 'update' where i = 1;
  NOTICE:  $_TD->{argc} = '2'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{args} = ['23', 'skidoo']
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{event} = 'UPDATE'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{level} = 'ROW'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{name} = 'show_trigger_data_trig'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{new} = {'foo' => {'rfoo' => {'i' => '1'}}, 'i' => '1', 'v' => 'update'}
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{old} = {'foo' => {'rfoo' => {'i' => '1'}}, 'i' => '1', 'v' => 'insert'}
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{relid} = 'bogus:12345'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{relname} = 'trigger_test'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{table_name} = 'trigger_test'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{table_schema} = 'public'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{when} = 'BEFORE'
- CONTEXT:  PL/Perl function "trigger_data"
  delete from trigger_test;
  NOTICE:  $_TD->{argc} = '2'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{args} = ['23', 'skidoo']
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{event} = 'DELETE'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{level} = 'ROW'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{name} = 'show_trigger_data_trig'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{old} = {'foo' => {'rfoo' => {'i' => '1'}}, 'i' => '1', 'v' => 'update'}
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{relid} = 'bogus:12345'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{relname} = 'trigger_test'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{table_name} = 'trigger_test'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{table_schema} = 'public'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{when} = 'BEFORE'
- CONTEXT:  PL/Perl function "trigger_data"
  DROP TRIGGER show_trigger_data_trig on trigger_test;
  insert into trigger_test values(1,'insert', '("(1)")');
  CREATE VIEW trigger_test_view AS SELECT * FROM trigger_test;
--- 62,102 ----
*************** INSTEAD OF INSERT OR UPDATE OR DELETE ON
*** 139,213 ****
  FOR EACH ROW EXECUTE PROCEDURE trigger_data(24,'skidoo view');
  insert into trigger_test_view values(2,'insert', '("(2)")');
  NOTICE:  $_TD->{argc} = '2'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{args} = ['24', 'skidoo view']
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{event} = 'INSERT'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{level} = 'ROW'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{name} = 'show_trigger_data_trig'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{new} = {'foo' => {'rfoo' => {'i' => '2'}}, 'i' => '2', 'v' => 'insert'}
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{relid} = 'bogus:12345'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{relname} = 'trigger_test_view'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{table_name} = 'trigger_test_view'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{table_schema} = 'public'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{when} = 'INSTEAD OF'
- CONTEXT:  PL/Perl function "trigger_data"
  update trigger_test_view set v = 'update', foo = '("(3)")' where i = 1;
  NOTICE:  $_TD->{argc} = '2'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{args} = ['24', 'skidoo view']
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{event} = 'UPDATE'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{level} = 'ROW'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{name} = 'show_trigger_data_trig'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{new} = {'foo' => {'rfoo' => {'i' => '3'}}, 'i' => '1', 'v' => 'update'}
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{old} = {'foo' => {'rfoo' => {'i' => '1'}}, 'i' => '1', 'v' => 'insert'}
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{relid} = 'bogus:12345'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{relname} = 'trigger_test_view'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{table_name} = 'trigger_test_view'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{table_schema} = 'public'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{when} = 'INSTEAD OF'
- CONTEXT:  PL/Perl function "trigger_data"
  delete from trigger_test_view;
  NOTICE:  $_TD->{argc} = '2'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{args} = ['24', 'skidoo view']
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{event} = 'DELETE'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{level} = 'ROW'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{name} = 'show_trigger_data_trig'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{old} = {'foo' => {'rfoo' => {'i' => '1'}}, 'i' => '1', 'v' => 'insert'}
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{relid} = 'bogus:12345'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{relname} = 'trigger_test_view'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{table_name} = 'trigger_test_view'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{table_schema} = 'public'
- CONTEXT:  PL/Perl function "trigger_data"
  NOTICE:  $_TD->{when} = 'INSTEAD OF'
- CONTEXT:  PL/Perl function "trigger_data"
  DROP VIEW trigger_test_view;
  delete from trigger_test;
  DROP FUNCTION trigger_data();
--- 105,145 ----
*************** create event trigger perl_b_snitch on dd
*** 319,346 ****
     execute procedure perlsnitch();
  create or replace function foobar() returns int language sql as $$select 1;$$;
  NOTICE:  perlsnitch: ddl_command_start CREATE FUNCTION 
- CONTEXT:  PL/Perl function "perlsnitch"
  NOTICE:  perlsnitch: ddl_command_end CREATE FUNCTION 
- CONTEXT:  PL/Perl function "perlsnitch"
  alter function foobar() cost 77;
  NOTICE:  perlsnitch: ddl_command_start ALTER FUNCTION 
- CONTEXT:  PL/Perl function "perlsnitch"
  NOTICE:  perlsnitch: ddl_command_end ALTER FUNCTION 
- CONTEXT:  PL/Perl function "perlsnitch"
  drop function foobar();
  NOTICE:  perlsnitch: ddl_command_start DROP FUNCTION 
- CONTEXT:  PL/Perl function "perlsnitch"
  NOTICE:  perlsnitch: ddl_command_end DROP FUNCTION 
- CONTEXT:  PL/Perl function "perlsnitch"
  create table foo();
  NOTICE:  perlsnitch: ddl_command_start CREATE TABLE 
- CONTEXT:  PL/Perl function "perlsnitch"
  NOTICE:  perlsnitch: ddl_command_end CREATE TABLE 
- CONTEXT:  PL/Perl function "perlsnitch"
  drop table foo;
  NOTICE:  perlsnitch: ddl_command_start DROP TABLE 
- CONTEXT:  PL/Perl function "perlsnitch"
  NOTICE:  perlsnitch: ddl_command_end DROP TABLE 
- CONTEXT:  PL/Perl function "perlsnitch"
  drop event trigger perl_a_snitch;
  drop event trigger perl_b_snitch;
--- 251,268 ----
diff --git a/src/pl/plperl/expected/plperlu.out b/src/pl/plperl/expected/plperlu.out
new file mode 100644
index 3daf4ce..a3edb38
*** a/src/pl/plperl/expected/plperlu.out
--- b/src/pl/plperl/expected/plperlu.out
*************** LOAD 'plperl';
*** 6,12 ****
  SET plperl.on_plperlu_init = '$_SHARED{init} = 42';
  DO $$ warn $_SHARED{init} $$ language plperlu;
  WARNING:  42 at line 1.
- CONTEXT:  PL/Perl anonymous code block
  --
  -- Test compilation of unicode regex - regardless of locale.
  -- This code fails in plain plperl in a non-UTF8 database.
--- 6,11 ----
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
new file mode 100644
index 7d4001c..e1a6b7d
*** a/src/pl/plpgsql/src/pl_exec.c
--- b/src/pl/plpgsql/src/pl_exec.c
***************
*** 42,49 ****
  #include "utils/typcache.h"
  
  
- static const char *const raise_skip_msg = "RAISE";
- 
  typedef struct
  {
  	int			nargs;			/* number of arguments */
--- 42,47 ----
*************** plpgsql_exec_error_callback(void *arg)
*** 939,948 ****
  {
  	PLpgSQL_execstate *estate = (PLpgSQL_execstate *) arg;
  
- 	/* if we are doing RAISE, don't report its location */
- 	if (estate->err_text == raise_skip_msg)
- 		return;
- 
  	if (estate->err_text != NULL)
  	{
  		/*
--- 937,942 ----
*************** exec_stmt_raise(PLpgSQL_execstate *estat
*** 3158,3165 ****
  	/*
  	 * Throw the error (may or may not come back)
  	 */
- 	estate->err_text = raise_skip_msg;	/* suppress traceback of raise */
- 
  	ereport(stmt->elog_level,
  			(err_code ? errcode(err_code) : 0,
  			 errmsg_internal("%s", err_message),
--- 3152,3157 ----
diff --git a/src/pl/plpython/expected/plpython_do.out b/src/pl/plpython/expected/plpython_do.out
new file mode 100644
index 0977812..e300530
*** a/src/pl/plpython/expected/plpython_do.out
--- b/src/pl/plpython/expected/plpython_do.out
***************
*** 1,9 ****
  DO $$ plpy.notice("This is plpythonu.") $$ LANGUAGE plpythonu;
  NOTICE:  This is plpythonu.
- CONTEXT:  PL/Python anonymous code block
  DO $$ plpy.notice("This is plpython2u.") $$ LANGUAGE plpython2u;
  NOTICE:  This is plpython2u.
- CONTEXT:  PL/Python anonymous code block
  DO $$ raise Exception("error test") $$ LANGUAGE plpythonu;
  ERROR:  Exception: error test
  CONTEXT:  Traceback (most recent call last):
--- 1,7 ----
diff --git a/src/pl/plpython/expected/plpython_error.out b/src/pl/plpython/expected/plpython_error.out
new file mode 100644
index be2ec97..1f52af7
*** a/src/pl/plpython/expected/plpython_error.out
--- b/src/pl/plpython/expected/plpython_error.out
*************** return None
*** 108,114 ****
  	LANGUAGE plpythonu;
  SELECT invalid_type_caught('rick');
  NOTICE:  type "test" does not exist
- CONTEXT:  PL/Python function "invalid_type_caught"
   invalid_type_caught 
  ---------------------
   
--- 108,113 ----
*************** return "you''ve been warned"
*** 232,238 ****
  	LANGUAGE plpythonu;
  SELECT nested_warning();
  WARNING:  boom
- CONTEXT:  PL/Python function "nested_warning"
     nested_warning   
  --------------------
   you've been warned
--- 231,236 ----
*************** SELECT specific_exception(2);
*** 336,342 ****
  
  SELECT specific_exception(NULL);
  NOTICE:  Violated the NOT NULL constraint, sqlstate 23502
- CONTEXT:  PL/Python function "specific_exception"
   specific_exception 
  --------------------
   
--- 334,339 ----
*************** CONTEXT:  PL/Python function "specific_e
*** 344,350 ****
  
  SELECT specific_exception(2);
  NOTICE:  Violated the UNIQUE constraint, sqlstate 23505
- CONTEXT:  PL/Python function "specific_exception"
   specific_exception 
  --------------------
   
--- 341,346 ----
diff --git a/src/pl/plpython/expected/plpython_spi.out b/src/pl/plpython/expected/plpython_spi.out
new file mode 100644
index e2861df..e715ee5
*** a/src/pl/plpython/expected/plpython_spi.out
--- b/src/pl/plpython/expected/plpython_spi.out
*************** else:
*** 130,142 ****
  $$ LANGUAGE plpythonu;
  SELECT result_metadata_test($$SELECT 1 AS foo, '11'::text AS bar UNION SELECT 2, '22'$$);
  INFO:  True
- CONTEXT:  PL/Python function "result_metadata_test"
  INFO:  ['foo', 'bar']
- CONTEXT:  PL/Python function "result_metadata_test"
  INFO:  [23, 25]
- CONTEXT:  PL/Python function "result_metadata_test"
  INFO:  [-1, -1]
- CONTEXT:  PL/Python function "result_metadata_test"
   result_metadata_test 
  ----------------------
                      2
--- 130,138 ----
*************** CONTEXT:  PL/Python function "result_met
*** 144,150 ****
  
  SELECT result_metadata_test($$CREATE TEMPORARY TABLE foo1 (a int, b text)$$);
  INFO:  True
- CONTEXT:  PL/Python function "result_metadata_test"
  ERROR:  plpy.Error: command did not produce a result set
  CONTEXT:  Traceback (most recent call last):
    PL/Python function "result_metadata_test", line 6, in <module>
--- 140,145 ----
*************** else:
*** 234,248 ****
  $$ LANGUAGE plpythonu;
  SELECT result_subscript_test();
  INFO:  2
- CONTEXT:  PL/Python function "result_subscript_test"
  INFO:  4
- CONTEXT:  PL/Python function "result_subscript_test"
  INFO:  [2, 3]
- CONTEXT:  PL/Python function "result_subscript_test"
  INFO:  [1, 3]
- CONTEXT:  PL/Python function "result_subscript_test"
  INFO:  [10, 100, 3, 1000]
- CONTEXT:  PL/Python function "result_subscript_test"
   result_subscript_test 
  -----------------------
   
--- 229,238 ----
*************** plpy.info(result[:])
*** 257,263 ****
  $$ LANGUAGE plpythonu;
  SELECT result_empty_test();
  INFO:  []
- CONTEXT:  PL/Python function "result_empty_test"
   result_empty_test 
  -------------------
   
--- 247,252 ----
diff --git a/src/pl/plpython/expected/plpython_subtransaction.out b/src/pl/plpython/expected/plpython_subtransaction.out
new file mode 100644
index ced4682..635bac6
*** a/src/pl/plpython/expected/plpython_subtransaction.out
--- b/src/pl/plpython/expected/plpython_subtransaction.out
*************** SELECT * FROM subtransaction_tbl;
*** 154,160 ****
  TRUNCATE subtransaction_tbl;
  SELECT subtransaction_nested_test('t');
  NOTICE:  Swallowed SyntaxError('syntax error at or near "error"',)
- CONTEXT:  PL/Python function "subtransaction_nested_test"
   subtransaction_nested_test 
  ----------------------------
   ok
--- 154,159 ----
*************** return "ok"
*** 180,188 ****
  $$ LANGUAGE plpythonu;
  SELECT subtransaction_deeply_nested_test();
  NOTICE:  Swallowed SyntaxError('syntax error at or near "error"',)
- CONTEXT:  PL/Python function "subtransaction_nested_test"
- SQL statement "SELECT subtransaction_nested_test('t')"
- PL/Python function "subtransaction_nested_test"
   subtransaction_deeply_nested_test 
  -----------------------------------
   ok
--- 179,184 ----
*************** CONTEXT:  Traceback (most recent call la
*** 251,257 ****
  PL/Python function "subtransaction_exit_without_enter"
  SELECT subtransaction_enter_without_exit();
  WARNING:  forcibly aborting a subtransaction that has not been exited
- CONTEXT:  PL/Python function "subtransaction_enter_without_exit"
   subtransaction_enter_without_exit 
  -----------------------------------
   
--- 247,252 ----
*************** CONTEXT:  PL/Python function "subtransac
*** 259,265 ****
  
  SELECT subtransaction_exit_twice();
  WARNING:  forcibly aborting a subtransaction that has not been exited
- CONTEXT:  PL/Python function "subtransaction_exit_twice"
  ERROR:  ValueError: this subtransaction has not been entered
  CONTEXT:  Traceback (most recent call last):
    PL/Python function "subtransaction_exit_twice", line 3, in <module>
--- 254,259 ----
*************** CONTEXT:  Traceback (most recent call la
*** 267,275 ****
  PL/Python function "subtransaction_exit_twice"
  SELECT subtransaction_enter_twice();
  WARNING:  forcibly aborting a subtransaction that has not been exited
- CONTEXT:  PL/Python function "subtransaction_enter_twice"
  WARNING:  forcibly aborting a subtransaction that has not been exited
- CONTEXT:  PL/Python function "subtransaction_enter_twice"
   subtransaction_enter_twice 
  ----------------------------
   
--- 261,267 ----
*************** CONTEXT:  Traceback (most recent call la
*** 283,289 ****
  PL/Python function "subtransaction_exit_same_subtransaction_twice"
  SELECT subtransaction_enter_same_subtransaction_twice();
  WARNING:  forcibly aborting a subtransaction that has not been exited
- CONTEXT:  PL/Python function "subtransaction_enter_same_subtransaction_twice"
  ERROR:  ValueError: this subtransaction has already been entered
  CONTEXT:  Traceback (most recent call last):
    PL/Python function "subtransaction_enter_same_subtransaction_twice", line 4, in <module>
--- 275,280 ----
*************** except plpy.SPIError:
*** 329,337 ****
  $$ LANGUAGE plpythonu;
  SELECT subtransaction_mix_explicit_and_implicit();
  WARNING:  Caught a SPI error from an explicit subtransaction
- CONTEXT:  PL/Python function "subtransaction_mix_explicit_and_implicit"
  WARNING:  Caught a SPI error
- CONTEXT:  PL/Python function "subtransaction_mix_explicit_and_implicit"
   subtransaction_mix_explicit_and_implicit 
  ------------------------------------------
   
--- 320,326 ----
*************** with plpy.subtransaction():
*** 370,376 ****
  $$ LANGUAGE plpythonu;
  SELECT try_catch_inside_subtransaction();
  NOTICE:  caught
- CONTEXT:  PL/Python function "try_catch_inside_subtransaction"
   try_catch_inside_subtransaction 
  ---------------------------------
   
--- 359,364 ----
*************** with plpy.subtransaction():
*** 395,401 ****
  $$ LANGUAGE plpythonu;
  SELECT pk_violation_inside_subtransaction();
  NOTICE:  caught
- CONTEXT:  PL/Python function "pk_violation_inside_subtransaction"
   pk_violation_inside_subtransaction 
  ------------------------------------
   
--- 383,388 ----
diff --git a/src/pl/plpython/expected/plpython_test.out b/src/pl/plpython/expected/plpython_test.out
new file mode 100644
index a884fc0..7b76faf
*** a/src/pl/plpython/expected/plpython_test.out
--- b/src/pl/plpython/expected/plpython_test.out
*************** plpy.error('error')
*** 62,78 ****
  $$ LANGUAGE plpythonu;
  SELECT elog_test();
  INFO:  info
- CONTEXT:  PL/Python function "elog_test"
  INFO:  37
- CONTEXT:  PL/Python function "elog_test"
  INFO:  ()
- CONTEXT:  PL/Python function "elog_test"
  INFO:  ('info', 37, [1, 2, 3])
- CONTEXT:  PL/Python function "elog_test"
  NOTICE:  notice
- CONTEXT:  PL/Python function "elog_test"
  WARNING:  warning
- CONTEXT:  PL/Python function "elog_test"
  ERROR:  plpy.Error: error
  CONTEXT:  Traceback (most recent call last):
    PL/Python function "elog_test", line 10, in <module>
--- 62,72 ----
diff --git a/src/pl/plpython/expected/plpython_trigger.out b/src/pl/plpython/expected/plpython_trigger.out
new file mode 100644
index 80e478b..4148963
*** a/src/pl/plpython/expected/plpython_trigger.out
--- b/src/pl/plpython/expected/plpython_trigger.out
*************** BEFORE INSERT OR UPDATE OR DELETE OR TRU
*** 98,305 ****
  FOR EACH STATEMENT EXECUTE PROCEDURE trigger_data(23,'skidoo');
  insert into trigger_test values(1,'insert');
  NOTICE:  TD[args] => ['23', 'skidoo']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => INSERT
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => STATEMENT
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig_stmt
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => BEFORE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[args] => ['23', 'skidoo']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => INSERT
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => ROW
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig_before
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => {'i': 1, 'v': 'insert'}
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => BEFORE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[args] => ['23', 'skidoo']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => INSERT
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => ROW
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig_after
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => {'i': 1, 'v': 'insert'}
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => AFTER
- CONTEXT:  PL/Python function "trigger_data"
  update trigger_test set v = 'update' where i = 1;
  NOTICE:  TD[args] => ['23', 'skidoo']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => UPDATE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => STATEMENT
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig_stmt
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => BEFORE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[args] => ['23', 'skidoo']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => UPDATE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => ROW
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig_before
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => {'i': 1, 'v': 'update'}
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => {'i': 1, 'v': 'insert'}
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => BEFORE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[args] => ['23', 'skidoo']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => UPDATE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => ROW
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig_after
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => {'i': 1, 'v': 'update'}
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => {'i': 1, 'v': 'insert'}
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => AFTER
- CONTEXT:  PL/Python function "trigger_data"
  delete from trigger_test;
  NOTICE:  TD[args] => ['23', 'skidoo']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => DELETE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => STATEMENT
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig_stmt
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => BEFORE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[args] => ['23', 'skidoo']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => DELETE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => ROW
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig_before
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => {'i': 1, 'v': 'update'}
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => BEFORE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[args] => ['23', 'skidoo']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => DELETE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => ROW
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig_after
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => {'i': 1, 'v': 'update'}
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => AFTER
- CONTEXT:  PL/Python function "trigger_data"
  truncate table trigger_test;
  NOTICE:  TD[args] => ['23', 'skidoo']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => TRUNCATE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => STATEMENT
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig_stmt
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => BEFORE
- CONTEXT:  PL/Python function "trigger_data"
  DROP TRIGGER show_trigger_data_trig_stmt on trigger_test;
  DROP TRIGGER show_trigger_data_trig_before on trigger_test;
  DROP TRIGGER show_trigger_data_trig_after on trigger_test;
--- 98,205 ----
*************** INSTEAD OF INSERT OR UPDATE OR DELETE ON
*** 310,376 ****
  FOR EACH ROW EXECUTE PROCEDURE trigger_data(24,'skidoo view');
  insert into trigger_test_view values(2,'insert');
  NOTICE:  TD[args] => ['24', 'skidoo view']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => INSERT
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => ROW
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => {'i': 2, 'v': 'insert'}
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test_view
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => INSTEAD OF
- CONTEXT:  PL/Python function "trigger_data"
  update trigger_test_view set v = 'update' where i = 1;
  NOTICE:  TD[args] => ['24', 'skidoo view']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => UPDATE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => ROW
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => {'i': 1, 'v': 'update'}
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => {'i': 1, 'v': 'insert'}
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test_view
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => INSTEAD OF
- CONTEXT:  PL/Python function "trigger_data"
  delete from trigger_test_view;
  NOTICE:  TD[args] => ['24', 'skidoo view']
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[event] => DELETE
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[level] => ROW
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[name] => show_trigger_data_trig
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[new] => None
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[old] => {'i': 1, 'v': 'insert'}
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[relid] => bogus:12345
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_name] => trigger_test_view
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[table_schema] => public
- CONTEXT:  PL/Python function "trigger_data"
  NOTICE:  TD[when] => INSTEAD OF
- CONTEXT:  PL/Python function "trigger_data"
  DROP FUNCTION trigger_data() CASCADE;
  NOTICE:  drop cascades to trigger show_trigger_data_trig on view trigger_test_view
  DROP VIEW trigger_test_view;
--- 210,246 ----
*************** BEFORE DELETE ON trigger_test
*** 402,408 ****
  FOR EACH ROW EXECUTE PROCEDURE stupid2();
  DELETE FROM trigger_test WHERE i = 0;
  WARNING:  PL/Python trigger function returned "MODIFY" in a DELETE trigger -- ignored
- CONTEXT:  PL/Python function "stupid2"
  DROP TRIGGER stupid_trigger2 ON trigger_test;
  INSERT INTO trigger_test VALUES (0, 'zero');
  -- returning unrecognized string from trigger function
--- 272,277 ----
diff --git a/src/pl/plpython/expected/plpython_types.out b/src/pl/plpython/expected/plpython_types.out
new file mode 100644
index 17057a5..f0b6abd
*** a/src/pl/plpython/expected/plpython_types.out
--- b/src/pl/plpython/expected/plpython_types.out
*************** return x
*** 10,16 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_bool(true);
  INFO:  (True, <type 'bool'>)
- CONTEXT:  PL/Python function "test_type_conversion_bool"
   test_type_conversion_bool 
  ---------------------------
   t
--- 10,15 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 18,24 ****
  
  SELECT * FROM test_type_conversion_bool(false);
  INFO:  (False, <type 'bool'>)
- CONTEXT:  PL/Python function "test_type_conversion_bool"
   test_type_conversion_bool 
  ---------------------------
   f
--- 17,22 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 26,32 ****
  
  SELECT * FROM test_type_conversion_bool(null);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_bool"
   test_type_conversion_bool 
  ---------------------------
   
--- 24,29 ----
*************** return ret
*** 54,60 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_bool_other(0);
  INFO:  (0, False)
- CONTEXT:  PL/Python function "test_type_conversion_bool_other"
   test_type_conversion_bool_other 
  ---------------------------------
   f
--- 51,56 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 62,68 ****
  
  SELECT * FROM test_type_conversion_bool_other(1);
  INFO:  (5, True)
- CONTEXT:  PL/Python function "test_type_conversion_bool_other"
   test_type_conversion_bool_other 
  ---------------------------------
   t
--- 58,63 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 70,76 ****
  
  SELECT * FROM test_type_conversion_bool_other(2);
  INFO:  ('', False)
- CONTEXT:  PL/Python function "test_type_conversion_bool_other"
   test_type_conversion_bool_other 
  ---------------------------------
   f
--- 65,70 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 78,84 ****
  
  SELECT * FROM test_type_conversion_bool_other(3);
  INFO:  ('fa', True)
- CONTEXT:  PL/Python function "test_type_conversion_bool_other"
   test_type_conversion_bool_other 
  ---------------------------------
   t
--- 72,77 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 86,92 ****
  
  SELECT * FROM test_type_conversion_bool_other(4);
  INFO:  ([], False)
- CONTEXT:  PL/Python function "test_type_conversion_bool_other"
   test_type_conversion_bool_other 
  ---------------------------------
   f
--- 79,84 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 94,100 ****
  
  SELECT * FROM test_type_conversion_bool_other(5);
  INFO:  ([0], True)
- CONTEXT:  PL/Python function "test_type_conversion_bool_other"
   test_type_conversion_bool_other 
  ---------------------------------
   t
--- 86,91 ----
*************** return x
*** 106,112 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_char('a');
  INFO:  ('a', <type 'str'>)
- CONTEXT:  PL/Python function "test_type_conversion_char"
   test_type_conversion_char 
  ---------------------------
   a
--- 97,102 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 114,120 ****
  
  SELECT * FROM test_type_conversion_char(null);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_char"
   test_type_conversion_char 
  ---------------------------
   
--- 104,109 ----
*************** return x
*** 126,132 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_int2(100::int2);
  INFO:  (100, <type 'int'>)
- CONTEXT:  PL/Python function "test_type_conversion_int2"
   test_type_conversion_int2 
  ---------------------------
                         100
--- 115,120 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 134,140 ****
  
  SELECT * FROM test_type_conversion_int2(-100::int2);
  INFO:  (-100, <type 'int'>)
- CONTEXT:  PL/Python function "test_type_conversion_int2"
   test_type_conversion_int2 
  ---------------------------
                        -100
--- 122,127 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 142,148 ****
  
  SELECT * FROM test_type_conversion_int2(null);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_int2"
   test_type_conversion_int2 
  ---------------------------
                            
--- 129,134 ----
*************** return x
*** 154,160 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_int4(100);
  INFO:  (100, <type 'int'>)
- CONTEXT:  PL/Python function "test_type_conversion_int4"
   test_type_conversion_int4 
  ---------------------------
                         100
--- 140,145 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 162,168 ****
  
  SELECT * FROM test_type_conversion_int4(-100);
  INFO:  (-100, <type 'int'>)
- CONTEXT:  PL/Python function "test_type_conversion_int4"
   test_type_conversion_int4 
  ---------------------------
                        -100
--- 147,152 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 170,176 ****
  
  SELECT * FROM test_type_conversion_int4(null);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_int4"
   test_type_conversion_int4 
  ---------------------------
                            
--- 154,159 ----
*************** return x
*** 182,188 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_int8(100);
  INFO:  (100L, <type 'long'>)
- CONTEXT:  PL/Python function "test_type_conversion_int8"
   test_type_conversion_int8 
  ---------------------------
                         100
--- 165,170 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 190,196 ****
  
  SELECT * FROM test_type_conversion_int8(-100);
  INFO:  (-100L, <type 'long'>)
- CONTEXT:  PL/Python function "test_type_conversion_int8"
   test_type_conversion_int8 
  ---------------------------
                        -100
--- 172,177 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 198,204 ****
  
  SELECT * FROM test_type_conversion_int8(5000000000);
  INFO:  (5000000000L, <type 'long'>)
- CONTEXT:  PL/Python function "test_type_conversion_int8"
   test_type_conversion_int8 
  ---------------------------
                  5000000000
--- 179,184 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 206,212 ****
  
  SELECT * FROM test_type_conversion_int8(null);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_int8"
   test_type_conversion_int8 
  ---------------------------
                            
--- 186,191 ----
*************** return x
*** 220,226 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_numeric(100);
  INFO:  ('100', 'Decimal')
- CONTEXT:  PL/Python function "test_type_conversion_numeric"
   test_type_conversion_numeric 
  ------------------------------
                            100
--- 199,204 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 228,234 ****
  
  SELECT * FROM test_type_conversion_numeric(-100);
  INFO:  ('-100', 'Decimal')
- CONTEXT:  PL/Python function "test_type_conversion_numeric"
   test_type_conversion_numeric 
  ------------------------------
                           -100
--- 206,211 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 236,242 ****
  
  SELECT * FROM test_type_conversion_numeric(100.0);
  INFO:  ('100.0', 'Decimal')
- CONTEXT:  PL/Python function "test_type_conversion_numeric"
   test_type_conversion_numeric 
  ------------------------------
                          100.0
--- 213,218 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 244,250 ****
  
  SELECT * FROM test_type_conversion_numeric(100.00);
  INFO:  ('100.00', 'Decimal')
- CONTEXT:  PL/Python function "test_type_conversion_numeric"
   test_type_conversion_numeric 
  ------------------------------
                         100.00
--- 220,225 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 252,258 ****
  
  SELECT * FROM test_type_conversion_numeric(5000000000.5);
  INFO:  ('5000000000.5', 'Decimal')
- CONTEXT:  PL/Python function "test_type_conversion_numeric"
   test_type_conversion_numeric 
  ------------------------------
                   5000000000.5
--- 227,232 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 260,266 ****
  
  SELECT * FROM test_type_conversion_numeric(1234567890.0987654321);
  INFO:  ('1234567890.0987654321', 'Decimal')
- CONTEXT:  PL/Python function "test_type_conversion_numeric"
   test_type_conversion_numeric 
  ------------------------------
          1234567890.0987654321
--- 234,239 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 268,274 ****
  
  SELECT * FROM test_type_conversion_numeric(-1234567890.0987654321);
  INFO:  ('-1234567890.0987654321', 'Decimal')
- CONTEXT:  PL/Python function "test_type_conversion_numeric"
   test_type_conversion_numeric 
  ------------------------------
         -1234567890.0987654321
--- 241,246 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 276,282 ****
  
  SELECT * FROM test_type_conversion_numeric(null);
  INFO:  ('None', 'NoneType')
- CONTEXT:  PL/Python function "test_type_conversion_numeric"
   test_type_conversion_numeric 
  ------------------------------
                               
--- 248,253 ----
*************** return x
*** 288,294 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_float4(100);
  INFO:  (100.0, <type 'float'>)
- CONTEXT:  PL/Python function "test_type_conversion_float4"
   test_type_conversion_float4 
  -----------------------------
                           100
--- 259,264 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 296,302 ****
  
  SELECT * FROM test_type_conversion_float4(-100);
  INFO:  (-100.0, <type 'float'>)
- CONTEXT:  PL/Python function "test_type_conversion_float4"
   test_type_conversion_float4 
  -----------------------------
                          -100
--- 266,271 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 304,310 ****
  
  SELECT * FROM test_type_conversion_float4(5000.5);
  INFO:  (5000.5, <type 'float'>)
- CONTEXT:  PL/Python function "test_type_conversion_float4"
   test_type_conversion_float4 
  -----------------------------
                        5000.5
--- 273,278 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 312,318 ****
  
  SELECT * FROM test_type_conversion_float4(null);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_float4"
   test_type_conversion_float4 
  -----------------------------
                              
--- 280,285 ----
*************** return x
*** 324,330 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_float8(100);
  INFO:  (100.0, <type 'float'>)
- CONTEXT:  PL/Python function "test_type_conversion_float8"
   test_type_conversion_float8 
  -----------------------------
                           100
--- 291,296 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 332,338 ****
  
  SELECT * FROM test_type_conversion_float8(-100);
  INFO:  (-100.0, <type 'float'>)
- CONTEXT:  PL/Python function "test_type_conversion_float8"
   test_type_conversion_float8 
  -----------------------------
                          -100
--- 298,303 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 340,346 ****
  
  SELECT * FROM test_type_conversion_float8(5000000000.5);
  INFO:  (5000000000.5, <type 'float'>)
- CONTEXT:  PL/Python function "test_type_conversion_float8"
   test_type_conversion_float8 
  -----------------------------
                  5000000000.5
--- 305,310 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 348,354 ****
  
  SELECT * FROM test_type_conversion_float8(null);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_float8"
   test_type_conversion_float8 
  -----------------------------
                              
--- 312,317 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 356,362 ****
  
  SELECT * FROM test_type_conversion_float8(100100100.654321);
  INFO:  (100100100.654321, <type 'float'>)
- CONTEXT:  PL/Python function "test_type_conversion_float8"
   test_type_conversion_float8 
  -----------------------------
              100100100.654321
--- 319,324 ----
*************** return x
*** 368,374 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_oid(100);
  INFO:  (100L, <type 'long'>)
- CONTEXT:  PL/Python function "test_type_conversion_oid"
   test_type_conversion_oid 
  --------------------------
                        100
--- 330,335 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 376,382 ****
  
  SELECT * FROM test_type_conversion_oid(2147483649);
  INFO:  (2147483649L, <type 'long'>)
- CONTEXT:  PL/Python function "test_type_conversion_oid"
   test_type_conversion_oid 
  --------------------------
                 2147483649
--- 337,342 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 384,390 ****
  
  SELECT * FROM test_type_conversion_oid(null);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_oid"
   test_type_conversion_oid 
  --------------------------
                           
--- 344,349 ----
*************** return x
*** 396,402 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_text('hello world');
  INFO:  ('hello world', <type 'str'>)
- CONTEXT:  PL/Python function "test_type_conversion_text"
   test_type_conversion_text 
  ---------------------------
   hello world
--- 355,360 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 404,410 ****
  
  SELECT * FROM test_type_conversion_text(null);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_text"
   test_type_conversion_text 
  ---------------------------
   
--- 362,367 ----
*************** return x
*** 416,422 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_bytea('hello world');
  INFO:  ('hello world', <type 'str'>)
- CONTEXT:  PL/Python function "test_type_conversion_bytea"
   test_type_conversion_bytea 
  ----------------------------
   \x68656c6c6f20776f726c64
--- 373,378 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 424,430 ****
  
  SELECT * FROM test_type_conversion_bytea(E'null\\000byte');
  INFO:  ('null\x00byte', <type 'str'>)
- CONTEXT:  PL/Python function "test_type_conversion_bytea"
   test_type_conversion_bytea 
  ----------------------------
   \x6e756c6c0062797465
--- 380,385 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 432,438 ****
  
  SELECT * FROM test_type_conversion_bytea(null);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_bytea"
   test_type_conversion_bytea 
  ----------------------------
   
--- 387,392 ----
*************** return y
*** 481,487 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_uint2(100::uint2, 50);
  INFO:  (100, <type 'int'>)
- CONTEXT:  PL/Python function "test_type_conversion_uint2"
   test_type_conversion_uint2 
  ----------------------------
                           50
--- 435,440 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 489,501 ****
  
  SELECT * FROM test_type_conversion_uint2(100::uint2, -50);
  INFO:  (100, <type 'int'>)
- CONTEXT:  PL/Python function "test_type_conversion_uint2"
  ERROR:  value for domain uint2 violates check constraint "uint2_check"
  CONTEXT:  while creating return value
  PL/Python function "test_type_conversion_uint2"
  SELECT * FROM test_type_conversion_uint2(null, 1);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_uint2"
   test_type_conversion_uint2 
  ----------------------------
                            1
--- 442,452 ----
*************** return y
*** 524,530 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_bytea10('hello wold', 'hello wold');
  INFO:  ('hello wold', <type 'str'>)
- CONTEXT:  PL/Python function "test_type_conversion_bytea10"
   test_type_conversion_bytea10 
  ------------------------------
   \x68656c6c6f20776f6c64
--- 475,480 ----
*************** SELECT * FROM test_type_conversion_bytea
*** 534,540 ****
  ERROR:  value for domain bytea10 violates check constraint "bytea10_check"
  SELECT * FROM test_type_conversion_bytea10('hello word', 'hello world');
  INFO:  ('hello word', <type 'str'>)
- CONTEXT:  PL/Python function "test_type_conversion_bytea10"
  ERROR:  value for domain bytea10 violates check constraint "bytea10_check"
  CONTEXT:  while creating return value
  PL/Python function "test_type_conversion_bytea10"
--- 484,489 ----
*************** SELECT * FROM test_type_conversion_bytea
*** 542,548 ****
  ERROR:  value for domain bytea10 violates check constraint "bytea10_check"
  SELECT * FROM test_type_conversion_bytea10('hello word', null);
  INFO:  ('hello word', <type 'str'>)
- CONTEXT:  PL/Python function "test_type_conversion_bytea10"
  ERROR:  value for domain bytea10 violates check constraint "bytea10_check"
  CONTEXT:  while creating return value
  PL/Python function "test_type_conversion_bytea10"
--- 491,496 ----
*************** return x
*** 555,561 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_array_int4(ARRAY[0, 100]);
  INFO:  ([0, 100], <type 'list'>)
- CONTEXT:  PL/Python function "test_type_conversion_array_int4"
   test_type_conversion_array_int4 
  ---------------------------------
   {0,100}
--- 503,508 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 563,569 ****
  
  SELECT * FROM test_type_conversion_array_int4(ARRAY[0,-100,55]);
  INFO:  ([0, -100, 55], <type 'list'>)
- CONTEXT:  PL/Python function "test_type_conversion_array_int4"
   test_type_conversion_array_int4 
  ---------------------------------
   {0,-100,55}
--- 510,515 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 571,577 ****
  
  SELECT * FROM test_type_conversion_array_int4(ARRAY[NULL,1]);
  INFO:  ([None, 1], <type 'list'>)
- CONTEXT:  PL/Python function "test_type_conversion_array_int4"
   test_type_conversion_array_int4 
  ---------------------------------
   {NULL,1}
--- 517,522 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 579,585 ****
  
  SELECT * FROM test_type_conversion_array_int4(ARRAY[]::integer[]);
  INFO:  ([], <type 'list'>)
- CONTEXT:  PL/Python function "test_type_conversion_array_int4"
   test_type_conversion_array_int4 
  ---------------------------------
   {}
--- 524,529 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 587,593 ****
  
  SELECT * FROM test_type_conversion_array_int4(NULL);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_array_int4"
   test_type_conversion_array_int4 
  ---------------------------------
   
--- 531,536 ----
*************** return x
*** 603,609 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_array_text(ARRAY['foo', 'bar']);
  INFO:  (['foo', 'bar'], <type 'list'>)
- CONTEXT:  PL/Python function "test_type_conversion_array_text"
   test_type_conversion_array_text 
  ---------------------------------
   {foo,bar}
--- 546,551 ----
*************** return x
*** 615,621 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_array_bytea(ARRAY[E'\\xdeadbeef'::bytea, NULL]);
  INFO:  (['\xde\xad\xbe\xef', None], <type 'list'>)
- CONTEXT:  PL/Python function "test_type_conversion_array_bytea"
   test_type_conversion_array_bytea 
  ----------------------------------
   {"\\xdeadbeef",NULL}
--- 557,562 ----
*************** return x
*** 681,687 ****
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_array_domain(ARRAY[0, 100]::ordered_pair_domain);
  INFO:  ([0, 100], <type 'list'>)
- CONTEXT:  PL/Python function "test_type_conversion_array_domain"
   test_type_conversion_array_domain 
  -----------------------------------
   {0,100}
--- 622,627 ----
*************** CONTEXT:  PL/Python function "test_type_
*** 689,695 ****
  
  SELECT * FROM test_type_conversion_array_domain(NULL::ordered_pair_domain);
  INFO:  (None, <type 'NoneType'>)
- CONTEXT:  PL/Python function "test_type_conversion_array_domain"
   test_type_conversion_array_domain 
  -----------------------------------
   
--- 629,634 ----
*************** return rv[0]['val']
*** 783,789 ****
  $$;
  SELECT test_prep_bool_output(); -- false
  INFO:  {'val': False}
- CONTEXT:  PL/Python function "test_prep_bool_output"
   test_prep_bool_output 
  -----------------------
   f
--- 722,727 ----
*************** return rv[0]['val']
*** 812,818 ****
  $$;
  SELECT test_prep_bytea_output();
  INFO:  {'val': '\xaa\x00\xbb'}
- CONTEXT:  PL/Python function "test_prep_bytea_output"
   test_prep_bytea_output 
  ------------------------
   \xaa00bb
--- 750,755 ----
diff --git a/src/test/regress/expected/copy2.out b/src/test/regress/expected/copy2.out
new file mode 100644
index 5e31737..72ada21
*** a/src/test/regress/expected/copy2.out
--- b/src/test/regress/expected/copy2.out
*************** Check constraints:
*** 447,458 ****
  
  copy check_con_tbl from stdin;
  NOTICE:  input = {"f1":1}
- CONTEXT:  COPY check_con_tbl, line 1: "1"
  NOTICE:  input = {"f1":null}
- CONTEXT:  COPY check_con_tbl, line 2: "\N"
  copy check_con_tbl from stdin;
  NOTICE:  input = {"f1":0}
- CONTEXT:  COPY check_con_tbl, line 1: "0"
  ERROR:  new row for relation "check_con_tbl" violates check constraint "check_con_tbl_check"
  DETAIL:  Failing row contains (0).
  CONTEXT:  COPY check_con_tbl, line 1: "0"
--- 447,455 ----
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
new file mode 100644
index e70c315..05ac0ad
*** a/src/test/regress/expected/event_trigger.out
--- b/src/test/regress/expected/event_trigger.out
*************** drop cascades to table schema_one.table_
*** 234,248 ****
  drop cascades to table schema_one."table two"
  drop cascades to table schema_one.table_three
  NOTICE:  table "schema_two_table_two" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_two"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "audit_tbls_schema_two_table_three" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.audit_tbls_schema_two_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
- SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  ERROR:  object audit_tbls.schema_two_table_three of type table cannot be dropped
! CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three"
  PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  DELETE FROM undroppable_objs WHERE object_identity = 'audit_tbls.schema_two_table_three';
  DROP SCHEMA schema_one, schema_two CASCADE;
--- 234,243 ----
  drop cascades to table schema_one."table two"
  drop cascades to table schema_one.table_three
  NOTICE:  table "schema_two_table_two" does not exist, skipping
  NOTICE:  table "audit_tbls_schema_two_table_three" does not exist, skipping
  ERROR:  object audit_tbls.schema_two_table_three of type table cannot be dropped
! CONTEXT:  PL/pgSQL function undroppable() line 14 at RAISE
! SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three"
  PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  DELETE FROM undroppable_objs WHERE object_identity = 'audit_tbls.schema_two_table_three';
  DROP SCHEMA schema_one, schema_two CASCADE;
*************** drop cascades to table schema_one.table_
*** 255,277 ****
  drop cascades to table schema_one."table two"
  drop cascades to table schema_one.table_three
  NOTICE:  table "schema_two_table_two" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_two"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "audit_tbls_schema_two_table_three" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.audit_tbls_schema_two_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
- SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "schema_one_table_one" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_one_table_one"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "schema_one_table two" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls."schema_one_table two""
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "schema_one_table_three" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_one_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  ERROR:  object schema_one.table_three of type table cannot be dropped
  DELETE FROM undroppable_objs WHERE object_identity = 'schema_one.table_three';
  DROP SCHEMA schema_one, schema_two CASCADE;
  NOTICE:  drop cascades to 7 other objects
--- 250,261 ----
  drop cascades to table schema_one."table two"
  drop cascades to table schema_one.table_three
  NOTICE:  table "schema_two_table_two" does not exist, skipping
  NOTICE:  table "audit_tbls_schema_two_table_three" does not exist, skipping
  NOTICE:  table "schema_one_table_one" does not exist, skipping
  NOTICE:  table "schema_one_table two" does not exist, skipping
  NOTICE:  table "schema_one_table_three" does not exist, skipping
  ERROR:  object schema_one.table_three of type table cannot be dropped
+ CONTEXT:  PL/pgSQL function undroppable() line 14 at RAISE
  DELETE FROM undroppable_objs WHERE object_identity = 'schema_one.table_three';
  DROP SCHEMA schema_one, schema_two CASCADE;
  NOTICE:  drop cascades to 7 other objects
*************** drop cascades to table schema_one.table_
*** 283,304 ****
  drop cascades to table schema_one."table two"
  drop cascades to table schema_one.table_three
  NOTICE:  table "schema_two_table_two" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_two"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "audit_tbls_schema_two_table_three" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.audit_tbls_schema_two_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
- SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "schema_one_table_one" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_one_table_one"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "schema_one_table two" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls."schema_one_table two""
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "schema_one_table_three" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_one_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  SELECT * FROM dropped_objects WHERE schema IS NULL OR schema <> 'pg_toast';
       type     |   schema   |               object                
  --------------+------------+-------------------------------------
--- 267,276 ----
*************** SELECT * FROM dropped_objects WHERE sche
*** 329,336 ****
  
  DROP OWNED BY regression_bob;
  NOTICE:  schema "audit_tbls" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.audit_tbls_schema_one_table_two"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  SELECT * FROM dropped_objects WHERE type = 'schema';
    type  | schema |   object   
  --------+--------+------------
--- 301,306 ----
*************** insert into rewriteme
*** 402,409 ****
--- 372,381 ----
       select x * 1.001 from generate_series(1, 500) as t(x);
  alter table rewriteme alter column foo type numeric;
  ERROR:  I'm sorry Sir, No Rewrite Allowed.
+ CONTEXT:  PL/pgSQL function test_evtrig_no_rewrite() line 3 at RAISE
  alter table rewriteme add column baz int default 0;
  ERROR:  I'm sorry Sir, No Rewrite Allowed.
+ CONTEXT:  PL/pgSQL function test_evtrig_no_rewrite() line 3 at RAISE
  -- test with more than one reason to rewrite a single table
  CREATE OR REPLACE FUNCTION test_evtrig_no_rewrite() RETURNS event_trigger
  LANGUAGE plpgsql AS $$
diff --git a/src/test/regress/expected/plancache.out b/src/test/regress/expected/plancache.out
new file mode 100644
index 864f70f..3f3db33
*** a/src/test/regress/expected/plancache.out
--- b/src/test/regress/expected/plancache.out
*************** begin
*** 234,241 ****
  end$$ language plpgsql;
  select cachebug();
  NOTICE:  table "temptable" does not exist, skipping
- CONTEXT:  SQL statement "drop table if exists temptable cascade"
- PL/pgSQL function cachebug() line 4 at SQL statement
  NOTICE:  1
  NOTICE:  2
  NOTICE:  3
--- 234,239 ----
*************** NOTICE:  3
*** 246,253 ****
  
  select cachebug();
  NOTICE:  drop cascades to view vv
- CONTEXT:  SQL statement "drop table if exists temptable cascade"
- PL/pgSQL function cachebug() line 4 at SQL statement
  NOTICE:  1
  NOTICE:  2
  NOTICE:  3
--- 244,249 ----
diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out
new file mode 100644
index 7ce5415..a19424d
*** a/src/test/regress/expected/plpgsql.out
--- b/src/test/regress/expected/plpgsql.out
*************** ERROR:  duplicate key value violates uni
*** 1518,1544 ****
  DETAIL:  Key (name)=(PF1_1) already exists.
  update PSlot set backlink = 'WS.not.there' where slotname = 'PS.base.a1';
  ERROR:  WS.not.there         does not exist
! CONTEXT:  PL/pgSQL function tg_backlink_a() line 17 at assignment
  update PSlot set backlink = 'XX.illegal' where slotname = 'PS.base.a1';
  ERROR:  illegal backlink beginning with XX
! CONTEXT:  PL/pgSQL function tg_backlink_a() line 17 at assignment
  update PSlot set slotlink = 'PS.not.there' where slotname = 'PS.base.a1';
  ERROR:  PS.not.there         does not exist
! CONTEXT:  PL/pgSQL function tg_slotlink_a() line 17 at assignment
  update PSlot set slotlink = 'XX.illegal' where slotname = 'PS.base.a1';
  ERROR:  illegal slotlink beginning with XX
! CONTEXT:  PL/pgSQL function tg_slotlink_a() line 17 at assignment
  insert into HSlot values ('HS', 'base.hub1', 1, '');
  ERROR:  duplicate key value violates unique constraint "hslot_name"
  DETAIL:  Key (slotname)=(HS.base.hub1.1      ) already exists.
  insert into HSlot values ('HS', 'base.hub1', 20, '');
  ERROR:  no manual manipulation of HSlot
  delete from HSlot;
  ERROR:  no manual manipulation of HSlot
  insert into IFace values ('IF', 'notthere', 'eth0', '');
  ERROR:  system "notthere" does not exist
  insert into IFace values ('IF', 'orion', 'ethernet_interface_name_too_long', '');
  ERROR:  IFace slotname "IF.orion.ethernet_interface_name_too_long" too long (20 char max)
  --
  -- The following tests are unrelated to the scenario outlined above;
  -- they merely exercise specific parts of PL/pgSQL
--- 1518,1552 ----
  DETAIL:  Key (name)=(PF1_1) already exists.
  update PSlot set backlink = 'WS.not.there' where slotname = 'PS.base.a1';
  ERROR:  WS.not.there         does not exist
! CONTEXT:  PL/pgSQL function tg_backlink_set(character,character) line 30 at RAISE
! PL/pgSQL function tg_backlink_a() line 17 at assignment
  update PSlot set backlink = 'XX.illegal' where slotname = 'PS.base.a1';
  ERROR:  illegal backlink beginning with XX
! CONTEXT:  PL/pgSQL function tg_backlink_set(character,character) line 47 at RAISE
! PL/pgSQL function tg_backlink_a() line 17 at assignment
  update PSlot set slotlink = 'PS.not.there' where slotname = 'PS.base.a1';
  ERROR:  PS.not.there         does not exist
! CONTEXT:  PL/pgSQL function tg_slotlink_set(character,character) line 30 at RAISE
! PL/pgSQL function tg_slotlink_a() line 17 at assignment
  update PSlot set slotlink = 'XX.illegal' where slotname = 'PS.base.a1';
  ERROR:  illegal slotlink beginning with XX
! CONTEXT:  PL/pgSQL function tg_slotlink_set(character,character) line 77 at RAISE
! PL/pgSQL function tg_slotlink_a() line 17 at assignment
  insert into HSlot values ('HS', 'base.hub1', 1, '');
  ERROR:  duplicate key value violates unique constraint "hslot_name"
  DETAIL:  Key (slotname)=(HS.base.hub1.1      ) already exists.
  insert into HSlot values ('HS', 'base.hub1', 20, '');
  ERROR:  no manual manipulation of HSlot
+ CONTEXT:  PL/pgSQL function tg_hslot_biu() line 12 at RAISE
  delete from HSlot;
  ERROR:  no manual manipulation of HSlot
+ CONTEXT:  PL/pgSQL function tg_hslot_bd() line 12 at RAISE
  insert into IFace values ('IF', 'notthere', 'eth0', '');
  ERROR:  system "notthere" does not exist
+ CONTEXT:  PL/pgSQL function tg_iface_biu() line 8 at RAISE
  insert into IFace values ('IF', 'orion', 'ethernet_interface_name_too_long', '');
  ERROR:  IFace slotname "IF.orion.ethernet_interface_name_too_long" too long (20 char max)
+ CONTEXT:  PL/pgSQL function tg_iface_biu() line 14 at RAISE
  --
  -- The following tests are unrelated to the scenario outlined above;
  -- they merely exercise specific parts of PL/pgSQL
*************** NOTICE:  should see this
*** 1963,1968 ****
--- 1971,1977 ----
  NOTICE:  should see this only if -100 <> 0
  NOTICE:  should see this only if -100 fits in smallint
  ERROR:  -100 is less than zero
+ CONTEXT:  PL/pgSQL function trap_zero_divide(integer) line 12 at RAISE
  create function trap_matching_test(int) returns int as $$
  declare x int;
  	sx smallint;
*************** begin
*** 2066,2079 ****
  end$$ language plpgsql;
  select test_variable_storage();
  NOTICE:  should see this
- CONTEXT:  SQL statement "SELECT trap_zero_divide(-100)"
- PL/pgSQL function test_variable_storage() line 8 at PERFORM
  NOTICE:  should see this only if -100 <> 0
- CONTEXT:  SQL statement "SELECT trap_zero_divide(-100)"
- PL/pgSQL function test_variable_storage() line 8 at PERFORM
  NOTICE:  should see this only if -100 fits in smallint
- CONTEXT:  SQL statement "SELECT trap_zero_divide(-100)"
- PL/pgSQL function test_variable_storage() line 8 at PERFORM
   test_variable_storage 
  -----------------------
   123456789012
--- 2075,2082 ----
*************** DETAIL:  some detail info
*** 4052,4057 ****
--- 4055,4061 ----
  HINT:  some hint
  ERROR:  1 2 3
  DETAIL:  some detail info
+ CONTEXT:  PL/pgSQL function raise_test() line 5 at RAISE
  -- Since we can't actually see the thrown SQLSTATE in default psql output,
  -- test it like this; this also tests re-RAISE
  create or replace function raise_test() returns void as $$
*************** select raise_test();
*** 4068,4073 ****
--- 4072,4078 ----
  NOTICE:  SQLSTATE: 22012 SQLERRM: check me
  ERROR:  check me
  DETAIL:  some detail info
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise 'check me'
*************** select raise_test();
*** 4082,4087 ****
--- 4087,4093 ----
  NOTICE:  SQLSTATE: 1234F SQLERRM: check me
  ERROR:  check me
  DETAIL:  some detail info
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  -- SQLSTATE specification in WHEN
  create or replace function raise_test() returns void as $$
  begin
*************** select raise_test();
*** 4097,4102 ****
--- 4103,4109 ----
  NOTICE:  SQLSTATE: 1234F SQLERRM: check me
  ERROR:  check me
  DETAIL:  some detail info
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise division_by_zero using detail = 'some detail info';
*************** select raise_test();
*** 4110,4115 ****
--- 4117,4123 ----
  NOTICE:  SQLSTATE: 22012 SQLERRM: division_by_zero
  ERROR:  division_by_zero
  DETAIL:  some detail info
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise division_by_zero;
*************** end;
*** 4117,4122 ****
--- 4125,4131 ----
  $$ language plpgsql;
  select raise_test();
  ERROR:  division_by_zero
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise sqlstate '1234F';
*************** end;
*** 4124,4129 ****
--- 4133,4139 ----
  $$ language plpgsql;
  select raise_test();
  ERROR:  1234F
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise division_by_zero using message = 'custom' || ' message';
*************** end;
*** 4131,4136 ****
--- 4141,4147 ----
  $$ language plpgsql;
  select raise_test();
  ERROR:  custom message
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise using message = 'custom' || ' message', errcode = '22012';
*************** end;
*** 4138,4143 ****
--- 4149,4155 ----
  $$ language plpgsql;
  select raise_test();
  ERROR:  custom message
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  -- conflict on message
  create or replace function raise_test() returns void as $$
  begin
*************** $$ language plpgsql;
*** 4254,4259 ****
--- 4266,4272 ----
  select raise_test();
  NOTICE:  22012
  ERROR:  substitute message
+ CONTEXT:  PL/pgSQL function raise_test() line 7 at RAISE
  drop function raise_test();
  -- test passing column_name, constraint_name, datatype_name, table_name
  -- and schema_name error fields
*************** LINE 1: SELECT 'foo\\bar\041baz'
*** 4744,4750 ****
                 ^
  HINT:  Use the escape string syntax for backslashes, e.g., E'\\'.
  QUERY:  SELECT 'foo\\bar\041baz'
- CONTEXT:  PL/pgSQL function strtest() line 4 at RETURN
     strtest   
  -------------
   foo\bar!baz
--- 4757,4762 ----
*************** $$ language plpgsql;
*** 5260,5281 ****
  select outer_outer_func(10);
  NOTICE:  calling down into outer_func()
  NOTICE:  calling down into inner_func()
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 4 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 7 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  lets make sure we didnt break anything
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  inner_func() done
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  outer_func() done
   outer_outer_func 
  ------------------
--- 5272,5285 ----
*************** NOTICE:  outer_func() done
*** 5286,5307 ****
  select outer_outer_func(20);
  NOTICE:  calling down into outer_func()
  NOTICE:  calling down into inner_func()
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 4 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 7 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  lets make sure we didnt break anything
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  inner_func() done
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  outer_func() done
   outer_outer_func 
  ------------------
--- 5290,5303 ----
*************** $$ language plpgsql;
*** 5358,5379 ****
  select outer_outer_func(10);
  NOTICE:  calling down into outer_func()
  NOTICE:  calling down into inner_func()
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 10 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 15 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  lets make sure we didnt break anything
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  inner_func() done
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  outer_func() done
   outer_outer_func 
  ------------------
--- 5354,5367 ----
*************** NOTICE:  outer_func() done
*** 5384,5405 ****
  select outer_outer_func(20);
  NOTICE:  calling down into outer_func()
  NOTICE:  calling down into inner_func()
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 10 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 15 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  lets make sure we didnt break anything
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  inner_func() done
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  outer_func() done
   outer_outer_func 
  ------------------
--- 5372,5385 ----
diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out
new file mode 100644
index c0cd9fa..88bdc2c
*** a/src/test/regress/expected/privileges.out
--- b/src/test/regress/expected/privileges.out
*************** GRANT regressgroup2 TO regressuser5; --
*** 1023,1029 ****
  ERROR:  must have admin option on role "regressgroup2"
  SELECT dogrant_ok();			-- ok: SECURITY DEFINER conveys ADMIN
  NOTICE:  role "regressuser5" is already a member of role "regressgroup2"
- CONTEXT:  SQL function "dogrant_ok" statement 1
   dogrant_ok 
  ------------
   
--- 1023,1028 ----
diff --git a/src/test/regress/expected/rangefuncs.out b/src/test/regress/expected/rangefuncs.out
new file mode 100644
index 6dabe50..00ef421
*** a/src/test/regress/expected/rangefuncs.out
--- b/src/test/regress/expected/rangefuncs.out
*************** create trigger tnoticetrigger after inse
*** 1704,1712 ****
  execute procedure noticetrigger();
  select insert_tt2('foolme','barme') limit 1;
  NOTICE:  noticetrigger 11 foolme
- CONTEXT:  SQL function "insert_tt2" statement 1
  NOTICE:  noticetrigger 12 barme
- CONTEXT:  SQL function "insert_tt2" statement 1
   insert_tt2 
  ------------
           11
--- 1704,1710 ----
*************** create rule insert_tt_rule as on insert
*** 1735,1743 ****
    insert into tt_log values(new.*);
  select insert_tt2('foollog','barlog') limit 1;
  NOTICE:  noticetrigger 13 foollog
- CONTEXT:  SQL function "insert_tt2" statement 1
  NOTICE:  noticetrigger 14 barlog
- CONTEXT:  SQL function "insert_tt2" statement 1
   insert_tt2 
  ------------
           13
--- 1733,1739 ----
diff --git a/src/test/regress/expected/triggers.out b/src/test/regress/expected/triggers.out
new file mode 100644
index 3b32e8f..cd43e46
*** a/src/test/regress/expected/triggers.out
--- b/src/test/regress/expected/triggers.out
*************** NOTICE:  main_view BEFORE INSERT STATEME
*** 958,968 ****
  NOTICE:  main_view INSTEAD OF INSERT ROW (instead_of_ins)
  NOTICE:  NEW: (20,30)
  NOTICE:  trigger_func(before_ins_stmt) called: action = INSERT, when = BEFORE, level = STATEMENT
- CONTEXT:  SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
- PL/pgSQL function view_trigger() line 17 at SQL statement
  NOTICE:  trigger_func(after_ins_stmt) called: action = INSERT, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
- PL/pgSQL function view_trigger() line 17 at SQL statement
  NOTICE:  main_view AFTER INSERT STATEMENT (after_view_ins_stmt)
  INSERT 0 1
  INSERT INTO main_view VALUES (21, 31) RETURNING a, b;
--- 958,964 ----
*************** NOTICE:  main_view BEFORE INSERT STATEME
*** 970,980 ****
  NOTICE:  main_view INSTEAD OF INSERT ROW (instead_of_ins)
  NOTICE:  NEW: (21,31)
  NOTICE:  trigger_func(before_ins_stmt) called: action = INSERT, when = BEFORE, level = STATEMENT
- CONTEXT:  SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
- PL/pgSQL function view_trigger() line 17 at SQL statement
  NOTICE:  trigger_func(after_ins_stmt) called: action = INSERT, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
- PL/pgSQL function view_trigger() line 17 at SQL statement
  NOTICE:  main_view AFTER INSERT STATEMENT (after_view_ins_stmt)
   a  | b  
  ----+----
--- 966,972 ----
*************** NOTICE:  main_view BEFORE UPDATE STATEME
*** 988,1004 ****
  NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
  NOTICE:  OLD: (20,30), NEW: (20,31)
  NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
  UPDATE 0
  UPDATE main_view SET b = 32 WHERE a = 21 AND b = 31 RETURNING a, b;
--- 980,988 ----
*************** NOTICE:  main_view BEFORE UPDATE STATEME
*** 1006,1022 ****
  NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
  NOTICE:  OLD: (21,31), NEW: (21,32)
  NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
   a | b 
  ---+---
--- 990,998 ----
*************** NOTICE:  main_view BEFORE UPDATE STATEME
*** 1031,1050 ****
  NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
  NOTICE:  OLD: (20,30), NEW: (20,31)
  NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
  UPDATE 1
  UPDATE main_view SET b = 32 WHERE a = 21 AND b = 31 RETURNING a, b;
--- 1007,1016 ----
*************** NOTICE:  main_view BEFORE UPDATE STATEME
*** 1052,1071 ****
  NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
  NOTICE:  OLD: (21,31), NEW: (21,32)
  NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
   a  | b  
  ----+----
--- 1018,1027 ----
*************** INSERT 0 1
*** 1277,1282 ****
--- 1233,1239 ----
  -- UPDATE .. RETURNING
  UPDATE city_view SET country_name = 'Japon' WHERE city_name = 'Tokyo'; -- error
  ERROR:  No such country: "Japon"
+ CONTEXT:  PL/pgSQL function city_update() line 9 at RAISE
  UPDATE city_view SET country_name = 'Japan' WHERE city_name = 'Takyo'; -- no match
  UPDATE 0
  UPDATE city_view SET country_name = 'Japan' WHERE city_name = 'Tokyo' RETURNING *; -- OK
*************** select pg_trigger_depth();
*** 1489,1514 ****
  insert into depth_a values (1);
  NOTICE:  depth_a_tr: depth = 1
  NOTICE:  depth_b_tr: depth = 2
- CONTEXT:  SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_c_tr: depth = 3
- CONTEXT:  SQL statement "insert into depth_c values (1)"
- PL/pgSQL function depth_b_tf() line 5 at EXECUTE statement
- SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  SQLSTATE = U9999: depth = 2
- CONTEXT:  SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_b_tr: depth = 2
- CONTEXT:  SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_c_tr: depth = 3
- CONTEXT:  SQL statement "insert into depth_c values (1)"
- PL/pgSQL function depth_b_tf() line 12 at EXECUTE statement
- SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  ERROR:  U9999
! CONTEXT:  SQL statement "insert into depth_c values (1)"
  PL/pgSQL function depth_b_tf() line 12 at EXECUTE statement
  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
--- 1446,1458 ----
  insert into depth_a values (1);
  NOTICE:  depth_a_tr: depth = 1
  NOTICE:  depth_b_tr: depth = 2
  NOTICE:  depth_c_tr: depth = 3
  NOTICE:  SQLSTATE = U9999: depth = 2
  NOTICE:  depth_b_tr: depth = 2
  NOTICE:  depth_c_tr: depth = 3
  ERROR:  U9999
! CONTEXT:  PL/pgSQL function depth_c_tf() line 5 at RAISE
! SQL statement "insert into depth_c values (1)"
  PL/pgSQL function depth_b_tf() line 12 at EXECUTE statement
  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
*************** select pg_trigger_depth();
*** 1521,1541 ****
  insert into depth_a values (2);
  NOTICE:  depth_a_tr: depth = 1
  NOTICE:  depth_b_tr: depth = 2
- CONTEXT:  SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_c_tr: depth = 3
- CONTEXT:  SQL statement "insert into depth_c values (2)"
- PL/pgSQL function depth_b_tf() line 5 at EXECUTE statement
- SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_c_tr: depth = 3
- CONTEXT:  SQL statement "insert into depth_c values (2)"
- PL/pgSQL function depth_b_tf() line 5 at EXECUTE statement
- SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_b_tr: depth = 2
- CONTEXT:  SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_a_tr: depth = 1
  select pg_trigger_depth();
   pg_trigger_depth 
--- 1465,1473 ----
diff --git a/src/test/regress/expected/xml.out b/src/test/regress/expected/xml.out
new file mode 100644
index 9b2d264..5691e47
*** a/src/test/regress/expected/xml.out
--- b/src/test/regress/expected/xml.out
*************** SELECT xpath('/*', '<relativens xmlns=''
*** 934,940 ****
  WARNING:  line 1: xmlns: URI relative is not absolute
  <relativens xmlns='relative'/>
                              ^
- CONTEXT:  SQL function "xpath" statement 1
                  xpath                 
  --------------------------------------
   {"<relativens xmlns=\"relative\"/>"}
--- 934,939 ----
#86Merlin Moncure
mmoncure@gmail.com
In reply to: Pavel Stehule (#85)
Re: PL/pgSQL, RAISE and error context

On Thu, Jul 9, 2015 at 3:31 PM, Pavel Stehule <pavel.stehule@gmail.com> wrote:

2015-07-09 20:08 GMT+02:00 Merlin Moncure <mmoncure@gmail.com>:

On Thu, Jul 9, 2015 at 10:48 AM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

2015-07-09 15:17 GMT+02:00 Merlin Moncure <mmoncure@gmail.com>:

On Wed, Jul 8, 2015 at 11:28 PM, Pavel Stehule
<pavel.stehule@gmail.com>
wrote:

Hi

second version of this patch

make check-world passed

quickly scanning the patch, the implementation is trivial (minus
regression test adjustments), and is, IMSNSHO, the right solution.

yes, it is right way - the behave of RAISE statement will be much more
cleaner

Several of the source level comments need some minor wordsmithing and
the GUCs are missing documentation. If we've got consensus on the
approach, I'll pitch in on that.

thank you

revised patch attached. added GUC docs and cleaned up pg_settings
language. Also tested patch and it works beautifully.

Note, Pavel's patch does adjust default behavior to what we think is
the "right" settings.

Thank you for documentation.

There is small error - default for client_min_context is error - not notice.
With this level a diff from regress tests is minimal. Default for
log_min_context should be warning.

whoop! thanks. Also, I was playing a bit with the idea of making
client_min_context "superuser only" setting. The idea being this
could be used to prevent leakage of stored procedure code in cases
where the admins don't want it to be exposed. I figured it was a bad
idea though; it would frustrate debugging in reasonable cases.

merlin

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#87Pavel Stehule
pavel.stehule@gmail.com
In reply to: Merlin Moncure (#86)
Re: PL/pgSQL, RAISE and error context

2015-07-09 22:57 GMT+02:00 Merlin Moncure <mmoncure@gmail.com>:

On Thu, Jul 9, 2015 at 3:31 PM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

2015-07-09 20:08 GMT+02:00 Merlin Moncure <mmoncure@gmail.com>:

On Thu, Jul 9, 2015 at 10:48 AM, Pavel Stehule <pavel.stehule@gmail.com

wrote:

2015-07-09 15:17 GMT+02:00 Merlin Moncure <mmoncure@gmail.com>:

On Wed, Jul 8, 2015 at 11:28 PM, Pavel Stehule
<pavel.stehule@gmail.com>
wrote:

Hi

second version of this patch

make check-world passed

quickly scanning the patch, the implementation is trivial (minus
regression test adjustments), and is, IMSNSHO, the right solution.

yes, it is right way - the behave of RAISE statement will be much more
cleaner

Several of the source level comments need some minor wordsmithing and
the GUCs are missing documentation. If we've got consensus on the
approach, I'll pitch in on that.

thank you

revised patch attached. added GUC docs and cleaned up pg_settings
language. Also tested patch and it works beautifully.

Note, Pavel's patch does adjust default behavior to what we think is
the "right" settings.

Thank you for documentation.

There is small error - default for client_min_context is error - not

notice.

With this level a diff from regress tests is minimal. Default for
log_min_context should be warning.

whoop! thanks. Also, I was playing a bit with the idea of making
client_min_context "superuser only" setting. The idea being this
could be used to prevent leakage of stored procedure code in cases
where the admins don't want it to be exposed. I figured it was a bad
idea though; it would frustrate debugging in reasonable cases.

This is not designed for security usage. Probably there can be some rule in
future - the possibility to see or don't see a error context - OFF, ON.
For this reason, the setting a some min level is not good way.

Regards

Pavel

Show quoted text

merlin

#88Pavel Stehule
pavel.stehule@gmail.com
In reply to: Pavel Stehule (#87)
Re: PL/pgSQL, RAISE and error context

2015-07-09 23:16 GMT+02:00 Pavel Stehule <pavel.stehule@gmail.com>:

2015-07-09 22:57 GMT+02:00 Merlin Moncure <mmoncure@gmail.com>:

On Thu, Jul 9, 2015 at 3:31 PM, Pavel Stehule <pavel.stehule@gmail.com>
wrote:

2015-07-09 20:08 GMT+02:00 Merlin Moncure <mmoncure@gmail.com>:

On Thu, Jul 9, 2015 at 10:48 AM, Pavel Stehule <

pavel.stehule@gmail.com>

wrote:

2015-07-09 15:17 GMT+02:00 Merlin Moncure <mmoncure@gmail.com>:

On Wed, Jul 8, 2015 at 11:28 PM, Pavel Stehule
<pavel.stehule@gmail.com>

wrote:

Hi

second version of this patch

make check-world passed

quickly scanning the patch, the implementation is trivial (minus
regression test adjustments), and is, IMSNSHO, the right solution.

yes, it is right way - the behave of RAISE statement will be much

more

cleaner

Several of the source level comments need some minor wordsmithing

and

the GUCs are missing documentation. If we've got consensus on the
approach, I'll pitch in on that.

thank you

revised patch attached. added GUC docs and cleaned up pg_settings
language. Also tested patch and it works beautifully.

Note, Pavel's patch does adjust default behavior to what we think is
the "right" settings.

Thank you for documentation.

There is small error - default for client_min_context is error - not

notice.

With this level a diff from regress tests is minimal. Default for
log_min_context should be warning.

whoop! thanks. Also, I was playing a bit with the idea of making
client_min_context "superuser only" setting. The idea being this
could be used to prevent leakage of stored procedure code in cases
where the admins don't want it to be exposed. I figured it was a bad
idea though; it would frustrate debugging in reasonable cases.

This is not designed for security usage. Probably there can be some rule
in future - the possibility to see or don't see a error context - OFF, ON.
For this reason, the setting a some min level is not good way.

Hi

where we are with this patch? Can I do some for it?

Regards

Pavel

Show quoted text

Regards

Pavel

merlin

#89Heikki Linnakangas
hlinnaka@iki.fi
In reply to: Pavel Stehule (#88)
Re: PL/pgSQL, RAISE and error context

On 07/21/2015 10:38 AM, Pavel Stehule wrote:

where we are with this patch? Can I do some for it?

I still feel this approach is misguided, and we should be tweaking psql
and/or libpq instead. I don't feel strongly though, and if some other
committer wants to pick this up in its current form, I won't object. So
this patch has reached an impasse, and if no-one else wants to pick this
up, I'm going to mark this as "Returned with Feedback" and move on.
- Heikki

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#90Pavel Stehule
pavel.stehule@gmail.com
In reply to: Heikki Linnakangas (#89)
Re: PL/pgSQL, RAISE and error context

2015-07-21 9:53 GMT+02:00 Heikki Linnakangas <hlinnaka@iki.fi>:

On 07/21/2015 10:38 AM, Pavel Stehule wrote:

where we are with this patch? Can I do some for it?

I still feel this approach is misguided, and we should be tweaking psql
and/or libpq instead. I don't feel strongly though, and if some other
committer wants to pick this up in its current form, I won't object. So
this patch has reached an impasse, and if no-one else wants to pick this
up, I'm going to mark this as "Returned with Feedback" and move on.

Can we define, when we have a agreement and where not? The missing context
for RAISE EXCEPTION statement is a important issue and I would to solve it.

last patch has two parts:

1. remove plpgsql fix, that remove context for plpgsql RAISE statement - it
is working good enough for less NOTICE level, and work badly for EXCEPTION
and higher level.

2. enforce filtering of CONTEXT field on both sides (client/log)

For me, @1 is important and good solution (because there is strange
inconsistency between PLpgSQL and any other PL), @2 allows more ways - but
probably log_min_context (WARNING) is good idea too.

The advantage of context filtering on server side (client_min_message) is
one - it can be controlled by plpgsql - so I can do dynamic decision if
some NOTICE will have context or not.

The complexity will be +/- same for psql/libpq or for server side filtering.

Regards

Pavel

Show quoted text

- Heikki

#91Merlin Moncure
mmoncure@gmail.com
In reply to: Heikki Linnakangas (#89)
Re: PL/pgSQL, RAISE and error context

On Tue, Jul 21, 2015 at 2:53 AM, Heikki Linnakangas <hlinnaka@iki.fi> wrote:

On 07/21/2015 10:38 AM, Pavel Stehule wrote:

where we are with this patch? Can I do some for it?

I still feel this approach is misguided, and we should be tweaking psql
and/or libpq instead. I don't feel strongly though, and if some other
committer wants to pick this up in its current form, I won't object. So this
patch has reached an impasse, and if no-one else wants to pick this up, I'm
going to mark this as "Returned with Feedback" and move on.

That's unfortunate. Maybe I'm missing something:

What does a client side implementation offer that a server side
implementation does not offer?

merlin

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#92Pavel Stehule
pavel.stehule@gmail.com
In reply to: Merlin Moncure (#91)
Re: PL/pgSQL, RAISE and error context

2015-07-21 16:58 GMT+02:00 Merlin Moncure <mmoncure@gmail.com>:

On Tue, Jul 21, 2015 at 2:53 AM, Heikki Linnakangas <hlinnaka@iki.fi>
wrote:

On 07/21/2015 10:38 AM, Pavel Stehule wrote:

where we are with this patch? Can I do some for it?

I still feel this approach is misguided, and we should be tweaking psql
and/or libpq instead. I don't feel strongly though, and if some other
committer wants to pick this up in its current form, I won't object. So

this

patch has reached an impasse, and if no-one else wants to pick this up,

I'm

going to mark this as "Returned with Feedback" and move on.

That's unfortunate. Maybe I'm missing something:

What does a client side implementation offer that a server side
implementation does not offer?

I have not any problem to change the filtering to client side. Primary
question is fix of PLpgSQL RAISE statement issue - The context field
filtering is a necessary follow-up and trivial in both cases.

In this case, it is acceptable for all?

Regards

Pavel

Show quoted text

merlin

#93Pavel Stehule
pavel.stehule@gmail.com
In reply to: Pavel Stehule (#92)
1 attachment(s)
Re: PL/pgSQL, RAISE and error context

Hi

I am sending a next variant of filtering context patch.

postgres=# do $$ begin raise notice 'kuku'; end $$;
NOTICE: kuku
DO
Time: 2.441 ms
postgres=# do $$ begin raise exception 'kuku'; end $$;
ERROR: kuku
CONTEXT: PL/pgSQL function inline_code_block line 1 at RAISE
Time: 0.648 ms
postgres=# \set SHOW_CONTEXT always
postgres=# do $$ begin raise notice 'kuku'; end $$;
NOTICE: kuku
CONTEXT: PL/pgSQL function inline_code_block line 1 at RAISE
DO
Time: 0.702 ms

It is a variant, when I try to filter CONTEXT in libpq. There is little bit
less granularity on libpq side than server side, but still it is enough -
always, error, none.

This patch is without documentation, but basic regress tests works.

Regards

Pavel

2015-07-25 10:01 GMT+02:00 Pavel Stehule <pavel.stehule@gmail.com>:

Show quoted text

2015-07-21 16:58 GMT+02:00 Merlin Moncure <mmoncure@gmail.com>:

On Tue, Jul 21, 2015 at 2:53 AM, Heikki Linnakangas <hlinnaka@iki.fi>
wrote:

On 07/21/2015 10:38 AM, Pavel Stehule wrote:

where we are with this patch? Can I do some for it?

I still feel this approach is misguided, and we should be tweaking psql
and/or libpq instead. I don't feel strongly though, and if some other
committer wants to pick this up in its current form, I won't object. So

this

patch has reached an impasse, and if no-one else wants to pick this up,

I'm

going to mark this as "Returned with Feedback" and move on.

That's unfortunate. Maybe I'm missing something:

What does a client side implementation offer that a server side
implementation does not offer?

I have not any problem to change the filtering to client side. Primary
question is fix of PLpgSQL RAISE statement issue - The context field
filtering is a necessary follow-up and trivial in both cases.

In this case, it is acceptable for all?

Regards

Pavel

merlin

Attachments:

libpq-context-filter.patchtext/x-patch; charset=US-ASCII; name=libpq-context-filter.patchDownload
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
new file mode 100644
index 6181a61..7168809
*** a/src/bin/psql/command.c
--- b/src/bin/psql/command.c
*************** SyncVariables(void)
*** 2029,2034 ****
--- 2029,2035 ----
  
  	/* send stuff to it, too */
  	PQsetErrorVerbosity(pset.db, pset.verbosity);
+ 	PQsetErrorContextVisibility(pset.db, pset.show_context);
  }
  
  /*
diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c
new file mode 100644
index d3e3114..0bc97de
*** a/src/bin/psql/help.c
--- b/src/bin/psql/help.c
*************** helpVariables(unsigned short int pager)
*** 307,313 ****
  {
  	FILE	   *output;
  
! 	output = PageOutput(85, pager ? &(pset.popt.topt) : NULL);
  
  	fprintf(output, _("List of specially treated variables.\n"));
  
--- 307,313 ----
  {
  	FILE	   *output;
  
! 	output = PageOutput(86, pager ? &(pset.popt.topt) : NULL);
  
  	fprintf(output, _("List of specially treated variables.\n"));
  
*************** helpVariables(unsigned short int pager)
*** 339,344 ****
--- 339,345 ----
  	fprintf(output, _("  PROMPT2            specify the prompt used when a statement continues from a previous line\n"));
  	fprintf(output, _("  PROMPT3            specify the prompt used during COPY ... FROM STDIN\n"));
  	fprintf(output, _("  QUIET              run quietly (same as -q option)\n"));
+ 	fprintf(output, _("  SHOW_CONTEXT       when a error context will be displayed [always, error, none]\n"));
  	fprintf(output, _("  SINGLELINE         end of line terminates SQL command mode (same as -S option)\n"));
  	fprintf(output, _("  SINGLESTEP         single-step mode (same as -s option)\n"));
  	fprintf(output, _("  USER               the currently connected database user\n"));
diff --git a/src/bin/psql/settings.h b/src/bin/psql/settings.h
new file mode 100644
index d34dc28..5b49059
*** a/src/bin/psql/settings.h
--- b/src/bin/psql/settings.h
*************** typedef struct _psqlSettings
*** 129,134 ****
--- 129,135 ----
  	const char *prompt2;
  	const char *prompt3;
  	PGVerbosity verbosity;		/* current error verbosity level */
+ 	bool		show_context;
  } PsqlSettings;
  
  extern PsqlSettings pset;
diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c
new file mode 100644
index 28ba75a..534c914
*** a/src/bin/psql/startup.c
--- b/src/bin/psql/startup.c
*************** main(int argc, char *argv[])
*** 157,162 ****
--- 157,163 ----
  	SetVariable(pset.vars, "PROMPT1", DEFAULT_PROMPT1);
  	SetVariable(pset.vars, "PROMPT2", DEFAULT_PROMPT2);
  	SetVariable(pset.vars, "PROMPT3", DEFAULT_PROMPT3);
+ 	SetVariable(pset.vars, "SHOW_CONTEXT", "error");;
  
  	parse_psql_options(argc, argv, &options);
  
*************** verbosity_hook(const char *newval)
*** 868,873 ****
--- 869,895 ----
  		PQsetErrorVerbosity(pset.db, pset.verbosity);
  }
  
+ static void
+ show_context_hook(const char *newval)
+ {
+ 	if (newval == NULL)
+ 		pset.show_context = PQSHOW_CONTEXT_ERROR;
+ 	else if (pg_strcasecmp(newval, "always") == 0)
+ 		pset.show_context = PQSHOW_CONTEXT_ALL;
+ 	else if (pg_strcasecmp(newval, "error") == 0)
+ 		pset.show_context = PQSHOW_CONTEXT_ERROR;
+ 	else if (pg_strcasecmp(newval, "none") == 0)
+ 		pset.show_context = PQSHOW_CONTEXT_NONE;
+ 	else
+ 	{
+ 		psql_error("unrecognized value \"%s\" for \"%s\"; assuming \"%s\"\n",
+ 				   newval, "SHOW_CONTEXT", "error");
+ 		pset.show_context = PQSHOW_CONTEXT_ERROR;
+ 	}
+ 
+ 	if (pset.db)
+ 		PQsetErrorContextVisibility(pset.db, pset.show_context);
+ }
  
  static void
  EstablishVariableSpace(void)
*************** EstablishVariableSpace(void)
*** 889,892 ****
--- 911,915 ----
  	SetVariableAssignHook(pset.vars, "PROMPT2", prompt2_hook);
  	SetVariableAssignHook(pset.vars, "PROMPT3", prompt3_hook);
  	SetVariableAssignHook(pset.vars, "VERBOSITY", verbosity_hook);
+ 	SetVariableAssignHook(pset.vars, "SHOW_CONTEXT", show_context_hook);
  }
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
new file mode 100644
index 9596af6..681e561
*** a/src/bin/psql/tab-complete.c
--- b/src/bin/psql/tab-complete.c
*************** psql_completion(const char *text, int st
*** 3934,3939 ****
--- 3934,3946 ----
  			COMPLETE_WITH_LIST_CS(boolean_value_list);
  		else if (strcmp(prev_wd, "SINGLESTEP") == 0)
  			COMPLETE_WITH_LIST_CS(boolean_value_list);
+ 		else if (strcmp(prev_wd, "SHOW_CONTEXT") == 0)
+ 		{
+ 			static const char *const my_list[] =
+ 			{"always", "error", "none", NULL};
+ 
+ 			COMPLETE_WITH_LIST_CS(my_list);
+ 		}
  		else if (strcmp(prev_wd, "VERBOSITY") == 0)
  		{
  			static const char *const my_list[] =
diff --git a/src/interfaces/libpq/exports.txt b/src/interfaces/libpq/exports.txt
new file mode 100644
index 4a21bf1..0bbcae5
*** a/src/interfaces/libpq/exports.txt
--- b/src/interfaces/libpq/exports.txt
*************** PQsslInUse                166
*** 169,171 ****
--- 169,172 ----
  PQsslStruct               167
  PQsslAttributes           168
  PQsslAttribute            169
+ PQsetErrorContextVisibility 170
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
new file mode 100644
index a45f4cb..81d6eb4
*** a/src/interfaces/libpq/fe-connect.c
--- b/src/interfaces/libpq/fe-connect.c
*************** PQsetErrorVerbosity(PGconn *conn, PGVerb
*** 5553,5558 ****
--- 5553,5570 ----
  	return old;
  }
  
+ PGContextVisibility
+ PQsetErrorContextVisibility(PGconn *conn, PGContextVisibility show_context)
+ {
+ 	bool	old;
+ 
+ 	if (!conn)
+ 		return PQSHOW_CONTEXT_ERROR;;
+ 	old = conn->show_context;
+ 	conn->show_context = show_context;
+ 	return old;
+ }
+ 
  void
  PQtrace(PGconn *conn, FILE *debug_port)
  {
diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c
new file mode 100644
index dbc0d89..38fa9ad
*** a/src/interfaces/libpq/fe-protocol3.c
--- b/src/interfaces/libpq/fe-protocol3.c
*************** pqGetErrorNotice3(PGconn *conn, bool isE
*** 935,941 ****
  		if (val)
  			appendPQExpBuffer(&workBuf, libpq_gettext("QUERY:  %s\n"), val);
  		val = PQresultErrorField(res, PG_DIAG_CONTEXT);
! 		if (val)
  			appendPQExpBuffer(&workBuf, libpq_gettext("CONTEXT:  %s\n"), val);
  	}
  	if (conn->verbosity == PQERRORS_VERBOSE)
--- 935,942 ----
  		if (val)
  			appendPQExpBuffer(&workBuf, libpq_gettext("QUERY:  %s\n"), val);
  		val = PQresultErrorField(res, PG_DIAG_CONTEXT);
! 		if (val && (conn->show_context == PQSHOW_CONTEXT_ALL
! 				 || (conn->show_context == PQSHOW_CONTEXT_ERROR && isError)))
  			appendPQExpBuffer(&workBuf, libpq_gettext("CONTEXT:  %s\n"), val);
  	}
  	if (conn->verbosity == PQERRORS_VERBOSE)
diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h
new file mode 100644
index a73eae2..030ad59
*** a/src/interfaces/libpq/libpq-fe.h
--- b/src/interfaces/libpq/libpq-fe.h
*************** typedef enum
*** 110,115 ****
--- 110,122 ----
  	PQERRORS_VERBOSE			/* all the facts, ma'am */
  } PGVerbosity;
  
+ typedef enum
+ {
+ 	PQSHOW_CONTEXT_ALL,		/* errors, warnings, notices */
+ 	PQSHOW_CONTEXT_ERROR,		/* errors only, default */
+ 	PQSHOW_CONTEXT_NONE		/* hide error context */
+ } PGContextVisibility;
+ 
  /*
   * PGPing - The ordering of this enum should not be altered because the
   * values are exposed externally via pg_isready.
*************** extern void PQinitOpenSSL(int do_ssl, in
*** 337,342 ****
--- 344,353 ----
  /* Set verbosity for PQerrorMessage and PQresultErrorMessage */
  extern PGVerbosity PQsetErrorVerbosity(PGconn *conn, PGVerbosity verbosity);
  
+ /* Hide a context of error message */
+ extern PGContextVisibility PQsetErrorContextVisibility(PGconn *conn,
+ 						    PGContextVisibility show_context);
+ 
  /* Enable/disable tracing */
  extern void PQtrace(PGconn *conn, FILE *debug_port);
  extern void PQuntrace(PGconn *conn);
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
new file mode 100644
index 2175957..0c5e4b5
*** a/src/interfaces/libpq/libpq-int.h
--- b/src/interfaces/libpq/libpq-int.h
*************** struct pg_conn
*** 395,400 ****
--- 395,401 ----
  	bool		std_strings;	/* standard_conforming_strings */
  	PGVerbosity verbosity;		/* error/notice message verbosity */
  	PGlobjfuncs *lobjfuncs;		/* private state for large-object access fns */
+ 	PGContextVisibility	show_context;	/* controll a error context visibility */
  
  	/* Buffer for data received from backend and not yet processed */
  	char	   *inBuffer;		/* currently allocated buffer */
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
new file mode 100644
index b7f6360..60e5d8d
*** a/src/pl/plpgsql/src/pl_exec.c
--- b/src/pl/plpgsql/src/pl_exec.c
***************
*** 42,49 ****
  #include "utils/typcache.h"
  
  
- static const char *const raise_skip_msg = "RAISE";
- 
  typedef struct
  {
  	int			nargs;			/* number of arguments */
--- 42,47 ----
*************** plpgsql_exec_error_callback(void *arg)
*** 957,966 ****
  {
  	PLpgSQL_execstate *estate = (PLpgSQL_execstate *) arg;
  
- 	/* if we are doing RAISE, don't report its location */
- 	if (estate->err_text == raise_skip_msg)
- 		return;
- 
  	if (estate->err_text != NULL)
  	{
  		/*
--- 955,960 ----
*************** exec_stmt_raise(PLpgSQL_execstate *estat
*** 3176,3183 ****
  	/*
  	 * Throw the error (may or may not come back)
  	 */
- 	estate->err_text = raise_skip_msg;	/* suppress traceback of raise */
- 
  	ereport(stmt->elog_level,
  			(err_code ? errcode(err_code) : 0,
  			 errmsg_internal("%s", err_message),
--- 3170,3175 ----
diff --git a/src/test/regress/expected/copy2.out b/src/test/regress/expected/copy2.out
new file mode 100644
index 5e31737..72ada21
*** a/src/test/regress/expected/copy2.out
--- b/src/test/regress/expected/copy2.out
*************** Check constraints:
*** 447,458 ****
  
  copy check_con_tbl from stdin;
  NOTICE:  input = {"f1":1}
- CONTEXT:  COPY check_con_tbl, line 1: "1"
  NOTICE:  input = {"f1":null}
- CONTEXT:  COPY check_con_tbl, line 2: "\N"
  copy check_con_tbl from stdin;
  NOTICE:  input = {"f1":0}
- CONTEXT:  COPY check_con_tbl, line 1: "0"
  ERROR:  new row for relation "check_con_tbl" violates check constraint "check_con_tbl_check"
  DETAIL:  Failing row contains (0).
  CONTEXT:  COPY check_con_tbl, line 1: "0"
--- 447,455 ----
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
new file mode 100644
index e70c315..05ac0ad
*** a/src/test/regress/expected/event_trigger.out
--- b/src/test/regress/expected/event_trigger.out
*************** drop cascades to table schema_one.table_
*** 234,248 ****
  drop cascades to table schema_one."table two"
  drop cascades to table schema_one.table_three
  NOTICE:  table "schema_two_table_two" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_two"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "audit_tbls_schema_two_table_three" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.audit_tbls_schema_two_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
- SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  ERROR:  object audit_tbls.schema_two_table_three of type table cannot be dropped
! CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three"
  PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  DELETE FROM undroppable_objs WHERE object_identity = 'audit_tbls.schema_two_table_three';
  DROP SCHEMA schema_one, schema_two CASCADE;
--- 234,243 ----
  drop cascades to table schema_one."table two"
  drop cascades to table schema_one.table_three
  NOTICE:  table "schema_two_table_two" does not exist, skipping
  NOTICE:  table "audit_tbls_schema_two_table_three" does not exist, skipping
  ERROR:  object audit_tbls.schema_two_table_three of type table cannot be dropped
! CONTEXT:  PL/pgSQL function undroppable() line 14 at RAISE
! SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three"
  PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  DELETE FROM undroppable_objs WHERE object_identity = 'audit_tbls.schema_two_table_three';
  DROP SCHEMA schema_one, schema_two CASCADE;
*************** drop cascades to table schema_one.table_
*** 255,277 ****
  drop cascades to table schema_one."table two"
  drop cascades to table schema_one.table_three
  NOTICE:  table "schema_two_table_two" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_two"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "audit_tbls_schema_two_table_three" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.audit_tbls_schema_two_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
- SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "schema_one_table_one" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_one_table_one"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "schema_one_table two" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls."schema_one_table two""
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "schema_one_table_three" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_one_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  ERROR:  object schema_one.table_three of type table cannot be dropped
  DELETE FROM undroppable_objs WHERE object_identity = 'schema_one.table_three';
  DROP SCHEMA schema_one, schema_two CASCADE;
  NOTICE:  drop cascades to 7 other objects
--- 250,261 ----
  drop cascades to table schema_one."table two"
  drop cascades to table schema_one.table_three
  NOTICE:  table "schema_two_table_two" does not exist, skipping
  NOTICE:  table "audit_tbls_schema_two_table_three" does not exist, skipping
  NOTICE:  table "schema_one_table_one" does not exist, skipping
  NOTICE:  table "schema_one_table two" does not exist, skipping
  NOTICE:  table "schema_one_table_three" does not exist, skipping
  ERROR:  object schema_one.table_three of type table cannot be dropped
+ CONTEXT:  PL/pgSQL function undroppable() line 14 at RAISE
  DELETE FROM undroppable_objs WHERE object_identity = 'schema_one.table_three';
  DROP SCHEMA schema_one, schema_two CASCADE;
  NOTICE:  drop cascades to 7 other objects
*************** drop cascades to table schema_one.table_
*** 283,304 ****
  drop cascades to table schema_one."table two"
  drop cascades to table schema_one.table_three
  NOTICE:  table "schema_two_table_two" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_two"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "audit_tbls_schema_two_table_three" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.audit_tbls_schema_two_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
- SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_two_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "schema_one_table_one" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_one_table_one"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "schema_one_table two" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls."schema_one_table two""
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  NOTICE:  table "schema_one_table_three" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.schema_one_table_three"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  SELECT * FROM dropped_objects WHERE schema IS NULL OR schema <> 'pg_toast';
       type     |   schema   |               object                
  --------------+------------+-------------------------------------
--- 267,276 ----
*************** SELECT * FROM dropped_objects WHERE sche
*** 329,336 ****
  
  DROP OWNED BY regression_bob;
  NOTICE:  schema "audit_tbls" does not exist, skipping
- CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.audit_tbls_schema_one_table_two"
- PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
  SELECT * FROM dropped_objects WHERE type = 'schema';
    type  | schema |   object   
  --------+--------+------------
--- 301,306 ----
*************** insert into rewriteme
*** 402,409 ****
--- 372,381 ----
       select x * 1.001 from generate_series(1, 500) as t(x);
  alter table rewriteme alter column foo type numeric;
  ERROR:  I'm sorry Sir, No Rewrite Allowed.
+ CONTEXT:  PL/pgSQL function test_evtrig_no_rewrite() line 3 at RAISE
  alter table rewriteme add column baz int default 0;
  ERROR:  I'm sorry Sir, No Rewrite Allowed.
+ CONTEXT:  PL/pgSQL function test_evtrig_no_rewrite() line 3 at RAISE
  -- test with more than one reason to rewrite a single table
  CREATE OR REPLACE FUNCTION test_evtrig_no_rewrite() RETURNS event_trigger
  LANGUAGE plpgsql AS $$
diff --git a/src/test/regress/expected/plancache.out b/src/test/regress/expected/plancache.out
new file mode 100644
index 864f70f..3f3db33
*** a/src/test/regress/expected/plancache.out
--- b/src/test/regress/expected/plancache.out
*************** begin
*** 234,241 ****
  end$$ language plpgsql;
  select cachebug();
  NOTICE:  table "temptable" does not exist, skipping
- CONTEXT:  SQL statement "drop table if exists temptable cascade"
- PL/pgSQL function cachebug() line 4 at SQL statement
  NOTICE:  1
  NOTICE:  2
  NOTICE:  3
--- 234,239 ----
*************** NOTICE:  3
*** 246,253 ****
  
  select cachebug();
  NOTICE:  drop cascades to view vv
- CONTEXT:  SQL statement "drop table if exists temptable cascade"
- PL/pgSQL function cachebug() line 4 at SQL statement
  NOTICE:  1
  NOTICE:  2
  NOTICE:  3
--- 244,249 ----
diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out
new file mode 100644
index 31182db..97105e5
*** a/src/test/regress/expected/plpgsql.out
--- b/src/test/regress/expected/plpgsql.out
*************** ERROR:  duplicate key value violates uni
*** 1518,1544 ****
  DETAIL:  Key (name)=(PF1_1) already exists.
  update PSlot set backlink = 'WS.not.there' where slotname = 'PS.base.a1';
  ERROR:  WS.not.there         does not exist
! CONTEXT:  PL/pgSQL function tg_backlink_a() line 17 at assignment
  update PSlot set backlink = 'XX.illegal' where slotname = 'PS.base.a1';
  ERROR:  illegal backlink beginning with XX
! CONTEXT:  PL/pgSQL function tg_backlink_a() line 17 at assignment
  update PSlot set slotlink = 'PS.not.there' where slotname = 'PS.base.a1';
  ERROR:  PS.not.there         does not exist
! CONTEXT:  PL/pgSQL function tg_slotlink_a() line 17 at assignment
  update PSlot set slotlink = 'XX.illegal' where slotname = 'PS.base.a1';
  ERROR:  illegal slotlink beginning with XX
! CONTEXT:  PL/pgSQL function tg_slotlink_a() line 17 at assignment
  insert into HSlot values ('HS', 'base.hub1', 1, '');
  ERROR:  duplicate key value violates unique constraint "hslot_name"
  DETAIL:  Key (slotname)=(HS.base.hub1.1      ) already exists.
  insert into HSlot values ('HS', 'base.hub1', 20, '');
  ERROR:  no manual manipulation of HSlot
  delete from HSlot;
  ERROR:  no manual manipulation of HSlot
  insert into IFace values ('IF', 'notthere', 'eth0', '');
  ERROR:  system "notthere" does not exist
  insert into IFace values ('IF', 'orion', 'ethernet_interface_name_too_long', '');
  ERROR:  IFace slotname "IF.orion.ethernet_interface_name_too_long" too long (20 char max)
  --
  -- The following tests are unrelated to the scenario outlined above;
  -- they merely exercise specific parts of PL/pgSQL
--- 1518,1552 ----
  DETAIL:  Key (name)=(PF1_1) already exists.
  update PSlot set backlink = 'WS.not.there' where slotname = 'PS.base.a1';
  ERROR:  WS.not.there         does not exist
! CONTEXT:  PL/pgSQL function tg_backlink_set(character,character) line 30 at RAISE
! PL/pgSQL function tg_backlink_a() line 17 at assignment
  update PSlot set backlink = 'XX.illegal' where slotname = 'PS.base.a1';
  ERROR:  illegal backlink beginning with XX
! CONTEXT:  PL/pgSQL function tg_backlink_set(character,character) line 47 at RAISE
! PL/pgSQL function tg_backlink_a() line 17 at assignment
  update PSlot set slotlink = 'PS.not.there' where slotname = 'PS.base.a1';
  ERROR:  PS.not.there         does not exist
! CONTEXT:  PL/pgSQL function tg_slotlink_set(character,character) line 30 at RAISE
! PL/pgSQL function tg_slotlink_a() line 17 at assignment
  update PSlot set slotlink = 'XX.illegal' where slotname = 'PS.base.a1';
  ERROR:  illegal slotlink beginning with XX
! CONTEXT:  PL/pgSQL function tg_slotlink_set(character,character) line 77 at RAISE
! PL/pgSQL function tg_slotlink_a() line 17 at assignment
  insert into HSlot values ('HS', 'base.hub1', 1, '');
  ERROR:  duplicate key value violates unique constraint "hslot_name"
  DETAIL:  Key (slotname)=(HS.base.hub1.1      ) already exists.
  insert into HSlot values ('HS', 'base.hub1', 20, '');
  ERROR:  no manual manipulation of HSlot
+ CONTEXT:  PL/pgSQL function tg_hslot_biu() line 12 at RAISE
  delete from HSlot;
  ERROR:  no manual manipulation of HSlot
+ CONTEXT:  PL/pgSQL function tg_hslot_bd() line 12 at RAISE
  insert into IFace values ('IF', 'notthere', 'eth0', '');
  ERROR:  system "notthere" does not exist
+ CONTEXT:  PL/pgSQL function tg_iface_biu() line 8 at RAISE
  insert into IFace values ('IF', 'orion', 'ethernet_interface_name_too_long', '');
  ERROR:  IFace slotname "IF.orion.ethernet_interface_name_too_long" too long (20 char max)
+ CONTEXT:  PL/pgSQL function tg_iface_biu() line 14 at RAISE
  --
  -- The following tests are unrelated to the scenario outlined above;
  -- they merely exercise specific parts of PL/pgSQL
*************** NOTICE:  should see this
*** 1963,1968 ****
--- 1971,1977 ----
  NOTICE:  should see this only if -100 <> 0
  NOTICE:  should see this only if -100 fits in smallint
  ERROR:  -100 is less than zero
+ CONTEXT:  PL/pgSQL function trap_zero_divide(integer) line 12 at RAISE
  create function trap_matching_test(int) returns int as $$
  declare x int;
  	sx smallint;
*************** begin
*** 2066,2079 ****
  end$$ language plpgsql;
  select test_variable_storage();
  NOTICE:  should see this
- CONTEXT:  SQL statement "SELECT trap_zero_divide(-100)"
- PL/pgSQL function test_variable_storage() line 8 at PERFORM
  NOTICE:  should see this only if -100 <> 0
- CONTEXT:  SQL statement "SELECT trap_zero_divide(-100)"
- PL/pgSQL function test_variable_storage() line 8 at PERFORM
  NOTICE:  should see this only if -100 fits in smallint
- CONTEXT:  SQL statement "SELECT trap_zero_divide(-100)"
- PL/pgSQL function test_variable_storage() line 8 at PERFORM
   test_variable_storage 
  -----------------------
   123456789012
--- 2075,2082 ----
*************** DETAIL:  some detail info
*** 4052,4057 ****
--- 4055,4061 ----
  HINT:  some hint
  ERROR:  1 2 3
  DETAIL:  some detail info
+ CONTEXT:  PL/pgSQL function raise_test() line 5 at RAISE
  -- Since we can't actually see the thrown SQLSTATE in default psql output,
  -- test it like this; this also tests re-RAISE
  create or replace function raise_test() returns void as $$
*************** select raise_test();
*** 4068,4073 ****
--- 4072,4078 ----
  NOTICE:  SQLSTATE: 22012 SQLERRM: check me
  ERROR:  check me
  DETAIL:  some detail info
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise 'check me'
*************** select raise_test();
*** 4082,4087 ****
--- 4087,4093 ----
  NOTICE:  SQLSTATE: 1234F SQLERRM: check me
  ERROR:  check me
  DETAIL:  some detail info
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  -- SQLSTATE specification in WHEN
  create or replace function raise_test() returns void as $$
  begin
*************** select raise_test();
*** 4097,4102 ****
--- 4103,4109 ----
  NOTICE:  SQLSTATE: 1234F SQLERRM: check me
  ERROR:  check me
  DETAIL:  some detail info
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise division_by_zero using detail = 'some detail info';
*************** select raise_test();
*** 4110,4115 ****
--- 4117,4123 ----
  NOTICE:  SQLSTATE: 22012 SQLERRM: division_by_zero
  ERROR:  division_by_zero
  DETAIL:  some detail info
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise division_by_zero;
*************** end;
*** 4117,4122 ****
--- 4125,4131 ----
  $$ language plpgsql;
  select raise_test();
  ERROR:  division_by_zero
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise sqlstate '1234F';
*************** end;
*** 4124,4129 ****
--- 4133,4139 ----
  $$ language plpgsql;
  select raise_test();
  ERROR:  1234F
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise division_by_zero using message = 'custom' || ' message';
*************** end;
*** 4131,4136 ****
--- 4141,4147 ----
  $$ language plpgsql;
  select raise_test();
  ERROR:  custom message
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  create or replace function raise_test() returns void as $$
  begin
    raise using message = 'custom' || ' message', errcode = '22012';
*************** end;
*** 4138,4143 ****
--- 4149,4155 ----
  $$ language plpgsql;
  select raise_test();
  ERROR:  custom message
+ CONTEXT:  PL/pgSQL function raise_test() line 3 at RAISE
  -- conflict on message
  create or replace function raise_test() returns void as $$
  begin
*************** $$ language plpgsql;
*** 4254,4259 ****
--- 4266,4272 ----
  select raise_test();
  NOTICE:  22012
  ERROR:  substitute message
+ CONTEXT:  PL/pgSQL function raise_test() line 7 at RAISE
  drop function raise_test();
  -- test passing column_name, constraint_name, datatype_name, table_name
  -- and schema_name error fields
*************** LINE 1: SELECT 'foo\\bar\041baz'
*** 4806,4812 ****
                 ^
  HINT:  Use the escape string syntax for backslashes, e.g., E'\\'.
  QUERY:  SELECT 'foo\\bar\041baz'
- CONTEXT:  PL/pgSQL function strtest() line 4 at RETURN
     strtest   
  -------------
   foo\bar!baz
--- 4819,4824 ----
*************** $$ language plpgsql;
*** 5322,5343 ****
  select outer_outer_func(10);
  NOTICE:  calling down into outer_func()
  NOTICE:  calling down into inner_func()
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 4 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 7 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  lets make sure we didnt break anything
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  inner_func() done
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  outer_func() done
   outer_outer_func 
  ------------------
--- 5334,5347 ----
*************** NOTICE:  outer_func() done
*** 5348,5369 ****
  select outer_outer_func(20);
  NOTICE:  calling down into outer_func()
  NOTICE:  calling down into inner_func()
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 4 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 7 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  lets make sure we didnt break anything
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  inner_func() done
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  outer_func() done
   outer_outer_func 
  ------------------
--- 5352,5365 ----
*************** $$ language plpgsql;
*** 5420,5441 ****
  select outer_outer_func(10);
  NOTICE:  calling down into outer_func()
  NOTICE:  calling down into inner_func()
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 10 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 15 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  lets make sure we didnt break anything
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  inner_func() done
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  outer_func() done
   outer_outer_func 
  ------------------
--- 5416,5429 ----
*************** NOTICE:  outer_func() done
*** 5446,5467 ****
  select outer_outer_func(20);
  NOTICE:  calling down into outer_func()
  NOTICE:  calling down into inner_func()
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 10 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  ***PL/pgSQL function inner_func(integer) line 15 at GET DIAGNOSTICS
  PL/pgSQL function outer_func(integer) line 6 at assignment
  PL/pgSQL function outer_outer_func(integer) line 6 at assignment***
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  lets make sure we didnt break anything
- CONTEXT:  PL/pgSQL function outer_func(integer) line 6 at assignment
- PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  inner_func() done
- CONTEXT:  PL/pgSQL function outer_outer_func(integer) line 6 at assignment
  NOTICE:  outer_func() done
   outer_outer_func 
  ------------------
--- 5434,5447 ----
diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out
new file mode 100644
index c0cd9fa..88bdc2c
*** a/src/test/regress/expected/privileges.out
--- b/src/test/regress/expected/privileges.out
*************** GRANT regressgroup2 TO regressuser5; --
*** 1023,1029 ****
  ERROR:  must have admin option on role "regressgroup2"
  SELECT dogrant_ok();			-- ok: SECURITY DEFINER conveys ADMIN
  NOTICE:  role "regressuser5" is already a member of role "regressgroup2"
- CONTEXT:  SQL function "dogrant_ok" statement 1
   dogrant_ok 
  ------------
   
--- 1023,1028 ----
diff --git a/src/test/regress/expected/rangefuncs.out b/src/test/regress/expected/rangefuncs.out
new file mode 100644
index 6dabe50..00ef421
*** a/src/test/regress/expected/rangefuncs.out
--- b/src/test/regress/expected/rangefuncs.out
*************** create trigger tnoticetrigger after inse
*** 1704,1712 ****
  execute procedure noticetrigger();
  select insert_tt2('foolme','barme') limit 1;
  NOTICE:  noticetrigger 11 foolme
- CONTEXT:  SQL function "insert_tt2" statement 1
  NOTICE:  noticetrigger 12 barme
- CONTEXT:  SQL function "insert_tt2" statement 1
   insert_tt2 
  ------------
           11
--- 1704,1710 ----
*************** create rule insert_tt_rule as on insert
*** 1735,1743 ****
    insert into tt_log values(new.*);
  select insert_tt2('foollog','barlog') limit 1;
  NOTICE:  noticetrigger 13 foollog
- CONTEXT:  SQL function "insert_tt2" statement 1
  NOTICE:  noticetrigger 14 barlog
- CONTEXT:  SQL function "insert_tt2" statement 1
   insert_tt2 
  ------------
           13
--- 1733,1739 ----
diff --git a/src/test/regress/expected/triggers.out b/src/test/regress/expected/triggers.out
new file mode 100644
index 3b32e8f..cd43e46
*** a/src/test/regress/expected/triggers.out
--- b/src/test/regress/expected/triggers.out
*************** NOTICE:  main_view BEFORE INSERT STATEME
*** 958,968 ****
  NOTICE:  main_view INSTEAD OF INSERT ROW (instead_of_ins)
  NOTICE:  NEW: (20,30)
  NOTICE:  trigger_func(before_ins_stmt) called: action = INSERT, when = BEFORE, level = STATEMENT
- CONTEXT:  SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
- PL/pgSQL function view_trigger() line 17 at SQL statement
  NOTICE:  trigger_func(after_ins_stmt) called: action = INSERT, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
- PL/pgSQL function view_trigger() line 17 at SQL statement
  NOTICE:  main_view AFTER INSERT STATEMENT (after_view_ins_stmt)
  INSERT 0 1
  INSERT INTO main_view VALUES (21, 31) RETURNING a, b;
--- 958,964 ----
*************** NOTICE:  main_view BEFORE INSERT STATEME
*** 970,980 ****
  NOTICE:  main_view INSTEAD OF INSERT ROW (instead_of_ins)
  NOTICE:  NEW: (21,31)
  NOTICE:  trigger_func(before_ins_stmt) called: action = INSERT, when = BEFORE, level = STATEMENT
- CONTEXT:  SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
- PL/pgSQL function view_trigger() line 17 at SQL statement
  NOTICE:  trigger_func(after_ins_stmt) called: action = INSERT, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "INSERT INTO main_table VALUES (NEW.a, NEW.b)"
- PL/pgSQL function view_trigger() line 17 at SQL statement
  NOTICE:  main_view AFTER INSERT STATEMENT (after_view_ins_stmt)
   a  | b  
  ----+----
--- 966,972 ----
*************** NOTICE:  main_view BEFORE UPDATE STATEME
*** 988,1004 ****
  NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
  NOTICE:  OLD: (20,30), NEW: (20,31)
  NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
  UPDATE 0
  UPDATE main_view SET b = 32 WHERE a = 21 AND b = 31 RETURNING a, b;
--- 980,988 ----
*************** NOTICE:  main_view BEFORE UPDATE STATEME
*** 1006,1022 ****
  NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
  NOTICE:  OLD: (21,31), NEW: (21,32)
  NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(before_upd_a_row) called: action = UPDATE, when = BEFORE, level = ROW
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
   a | b 
  ---+---
--- 990,998 ----
*************** NOTICE:  main_view BEFORE UPDATE STATEME
*** 1031,1050 ****
  NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
  NOTICE:  OLD: (20,30), NEW: (20,31)
  NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
  UPDATE 1
  UPDATE main_view SET b = 32 WHERE a = 21 AND b = 31 RETURNING a, b;
--- 1007,1016 ----
*************** NOTICE:  main_view BEFORE UPDATE STATEME
*** 1052,1071 ****
  NOTICE:  main_view INSTEAD OF UPDATE ROW (instead_of_upd)
  NOTICE:  OLD: (21,31), NEW: (21,32)
  NOTICE:  trigger_func(before_upd_a_stmt) called: action = UPDATE, when = BEFORE, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER, level = ROW
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
- CONTEXT:  SQL statement "UPDATE main_table SET a = NEW.a, b = NEW.b WHERE a = OLD.a AND b = OLD.b"
- PL/pgSQL function view_trigger() line 23 at SQL statement
  NOTICE:  main_view AFTER UPDATE STATEMENT (after_view_upd_stmt)
   a  | b  
  ----+----
--- 1018,1027 ----
*************** INSERT 0 1
*** 1277,1282 ****
--- 1233,1239 ----
  -- UPDATE .. RETURNING
  UPDATE city_view SET country_name = 'Japon' WHERE city_name = 'Tokyo'; -- error
  ERROR:  No such country: "Japon"
+ CONTEXT:  PL/pgSQL function city_update() line 9 at RAISE
  UPDATE city_view SET country_name = 'Japan' WHERE city_name = 'Takyo'; -- no match
  UPDATE 0
  UPDATE city_view SET country_name = 'Japan' WHERE city_name = 'Tokyo' RETURNING *; -- OK
*************** select pg_trigger_depth();
*** 1489,1514 ****
  insert into depth_a values (1);
  NOTICE:  depth_a_tr: depth = 1
  NOTICE:  depth_b_tr: depth = 2
- CONTEXT:  SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_c_tr: depth = 3
- CONTEXT:  SQL statement "insert into depth_c values (1)"
- PL/pgSQL function depth_b_tf() line 5 at EXECUTE statement
- SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  SQLSTATE = U9999: depth = 2
- CONTEXT:  SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_b_tr: depth = 2
- CONTEXT:  SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_c_tr: depth = 3
- CONTEXT:  SQL statement "insert into depth_c values (1)"
- PL/pgSQL function depth_b_tf() line 12 at EXECUTE statement
- SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  ERROR:  U9999
! CONTEXT:  SQL statement "insert into depth_c values (1)"
  PL/pgSQL function depth_b_tf() line 12 at EXECUTE statement
  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
--- 1446,1458 ----
  insert into depth_a values (1);
  NOTICE:  depth_a_tr: depth = 1
  NOTICE:  depth_b_tr: depth = 2
  NOTICE:  depth_c_tr: depth = 3
  NOTICE:  SQLSTATE = U9999: depth = 2
  NOTICE:  depth_b_tr: depth = 2
  NOTICE:  depth_c_tr: depth = 3
  ERROR:  U9999
! CONTEXT:  PL/pgSQL function depth_c_tf() line 5 at RAISE
! SQL statement "insert into depth_c values (1)"
  PL/pgSQL function depth_b_tf() line 12 at EXECUTE statement
  SQL statement "insert into depth_b values (new.id)"
  PL/pgSQL function depth_a_tf() line 4 at SQL statement
*************** select pg_trigger_depth();
*** 1521,1541 ****
  insert into depth_a values (2);
  NOTICE:  depth_a_tr: depth = 1
  NOTICE:  depth_b_tr: depth = 2
- CONTEXT:  SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_c_tr: depth = 3
- CONTEXT:  SQL statement "insert into depth_c values (2)"
- PL/pgSQL function depth_b_tf() line 5 at EXECUTE statement
- SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_c_tr: depth = 3
- CONTEXT:  SQL statement "insert into depth_c values (2)"
- PL/pgSQL function depth_b_tf() line 5 at EXECUTE statement
- SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_b_tr: depth = 2
- CONTEXT:  SQL statement "insert into depth_b values (new.id)"
- PL/pgSQL function depth_a_tf() line 4 at SQL statement
  NOTICE:  depth_a_tr: depth = 1
  select pg_trigger_depth();
   pg_trigger_depth 
--- 1465,1473 ----
diff --git a/src/test/regress/expected/xml.out b/src/test/regress/expected/xml.out
new file mode 100644
index 9b2d264..5691e47
*** a/src/test/regress/expected/xml.out
--- b/src/test/regress/expected/xml.out
*************** SELECT xpath('/*', '<relativens xmlns=''
*** 934,940 ****
  WARNING:  line 1: xmlns: URI relative is not absolute
  <relativens xmlns='relative'/>
                              ^
- CONTEXT:  SQL function "xpath" statement 1
                  xpath                 
  --------------------------------------
   {"<relativens xmlns=\"relative\"/>"}
--- 934,939 ----
#94Pavel Stehule
pavel.stehule@gmail.com
In reply to: Pavel Stehule (#93)
1 attachment(s)
Re: PL/pgSQL, RAISE and error context

Hi

here is complete patch, that introduce context filtering on client side.
The core of this patch is trivial and small - almost all of size are
trivial changes in regress tests - removing useless context.

Documentation, check-world

Regards

Pavel

2015-07-26 0:42 GMT+02:00 Pavel Stehule <pavel.stehule@gmail.com>:

Show quoted text

Hi

I am sending a next variant of filtering context patch.

postgres=# do $$ begin raise notice 'kuku'; end $$;
NOTICE: kuku
DO
Time: 2.441 ms
postgres=# do $$ begin raise exception 'kuku'; end $$;
ERROR: kuku
CONTEXT: PL/pgSQL function inline_code_block line 1 at RAISE
Time: 0.648 ms
postgres=# \set SHOW_CONTEXT always
postgres=# do $$ begin raise notice 'kuku'; end $$;
NOTICE: kuku
CONTEXT: PL/pgSQL function inline_code_block line 1 at RAISE
DO
Time: 0.702 ms

It is a variant, when I try to filter CONTEXT in libpq. There is little
bit less granularity on libpq side than server side, but still it is enough
- always, error, none.

This patch is without documentation, but basic regress tests works.

Regards

Pavel

2015-07-25 10:01 GMT+02:00 Pavel Stehule <pavel.stehule@gmail.com>:

2015-07-21 16:58 GMT+02:00 Merlin Moncure <mmoncure@gmail.com>:

On Tue, Jul 21, 2015 at 2:53 AM, Heikki Linnakangas <hlinnaka@iki.fi>
wrote:

On 07/21/2015 10:38 AM, Pavel Stehule wrote:

where we are with this patch? Can I do some for it?

I still feel this approach is misguided, and we should be tweaking psql
and/or libpq instead. I don't feel strongly though, and if some other
committer wants to pick this up in its current form, I won't object.

So this

patch has reached an impasse, and if no-one else wants to pick this

up, I'm

going to mark this as "Returned with Feedback" and move on.

That's unfortunate. Maybe I'm missing something:

What does a client side implementation offer that a server side
implementation does not offer?

I have not any problem to change the filtering to client side. Primary
question is fix of PLpgSQL RAISE statement issue - The context field
filtering is a necessary follow-up and trivial in both cases.

In this case, it is acceptable for all?

Regards

Pavel

merlin

Attachments:

libpq-context-filter-20150726-01.patch.gzapplication/x-gzip; name=libpq-context-filter-20150726-01.patch.gzDownload
#95Heikki Linnakangas
hlinnaka@iki.fi
In reply to: Pavel Stehule (#94)
Re: PL/pgSQL, RAISE and error context

On 07/26/2015 08:34 AM, Pavel Stehule wrote:

Hi

here is complete patch, that introduce context filtering on client side.
The core of this patch is trivial and small - almost all of size are
trivial changes in regress tests - removing useless context.

Documentation, check-world

Looks good to me at first glance. I'll mark this as Ready for Committer.

- Heikki

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#96Pavel Stehule
pavel.stehule@gmail.com
In reply to: Heikki Linnakangas (#95)
Re: PL/pgSQL, RAISE and error context

2015-08-10 9:11 GMT+02:00 Heikki Linnakangas <hlinnaka@iki.fi>:

On 07/26/2015 08:34 AM, Pavel Stehule wrote:

Hi

here is complete patch, that introduce context filtering on client side.
The core of this patch is trivial and small - almost all of size are
trivial changes in regress tests - removing useless context.

Documentation, check-world

Looks good to me at first glance. I'll mark this as Ready for Committer.

Is it acceptable for all?

I have not a problem with this way.

Regards

Pavel

Show quoted text

- Heikki

#97Pavel Stehule
pavel.stehule@gmail.com
In reply to: Pavel Stehule (#96)
Re: PL/pgSQL, RAISE and error context

2015-08-10 18:43 GMT+02:00 Pavel Stehule <pavel.stehule@gmail.com>:

2015-08-10 9:11 GMT+02:00 Heikki Linnakangas <hlinnaka@iki.fi>:

On 07/26/2015 08:34 AM, Pavel Stehule wrote:

Hi

here is complete patch, that introduce context filtering on client side.
The core of this patch is trivial and small - almost all of size are
trivial changes in regress tests - removing useless context.

Documentation, check-world

Looks good to me at first glance. I'll mark this as Ready for Committer.

Is it acceptable for all?

I have not a problem with this way.

So, there is common agreement on this version.

Best regards

Pavel

Show quoted text

Regards

Pavel

- Heikki

#98Marko Tiikkaja
marko@joh.to
In reply to: Pavel Stehule (#97)
Re: PL/pgSQL, RAISE and error context

On 8/12/15 9:36 AM, Pavel Stehule wrote:

So, there is common agreement on this version.

There are several instances of double semicolons. Also,
PsqlSettings.show_context doesn't look like a boolean to me. For
SHOW_CONTEXT, it would be good if the documentation mentioned the
default value.

I'm somewhat worried that this is hiding important context from some
NOTICE or WARNING messages intended for novice users, but probably not
worried enough to go through all of them. +3/8 from me, I guess.

.m

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#99Pavel Stehule
pavel.stehule@gmail.com
In reply to: Marko Tiikkaja (#98)
Re: PL/pgSQL, RAISE and error context

2015-08-12 11:07 GMT+02:00 Marko Tiikkaja <marko@joh.to>:

On 8/12/15 9:36 AM, Pavel Stehule wrote:

So, there is common agreement on this version.

There are several instances of double semicolons. Also,
PsqlSettings.show_context doesn't look like a boolean to me. For
SHOW_CONTEXT, it would be good if the documentation mentioned the default
value.

I'm somewhat worried that this is hiding important context from some
NOTICE or WARNING messages intended for novice users, but probably not
worried enough to go through all of them. +3/8 from me, I guess.

Thank you for info

I'll fix it

Show quoted text

.m

#100Pavel Stehule
pavel.stehule@gmail.com
In reply to: Marko Tiikkaja (#98)
1 attachment(s)
Re: PL/pgSQL, RAISE and error context

Hi

2015-08-12 11:07 GMT+02:00 Marko Tiikkaja <marko@joh.to>:

On 8/12/15 9:36 AM, Pavel Stehule wrote:

So, there is common agreement on this version.

There are several instances of double semicolons. Also,
PsqlSettings.show_context doesn't look like a boolean to me. For
SHOW_CONTEXT, it would be good if the documentation mentioned the default
value.

I'm somewhat worried that this is hiding important context from some
NOTICE or WARNING messages intended for novice users, but probably not
worried enough to go through all of them. +3/8 from me, I guess.

I fixed mentioned issues.

Regards

Pavel

Show quoted text

.m

Attachments:

libpq-context-filter-20150813-01.patch.gzapplication/x-gzip; name=libpq-context-filter-20150813-01.patch.gzDownload
#101Tom Lane
tgl@sss.pgh.pa.us
In reply to: Pavel Stehule (#100)
Re: PL/pgSQL, RAISE and error context

Pavel Stehule <pavel.stehule@gmail.com> writes:

2015-08-12 11:07 GMT+02:00 Marko Tiikkaja <marko@joh.to>:

I'm somewhat worried that this is hiding important context from some
NOTICE or WARNING messages intended for novice users, but probably not
worried enough to go through all of them. +3/8 from me, I guess.

I fixed mentioned issues.

Okay, so to summarize where we seem to have ended up:

1. Remove the wart in plpgsql that causes it to suppress the innermost
CONTEXT line for RAISE. (I think pretty much everyone agrees that this
*is* a wart. The question is how to get rid of it without a decrease
in usability for simple cases.)

2. Change psql so that by default, it hides the entire CONTEXT output
for messages that are of less than ERROR severity. Add a new magic
\set variable that allows choosing this behavior, or display CONTEXT
always, or display CONTEXT never.

3. Since psql actually uses libpq for formatting server messages,
add an API to libpq that implements these CONTEXT hide/show options.

The actual code changes are pretty small, but there's rather a large
change in regression test outputs; which is unsurprising, because this
heuristic for what's of interest is entirely different from the old one.

Is everyone satisfied with this solution? It's okay with me, though
I'm concerned that there will be complaints about loss of backwards
compatibility. (It's hard to see how the contents of CONTEXT error
fields would be a big application compatibility issue, but you never
know.)

If there are not major objections, I'll work on cleaning up and
committing the patch. There is still work needed (eg, the API addition
of point 3 is undocumented), but the main question is just whether we
are happy with making things work this way.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#102Tom Lane
tgl@sss.pgh.pa.us
In reply to: Tom Lane (#101)
Re: PL/pgSQL, RAISE and error context

I wrote:

If there are not major objections, I'll work on cleaning up and
committing the patch.

Pushed. I'm not too sure about the expected outputs for python other
than 2.6, nor for sepgsql, but hopefully the buildfarm will provide
feedback.

BTW, I noticed that the PageOutput line counts for psql's usage(),
slashUsage(), and helpVariables() were all three wrong, which I'm afraid
has been their usual state in the past too. Since commit 07c8651dd91d5aea
there's been a pretty easy way to check them, which I added comments
about; but I don't hold much hope that that will fix anything. I wonder
whether there's some way to not need to maintain those counts manually.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#103Joe Conway
mail@joeconway.com
In reply to: Tom Lane (#102)
Re: PL/pgSQL, RAISE and error context

On 09/05/2015 09:05 AM, Tom Lane wrote:

I wrote:

If there are not major objections, I'll work on cleaning up and
committing the patch.

Pushed. I'm not too sure about the expected outputs for python other
than 2.6, nor for sepgsql, but hopefully the buildfarm will provide
feedback.

We don't have the buildfarm actually checking sepgsql yet, but I'll
check it out manually today or tomorrow.

Joe

--
Crunchy Data - http://crunchydata.com
PostgreSQL Support for Secure Enterprises
Consulting, Training, & Open Source Development

#104Tom Lane
tgl@sss.pgh.pa.us
In reply to: Tom Lane (#102)
Counting lines correctly in psql help displays

I wrote:

BTW, I noticed that the PageOutput line counts for psql's usage(),
slashUsage(), and helpVariables() were all three wrong, which I'm afraid
has been their usual state in the past too. Since commit 07c8651dd91d5aea
there's been a pretty easy way to check them, which I added comments
about; but I don't hold much hope that that will fix anything. I wonder
whether there's some way to not need to maintain those counts manually.

I seem to recall past proposals to fix that by putting the lines into
static char * arrays, which foundered on the fact that the output's not
necessarily constant. But it suddenly strikes me that there's an easy
fix. We can generate the output into a PQExpBuffer, which is just as
flexible as fprintf() is today, then count the lines and finally print.

Ordinarily I might think that was overkill, but given the number of times
that we've failed to update those counts in the past, I think this is
definitely a worthwhile investment in maintainability.

Or we could just give up and replace the counts by INT_MAX, forcing use
of the pager unless you've turned it off. All of those outputs are long
enough now that it's hard to believe there are any common screen layouts
where you don't end up invoking the pager anyway. (usage() is 60 lines,
the others are more.) This is probably the reason why we've seldom
noticed they're wrong --- it barely matters anymore.

One way or the other I think it's past time to get out of the business
of maintaining these counts. I'm willing to do the work of using a
PQExpBuffer if people think it's worth the trouble to have an accurate
count, but it may not be worth the code space.

Thoughts?

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#105Greg Stark
stark@mit.edu
In reply to: Tom Lane (#104)
1 attachment(s)
Re: Counting lines correctly in psql help displays

On Sat, Sep 5, 2015 at 5:55 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Ordinarily I might think that was overkill, but given the number of times
that we've failed to update those counts in the past, I think this is
definitely a worthwhile investment in maintainability.

So to preface this, this was just a silly hack that turned out to be
more effective and simpler to code than I expected. But I suspect it's
still just a silly idea and easier to do what you suggested. Also, it
seems we often get the count wrong on SQL output and elsewhere anyways
and I'm not sure we really want to make that a strict rule. Also, as
someone who doesn't really like the whole "sometimes you get a pager
sometimes you don't" thing and turns it off whenever he sees it I'm
not in the best place to judge how much work it's worth to get the
line count right.

But that said, here's a tricksy patch that triggers an assertion
failure if the expected_lines is wrong. I intended it to trigger in
the regression tests so it only checks if the pager is actually off.
It wouldn't be hard to make it always check though.

--
greg

Attachments:

psql-assert-newlines.difftext/plain; charset=US-ASCII; name=psql-assert-newlines.diffDownload
diff --git a/src/bin/psql/print.c b/src/bin/psql/print.c
index cab9e6e..5e2ff09 100644
--- a/src/bin/psql/print.c
+++ b/src/bin/psql/print.c
@@ -2725,6 +2725,12 @@ print_troff_ms_vertical(const printTableContent *cont, FILE *fout)
 /* Public functions		*/
 /********************************/
 
+#ifdef USE_ASSERT_CHECKING
+#define MAX_PAGEOUTPUT_LINES 1000
+#define MAX_PAGEOUTPUT_BUF (1000 * 80 * 2)
+static char *PageOutputBuf;
+static int expected_lines;
+#endif
 
 /*
  * PageOutput
@@ -2770,6 +2776,21 @@ PageOutput(int lines, const printTableOpt *topt)
 #endif
 	}
 
+#ifdef USE_ASSERT_CHECKING
+	if (lines < MAX_PAGEOUTPUT_LINES)
+	{
+		fflush(stdout);
+		expected_lines = lines;
+		if (!PageOutputBuf)
+		{
+			PageOutputBuf = pg_malloc0(MAX_PAGEOUTPUT_BUF);
+			setvbuf(stdout, PageOutputBuf, _IOFBF, MAX_PAGEOUTPUT_BUF);
+		} else {
+			memset(PageOutputBuf, MAX_PAGEOUTPUT_BUF, 0);
+		}
+	}
+#endif
+
 	return stdout;
 }
 
@@ -2799,6 +2820,33 @@ ClosePager(FILE *pagerpipe)
 		pqsignal(SIGPIPE, SIG_DFL);
 #endif
 	}
+
+#ifdef USE_ASSERT_CHECKING
+	if (PageOutputBuf && expected_lines)
+	{
+		int n_newlines = 0;
+		int i;
+		for (i=0;i<MAX_PAGEOUTPUT_BUF;i++)
+		{
+			if (PageOutputBuf[i]=='\n')
+			{
+				n_newlines++;
+			}
+		}
+		fprintf(stderr, "Expected %d lines, actually printed %d lines\n",
+				expected_lines, n_newlines);
+		Assert(n_newlines == expected_lines);
+
+		expected_lines = 0;
+		fflush(stdout);
+
+		/* XXX leave this set? not sure. */
+		setbuffer(stdout, NULL, 0);
+		pg_free(PageOutputBuf);
+		PageOutputBuf = 0;
+		
+	}
+#endif
 }
 
 /*
#106Tom Lane
tgl@sss.pgh.pa.us
In reply to: Greg Stark (#105)
Re: Counting lines correctly in psql help displays

Greg Stark <stark@mit.edu> writes:

But that said, here's a tricksy patch that triggers an assertion
failure if the expected_lines is wrong. I intended it to trigger in
the regression tests so it only checks if the pager is actually off.
It wouldn't be hard to make it always check though.

Hmm ... that would put a premium on the linecount always being exactly
right (for all callers, not just the help functions). Not sure that
I want to buy into that --- it would require more complexity in the
callers than is there now, for sure.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#107Pavel Stehule
pavel.stehule@gmail.com
In reply to: Tom Lane (#102)
Re: PL/pgSQL, RAISE and error context

Pushed. I'm not too sure about the expected outputs for python other
than 2.6, nor for sepgsql, but hopefully the buildfarm will provide
feedback.

Thank you very much

Pavel

#108Joe Conway
mail@joeconway.com
In reply to: Joe Conway (#103)
1 attachment(s)
Re: PL/pgSQL, RAISE and error context

On 09/05/2015 09:14 AM, Joe Conway wrote:

On 09/05/2015 09:05 AM, Tom Lane wrote:

I wrote:

If there are not major objections, I'll work on cleaning up and
committing the patch.

Pushed. I'm not too sure about the expected outputs for python other
than 2.6, nor for sepgsql, but hopefully the buildfarm will provide
feedback.

We don't have the buildfarm actually checking sepgsql yet, but I'll
check it out manually today or tomorrow.

One-liner required for sepgsql -- attached committed and pushed.

Joe

--
Crunchy Data - http://crunchydata.com
PostgreSQL Support for Secure Enterprises
Consulting, Training, & Open Source Development

Attachments:

sepgsql-context-rpt-fix.difftext/x-diff; name=sepgsql-context-rpt-fix.diffDownload
diff --git a/contrib/sepgsql/expected/label.out b/contrib/sepgsql/expected/label.out
index c84aef7..7af5189 100644
--- a/contrib/sepgsql/expected/label.out
+++ b/contrib/sepgsql/expected/label.out
@@ -156,6 +156,7 @@ LOG:  SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_re
 LOG:  SELinux: allowed { entrypoint } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_trusted_proc_exec_t:s0 tclass=db_procedure name="function f3()"
 LOG:  SELinux: allowed { transition } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=unconfined_u:unconfined_r:sepgsql_trusted_proc_t:s0 tclass=process
 ERROR:  an exception from f3()
+CONTEXT:  PL/pgSQL function f3() line 2 at RAISE
 SELECT f4();			-- failed on domain transition
 LOG:  SELinux: allowed { execute } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_nosuch_trusted_proc_exec_t:s0 tclass=db_procedure name="public.f4()"
 LOG:  SELinux: allowed { entrypoint } scontext=unconfined_u:unconfined_r:sepgsql_regtest_user_t:s0 tcontext=system_u:object_r:sepgsql_nosuch_trusted_proc_exec_t:s0 tclass=db_procedure name="function f4()"
#109Tom Lane
tgl@sss.pgh.pa.us
In reply to: Joe Conway (#108)
Re: PL/pgSQL, RAISE and error context

Joe Conway <mail@joeconway.com> writes:

On 09/05/2015 09:05 AM, Tom Lane wrote:

Pushed. I'm not too sure about the expected outputs for python other
than 2.6, nor for sepgsql, but hopefully the buildfarm will provide
feedback.

One-liner required for sepgsql -- attached committed and pushed.

Thanks for checking!

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#110Jim Nasby
Jim.Nasby@BlueTreble.com
In reply to: Tom Lane (#106)
Re: Counting lines correctly in psql help displays

On 9/5/15 3:50 PM, Tom Lane wrote:

Greg Stark <stark@mit.edu> writes:

But that said, here's a tricksy patch that triggers an assertion
failure if the expected_lines is wrong. I intended it to trigger in
the regression tests so it only checks if the pager is actually off.
It wouldn't be hard to make it always check though.

Hmm ... that would put a premium on the linecount always being exactly
right (for all callers, not just the help functions). Not sure that
I want to buy into that --- it would require more complexity in the
callers than is there now, for sure.

But only in an assert-enabled build. Surely there's enough other
performance hits with asserts enabled that this wouldn't matter?

As for paging, ISTM the only people that would care are those with
enormous terminal sizes would care, and assuming their pager is less
simply adding -F to $LESS would get them their old behavior. So I think
it's safe to just force paging.
--
Jim Nasby, Data Architect, Blue Treble Consulting, Austin TX
Experts in Analytics, Data Architecture and PostgreSQL
Data in Trouble? Get it in Treble! http://BlueTreble.com

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#111Tom Lane
tgl@sss.pgh.pa.us
In reply to: Jim Nasby (#110)
Re: Counting lines correctly in psql help displays

Jim Nasby <Jim.Nasby@bluetreble.com> writes:

On 9/5/15 3:50 PM, Tom Lane wrote:

Greg Stark <stark@mit.edu> writes:

But that said, here's a tricksy patch that triggers an assertion
failure if the expected_lines is wrong.

Hmm ... that would put a premium on the linecount always being exactly
right (for all callers, not just the help functions). Not sure that
I want to buy into that --- it would require more complexity in the
callers than is there now, for sure.

But only in an assert-enabled build. Surely there's enough other
performance hits with asserts enabled that this wouldn't matter?

It's not about performance, it's about code complexity and maintenance
overhead. I'm looking to *reduce* the amount of personpower expended
on those line counts, not increase it; but adding an assertion requirement
that the counts be exactly right would require us to spend more development
effort on making them right.

As for paging, ISTM the only people that would care are those with
enormous terminal sizes would care, and assuming their pager is less
simply adding -F to $LESS would get them their old behavior. So I think
it's safe to just force paging.

Yeah, I'm leaning to just changing the counts to INT_MAX and being
done with it.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#112Andrew Dunstan
andrew@dunslane.net
In reply to: Tom Lane (#104)
Re: Counting lines correctly in psql help displays

On 09/05/2015 12:55 PM, Tom Lane wrote:

I wrote:

BTW, I noticed that the PageOutput line counts for psql's usage(),
slashUsage(), and helpVariables() were all three wrong, which I'm afraid
has been their usual state in the past too. Since commit 07c8651dd91d5aea
there's been a pretty easy way to check them, which I added comments
about; but I don't hold much hope that that will fix anything. I wonder
whether there's some way to not need to maintain those counts manually.

I seem to recall past proposals to fix that by putting the lines into
static char * arrays, which foundered on the fact that the output's not
necessarily constant. But it suddenly strikes me that there's an easy
fix. We can generate the output into a PQExpBuffer, which is just as
flexible as fprintf() is today, then count the lines and finally print.

Ordinarily I might think that was overkill, but given the number of times
that we've failed to update those counts in the past, I think this is
definitely a worthwhile investment in maintainability.

Or we could just give up and replace the counts by INT_MAX, forcing use
of the pager unless you've turned it off. All of those outputs are long
enough now that it's hard to believe there are any common screen layouts
where you don't end up invoking the pager anyway. (usage() is 60 lines,
the others are more.) This is probably the reason why we've seldom
noticed they're wrong --- it barely matters anymore.

One way or the other I think it's past time to get out of the business
of maintaining these counts. I'm willing to do the work of using a
PQExpBuffer if people think it's worth the trouble to have an accurate
count, but it may not be worth the code space.

Thoughts?

I'm not terribly happy about the INT_MAX idea. Counting lines in a
PGExpBuffer seems OK. That way we could honor pager_min_lines, I hope.

cheers

andrew

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#113Tom Lane
tgl@sss.pgh.pa.us
In reply to: Andrew Dunstan (#112)
Re: Counting lines correctly in psql help displays

Andrew Dunstan <andrew@dunslane.net> writes:

On 09/05/2015 12:55 PM, Tom Lane wrote:

Or we could just give up and replace the counts by INT_MAX, forcing use
of the pager unless you've turned it off. All of those outputs are long
enough now that it's hard to believe there are any common screen layouts
where you don't end up invoking the pager anyway. (usage() is 60 lines,
the others are more.) This is probably the reason why we've seldom
noticed they're wrong --- it barely matters anymore.

One way or the other I think it's past time to get out of the business
of maintaining these counts. I'm willing to do the work of using a
PQExpBuffer if people think it's worth the trouble to have an accurate
count, but it may not be worth the code space.

I'm not terribly happy about the INT_MAX idea. Counting lines in a
PGExpBuffer seems OK. That way we could honor pager_min_lines, I hope.

TBH, I'm not detecting enough concern about this issue to make it worth
doing more than replacing the counts by INT_MAX. Nobody has stepped up
and said "yeah, my terminal window is 100 lines high and I'll be really
annoyed if \? invokes the pager unnecessarily". I plan to just do the
three-line fix and move on.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#114Andrew Dunstan
andrew@dunslane.net
In reply to: Tom Lane (#113)
Re: Counting lines correctly in psql help displays

On 09/09/2015 10:27 AM, Tom Lane wrote:

Andrew Dunstan <andrew@dunslane.net> writes:

On 09/05/2015 12:55 PM, Tom Lane wrote:

Or we could just give up and replace the counts by INT_MAX, forcing use
of the pager unless you've turned it off. All of those outputs are long
enough now that it's hard to believe there are any common screen layouts
where you don't end up invoking the pager anyway. (usage() is 60 lines,
the others are more.) This is probably the reason why we've seldom
noticed they're wrong --- it barely matters anymore.

One way or the other I think it's past time to get out of the business
of maintaining these counts. I'm willing to do the work of using a
PQExpBuffer if people think it's worth the trouble to have an accurate
count, but it may not be worth the code space.

I'm not terribly happy about the INT_MAX idea. Counting lines in a
PGExpBuffer seems OK. That way we could honor pager_min_lines, I hope.

TBH, I'm not detecting enough concern about this issue to make it worth
doing more than replacing the counts by INT_MAX. Nobody has stepped up
and said "yeah, my terminal window is 100 lines high and I'll be really
annoyed if \? invokes the pager unnecessarily". I plan to just do the
three-line fix and move on.

Do people really use terminals without scrollbars for serious work any
more? Personally I'm in favor of forcing the pager less, not more. But
I'm not going to make a fuss, I'm just surprised.

cheers

andrew

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers