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