Tom Lane wrote:
I'd lean to the former myself --- which actually does suggest that this
patch is not ready for application yet, because it banks on the
assumption that "x,y,z" should be treated as a single expression.

Attached is a revised patch that stores the RAISE parameters as a list of expressions, and evaluates that list via repeated application of exec_eval_expr(). I also updated the regression tests to not remove the SQLERRM/SQLSTATE tests. Applied to HEAD.

-Neil
Index: doc/src/sgml/plpgsql.sgml
===================================================================
RCS file: /var/lib/cvs/pgsql/doc/src/sgml/plpgsql.sgml,v
retrieving revision 1.71
diff -c -r1.71 plpgsql.sgml
*** doc/src/sgml/plpgsql.sgml	10 Jun 2005 16:23:09 -0000	1.71
--- doc/src/sgml/plpgsql.sgml	14 Jun 2005 04:57:37 -0000
***************
*** 2533,2541 ****
     <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.
     </para>
  
     <!--
--- 2533,2541 ----
     <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>. 
!     Arguments can be simple variables or expressions, 
!     and the format must be a simple string literal.
     </para>
  
     <!--
Index: src/pl/plpgsql/src/gram.y
===================================================================
RCS file: /var/lib/cvs/pgsql/src/pl/plpgsql/src/gram.y,v
retrieving revision 1.75
diff -c -r1.75 gram.y
*** src/pl/plpgsql/src/gram.y	10 Jun 2005 16:23:11 -0000	1.75
--- src/pl/plpgsql/src/gram.y	14 Jun 2005 06:24:36 -0000
***************
*** 135,142 ****
  %type <exception>	proc_exception
  %type <condition>	proc_conditions
  
! %type <list>	raise_params
! %type <ival>	raise_level raise_param
  %type <str>		raise_msg
  
  %type <list>	getdiag_list
--- 135,142 ----
  %type <exception>	proc_exception
  %type <condition>	proc_conditions
  
! 
! %type <ival>	raise_level
  %type <str>		raise_msg
  
  %type <list>	getdiag_list
***************
*** 1157,1165 ****
  					}
  				;
  
! stmt_raise		: K_RAISE lno raise_level raise_msg raise_params ';'
  					{
  						PLpgSQL_stmt_raise		*new;
  
  						new = palloc(sizeof(PLpgSQL_stmt_raise));
  
--- 1157,1166 ----
  					}
  				;
  
! stmt_raise		: K_RAISE lno raise_level raise_msg
  					{
  						PLpgSQL_stmt_raise		*new;
+ 						int	tok;
  
  						new = palloc(sizeof(PLpgSQL_stmt_raise));
  
***************
*** 1167,1187 ****
  						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;
  
! 						new = palloc(sizeof(PLpgSQL_stmt_raise));
  
! 						new->cmd_type	= PLPGSQL_STMT_RAISE;
! 						new->lineno		= $2;
! 						new->elog_level = $3;
! 						new->message	= $4;
! 						new->params		= NIL;
  
  						$$ = (PLpgSQL_stmt *)new;
  					}
--- 1168,1200 ----
  						new->lineno		= $2;
  						new->elog_level = $3;
  						new->message	= $4;
! 						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;
  					}
***************
*** 1219,1240 ****
  					}
  				;
  
- 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; }
  				;
--- 1232,1237 ----
***************
*** 1658,1664 ****
   * 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)
   * endtoken:	if not NULL, ending token is stored at *endtoken
   *				(this is only interesting if until2 isn't zero)
   */
--- 1655,1661 ----
   * 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 expr (prefixed with sqlstart)
   * endtoken:	if not NULL, ending token is stored at *endtoken
   *				(this is only interesting if until2 isn't zero)
   */
Index: src/pl/plpgsql/src/pl_exec.c
===================================================================
RCS file: /var/lib/cvs/pgsql/src/pl/plpgsql/src/pl_exec.c,v
retrieving revision 1.143
diff -c -r1.143 pl_exec.c
*** src/pl/plpgsql/src/pl_exec.c	10 Jun 2005 16:23:11 -0000	1.143
--- src/pl/plpgsql/src/pl_exec.c	14 Jun 2005 06:25:50 -0000
***************
*** 594,600 ****
  	error_context_stack = plerrcontext.previous;
  
  	/*
! 	 * Return the triggers result
  	 */
  	return rettup;
  }
--- 594,600 ----
  	error_context_stack = plerrcontext.previous;
  
  	/*
! 	 * Return the trigger's result
  	 */
  	return rettup;
  }
