Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit c1008f0

Browse files
committed
Check number of parameters in RAISE statement at compile time.
The number of % parameter markers in RAISE statement should match the number of parameters given. We used to check that at execution time, but we have all the information needed at compile time, so let's check it at compile time instead. It's generally better to find mistakes earlier. Marko Tiikkaja, reviewed by Fabien Coelho
1 parent f8f4227 commit c1008f0

File tree

5 files changed

+68
-17
lines changed

5 files changed

+68
-17
lines changed

doc/src/sgml/plpgsql.sgml

+3
Original file line numberDiff line numberDiff line change
@@ -3403,6 +3403,9 @@ RAISE ;
34033403
Inside the format string, <literal>%</literal> is replaced by the
34043404
string representation of the next optional argument's value. Write
34053405
<literal>%%</literal> to emit a literal <literal>%</literal>.
3406+
The number of arguments must match the number of <literal>%</>
3407+
placeholders in the format string, or an error is raised during
3408+
the compilation of the function.
34063409
</para>
34073410

34083411
<para>

src/pl/plpgsql/src/pl_exec.c

+4-10
Original file line numberDiff line numberDiff line change
@@ -2939,10 +2939,9 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
29392939
continue;
29402940
}
29412941

2942+
/* should have been checked at compile time */
29422943
if (current_param == NULL)
2943-
ereport(ERROR,
2944-
(errcode(ERRCODE_SYNTAX_ERROR),
2945-
errmsg("too few parameters specified for RAISE")));
2944+
elog(ERROR, "unexpected RAISE parameter list length");
29462945

29472946
paramvalue = exec_eval_expr(estate,
29482947
(PLpgSQL_expr *) lfirst(current_param),
@@ -2963,14 +2962,9 @@ exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
29632962
appendStringInfoChar(&ds, cp[0]);
29642963
}
29652964

2966-
/*
2967-
* If more parameters were specified than were required to process the
2968-
* format string, throw an error
2969-
*/
2965+
/* should have been checked at compile time */
29702966
if (current_param != NULL)
2971-
ereport(ERROR,
2972-
(errcode(ERRCODE_SYNTAX_ERROR),
2973-
errmsg("too many parameters specified for RAISE")));
2967+
elog(ERROR, "unexpected RAISE parameter list length");
29742968

29752969
err_message = ds.data;
29762970
/* No pfree(ds.data), the pfree(err_message) does it */

src/pl/plpgsql/src/pl_gram.y

+38
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ static void check_labels(const char *start_label,
106106
static PLpgSQL_expr *read_cursor_args(PLpgSQL_var *cursor,
107107
int until, const char *expected);
108108
static List *read_raise_options(void);
109+
static void check_raise_parameters(PLpgSQL_stmt_raise *stmt);
109110

110111
%}
111112

@@ -1849,6 +1850,8 @@ stmt_raise : K_RAISE
18491850
new->options = read_raise_options();
18501851
}
18511852

1853+
check_raise_parameters(new);
1854+
18521855
$$ = (PLpgSQL_stmt *)new;
18531856
}
18541857
;
@@ -3767,6 +3770,41 @@ read_raise_options(void)
37673770
return result;
37683771
}
37693772

3773+
/*
3774+
* Check that the number of parameter placeholders in the message matches the
3775+
* number of parameters passed to it, if a message was given.
3776+
*/
3777+
static void
3778+
check_raise_parameters(PLpgSQL_stmt_raise *stmt)
3779+
{
3780+
char *cp;
3781+
int expected_nparams = 0;
3782+
3783+
if (stmt->message == NULL)
3784+
return;
3785+
3786+
for (cp = stmt->message; *cp; cp++)
3787+
{
3788+
if (cp[0] == '%')
3789+
{
3790+
/* ignore literal % characters */
3791+
if (cp[1] == '%')
3792+
cp++;
3793+
else
3794+
expected_nparams++;
3795+
}
3796+
}
3797+
3798+
if (expected_nparams < list_length(stmt->params))
3799+
ereport(ERROR,
3800+
(errcode(ERRCODE_SYNTAX_ERROR),
3801+
errmsg("too many parameters specified for RAISE")));
3802+
if (expected_nparams > list_length(stmt->params))
3803+
ereport(ERROR,
3804+
(errcode(ERRCODE_SYNTAX_ERROR),
3805+
errmsg("too few parameters specified for RAISE")));
3806+
}
3807+
37703808
/*
37713809
* Fix up CASE statement
37723810
*/

src/test/regress/expected/plpgsql.out

+15-4
Original file line numberDiff line numberDiff line change
@@ -2446,18 +2446,29 @@ begin
24462446
return $1;
24472447
end;
24482448
$$ language plpgsql;
2449-
select raise_test1(5);
24502449
ERROR: too many parameters specified for RAISE
2451-
CONTEXT: PL/pgSQL function raise_test1(integer) line 3 at RAISE
2450+
CONTEXT: compilation of PL/pgSQL function "raise_test1" near line 3
24522451
create function raise_test2(int) returns int as $$
24532452
begin
24542453
raise notice 'This message has too few parameters: %, %, %', $1, $1;
24552454
return $1;
24562455
end;
24572456
$$ language plpgsql;
2458-
select raise_test2(10);
24592457
ERROR: too few parameters specified for RAISE
2460-
CONTEXT: PL/pgSQL function raise_test2(integer) line 3 at RAISE
2458+
CONTEXT: compilation of PL/pgSQL function "raise_test2" near line 3
2459+
create function raise_test3(int) returns int as $$
2460+
begin
2461+
raise notice 'This message has no parameters (despite having %% signs in it)!';
2462+
return $1;
2463+
end;
2464+
$$ language plpgsql;
2465+
select raise_test3(1);
2466+
NOTICE: This message has no parameters (despite having % signs in it)!
2467+
raise_test3
2468+
-------------
2469+
1
2470+
(1 row)
2471+
24612472
-- Test re-RAISE inside a nested exception block. This case is allowed
24622473
-- by Oracle's PL/SQL but was handled differently by PG before 9.1.
24632474
CREATE FUNCTION reraise_test() RETURNS void AS $$

src/test/regress/sql/plpgsql.sql

+8-3
Original file line numberDiff line numberDiff line change
@@ -2078,16 +2078,21 @@ begin
20782078
end;
20792079
$$ language plpgsql;
20802080

2081-
select raise_test1(5);
2082-
20832081
create function raise_test2(int) returns int as $$
20842082
begin
20852083
raise notice 'This message has too few parameters: %, %, %', $1, $1;
20862084
return $1;
20872085
end;
20882086
$$ language plpgsql;
20892087

2090-
select raise_test2(10);
2088+
create function raise_test3(int) returns int as $$
2089+
begin
2090+
raise notice 'This message has no parameters (despite having %% signs in it)!';
2091+
return $1;
2092+
end;
2093+
$$ language plpgsql;
2094+
2095+
select raise_test3(1);
20912096

20922097
-- Test re-RAISE inside a nested exception block. This case is allowed
20932098
-- by Oracle's PL/SQL but was handled differently by PG before 9.1.

0 commit comments

Comments
 (0)