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

Reply via email to