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.steh...@gmail.com>: > Hi > > 2015-04-24 19:16 GMT+02:00 Joel Jacobson <j...@trustly.com>: > >> On Fri, Apr 24, 2015 at 6:07 PM, Pavel Stehule <pavel.steh...@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 > >
commit 33951bc23365029ee94af5ec43e90893dcd737a8 Author: Pavel Stehule <pavel.steh...@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; +$$; + +
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers