2014-09-09 7:55 GMT+02:00 Craig Ringer <cr...@2ndquadrant.com>:

> On 09/09/2014 05:20 AM, Robert Haas wrote:
> >
> > I previously proposed RAISE ASSERT ... WHERE, which seems like a nice
> > variant of what we've already got, but perhaps this whole discussion
> > merely illustrates that it's hard to get more than 1 vote for any
> > proposal in this area.
>
> Well, you have Petr's for RAISE EXCEPTION ... WHEN, and I'd also like
> that or RAISE ASSERT ... WHEN.
>

Ada is language with strong character, and PLpgSQL is little bit strange
fork - so it isn't easy to find some form, how to solve all requirements.

My requests:

* be consistent with current PLpgSQL syntax and logic
* allow some future extensibility
* allow a static analyses without hard expression processing

But I am thinking so there are some points where can be some agreement -
although it is not ASSERT implementation.

enhancing RAISE WHEN - please, see attached patch -

I prefer RAISE WHEN again RAISE WHERE due consistency with EXIT and
CONTINUE [ WHEN ];

Next we can reserve some SQLCODE for assertation and we can implement it as
not handled exception. It is only "cancel" now, and it is not usable .
Probably it should be implement on SQL level - not on plpgsql only.

Regards

Pavel








>
> Much (much) saner than the other proposals on this thread IMO.
>
> --
>  Craig Ringer                   http://www.2ndQuadrant.com/
>  PostgreSQL Development, 24x7 Support, Training & Services
>
commit 77ff7203d83e889aa9f5190fe54b04dc7c26a5aa
Author: Pavel Stehule <pavel.steh...@gooddata.com>
Date:   Tue Sep 9 12:11:15 2014 +0200

    initial

diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 11cb47b..f8ac200 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -2890,8 +2890,20 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
 	char	   *err_datatype = NULL;
 	char	   *err_table = NULL;
 	char	   *err_schema = NULL;
+	
 	ListCell   *lc;
 
+	if (stmt->cond != NULL)
+	{
+		bool	value;
+		bool	isnull;
+
+		value = exec_eval_boolean(estate, stmt->cond, &isnull);
+		exec_eval_cleanup(estate);
+		if (isnull || value == false)
+			return PLPGSQL_RC_OK;
+	}
+
 	/* RAISE with no parameters: re-throw current exception */
 	if (stmt->condname == NULL && stmt->message == NULL &&
 		stmt->options == NIL)
diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y
index 893f3a4..1f0b861 100644
--- a/src/pl/plpgsql/src/pl_gram.y
+++ b/src/pl/plpgsql/src/pl_gram.y
@@ -63,6 +63,7 @@ static	void			current_token_is_not_variable(int tok);
 static	PLpgSQL_expr	*read_sql_construct(int until,
 											int until2,
 											int until3,
+											int until4,
 											const char *expected,
 											const char *sqlstart,
 											bool isexpression,
@@ -105,7 +106,7 @@ static	void			 check_labels(const char *start_label,
 									  int end_location);
 static	PLpgSQL_expr	*read_cursor_args(PLpgSQL_var *cursor,
 										  int until, const char *expected);
-static	List			*read_raise_options(void);
+static	List			*read_raise_options(int *endtok);
 static	void			check_raise_parameters(PLpgSQL_stmt_raise *stmt);
 
 %}
@@ -1422,6 +1423,7 @@ for_control		: for_variable K_IN
 							expr1 = read_sql_construct(DOT_DOT,
 													   K_LOOP,
 													   0,
+													   0,
 													   "LOOP",
 													   "SELECT ",
 													   true,
@@ -1716,6 +1718,7 @@ stmt_raise		: K_RAISE
 					{
 						PLpgSQL_stmt_raise		*new;
 						int	tok;
+						int	endtok;
 
 						new = palloc(sizeof(PLpgSQL_stmt_raise));
 
@@ -1726,6 +1729,7 @@ stmt_raise		: K_RAISE
 						new->message	= NULL;
 						new->params		= NIL;
 						new->options	= NIL;
+						new->cond = NULL;
 
 						tok = yylex();
 						if (tok == 0)
@@ -1796,22 +1800,22 @@ stmt_raise		: K_RAISE
 								 * or USING to begin the options list.
 								 */
 								tok = yylex();
-								if (tok != ',' && tok != ';' && tok != K_USING)
+								if (tok != ',' && tok != ';' && tok != K_USING && tok != K_WHEN)
 									yyerror("syntax error");
 
 								while (tok == ',')
 								{
 									PLpgSQL_expr *expr;
 
-									expr = read_sql_construct(',', ';', K_USING,
-															  ", or ; or USING",
+									expr = read_sql_construct(',', ';', K_USING, K_WHEN,
+															  ", or ; or USING or WHEN",
 															  "SELECT ",
 															  true, true, true,
 															  NULL, &tok);
 									new->params = lappend(new->params, expr);
 								}
 							}
-							else if (tok != K_USING)
+							else if (tok != K_USING && tok != K_WHEN)
 							{
 								/* must be condition name or SQLSTATE */
 								if (tok_is_keyword(tok, &yylval,
@@ -1847,7 +1851,13 @@ stmt_raise		: K_RAISE
 							}
 
 							if (tok == K_USING)
-								new->options = read_raise_options();
+							{
+								new->options = read_raise_options(&endtok);
+								if (endtok == K_WHEN)
+									new->cond = read_sql_expression(';', ";");
+							}
+							if (tok == K_WHEN)
+								new->cond = read_sql_expression(';', ";");
 						}
 
 						check_raise_parameters(new);
@@ -1906,7 +1916,7 @@ stmt_dynexecute : K_EXECUTE
 						PLpgSQL_expr *expr;
 						int endtoken;
 
-						expr = read_sql_construct(K_INTO, K_USING, ';',
+						expr = read_sql_construct(K_INTO, K_USING, ';', 0,
 												  "INTO or USING or ;",
 												  "SELECT ",
 												  true, true, true,
@@ -1945,7 +1955,7 @@ stmt_dynexecute : K_EXECUTE
 									yyerror("syntax error");
 								do
 								{
-									expr = read_sql_construct(',', ';', K_INTO,
+									expr = read_sql_construct(',', ';', K_INTO, 0,
 															  ", or ; or INTO",
 															  "SELECT ",
 															  true, true, true,
@@ -2456,7 +2466,7 @@ current_token_is_not_variable(int tok)
 static PLpgSQL_expr *
 read_sql_expression(int until, const char *expected)
 {
-	return read_sql_construct(until, 0, 0, expected,
+	return read_sql_construct(until, 0, 0, 0, expected,
 							  "SELECT ", true, true, true, NULL, NULL);
 }
 
@@ -2465,7 +2475,7 @@ static PLpgSQL_expr *
 read_sql_expression2(int until, int until2, const char *expected,
 					 int *endtoken)
 {
-	return read_sql_construct(until, until2, 0, expected,
+	return read_sql_construct(until, until2, 0, 0, expected,
 							  "SELECT ", true, true, true, NULL, endtoken);
 }
 
@@ -2473,7 +2483,7 @@ read_sql_expression2(int until, int until2, const char *expected,
 static PLpgSQL_expr *
 read_sql_stmt(const char *sqlstart)
 {
-	return read_sql_construct(';', 0, 0, ";",
+	return read_sql_construct(';', 0, 0, 0, ";",
 							  sqlstart, false, true, true, NULL, NULL);
 }
 
@@ -2496,6 +2506,7 @@ static PLpgSQL_expr *
 read_sql_construct(int until,
 				   int until2,
 				   int until3,
+				   int until4,
 				   const char *expected,
 				   const char *sqlstart,
 				   bool isexpression,
@@ -2529,6 +2540,8 @@ read_sql_construct(int until,
 			break;
 		if (tok == until3 && parenlevel == 0)
 			break;
+		if (tok == until4 && parenlevel == 0)
+			break;
 		if (tok == '(' || tok == '[')
 			parenlevel++;
 		else if (tok == ')' || tok == ']')
@@ -3647,7 +3660,7 @@ read_cursor_args(PLpgSQL_var *cursor, int until, const char *expected)
 		 * translated into a form where the second parameter is commented
 		 * out.
 		 */
-		item = read_sql_construct(',', ')', 0,
+		item = read_sql_construct(',', ')', 0, 0,
 								  ",\" or \")",
 								  sqlstart,
 								  true, true,
@@ -3711,14 +3724,14 @@ read_cursor_args(PLpgSQL_var *cursor, int until, const char *expected)
  * Parse RAISE ... USING options
  */
 static List *
-read_raise_options(void)
+read_raise_options(int *endtok)
 {
 	List	   *result = NIL;
+	int		tok;
 
 	for (;;)
 	{
 		PLpgSQL_raise_option *opt;
-		int		tok;
 
 		if ((tok = yylex()) == 0)
 			yyerror("unexpected end of function definition");
@@ -3759,14 +3772,17 @@ read_raise_options(void)
 		if (tok != '=' && tok != COLON_EQUALS)
 			yyerror("syntax error, expected \"=\"");
 
-		opt->expr = read_sql_expression2(',', ';', ", or ;", &tok);
+		opt->expr = read_sql_construct(',', ';', K_WHEN, 0, ", or ; or WHEN",
+									   "SELECT ", true, true, true, NULL, &tok);
 
 		result = lappend(result, opt);
 
-		if (tok == ';')
+		if (tok == ';' || tok == K_WHEN)
 			break;
 	}
 
+	*endtok = tok;
+
 	return result;
 }
 
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index d6f31ff..3dee7f3 100644
--- a/src/pl/plpgsql/src/plpgsql.h
+++ b/src/pl/plpgsql/src/plpgsql.h
@@ -621,6 +621,7 @@ typedef struct
 	char	   *message;		/* old-style message format literal, or NULL */
 	List	   *params;			/* list of expressions for old-style message */
 	List	   *options;		/* list of PLpgSQL_raise_option */
+	PLpgSQL_expr *cond;
 } PLpgSQL_stmt_raise;
 
 typedef struct
diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out
index 983f1b8..b5333b2 100644
--- a/src/test/regress/expected/plpgsql.out
+++ b/src/test/regress/expected/plpgsql.out
@@ -5351,3 +5351,29 @@ NOTICE:  outer_func() done
 drop function outer_outer_func(int);
 drop function outer_func(int);
 drop function inner_func(int);
+create or replace function test_func(text)
+returns void as $$
+begin
+  raise notice 'Hello %', $1;
+  raise notice 'Hello %', $1 when false;
+  raise notice 'Hello % %', $1, $1 when true;
+  raise notice 'Hello % % %', $1, $2, $3 when null;
+  
+  raise notice using message = 'Nazdar';
+  raise notice using message = 'Nazdar ' || $1 when true;
+  raise notice using message = 'Nazdar ' || $1, detail = 'Svete' when true;
+end;
+$$ language plpgsql;
+select test_func('world');
+NOTICE:  Hello world
+NOTICE:  Hello world world
+NOTICE:  Nazdar
+NOTICE:  Nazdar world
+NOTICE:  Nazdar world
+DETAIL:  Svete
+ test_func 
+-----------
+ 
+(1 row)
+
+drop function test_func(text);
diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql
index 2abcbc8..279a8be 100644
--- a/src/test/regress/sql/plpgsql.sql
+++ b/src/test/regress/sql/plpgsql.sql
@@ -4198,3 +4198,21 @@ select outer_outer_func(20);
 drop function outer_outer_func(int);
 drop function outer_func(int);
 drop function inner_func(int);
+
+create or replace function test_func(text)
+returns void as $$
+begin
+  raise notice 'Hello %', $1;
+  raise notice 'Hello %', $1 when false;
+  raise notice 'Hello % %', $1, $1 when true;
+  raise notice 'Hello % % %', $1, $2, $3 when null;
+  
+  raise notice using message = 'Nazdar';
+  raise notice using message = 'Nazdar ' || $1 when true;
+  raise notice using message = 'Nazdar ' || $1, detail = 'Svete' when true;
+end;
+$$ language plpgsql;
+
+select test_func('world');
+
+drop function test_func(text);
-- 
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