***************
*** 1095,1116 ****
  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)));
  
  	exec_set_found(estate, (estate->eval_processed != 0));
- 
  	exec_eval_cleanup(estate);
  
  	return PLPGSQL_RC_OK;
--- 1095,1103 ----
  exec_stmt_perform(PLpgSQL_execstate *estate, PLpgSQL_stmt_perform *stmt)
  {
  	PLpgSQL_expr *expr = stmt->expr;
  
+ 	(void) exec_run_select(estate, expr, 0, NULL);
  	exec_set_found(estate, (estate->eval_processed != 0));
  	exec_eval_cleanup(estate);
  
  	return PLPGSQL_RC_OK;
***************
*** 1941,1955 ****
  						(errcode(ERRCODE_SYNTAX_ERROR),
  						 errmsg("too few parameters specified for RAISE")));
  
! 			exec_eval_datum(estate, estate->datums[lfirst_int(current_param)],
! 							InvalidOid,
! 							&paramtypeid, &paramvalue, &paramisnull);
  			if (paramisnull)
  				extval = "<NULL>";
  			else
  				extval = convert_value_to_string(paramvalue, paramtypeid);
  			plpgsql_dstring_append(&ds, extval);
  			current_param = lnext(current_param);
  			continue;
  		}
  
--- 1928,1945 ----
  						(errcode(ERRCODE_SYNTAX_ERROR),
  						 errmsg("too few parameters specified for RAISE")));
  
! 			paramvalue = exec_eval_expr(estate,
! 										(PLpgSQL_expr *) lfirst(current_param),
! 										&paramisnull,
! 										&paramtypeid);
! 
  			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;
  		}
  
Index: src/pl/plpgsql/src/pl_funcs.c
===================================================================
RCS file: /var/lib/cvs/pgsql/src/pl/plpgsql/src/pl_funcs.c,v
retrieving revision 1.42
diff -c -r1.42 pl_funcs.c
*** src/pl/plpgsql/src/pl_funcs.c	14 Jun 2005 00:10:02 -0000	1.42
--- src/pl/plpgsql/src/pl_funcs.c	14 Jun 2005 06:23:23 -0000
***************
*** 885,897 ****
  static void
  dump_raise(PLpgSQL_stmt_raise *stmt)
  {
! 	ListCell *l;
  
  	dump_ind();
! 	printf("RAISE '%s'", stmt->message);
! 	foreach (l, stmt->params)
! 		printf(" %d", lfirst_int(l));
! 	printf("\n");
  }
  
  static void
--- 885,904 ----
  static void
  dump_raise(PLpgSQL_stmt_raise *stmt)
  {
! 	ListCell *lc;
! 	int i = 0;
  
  	dump_ind();
! 	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
***************
*** 916,922 ****
  	{
  		dump_ind();
  		printf("    target = %d %s\n", stmt->rec->recno, stmt->rec->refname);
! 	} else if (stmt->row != NULL)
  	{
  		dump_ind();
  		printf("    target = %d %s\n", stmt->row->rowno, stmt->row->refname);
--- 923,930 ----
  	{
  		dump_ind();
  		printf("    target = %d %s\n", stmt->rec->recno, stmt->rec->refname);
! 	}
! 	else if (stmt->row != NULL)
  	{
  		dump_ind();
  		printf("    target = %d %s\n", stmt->row->rowno, stmt->row->refname);
Index: src/pl/plpgsql/src/plpgsql.h
===================================================================
RCS file: /var/lib/cvs/pgsql/src/pl/plpgsql/src/plpgsql.h,v
retrieving revision 1.62
diff -c -r1.62 plpgsql.h
*** src/pl/plpgsql/src/plpgsql.h	10 Jun 2005 16:23:11 -0000	1.62
--- src/pl/plpgsql/src/plpgsql.h	14 Jun 2005 06:33:24 -0000
***************
*** 515,521 ****
  	int			lineno;
  	int			elog_level;
  	char	   *message;
! 	List	   *params;
  } PLpgSQL_stmt_raise;
  
  
--- 515,521 ----
  	int			lineno;
  	int			elog_level;
  	char	   *message;
! 	List	   *params;			/* list of expressions */
  } PLpgSQL_stmt_raise;
  
  
Index: src/test/regress/expected/plpgsql.out
===================================================================
RCS file: /var/lib/cvs/pgsql/src/test/regress/expected/plpgsql.out,v
retrieving revision 1.33
diff -c -r1.33 plpgsql.out
*** src/test/regress/expected/plpgsql.out	10 Jun 2005 16:23:11 -0000	1.33
--- src/test/regress/expected/plpgsql.out	14 Jun 2005 06:30:31 -0000
***************
*** 2418,2434 ****
  --
  -- SQLSTATE and SQLERRM test
  --
! -- should fail: SQLSTATE and SQLERRM are only in defined EXCEPTION
! -- blocks
! create function excpt_test() 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 $$
  begin
      begin
          begin
--- 2418,2434 ----
  --
  -- SQLSTATE and SQLERRM test
  --
! 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();
! 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
***************
*** 2436,2445 ****
          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 $$
  begin
      begin
      	raise exception 'user exception';
--- 2436,2447 ----
          end;
      end;
  end; $$ language plpgsql;
! -- 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';
***************
*** 2458,2471 ****
  	    raise notice '% %', sqlstate, sqlerrm;
      end;
  end; $$ language plpgsql;
! select excpt_test();
  NOTICE:  caught exception P0001 user exception
  NOTICE:  P0001 user exception
  NOTICE:  caught exception 22012 division by zero
  NOTICE:  P0001 user exception
!  excpt_test 
! ------------
   
  (1 row)
  
! drop function excpt_test();
--- 2460,2493 ----
  	    raise notice '% %', sqlstate, sqlerrm;
      end;
  end; $$ language plpgsql;
! 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_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 raise_exprs();
Index: src/test/regress/sql/plpgsql.sql
===================================================================
RCS file: /var/lib/cvs/pgsql/src/test/regress/sql/plpgsql.sql,v
retrieving revision 1.28
diff -c -r1.28 plpgsql.sql
*** src/test/regress/sql/plpgsql.sql	10 Jun 2005 16:23:11 -0000	1.28
--- src/test/regress/sql/plpgsql.sql	14 Jun 2005 06:26:52 -0000
***************
*** 2055,2069 ****
  -- SQLSTATE and SQLERRM test
  --
  
! -- should fail: SQLSTATE and SQLERRM are only in defined EXCEPTION
! -- blocks
! create function excpt_test() returns void as $$
  begin
      raise notice '% %', sqlstate, sqlerrm;
  end; $$ language plpgsql;
  
! -- should fail
! create function excpt_test() returns void as $$
  begin
      begin
          begin
--- 2055,2069 ----
  -- SQLSTATE and SQLERRM test
  --
  
! 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();
  
! create function excpt_test2() returns void as $$
  begin
      begin
          begin
***************
*** 2071,2078 ****
          end;
      end;
  end; $$ language plpgsql;
  
! create function excpt_test() returns void as $$
  begin
      begin
      	raise exception 'user exception';
--- 2071,2080 ----
          end;
      end;
  end; $$ language plpgsql;
+ -- should fail
+ select excpt_test2();
  
! create function excpt_test3() returns void as $$
  begin
      begin
      	raise exception 'user exception';
***************
*** 2092,2096 ****
      end;
  end; $$ language plpgsql;
  
! select excpt_test();
! drop function excpt_test();
--- 2094,2114 ----
      end;
  end; $$ language plpgsql;
  
! 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();
---------------------------(end of broadcast)---------------------------
TIP 7: don't forget to increase your free space map settings

Reply via email to