mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-01-06 15:24:56 +08:00
Allow the parameters to PL/PgSQL's RAISE statement to be expressions,
instead of just scalar variables. Add regression tests and update the documentation. Along the way, remove some redundant error checking code from exec_stmt_perform(). Original patch from Pavel Stehule, reworked by Neil Conway.
This commit is contained in:
parent
bd6bf50b03
commit
d6636543c4
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.71 2005/06/10 16:23:09 neilc Exp $
|
$PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.72 2005/06/14 06:43:14 neilc Exp $
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<chapter id="plpgsql">
|
<chapter id="plpgsql">
|
||||||
@ -2533,9 +2533,9 @@ RAISE <replaceable class="parameter">level</replaceable> '<replaceable class="pa
|
|||||||
<para>
|
<para>
|
||||||
Inside the format string, <literal>%</literal> is replaced by the
|
Inside the format string, <literal>%</literal> is replaced by the
|
||||||
next optional argument's string representation. Write
|
next optional argument's string representation. Write
|
||||||
<literal>%%</literal> to emit a literal <literal>%</literal>. Note
|
<literal>%%</literal> to emit a literal <literal>%</literal>.
|
||||||
that the optional arguments must presently be simple variables,
|
Arguments can be simple variables or expressions,
|
||||||
not expressions, and the format must be a simple string literal.
|
and the format must be a simple string literal.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
* procedural language
|
* procedural language
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.75 2005/06/10 16:23:11 neilc Exp $
|
* $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.76 2005/06/14 06:43:14 neilc Exp $
|
||||||
*
|
*
|
||||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||||
*
|
*
|
||||||
@ -135,8 +135,8 @@ static void plpgsql_sql_error_callback(void *arg);
|
|||||||
%type <exception> proc_exception
|
%type <exception> proc_exception
|
||||||
%type <condition> proc_conditions
|
%type <condition> proc_conditions
|
||||||
|
|
||||||
%type <list> raise_params
|
|
||||||
%type <ival> raise_level raise_param
|
%type <ival> raise_level
|
||||||
%type <str> raise_msg
|
%type <str> raise_msg
|
||||||
|
|
||||||
%type <list> getdiag_list
|
%type <list> getdiag_list
|
||||||
@ -1157,23 +1157,10 @@ stmt_return_next: K_RETURN_NEXT lno
|
|||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
stmt_raise : K_RAISE lno raise_level raise_msg raise_params ';'
|
stmt_raise : K_RAISE lno raise_level raise_msg
|
||||||
{
|
|
||||||
PLpgSQL_stmt_raise *new;
|
|
||||||
|
|
||||||
new = palloc(sizeof(PLpgSQL_stmt_raise));
|
|
||||||
|
|
||||||
new->cmd_type = PLPGSQL_STMT_RAISE;
|
|
||||||
new->lineno = $2;
|
|
||||||
new->elog_level = $3;
|
|
||||||
new->message = $4;
|
|
||||||
new->params = $5;
|
|
||||||
|
|
||||||
$$ = (PLpgSQL_stmt *)new;
|
|
||||||
}
|
|
||||||
| K_RAISE lno raise_level raise_msg ';'
|
|
||||||
{
|
{
|
||||||
PLpgSQL_stmt_raise *new;
|
PLpgSQL_stmt_raise *new;
|
||||||
|
int tok;
|
||||||
|
|
||||||
new = palloc(sizeof(PLpgSQL_stmt_raise));
|
new = palloc(sizeof(PLpgSQL_stmt_raise));
|
||||||
|
|
||||||
@ -1183,6 +1170,32 @@ stmt_raise : K_RAISE lno raise_level raise_msg raise_params ';'
|
|||||||
new->message = $4;
|
new->message = $4;
|
||||||
new->params = NIL;
|
new->params = NIL;
|
||||||
|
|
||||||
|
tok = yylex();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We expect either a semi-colon, which
|
||||||
|
* indicates no parameters, or a comma that
|
||||||
|
* begins the list of parameter expressions
|
||||||
|
*/
|
||||||
|
if (tok != ',' && tok != ';')
|
||||||
|
yyerror("syntax error");
|
||||||
|
|
||||||
|
if (tok == ',')
|
||||||
|
{
|
||||||
|
PLpgSQL_expr *expr;
|
||||||
|
int term;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
expr = read_sql_construct(',', ';', ", or ;",
|
||||||
|
"SELECT ",
|
||||||
|
true, true, &term);
|
||||||
|
new->params = lappend(new->params, expr);
|
||||||
|
if (term == ';')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$$ = (PLpgSQL_stmt *)new;
|
$$ = (PLpgSQL_stmt *)new;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
@ -1219,22 +1232,6 @@ raise_level : K_EXCEPTION
|
|||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
raise_params : raise_params raise_param
|
|
||||||
{
|
|
||||||
$$ = lappend_int($1, $2);
|
|
||||||
}
|
|
||||||
| raise_param
|
|
||||||
{
|
|
||||||
$$ = list_make1_int($1);
|
|
||||||
}
|
|
||||||
;
|
|
||||||
|
|
||||||
raise_param : ',' T_SCALAR
|
|
||||||
{
|
|
||||||
$$ = yylval.scalar->dno;
|
|
||||||
}
|
|
||||||
;
|
|
||||||
|
|
||||||
loop_body : proc_sect K_END K_LOOP ';'
|
loop_body : proc_sect K_END K_LOOP ';'
|
||||||
{ $$ = $1; }
|
{ $$ = $1; }
|
||||||
;
|
;
|
||||||
@ -1658,7 +1655,7 @@ read_sql_stmt(const char *sqlstart)
|
|||||||
* expected: text to use in complaining that terminator was not found
|
* expected: text to use in complaining that terminator was not found
|
||||||
* sqlstart: text to prefix to the accumulated SQL text
|
* sqlstart: text to prefix to the accumulated SQL text
|
||||||
* isexpression: whether to say we're reading an "expression" or a "statement"
|
* isexpression: whether to say we're reading an "expression" or a "statement"
|
||||||
* valid_sql: whether to check the syntax of the expression (plus sqlstart)
|
* valid_sql: whether to check the syntax of the expr (prefixed with sqlstart)
|
||||||
* endtoken: if not NULL, ending token is stored at *endtoken
|
* endtoken: if not NULL, ending token is stored at *endtoken
|
||||||
* (this is only interesting if until2 isn't zero)
|
* (this is only interesting if until2 isn't zero)
|
||||||
*/
|
*/
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
* procedural language
|
* procedural language
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.143 2005/06/10 16:23:11 neilc Exp $
|
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.144 2005/06/14 06:43:14 neilc Exp $
|
||||||
*
|
*
|
||||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||||
*
|
*
|
||||||
@ -594,7 +594,7 @@ plpgsql_exec_trigger(PLpgSQL_function *func,
|
|||||||
error_context_stack = plerrcontext.previous;
|
error_context_stack = plerrcontext.previous;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return the triggers result
|
* Return the trigger's result
|
||||||
*/
|
*/
|
||||||
return rettup;
|
return rettup;
|
||||||
}
|
}
|
||||||
@ -1095,22 +1095,9 @@ static int
|
|||||||
exec_stmt_perform(PLpgSQL_execstate *estate, PLpgSQL_stmt_perform *stmt)
|
exec_stmt_perform(PLpgSQL_execstate *estate, PLpgSQL_stmt_perform *stmt)
|
||||||
{
|
{
|
||||||
PLpgSQL_expr *expr = stmt->expr;
|
PLpgSQL_expr *expr = stmt->expr;
|
||||||
int rc;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If not already done create a plan for this expression
|
|
||||||
*/
|
|
||||||
if (expr->plan == NULL)
|
|
||||||
exec_prepare_plan(estate, expr);
|
|
||||||
|
|
||||||
rc = exec_run_select(estate, expr, 0, NULL);
|
|
||||||
if (rc != SPI_OK_SELECT)
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
|
||||||
errmsg("query \"%s\" did not return data", expr->query)));
|
|
||||||
|
|
||||||
|
(void) exec_run_select(estate, expr, 0, NULL);
|
||||||
exec_set_found(estate, (estate->eval_processed != 0));
|
exec_set_found(estate, (estate->eval_processed != 0));
|
||||||
|
|
||||||
exec_eval_cleanup(estate);
|
exec_eval_cleanup(estate);
|
||||||
|
|
||||||
return PLPGSQL_RC_OK;
|
return PLPGSQL_RC_OK;
|
||||||
@ -1941,15 +1928,18 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
|
|||||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||||
errmsg("too few parameters specified for RAISE")));
|
errmsg("too few parameters specified for RAISE")));
|
||||||
|
|
||||||
exec_eval_datum(estate, estate->datums[lfirst_int(current_param)],
|
paramvalue = exec_eval_expr(estate,
|
||||||
InvalidOid,
|
(PLpgSQL_expr *) lfirst(current_param),
|
||||||
¶mtypeid, ¶mvalue, ¶misnull);
|
¶misnull,
|
||||||
|
¶mtypeid);
|
||||||
|
|
||||||
if (paramisnull)
|
if (paramisnull)
|
||||||
extval = "<NULL>";
|
extval = "<NULL>";
|
||||||
else
|
else
|
||||||
extval = convert_value_to_string(paramvalue, paramtypeid);
|
extval = convert_value_to_string(paramvalue, paramtypeid);
|
||||||
plpgsql_dstring_append(&ds, extval);
|
plpgsql_dstring_append(&ds, extval);
|
||||||
current_param = lnext(current_param);
|
current_param = lnext(current_param);
|
||||||
|
exec_eval_cleanup(estate);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
* procedural language
|
* procedural language
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.42 2005/06/14 00:10:02 neilc Exp $
|
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.43 2005/06/14 06:43:14 neilc Exp $
|
||||||
*
|
*
|
||||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||||
*
|
*
|
||||||
@ -885,13 +885,20 @@ dump_return_next(PLpgSQL_stmt_return_next *stmt)
|
|||||||
static void
|
static void
|
||||||
dump_raise(PLpgSQL_stmt_raise *stmt)
|
dump_raise(PLpgSQL_stmt_raise *stmt)
|
||||||
{
|
{
|
||||||
ListCell *l;
|
ListCell *lc;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
dump_ind();
|
dump_ind();
|
||||||
printf("RAISE '%s'", stmt->message);
|
printf("RAISE '%s'\n", stmt->message);
|
||||||
foreach (l, stmt->params)
|
dump_indent += 2;
|
||||||
printf(" %d", lfirst_int(l));
|
foreach (lc, stmt->params)
|
||||||
printf("\n");
|
{
|
||||||
|
dump_ind();
|
||||||
|
printf(" parameter %d: ", i++);
|
||||||
|
dump_expr((PLpgSQL_expr *) lfirst(lc));
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
dump_indent -= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -916,7 +923,8 @@ dump_dynexecute(PLpgSQL_stmt_dynexecute *stmt)
|
|||||||
{
|
{
|
||||||
dump_ind();
|
dump_ind();
|
||||||
printf(" target = %d %s\n", stmt->rec->recno, stmt->rec->refname);
|
printf(" target = %d %s\n", stmt->rec->recno, stmt->rec->refname);
|
||||||
} else if (stmt->row != NULL)
|
}
|
||||||
|
else if (stmt->row != NULL)
|
||||||
{
|
{
|
||||||
dump_ind();
|
dump_ind();
|
||||||
printf(" target = %d %s\n", stmt->row->rowno, stmt->row->refname);
|
printf(" target = %d %s\n", stmt->row->rowno, stmt->row->refname);
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
* procedural language
|
* procedural language
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.62 2005/06/10 16:23:11 neilc Exp $
|
* $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.63 2005/06/14 06:43:14 neilc Exp $
|
||||||
*
|
*
|
||||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||||
*
|
*
|
||||||
@ -515,7 +515,7 @@ typedef struct
|
|||||||
int lineno;
|
int lineno;
|
||||||
int elog_level;
|
int elog_level;
|
||||||
char *message;
|
char *message;
|
||||||
List *params;
|
List *params; /* list of expressions */
|
||||||
} PLpgSQL_stmt_raise;
|
} PLpgSQL_stmt_raise;
|
||||||
|
|
||||||
|
|
||||||
|
@ -2418,17 +2418,17 @@ drop type eitype cascade;
|
|||||||
--
|
--
|
||||||
-- SQLSTATE and SQLERRM test
|
-- SQLSTATE and SQLERRM test
|
||||||
--
|
--
|
||||||
-- should fail: SQLSTATE and SQLERRM are only in defined EXCEPTION
|
create function excpt_test1() returns void as $$
|
||||||
-- blocks
|
|
||||||
create function excpt_test() returns void as $$
|
|
||||||
begin
|
begin
|
||||||
raise notice '% %', sqlstate, sqlerrm;
|
raise notice '% %', sqlstate, sqlerrm;
|
||||||
end; $$ language plpgsql;
|
end; $$ language plpgsql;
|
||||||
ERROR: syntax error at or near "sqlstate" at character 79
|
-- should fail: SQLSTATE and SQLERRM are only in defined EXCEPTION
|
||||||
LINE 3: raise notice '% %', sqlstate, sqlerrm;
|
-- blocks
|
||||||
^
|
select excpt_test1();
|
||||||
-- should fail
|
ERROR: column "sqlstate" does not exist
|
||||||
create function excpt_test() returns void as $$
|
CONTEXT: SQL statement "SELECT sqlstate"
|
||||||
|
PL/pgSQL function "excpt_test1" line 2 at raise
|
||||||
|
create function excpt_test2() returns void as $$
|
||||||
begin
|
begin
|
||||||
begin
|
begin
|
||||||
begin
|
begin
|
||||||
@ -2436,10 +2436,12 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end; $$ language plpgsql;
|
end; $$ language plpgsql;
|
||||||
ERROR: syntax error at or near "sqlstate" at character 108
|
-- should fail
|
||||||
LINE 5: raise notice '% %', sqlstate, sqlerrm;
|
select excpt_test2();
|
||||||
^
|
ERROR: column "sqlstate" does not exist
|
||||||
create function excpt_test() returns void as $$
|
CONTEXT: SQL statement "SELECT sqlstate"
|
||||||
|
PL/pgSQL function "excpt_test2" line 4 at raise
|
||||||
|
create function excpt_test3() returns void as $$
|
||||||
begin
|
begin
|
||||||
begin
|
begin
|
||||||
raise exception 'user exception';
|
raise exception 'user exception';
|
||||||
@ -2458,14 +2460,34 @@ begin
|
|||||||
raise notice '% %', sqlstate, sqlerrm;
|
raise notice '% %', sqlstate, sqlerrm;
|
||||||
end;
|
end;
|
||||||
end; $$ language plpgsql;
|
end; $$ language plpgsql;
|
||||||
select excpt_test();
|
select excpt_test3();
|
||||||
NOTICE: caught exception P0001 user exception
|
NOTICE: caught exception P0001 user exception
|
||||||
NOTICE: P0001 user exception
|
NOTICE: P0001 user exception
|
||||||
NOTICE: caught exception 22012 division by zero
|
NOTICE: caught exception 22012 division by zero
|
||||||
NOTICE: P0001 user exception
|
NOTICE: P0001 user exception
|
||||||
excpt_test
|
excpt_test3
|
||||||
------------
|
-------------
|
||||||
|
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
drop function excpt_test();
|
drop function excpt_test1();
|
||||||
|
drop function excpt_test2();
|
||||||
|
drop function excpt_test3();
|
||||||
|
-- parameters of raise stmt can be expressions
|
||||||
|
create function raise_exprs() returns void as $$
|
||||||
|
declare
|
||||||
|
a integer[] = '{10,20,30}';
|
||||||
|
c varchar = 'xyz';
|
||||||
|
i integer;
|
||||||
|
begin
|
||||||
|
i := 2;
|
||||||
|
raise notice '%; %; %; %; %; %', a, a[i], c, (select c || 'abc'), row(10,'aaa',NULL,30), NULL;
|
||||||
|
end;$$ language plpgsql;
|
||||||
|
select raise_exprs();
|
||||||
|
NOTICE: {10,20,30}; 20; xyz; xyzabc; (10,aaa,,30); <NULL>
|
||||||
|
raise_exprs
|
||||||
|
-------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
drop function raise_exprs();
|
||||||
|
@ -2055,15 +2055,15 @@ drop type eitype cascade;
|
|||||||
-- SQLSTATE and SQLERRM test
|
-- SQLSTATE and SQLERRM test
|
||||||
--
|
--
|
||||||
|
|
||||||
-- should fail: SQLSTATE and SQLERRM are only in defined EXCEPTION
|
create function excpt_test1() returns void as $$
|
||||||
-- blocks
|
|
||||||
create function excpt_test() returns void as $$
|
|
||||||
begin
|
begin
|
||||||
raise notice '% %', sqlstate, sqlerrm;
|
raise notice '% %', sqlstate, sqlerrm;
|
||||||
end; $$ language plpgsql;
|
end; $$ language plpgsql;
|
||||||
|
-- should fail: SQLSTATE and SQLERRM are only in defined EXCEPTION
|
||||||
|
-- blocks
|
||||||
|
select excpt_test1();
|
||||||
|
|
||||||
-- should fail
|
create function excpt_test2() returns void as $$
|
||||||
create function excpt_test() returns void as $$
|
|
||||||
begin
|
begin
|
||||||
begin
|
begin
|
||||||
begin
|
begin
|
||||||
@ -2071,8 +2071,10 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end; $$ language plpgsql;
|
end; $$ language plpgsql;
|
||||||
|
-- should fail
|
||||||
|
select excpt_test2();
|
||||||
|
|
||||||
create function excpt_test() returns void as $$
|
create function excpt_test3() returns void as $$
|
||||||
begin
|
begin
|
||||||
begin
|
begin
|
||||||
raise exception 'user exception';
|
raise exception 'user exception';
|
||||||
@ -2092,5 +2094,21 @@ begin
|
|||||||
end;
|
end;
|
||||||
end; $$ language plpgsql;
|
end; $$ language plpgsql;
|
||||||
|
|
||||||
select excpt_test();
|
select excpt_test3();
|
||||||
drop function excpt_test();
|
drop function excpt_test1();
|
||||||
|
drop function excpt_test2();
|
||||||
|
drop function excpt_test3();
|
||||||
|
|
||||||
|
-- parameters of raise stmt can be expressions
|
||||||
|
create function raise_exprs() returns void as $$
|
||||||
|
declare
|
||||||
|
a integer[] = '{10,20,30}';
|
||||||
|
c varchar = 'xyz';
|
||||||
|
i integer;
|
||||||
|
begin
|
||||||
|
i := 2;
|
||||||
|
raise notice '%; %; %; %; %; %', a, a[i], c, (select c || 'abc'), row(10,'aaa',NULL,30), NULL;
|
||||||
|
end;$$ language plpgsql;
|
||||||
|
|
||||||
|
select raise_exprs();
|
||||||
|
drop function raise_exprs();
|
||||||
|
Loading…
Reference in New Issue
Block a user