2015-04-28 19:44 GMT+02:00 Jim Nasby <jim.na...@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 > > -- > Jim Nasby, Data Architect, Blue Treble Consulting > Data in Trouble? Get it in Treble! http://BlueTreble.com >
commit c2f49938f636864234d03994d2f64f8095392d11 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.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; +$$; + +
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers