<!--
-$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">
<para>
Inside the format string, <literal>%</literal> is replaced by the
next optional argument's string representation. Write
- <literal>%%</literal> to emit a literal <literal>%</literal>. Note
- that the optional arguments must presently be simple variables,
- not expressions, and the format must be a simple string literal.
+ <literal>%%</literal> to emit a literal <literal>%</literal>.
+ Arguments can be simple variables or expressions,
+ and the format must be a simple string literal.
</para>
<!--
* procedural language
*
* 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.
*
%type <exception> proc_exception
%type <condition> proc_conditions
-%type <list> raise_params
-%type <ival> raise_level raise_param
+
+%type <ival> raise_level
%type <str> raise_msg
%type <list> getdiag_list
}
;
-stmt_raise : K_RAISE lno raise_level raise_msg raise_params ';'
+stmt_raise : K_RAISE lno raise_level raise_msg
{
PLpgSQL_stmt_raise *new;
+ int tok;
new = palloc(sizeof(PLpgSQL_stmt_raise));
new->lineno = $2;
new->elog_level = $3;
new->message = $4;
- new->params = $5;
+ new->params = NIL;
- $$ = (PLpgSQL_stmt *)new;
- }
- | K_RAISE lno raise_level raise_msg ';'
- {
- PLpgSQL_stmt_raise *new;
+ tok = yylex();
- new = palloc(sizeof(PLpgSQL_stmt_raise));
+ /*
+ * 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");
- new->cmd_type = PLPGSQL_STMT_RAISE;
- new->lineno = $2;
- new->elog_level = $3;
- new->message = $4;
- new->params = NIL;
+ 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;
}
}
;
-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 ';'
{ $$ = $1; }
;
* expected: text to use in complaining that terminator was not found
* sqlstart: text to prefix to the accumulated SQL text
* 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
* (this is only interesting if until2 isn't zero)
*/
* procedural language
*
* 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.
*
error_context_stack = plerrcontext.previous;
/*
- * Return the triggers result
+ * Return the trigger's result
*/
return rettup;
}
exec_stmt_perform(PLpgSQL_execstate *estate, PLpgSQL_stmt_perform *stmt)
{
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_eval_cleanup(estate);
return PLPGSQL_RC_OK;
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("too few parameters specified for RAISE")));
- exec_eval_datum(estate, estate->datums[lfirst_int(current_param)],
- InvalidOid,
- ¶mtypeid, ¶mvalue, ¶misnull);
+ paramvalue = exec_eval_expr(estate,
+ (PLpgSQL_expr *) lfirst(current_param),
+ ¶misnull,
+ ¶mtypeid);
+
if (paramisnull)
extval = "<NULL>";
else
extval = convert_value_to_string(paramvalue, paramtypeid);
plpgsql_dstring_append(&ds, extval);
current_param = lnext(current_param);
+ exec_eval_cleanup(estate);
continue;
}
* procedural language
*
* 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.
*
static void
dump_raise(PLpgSQL_stmt_raise *stmt)
{
- ListCell *l;
+ ListCell *lc;
+ int i = 0;
dump_ind();
- printf("RAISE '%s'", stmt->message);
- foreach (l, stmt->params)
- printf(" %d", lfirst_int(l));
- printf("\n");
+ printf("RAISE '%s'\n", stmt->message);
+ dump_indent += 2;
+ foreach (lc, stmt->params)
+ {
+ dump_ind();
+ printf(" parameter %d: ", i++);
+ dump_expr((PLpgSQL_expr *) lfirst(lc));
+ printf("\n");
+ }
+ dump_indent -= 2;
}
static void
{
dump_ind();
printf(" target = %d %s\n", stmt->rec->recno, stmt->rec->refname);
- } else if (stmt->row != NULL)
+ }
+ else if (stmt->row != NULL)
{
dump_ind();
printf(" target = %d %s\n", stmt->row->rowno, stmt->row->refname);
* procedural language
*
* 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.
*
int lineno;
int elog_level;
char *message;
- List *params;
+ List *params; /* list of expressions */
} PLpgSQL_stmt_raise;
--
-- SQLSTATE and SQLERRM test
--
--- should fail: SQLSTATE and SQLERRM are only in defined EXCEPTION
--- blocks
-create function excpt_test() returns void as $$
+create function excpt_test1() returns void as $$
begin
raise notice '% %', sqlstate, sqlerrm;
end; $$ language plpgsql;
-ERROR: syntax error at or near "sqlstate" at character 79
-LINE 3: raise notice '% %', sqlstate, sqlerrm;
- ^
--- should fail
-create function excpt_test() returns void as $$
+-- should fail: SQLSTATE and SQLERRM are only in defined EXCEPTION
+-- blocks
+select excpt_test1();
+ERROR: column "sqlstate" does not exist
+CONTEXT: SQL statement "SELECT sqlstate"
+PL/pgSQL function "excpt_test1" line 2 at raise
+create function excpt_test2() returns void as $$
begin
begin
begin
end;
end;
end; $$ language plpgsql;
-ERROR: syntax error at or near "sqlstate" at character 108
-LINE 5: raise notice '% %', sqlstate, sqlerrm;
- ^
-create function excpt_test() returns void as $$
+-- should fail
+select excpt_test2();
+ERROR: column "sqlstate" does not exist
+CONTEXT: SQL statement "SELECT sqlstate"
+PL/pgSQL function "excpt_test2" line 4 at raise
+create function excpt_test3() returns void as $$
begin
begin
raise exception 'user exception';
raise notice '% %', sqlstate, sqlerrm;
end;
end; $$ language plpgsql;
-select excpt_test();
+select excpt_test3();
NOTICE: caught exception P0001 user exception
NOTICE: P0001 user exception
NOTICE: caught exception 22012 division by zero
NOTICE: P0001 user exception
- excpt_test
-------------
+ excpt_test3
+-------------
+
+(1 row)
+
+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 excpt_test();
+drop function raise_exprs();
-- SQLSTATE and SQLERRM test
--
--- should fail: SQLSTATE and SQLERRM are only in defined EXCEPTION
--- blocks
-create function excpt_test() returns void as $$
+create function excpt_test1() returns void as $$
begin
raise notice '% %', sqlstate, sqlerrm;
end; $$ language plpgsql;
+-- should fail: SQLSTATE and SQLERRM are only in defined EXCEPTION
+-- blocks
+select excpt_test1();
--- should fail
-create function excpt_test() returns void as $$
+create function excpt_test2() returns void as $$
begin
begin
begin
end;
end;
end; $$ language plpgsql;
+-- should fail
+select excpt_test2();
-create function excpt_test() returns void as $$
+create function excpt_test3() returns void as $$
begin
begin
raise exception 'user exception';
end;
end; $$ language plpgsql;
-select excpt_test();
-drop function excpt_test();
+select excpt_test3();
+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();