Index: src/pl/plpgsql/src/gram.y
===================================================================
RCS file: /var/lib/cvs/pgsql/src/pl/plpgsql/src/gram.y,v
retrieving revision 1.64
diff -c -r1.64 gram.y
*** src/pl/plpgsql/src/gram.y	25 Oct 2004 06:27:21 -0000	1.64
--- src/pl/plpgsql/src/gram.y	18 Jan 2005 04:51:16 -0000
***************
*** 86,91 ****
--- 86,92 ----
  			int  n_initvars;
  			int  *initvarnos;
  		}						declhdr;
+ 		List					*list;
  		PLpgSQL_type			*dtype;
  		PLpgSQL_datum			*scalar;	/* a VAR, RECFIELD, or TRIGARG */
  		PLpgSQL_variable		*variable;	/* a VAR, REC, or ROW */
***************
*** 94,104 ****
  		PLpgSQL_rec				*rec;
  		PLpgSQL_expr			*expr;
  		PLpgSQL_stmt			*stmt;
- 		PLpgSQL_stmts			*stmts;
  		PLpgSQL_stmt_block		*program;
  		PLpgSQL_condition		*condition;
  		PLpgSQL_exception		*exception;
- 		PLpgSQL_exceptions		*exceptions;
  		PLpgSQL_nsitem			*nsitem;
  }
  
--- 95,103 ----
***************
*** 126,132 ****
  %type <str>		opt_exitlabel
  %type <str>		execsql_start
  
! %type <stmts>	proc_sect proc_stmts stmt_else loop_body
  %type <stmt>	proc_stmt pl_block
  %type <stmt>	stmt_assign stmt_if stmt_loop stmt_while stmt_exit
  %type <stmt>	stmt_return stmt_return_next stmt_raise stmt_execsql
--- 125,131 ----
  %type <str>		opt_exitlabel
  %type <str>		execsql_start
  
! %type <list>	proc_sect proc_stmts stmt_else loop_body
  %type <stmt>	proc_stmt pl_block
  %type <stmt>	stmt_assign stmt_if stmt_loop stmt_while stmt_exit
  %type <stmt>	stmt_return stmt_return_next stmt_raise stmt_execsql
***************
*** 134,140 ****
  %type <stmt>	stmt_dynexecute stmt_getdiag
  %type <stmt>	stmt_open stmt_fetch stmt_close stmt_null
  
! %type <exceptions>	exception_sect proc_exceptions
  %type <exception>	proc_exception
  %type <condition>	proc_conditions
  
--- 133,139 ----
  %type <stmt>	stmt_dynexecute stmt_getdiag
  %type <stmt>	stmt_open stmt_fetch stmt_close stmt_null
  
! %type <list>	exception_sect proc_exceptions
  %type <exception>	proc_exception
  %type <condition>	proc_conditions
  
***************
*** 240,246 ****
  
  comp_option		: O_OPTION O_DUMP
  					{
! 						plpgsql_DumpExecTree = 1;
  					}
  				;
  
--- 239,245 ----
  
  comp_option		: O_OPTION O_DUMP
  					{
! 						plpgsql_DumpExecTree = true;
  					}
  				;
  
***************
*** 252,259 ****
  					{
  						PLpgSQL_stmt_block *new;
  
! 						new = malloc(sizeof(PLpgSQL_stmt_block));
! 						memset(new, 0, sizeof(PLpgSQL_stmt_block));
  
  						new->cmd_type	= PLPGSQL_STMT_BLOCK;
  						new->lineno		= $3;
--- 251,257 ----
  					{
  						PLpgSQL_stmt_block *new;
  
! 						new = palloc0(sizeof(PLpgSQL_stmt_block));
  
  						new->cmd_type	= PLPGSQL_STMT_BLOCK;
  						new->lineno		= $3;
***************
*** 379,386 ****
  																		  -1),
  												   true);
  
! 						curname_def = malloc(sizeof(PLpgSQL_expr));
! 						memset(curname_def, 0, sizeof(PLpgSQL_expr));
  
  						curname_def->dtype = PLPGSQL_DTYPE_EXPR;
  						strcpy(buf, "SELECT '");
--- 377,383 ----
  																		  -1),
  												   true);
  
! 						curname_def = palloc0(sizeof(PLpgSQL_expr));
  
  						curname_def->dtype = PLPGSQL_DTYPE_EXPR;
  						strcpy(buf, "SELECT '");
***************
*** 393,399 ****
  							*cp2++ = *cp1++;
  						}
  						strcpy(cp2, "'::refcursor");
! 						curname_def->query = strdup(buf);
  						new->default_val = curname_def;
  
  						new->cursor_explicit_expr = $6;
--- 390,396 ----
  							*cp2++ = *cp1++;
  						}
  						strcpy(cp2, "'::refcursor");
! 						curname_def->query = pstrdup(buf);
  						new->default_val = curname_def;
  
  						new->cursor_explicit_expr = $6;
***************
*** 422,445 ****
  					}
  				| '(' decl_cursor_arglist ')'
  					{
- 						/* Copy the temp arrays to malloc'd storage */
- 						int nfields = $2->nfields;
- 						char **ftmp;
- 						int *vtmp;
- 
- 						ftmp = malloc(nfields * sizeof(char *));
- 						vtmp = malloc(nfields * sizeof(int));
- 						memcpy(ftmp, $2->fieldnames, nfields * sizeof(char *));
- 						memcpy(vtmp, $2->varnos, nfields * sizeof(int));
- 
- 						pfree($2->fieldnames);
- 						pfree($2->varnos);
- 
- 						$2->fieldnames = ftmp;
- 						$2->varnos = vtmp;
- 
  						plpgsql_adddatum((PLpgSQL_datum *)$2);
- 
  						$$ = $2;
  					}
  				;
--- 419,425 ----
***************
*** 448,458 ****
  					{
  						PLpgSQL_row *new;
  
! 						new = malloc(sizeof(PLpgSQL_row));
! 						memset(new, 0, sizeof(PLpgSQL_row));
  
  						new->dtype = PLPGSQL_DTYPE_ROW;
! 						new->refname = strdup("*internal*");
  						new->lineno = plpgsql_scanner_lineno();
  						new->rowtupdesc = NULL;
  						/*
--- 428,437 ----
  					{
  						PLpgSQL_row *new;
  
! 						new = palloc0(sizeof(PLpgSQL_row));
  
  						new->dtype = PLPGSQL_DTYPE_ROW;
! 						new->refname = pstrdup("*internal*");
  						new->lineno = plpgsql_scanner_lineno();
  						new->rowtupdesc = NULL;
  						/*
***************
*** 524,531 ****
  						char	*name;
  
  						plpgsql_convert_ident(yytext, &name, 1);
! 						/* name should be malloc'd for use as varname */
! 						$$.name = strdup(name);
  						$$.lineno  = plpgsql_scanner_lineno();
  						pfree(name);
  					}
--- 503,509 ----
  						char	*name;
  
  						plpgsql_convert_ident(yytext, &name, 1);
! 						$$.name = pstrdup(name);
  						$$.lineno  = plpgsql_scanner_lineno();
  						pfree(name);
  					}
***************
*** 580,590 ****
  
  proc_sect		:
  					{
! 							PLpgSQL_stmts	*new;
! 
! 							new = malloc(sizeof(PLpgSQL_stmts));
! 							memset(new, 0, sizeof(PLpgSQL_stmts));
! 							$$ = new;
  					}
  				| proc_stmts
  					{ $$ = $1; }
--- 558,564 ----
  
  proc_sect		:
  					{
! 						$$ = NIL;
  					}
  				| proc_stmts
  					{ $$ = $1; }
***************
*** 592,622 ****
  
  proc_stmts		: proc_stmts proc_stmt
  						{
! 							if ($2 != NULL)
! 							{
! 								if ($1->stmts_used == $1->stmts_alloc)
! 								{
! 									$1->stmts_alloc *= 2;
! 									$1->stmts = realloc($1->stmts, sizeof(PLpgSQL_stmt *) * $1->stmts_alloc);
! 								}
! 								$1->stmts[$1->stmts_used++] = $2;
! 							}
! 							$$ = $1;
  						}
  				| proc_stmt
  						{
! 							PLpgSQL_stmts	*new;
! 
! 							new = malloc(sizeof(PLpgSQL_stmts));
! 							memset(new, 0, sizeof(PLpgSQL_stmts));
! 
! 							new->stmts_alloc = 32;
! 							new->stmts = malloc(sizeof(PLpgSQL_stmt *) * new->stmts_alloc);
! 
! 							if ($1 != NULL)
! 								new->stmts[new->stmts_used++] = $1;
! 
! 							$$ = new;
  						}
  				;
  
--- 566,582 ----
  
  proc_stmts		: proc_stmts proc_stmt
  						{
! 							if ($2 == NULL)
! 								$$ = $1;
! 							else
! 								$$ = lappend($1, $2);
  						}
  				| proc_stmt
  						{
! 							if ($1 == NULL)
! 								$$ = NULL;
! 							else
! 								$$ = list_make1($1);
  						}
  				;
  
***************
*** 664,672 ****
  					{
  						PLpgSQL_stmt_perform *new;
  
! 						new = malloc(sizeof(PLpgSQL_stmt_perform));
! 						memset(new, 0, sizeof(PLpgSQL_stmt_perform));
! 
  						new->cmd_type = PLPGSQL_STMT_PERFORM;
  						new->lineno   = $2;
  						new->expr  = $3;
--- 624,630 ----
  					{
  						PLpgSQL_stmt_perform *new;
  
! 						new = palloc0(sizeof(PLpgSQL_stmt_perform));
  						new->cmd_type = PLPGSQL_STMT_PERFORM;
  						new->lineno   = $2;
  						new->expr  = $3;
***************
*** 679,687 ****
  					{
  						PLpgSQL_stmt_assign *new;
  
! 						new = malloc(sizeof(PLpgSQL_stmt_assign));
! 						memset(new, 0, sizeof(PLpgSQL_stmt_assign));
! 
  						new->cmd_type = PLPGSQL_STMT_ASSIGN;
  						new->lineno   = $2;
  						new->varno = $1;
--- 637,643 ----
  					{
  						PLpgSQL_stmt_assign *new;
  
! 						new = palloc0(sizeof(PLpgSQL_stmt_assign));
  						new->cmd_type = PLPGSQL_STMT_ASSIGN;
  						new->lineno   = $2;
  						new->varno = $1;
***************
*** 695,707 ****
  					{
  						PLpgSQL_stmt_getdiag	 *new;
  
! 						new = malloc(sizeof(PLpgSQL_stmt_getdiag));
! 						memset(new, 0, sizeof(PLpgSQL_stmt_getdiag));
! 
  						new->cmd_type = PLPGSQL_STMT_GETDIAG;
  						new->lineno   = $3;
  						new->ndtitems = $4.nused;
! 						new->dtitems  = malloc(sizeof(PLpgSQL_diag_item) * $4.nused);
  						memcpy(new->dtitems, $4.dtitems, sizeof(PLpgSQL_diag_item) * $4.nused);
  
  						$$ = (PLpgSQL_stmt *)new;
--- 651,661 ----
  					{
  						PLpgSQL_stmt_getdiag	 *new;
  
! 						new = palloc0(sizeof(PLpgSQL_stmt_getdiag));
  						new->cmd_type = PLPGSQL_STMT_GETDIAG;
  						new->lineno   = $3;
  						new->ndtitems = $4.nused;
! 						new->dtitems  = palloc(sizeof(PLpgSQL_diag_item) * $4.nused);
  						memcpy(new->dtitems, $4.dtitems, sizeof(PLpgSQL_diag_item) * $4.nused);
  
  						$$ = (PLpgSQL_stmt *)new;
***************
*** 770,778 ****
  					{
  						PLpgSQL_arrayelem	*new;
  
! 						new = malloc(sizeof(PLpgSQL_arrayelem));
! 						memset(new, 0, sizeof(PLpgSQL_arrayelem));
! 
  						new->dtype		= PLPGSQL_DTYPE_ARRAYELEM;
  						new->subscript	= $3;
  						new->arrayparentno = $1;
--- 724,730 ----
  					{
  						PLpgSQL_arrayelem	*new;
  
! 						new = palloc0(sizeof(PLpgSQL_arrayelem));
  						new->dtype		= PLPGSQL_DTYPE_ARRAYELEM;
  						new->subscript	= $3;
  						new->arrayparentno = $1;
***************
*** 787,795 ****
  					{
  						PLpgSQL_stmt_if *new;
  
! 						new = malloc(sizeof(PLpgSQL_stmt_if));
! 						memset(new, 0, sizeof(PLpgSQL_stmt_if));
! 
  						new->cmd_type	= PLPGSQL_STMT_IF;
  						new->lineno		= $2;
  						new->cond		= $3;
--- 739,745 ----
  					{
  						PLpgSQL_stmt_if *new;
  
! 						new = palloc0(sizeof(PLpgSQL_stmt_if));
  						new->cmd_type	= PLPGSQL_STMT_IF;
  						new->lineno		= $2;
  						new->cond		= $3;
***************
*** 802,853 ****
  
  stmt_else		:
  					{
! 							PLpgSQL_stmts	*new;
! 
! 							new = malloc(sizeof(PLpgSQL_stmts));
! 							memset(new, 0, sizeof(PLpgSQL_stmts));
! 							$$ = new;
  					}
  				| K_ELSIF lno expr_until_then proc_sect stmt_else
  					{
! 					  /*
! 					   * Translate the structure:	   into:
! 					   *
! 					   * IF c1 THEN					   IF c1 THEN		 
! 					   *	 ...						   ...				 
! 					   * ELSIF c2 THEN				   ELSE 
! 					   *								   IF c2 THEN	
! 					   *	 ...							   ...				 
! 					   * ELSE							   ELSE				 
! 					   *	 ...							   ...				 
! 					   * END IF							   END IF			 
! 					   *							   END IF
! 					   * 
! 					   */
! 
! 						PLpgSQL_stmts	*new;
  						PLpgSQL_stmt_if *new_if;
  
  						/* first create a new if-statement */
! 						new_if = malloc(sizeof(PLpgSQL_stmt_if));
! 						memset(new_if, 0, sizeof(PLpgSQL_stmt_if));
! 
  						new_if->cmd_type	= PLPGSQL_STMT_IF;
  						new_if->lineno		= $2;
  						new_if->cond		= $3;
  						new_if->true_body	= $4;
  						new_if->false_body	= $5;
- 						
- 						/* this is a 'container' for the if-statement */
- 						new = malloc(sizeof(PLpgSQL_stmts));
- 						memset(new, 0, sizeof(PLpgSQL_stmts));
- 						
- 						new->stmts_alloc = 64;
- 						new->stmts_used	 = 1;
- 						new->stmts = malloc(sizeof(PLpgSQL_stmt *) * new->stmts_alloc);
- 						new->stmts[0] = (PLpgSQL_stmt *) new_if;
  
! 						$$ = new;
  						
  					}
  
--- 752,786 ----
  
  stmt_else		:
  					{
! 						$$ = NIL;
  					}
  				| K_ELSIF lno expr_until_then proc_sect stmt_else
  					{
! 						/*
! 						 * Translate the structure:	   into:
! 						 *
! 						 * IF c1 THEN				   IF c1 THEN
! 						 *	 ...						   ...
! 						 * ELSIF c2 THEN			   ELSE
! 						 *								   IF c2 THEN
! 						 *	 ...							   ...
! 						 * ELSE							   ELSE
! 						 *	 ...							   ...
! 						 * END IF						   END IF			 
! 						 *							   END IF
! 						 */
  						PLpgSQL_stmt_if *new_if;
  
  						/* first create a new if-statement */
! 						new_if = palloc0(sizeof(PLpgSQL_stmt_if));
  						new_if->cmd_type	= PLPGSQL_STMT_IF;
  						new_if->lineno		= $2;
  						new_if->cond		= $3;
  						new_if->true_body	= $4;
  						new_if->false_body	= $5;
  
! 						/* wrap the if-statement in a "container" list */
! 						$$ = list_make1(new_if);
  						
  					}
  
***************
*** 861,869 ****
  					{
  						PLpgSQL_stmt_loop *new;
  
! 						new = malloc(sizeof(PLpgSQL_stmt_loop));
! 						memset(new, 0, sizeof(PLpgSQL_stmt_loop));
! 
  						new->cmd_type = PLPGSQL_STMT_LOOP;
  						new->lineno   = $3;
  						new->label	  = $1;
--- 794,800 ----
  					{
  						PLpgSQL_stmt_loop *new;
  
! 						new = palloc0(sizeof(PLpgSQL_stmt_loop));
  						new->cmd_type = PLPGSQL_STMT_LOOP;
  						new->lineno   = $3;
  						new->label	  = $1;
***************
*** 879,887 ****
  					{
  						PLpgSQL_stmt_while *new;
  
! 						new = malloc(sizeof(PLpgSQL_stmt_while));
! 						memset(new, 0, sizeof(PLpgSQL_stmt_while));
! 
  						new->cmd_type = PLPGSQL_STMT_WHILE;
  						new->lineno   = $3;
  						new->label	  = $1;
--- 810,816 ----
  					{
  						PLpgSQL_stmt_while *new;
  
! 						new = palloc0(sizeof(PLpgSQL_stmt_while));
  						new->cmd_type = PLPGSQL_STMT_WHILE;
  						new->lineno   = $3;
  						new->label	  = $1;
***************
*** 974,982 ****
  								yyerror("cannot specify EXECUTE in integer for-loop");
  							}
  
- 							/* name should be malloc'd for use as varname */
  							fvar = (PLpgSQL_var *)
! 								plpgsql_build_variable(strdup($2.name),
  													   $2.lineno,
  													   plpgsql_build_datatype(INT4OID,
  																			  -1),
--- 903,910 ----
  								yyerror("cannot specify EXECUTE in integer for-loop");
  							}
  
  							fvar = (PLpgSQL_var *)
! 								plpgsql_build_variable($2.name,
  													   $2.lineno,
  													   plpgsql_build_datatype(INT4OID,
  																			  -1),
***************
*** 985,993 ****
  							/* put the for-variable into the local block */
  							plpgsql_add_initdatums(NULL);
  
! 							new = malloc(sizeof(PLpgSQL_stmt_fori));
! 							memset(new, 0, sizeof(PLpgSQL_stmt_fori));
! 
  							new->cmd_type = PLPGSQL_STMT_FORI;
  							new->lineno   = $1;
  							new->var	  = fvar;
--- 913,919 ----
  							/* put the for-variable into the local block */
  							plpgsql_add_initdatums(NULL);
  
! 							new = palloc0(sizeof(PLpgSQL_stmt_fori));
  							new->cmd_type = PLPGSQL_STMT_FORI;
  							new->lineno   = $1;
  							new->var	  = fvar;
***************
*** 1008,1016 ****
  								yyerror("cannot specify REVERSE in loop over rows");
  							}
  
! 							new = malloc(sizeof(PLpgSQL_stmt_dynfors));
! 							memset(new, 0, sizeof(PLpgSQL_stmt_dynfors));
! 
  							new->cmd_type = PLPGSQL_STMT_DYNFORS;
  							new->lineno   = $1;
  							if ($2.rec)
--- 934,940 ----
  								yyerror("cannot specify REVERSE in loop over rows");
  							}
  
! 							new = palloc0(sizeof(PLpgSQL_stmt_dynfors));
  							new->cmd_type = PLPGSQL_STMT_DYNFORS;
  							new->lineno   = $1;
  							if ($2.rec)
***************
*** 1038,1046 ****
  								yyerror("cannot specify REVERSE in loop over rows");
  							}
  
! 							new = malloc(sizeof(PLpgSQL_stmt_fors));
! 							memset(new, 0, sizeof(PLpgSQL_stmt_fors));
! 
  							new->cmd_type = PLPGSQL_STMT_FORS;
  							new->lineno   = $1;
  							if ($2.rec)
--- 962,968 ----
  								yyerror("cannot specify REVERSE in loop over rows");
  							}
  
! 							new = palloc0(sizeof(PLpgSQL_stmt_fors));
  							new->cmd_type = PLPGSQL_STMT_FORS;
  							new->lineno   = $1;
  							if ($2.rec)
***************
*** 1056,1063 ****
  							 * Must get rid of the "SELECT " we prepended
  							 * to expr1's text
  							 */
! 							newquery = strdup(expr1->query + 7);
! 							free(expr1->query);
  							expr1->query = newquery;
  
  							new->query = expr1;
--- 978,985 ----
  							 * Must get rid of the "SELECT " we prepended
  							 * to expr1's text
  							 */
! 							newquery = pstrdup(expr1->query + 7);
! 							pfree(expr1->query);
  							expr1->query = newquery;
  
  							new->query = expr1;
***************
*** 1120,1128 ****
  					{
  						PLpgSQL_stmt_exit *new;
  
! 						new = malloc(sizeof(PLpgSQL_stmt_exit));
! 						memset(new, 0, sizeof(PLpgSQL_stmt_exit));
! 
  						new->cmd_type = PLPGSQL_STMT_EXIT;
  						new->lineno   = $2;
  						new->label	  = $3;
--- 1042,1048 ----
  					{
  						PLpgSQL_stmt_exit *new;
  
! 						new = palloc0(sizeof(PLpgSQL_stmt_exit));
  						new->cmd_type = PLPGSQL_STMT_EXIT;
  						new->lineno   = $2;
  						new->label	  = $3;
***************
*** 1136,1143 ****
  					{
  						PLpgSQL_stmt_return *new;
  
! 						new = malloc(sizeof(PLpgSQL_stmt_return));
! 						memset(new, 0, sizeof(PLpgSQL_stmt_return));
  						new->expr = NULL;
  						new->retrecno	= -1;
  						new->retrowno	= -1;
--- 1056,1062 ----
  					{
  						PLpgSQL_stmt_return *new;
  
! 						new = palloc0(sizeof(PLpgSQL_stmt_return));
  						new->expr = NULL;
  						new->retrecno	= -1;
  						new->retrowno	= -1;
***************
*** 1189,1197 ****
  						if (!plpgsql_curr_compile->fn_retset)
  							yyerror("cannot use RETURN NEXT in a non-SETOF function");
  
! 						new = malloc(sizeof(PLpgSQL_stmt_return_next));
! 						memset(new, 0, sizeof(PLpgSQL_stmt_return_next));
! 
  						new->cmd_type	= PLPGSQL_STMT_RETURN_NEXT;
  						new->lineno		= $2;
  
--- 1108,1114 ----
  						if (!plpgsql_curr_compile->fn_retset)
  							yyerror("cannot use RETURN NEXT in a non-SETOF function");
  
! 						new = palloc0(sizeof(PLpgSQL_stmt_return_next));
  						new->cmd_type	= PLPGSQL_STMT_RETURN_NEXT;
  						new->lineno		= $2;
  
***************
*** 1220,1226 ****
  					{
  						PLpgSQL_stmt_raise		*new;
  
! 						new = malloc(sizeof(PLpgSQL_stmt_raise));
  
  						new->cmd_type	= PLPGSQL_STMT_RAISE;
  						new->lineno		= $2;
--- 1137,1143 ----
  					{
  						PLpgSQL_stmt_raise		*new;
  
! 						new = palloc(sizeof(PLpgSQL_stmt_raise));
  
  						new->cmd_type	= PLPGSQL_STMT_RAISE;
  						new->lineno		= $2;
***************
*** 1236,1242 ****
  					{
  						PLpgSQL_stmt_raise		*new;
  
! 						new = malloc(sizeof(PLpgSQL_stmt_raise));
  
  						new->cmd_type	= PLPGSQL_STMT_RAISE;
  						new->lineno		= $2;
--- 1153,1159 ----
  					{
  						PLpgSQL_stmt_raise		*new;
  
! 						new = palloc(sizeof(PLpgSQL_stmt_raise));
  
  						new->cmd_type	= PLPGSQL_STMT_RAISE;
  						new->lineno		= $2;
***************
*** 1317,1323 ****
  					{
  						PLpgSQL_stmt_execsql	*new;
  
! 						new = malloc(sizeof(PLpgSQL_stmt_execsql));
  						new->cmd_type = PLPGSQL_STMT_EXECSQL;
  						new->lineno   = $2;
  						new->sqlstmt  = read_sql_stmt($1);
--- 1234,1240 ----
  					{
  						PLpgSQL_stmt_execsql	*new;
  
! 						new = palloc(sizeof(PLpgSQL_stmt_execsql));
  						new->cmd_type = PLPGSQL_STMT_EXECSQL;
  						new->lineno   = $2;
  						new->sqlstmt  = read_sql_stmt($1);
***************
*** 1330,1336 ****
  						{
  							PLpgSQL_stmt_dynexecute *new;
  
! 							new = malloc(sizeof(PLpgSQL_stmt_dynexecute));
  							new->cmd_type = PLPGSQL_STMT_DYNEXECUTE;
  							new->lineno   = $2;
  							new->query	  = $3;
--- 1247,1253 ----
  						{
  							PLpgSQL_stmt_dynexecute *new;
  
! 							new = palloc(sizeof(PLpgSQL_stmt_dynexecute));
  							new->cmd_type = PLPGSQL_STMT_DYNEXECUTE;
  							new->lineno   = $2;
  							new->query	  = $3;
***************
*** 1344,1352 ****
  						PLpgSQL_stmt_open *new;
  						int				  tok;
  
! 						new = malloc(sizeof(PLpgSQL_stmt_open));
! 						memset(new, 0, sizeof(PLpgSQL_stmt_open));
! 
  						new->cmd_type = PLPGSQL_STMT_OPEN;
  						new->lineno = $2;
  						new->curvar = $3->varno;
--- 1261,1267 ----
  						PLpgSQL_stmt_open *new;
  						int				  tok;
  
! 						new = palloc0(sizeof(PLpgSQL_stmt_open));
  						new->cmd_type = PLPGSQL_STMT_OPEN;
  						new->lineno = $2;
  						new->curvar = $3->varno;
***************
*** 1488,1494 ****
  					{
  						PLpgSQL_stmt_close *new;
  
! 						new = malloc(sizeof(PLpgSQL_stmt_close));
  						new->cmd_type = PLPGSQL_STMT_CLOSE;
  						new->lineno = $2;
  						new->curvar = $3;
--- 1403,1409 ----
  					{
  						PLpgSQL_stmt_close *new;
  
! 						new = palloc(sizeof(PLpgSQL_stmt_close));
  						new->cmd_type = PLPGSQL_STMT_CLOSE;
  						new->lineno = $2;
  						new->curvar = $3;
***************
*** 1539,1579 ****
  				;
  
  execsql_start	: T_WORD
! 					{ $$ = strdup(yytext); }
  				| T_ERROR
! 					{ $$ = strdup(yytext); }
  				;
  
  exception_sect	:
! 					{ $$ = NULL; }
  				| K_EXCEPTION proc_exceptions
  					{ $$ = $2; }
  				;
  
  proc_exceptions	: proc_exceptions proc_exception
  						{
! 								if ($1->exceptions_used == $1->exceptions_alloc)
! 								{
! 									$1->exceptions_alloc *= 2;
! 									$1->exceptions = realloc($1->exceptions, sizeof(PLpgSQL_exception *) * $1->exceptions_alloc);
! 								}
! 								$1->exceptions[$1->exceptions_used++] = $2;
! 
! 								$$ = $1;
  						}
  				| proc_exception
  						{
! 								PLpgSQL_exceptions	*new;
! 
! 								new = malloc(sizeof(PLpgSQL_exceptions));
! 								memset(new, 0, sizeof(PLpgSQL_exceptions));
! 
! 								new->exceptions_alloc = 16;
! 								new->exceptions_used  = 1;
! 								new->exceptions = malloc(sizeof(PLpgSQL_exception *) * new->exceptions_alloc);
! 								new->exceptions[0] = $1;
! 
! 								$$ = new;
  						}
  				;
  
--- 1454,1477 ----
  				;
  
  execsql_start	: T_WORD
! 					{ $$ = pstrdup(yytext); }
  				| T_ERROR
! 					{ $$ = pstrdup(yytext); }
  				;
  
  exception_sect	:
! 					{ $$ = NIL; }
  				| K_EXCEPTION proc_exceptions
  					{ $$ = $2; }
  				;
  
  proc_exceptions	: proc_exceptions proc_exception
  						{
! 							$$ = lappend($1, $2);
  						}
  				| proc_exception
  						{
! 							$$ = list_make1($1);
  						}
  				;
  
***************
*** 1581,1589 ****
  					{
  						PLpgSQL_exception *new;
  
! 						new = malloc(sizeof(PLpgSQL_exception));
! 						memset(new, 0, sizeof(PLpgSQL_exception));
! 
  						new->lineno     = $2;
  						new->conditions = $3;
  						new->action	    = $5;
--- 1479,1485 ----
  					{
  						PLpgSQL_exception *new;
  
! 						new = palloc0(sizeof(PLpgSQL_exception));
  						new->lineno     = $2;
  						new->conditions = $3;
  						new->action	    = $5;
***************
*** 1643,1650 ****
  						char	*name;
  
  						plpgsql_convert_ident(yytext, &name, 1);
! 						$$ = strdup(name);
! 						pfree(name);
  					}
  				| T_WORD
  					{
--- 1539,1545 ----
  						char	*name;
  
  						plpgsql_convert_ident(yytext, &name, 1);
! 						$$ = name;
  					}
  				| T_WORD
  					{
***************
*** 1664,1671 ****
  						char	*name;
  
  						plpgsql_convert_ident(yytext, &name, 1);
! 						$$ = strdup(name);
! 						pfree(name);
  					}
  				;
  
--- 1559,1565 ----
  						char	*name;
  
  						plpgsql_convert_ident(yytext, &name, 1);
! 						$$ = name;
  					}
  				;
  
***************
*** 1793,1801 ****
  	if (endtoken)
  		*endtoken = tok;
  
! 	expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - sizeof(int));
  	expr->dtype			= PLPGSQL_DTYPE_EXPR;
! 	expr->query			= strdup(plpgsql_dstring_get(&ds));
  	expr->plan			= NULL;
  	expr->nparams		= nparams;
  	while(nparams-- > 0)
--- 1687,1695 ----
  	if (endtoken)
  		*endtoken = tok;
  
! 	expr = palloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - sizeof(int));
  	expr->dtype			= PLPGSQL_DTYPE_EXPR;
! 	expr->query			= pstrdup(plpgsql_dstring_get(&ds));
  	expr->plan			= NULL;
  	expr->nparams		= nparams;
  	while(nparams-- > 0)
***************
*** 1931,1937 ****
  					int				varnos[1024];
  
  					check_assignable(yylval.scalar);
! 					fieldnames[0] = strdup(yytext);
  					varnos[0]	  = yylval.scalar->dno;
  
  					while ((tok = yylex()) == ',')
--- 1825,1831 ----
  					int				varnos[1024];
  
  					check_assignable(yylval.scalar);
! 					fieldnames[0] = pstrdup(yytext);
  					varnos[0]	  = yylval.scalar->dno;
  
  					while ((tok = yylex()) == ',')
***************
*** 1941,1947 ****
  						{
  							case T_SCALAR:
  								check_assignable(yylval.scalar);
! 								fieldnames[nfields] = strdup(yytext);
  								varnos[nfields++]	= yylval.scalar->dno;
  								break;
  
--- 1835,1841 ----
  						{
  							case T_SCALAR:
  								check_assignable(yylval.scalar);
! 								fieldnames[nfields] = pstrdup(yytext);
  								varnos[nfields++]	= yylval.scalar->dno;
  								break;
  
***************
*** 1955,1968 ****
  					}
  					have_nexttok = 1;
  
! 					row = malloc(sizeof(PLpgSQL_row));
  					row->dtype = PLPGSQL_DTYPE_ROW;
! 					row->refname = strdup("*internal*");
  					row->lineno = plpgsql_scanner_lineno();
  					row->rowtupdesc = NULL;
  					row->nfields = nfields;
! 					row->fieldnames = malloc(sizeof(char *) * nfields);
! 					row->varnos = malloc(sizeof(int) * nfields);
  					while (--nfields >= 0)
  					{
  						row->fieldnames[nfields] = fieldnames[nfields];
--- 1849,1862 ----
  					}
  					have_nexttok = 1;
  
! 					row = palloc(sizeof(PLpgSQL_row));
  					row->dtype = PLPGSQL_DTYPE_ROW;
! 					row->refname = pstrdup("*internal*");
  					row->lineno = plpgsql_scanner_lineno();
  					row->rowtupdesc = NULL;
  					row->nfields = nfields;
! 					row->fieldnames = palloc(sizeof(char *) * nfields);
! 					row->varnos = palloc(sizeof(int) * nfields);
  					while (--nfields >= 0)
  					{
  						row->fieldnames[nfields] = fieldnames[nfields];
***************
*** 2012,2020 ****
  		}
  	}
  
! 	expr = malloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - sizeof(int));
  	expr->dtype			= PLPGSQL_DTYPE_EXPR;
! 	expr->query			= strdup(plpgsql_dstring_get(&ds));
  	expr->plan			= NULL;
  	expr->nparams		= nparams;
  	while(nparams-- > 0)
--- 1906,1914 ----
  		}
  	}
  
! 	expr = palloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - sizeof(int));
  	expr->dtype			= PLPGSQL_DTYPE_EXPR;
! 	expr->query			= pstrdup(plpgsql_dstring_get(&ds));
  	expr->plan			= NULL;
  	expr->nparams		= nparams;
  	while(nparams-- > 0)
***************
*** 2025,2032 ****
  	{
  		PLpgSQL_stmt_select *select;
  
! 		select = malloc(sizeof(PLpgSQL_stmt_select));
! 		memset(select, 0, sizeof(PLpgSQL_stmt_select));
  		select->cmd_type = PLPGSQL_STMT_SELECT;
  		select->rec		 = rec;
  		select->row		 = row;
--- 1919,1925 ----
  	{
  		PLpgSQL_stmt_select *select;
  
! 		select = palloc0(sizeof(PLpgSQL_stmt_select));
  		select->cmd_type = PLPGSQL_STMT_SELECT;
  		select->rec		 = rec;
  		select->row		 = row;
***************
*** 2038,2044 ****
  	{
  		PLpgSQL_stmt_execsql *execsql;
  
! 		execsql = malloc(sizeof(PLpgSQL_stmt_execsql));
  		execsql->cmd_type = PLPGSQL_STMT_EXECSQL;
  		execsql->sqlstmt  = expr;
  
--- 1931,1937 ----
  	{
  		PLpgSQL_stmt_execsql *execsql;
  
! 		execsql = palloc(sizeof(PLpgSQL_stmt_execsql));
  		execsql->cmd_type = PLPGSQL_STMT_EXECSQL;
  		execsql->sqlstmt  = expr;
  
***************
*** 2076,2082 ****
  				int				varnos[1024];
  
  				check_assignable(yylval.scalar);
! 				fieldnames[0] = strdup(yytext);
  				varnos[0]	  = yylval.scalar->dno;
  
  				while ((tok = yylex()) == ',')
--- 1969,1975 ----
  				int				varnos[1024];
  
  				check_assignable(yylval.scalar);
! 				fieldnames[0] = pstrdup(yytext);
  				varnos[0]	  = yylval.scalar->dno;
  
  				while ((tok = yylex()) == ',')
***************
*** 2086,2092 ****
  					{
  						case T_SCALAR:
  							check_assignable(yylval.scalar);
! 							fieldnames[nfields] = strdup(yytext);
  							varnos[nfields++]	= yylval.scalar->dno;
  							break;
  
--- 1979,1985 ----
  					{
  						case T_SCALAR:
  							check_assignable(yylval.scalar);
! 							fieldnames[nfields] = pstrdup(yytext);
  							varnos[nfields++]	= yylval.scalar->dno;
  							break;
  
***************
*** 2100,2113 ****
  				}
  				have_nexttok = 1;
  
! 				row = malloc(sizeof(PLpgSQL_row));
  				row->dtype = PLPGSQL_DTYPE_ROW;
! 				row->refname = strdup("*internal*");
  				row->lineno = plpgsql_scanner_lineno();
  				row->rowtupdesc = NULL;
  				row->nfields = nfields;
! 				row->fieldnames = malloc(sizeof(char *) * nfields);
! 				row->varnos = malloc(sizeof(int) * nfields);
  				while (--nfields >= 0)
  				{
  					row->fieldnames[nfields] = fieldnames[nfields];
--- 1993,2006 ----
  				}
  				have_nexttok = 1;
  
! 				row = palloc(sizeof(PLpgSQL_row));
  				row->dtype = PLPGSQL_DTYPE_ROW;
! 				row->refname = pstrdup("*internal*");
  				row->lineno = plpgsql_scanner_lineno();
  				row->rowtupdesc = NULL;
  				row->nfields = nfields;
! 				row->fieldnames = palloc(sizeof(char *) * nfields);
! 				row->varnos = palloc(sizeof(int) * nfields);
  				while (--nfields >= 0)
  				{
  					row->fieldnames[nfields] = fieldnames[nfields];
***************
*** 2128,2135 ****
  	if (tok != ';')
  		yyerror("syntax error");
  
! 	fetch = malloc(sizeof(PLpgSQL_stmt_select));
! 	memset(fetch, 0, sizeof(PLpgSQL_stmt_fetch));
  	fetch->cmd_type = PLPGSQL_STMT_FETCH;
  	fetch->rec		 = rec;
  	fetch->row		 = row;
--- 2021,2027 ----
  	if (tok != ';')
  		yyerror("syntax error");
  
! 	fetch = palloc0(sizeof(PLpgSQL_stmt_select));
  	fetch->cmd_type = PLPGSQL_STMT_FETCH;
  	fetch->rec		 = rec;
  	fetch->row		 = row;
Index: src/pl/plpgsql/src/pl_comp.c
===================================================================
RCS file: /var/lib/cvs/pgsql/src/pl/plpgsql/src/pl_comp.c,v
retrieving revision 1.83
diff -c -r1.83 pl_comp.c
*** src/pl/plpgsql/src/pl_comp.c	30 Nov 2004 03:50:29 -0000	1.83
--- src/pl/plpgsql/src/pl_comp.c	18 Jan 2005 04:52:44 -0000
***************
*** 76,82 ****
  
  int			plpgsql_error_lineno;
  char	   *plpgsql_error_funcname;
! int			plpgsql_DumpExecTree = 0;
  
  PLpgSQL_function *plpgsql_curr_compile;
  
--- 76,82 ----
  
  int			plpgsql_error_lineno;
  char	   *plpgsql_error_funcname;
! bool		plpgsql_DumpExecTree = false;
  
  PLpgSQL_function *plpgsql_curr_compile;
  
***************
*** 130,153 ****
  static void plpgsql_HashTableInsert(PLpgSQL_function *function,
  						PLpgSQL_func_hashkey *func_key);
  static void plpgsql_HashTableDelete(PLpgSQL_function *function);
! 
! /*
!  * This routine is a crock, and so is everyplace that calls it.  The problem
!  * is that the compiled form of a plpgsql function is allocated permanently
!  * (mostly via malloc()) and never released until backend exit.  Subsidiary
!  * data structures such as fmgr info records therefore must live forever
!  * as well.  A better implementation would store all this stuff in a per-
!  * function memory context that could be reclaimed at need.  In the meantime,
!  * fmgr_info_cxt must be called specifying TopMemoryContext so that whatever
!  * it might allocate, and whatever the eventual function might allocate using
!  * fn_mcxt, will live forever too.
!  */
! static void
! perm_fmgr_info(Oid functionId, FmgrInfo *finfo)
! {
! 	fmgr_info_cxt(functionId, finfo, TopMemoryContext);
! }
! 
  
  /* ----------
   * plpgsql_compile		Make an execution tree for a PL/pgSQL function.
--- 130,136 ----
  static void plpgsql_HashTableInsert(PLpgSQL_function *function,
  						PLpgSQL_func_hashkey *func_key);
  static void plpgsql_HashTableDelete(PLpgSQL_function *function);
! static void delete_function(PLpgSQL_function *func);
  
  /* ----------
   * plpgsql_compile		Make an execution tree for a PL/pgSQL function.
***************
*** 187,196 ****
  
  	if (!function)
  	{
- 		/* First time through in this backend?	If so, init hashtable */
- 		if (!plpgsql_HashTable)
- 			plpgsql_HashTableInit();
- 
  		/* Compute hashkey using function signature and actual arg types */
  		compute_function_hashkey(fcinfo, procStruct, &hashkey, forValidator);
  		hashkey_valid = true;
--- 170,175 ----
***************
*** 205,216 ****
  		if (!(function->fn_xmin == HeapTupleHeaderGetXmin(procTup->t_data) &&
  		   function->fn_cmin == HeapTupleHeaderGetCmin(procTup->t_data)))
  		{
! 			/*
! 			 * Nope, drop the hashtable entry.	XXX someday, free all the
! 			 * subsidiary storage as well.
! 			 */
! 			plpgsql_HashTableDelete(function);
! 
  			function = NULL;
  		}
  	}
--- 184,191 ----
  		if (!(function->fn_xmin == HeapTupleHeaderGetXmin(procTup->t_data) &&
  		   function->fn_cmin == HeapTupleHeaderGetCmin(procTup->t_data)))
  		{
! 			/* Nope, drop the function and associated storage */
! 			delete_function(function);
  			function = NULL;
  		}
  	}
***************
*** 273,278 ****
--- 248,255 ----
  	int			parse_rc;
  	Oid			rettypeid;
  	char	  **argnames;
+ 	MemoryContext old_cxt;
+ 	MemoryContext func_cxt;
  
  	/*
  	 * Setup the scanner input and error info.	We assume that this
***************
*** 293,299 ****
  	 * Setup error traceback support for ereport()
  	 */
  	plerrcontext.callback = plpgsql_compile_error_callback;
! 	plerrcontext.arg = forValidator ? proc_source : (char *) NULL;
  	plerrcontext.previous = error_context_stack;
  	error_context_stack = &plerrcontext;
  
--- 270,276 ----
  	 * Setup error traceback support for ereport()
  	 */
  	plerrcontext.callback = plpgsql_compile_error_callback;
! 	plerrcontext.arg = forValidator ? proc_source : NULL;
  	plerrcontext.previous = error_context_stack;
  	error_context_stack = &plerrcontext;
  
***************
*** 302,308 ****
  	 */
  	plpgsql_ns_init();
  	plpgsql_ns_push(NULL);
! 	plpgsql_DumpExecTree = 0;
  
  	datums_alloc = 128;
  	plpgsql_nDatums = 0;
--- 279,285 ----
  	 */
  	plpgsql_ns_init();
  	plpgsql_ns_push(NULL);
! 	plpgsql_DumpExecTree = false;
  
  	datums_alloc = 128;
  	plpgsql_nDatums = 0;
***************
*** 310,331 ****
  	datums_last = 0;
  
  	/*
! 	 * Create the new function node
! 	 */
! 	function = malloc(sizeof(PLpgSQL_function));
! 	MemSet(function, 0, sizeof(PLpgSQL_function));
  	plpgsql_curr_compile = function;
  
! 	function->fn_name = strdup(NameStr(procStruct->proname));
  	function->fn_oid = fcinfo->flinfo->fn_oid;
  	function->fn_xmin = HeapTupleHeaderGetXmin(procTup->t_data);
  	function->fn_cmin = HeapTupleHeaderGetCmin(procTup->t_data);
  	function->fn_functype = functype;
  
  	switch (functype)
  	{
  		case T_FUNCTION:
- 
  			/*
  			 * Check for a polymorphic returntype. If found, use the
  			 * actual returntype type from the caller's FuncExpr node, if
--- 287,316 ----
  	datums_last = 0;
  
  	/*
! 	 * Create the new function node. We allocate the function and all
! 	 * of its compile-time storage (e.g. parse tree) in its own memory
! 	 * context. This allows us to reclaim the function's storage
! 	 * cleanly.
! 	 */
! 	func_cxt = AllocSetContextCreate(TopMemoryContext,
! 									 "PL/PgSQL function context",
! 									 ALLOCSET_DEFAULT_MINSIZE,
! 									 ALLOCSET_DEFAULT_INITSIZE,
! 									 ALLOCSET_DEFAULT_MAXSIZE);
! 	old_cxt = MemoryContextSwitchTo(func_cxt);
! 	function = palloc0(sizeof(*function));
  	plpgsql_curr_compile = function;
  
! 	function->fn_name = pstrdup(NameStr(procStruct->proname));
  	function->fn_oid = fcinfo->flinfo->fn_oid;
  	function->fn_xmin = HeapTupleHeaderGetXmin(procTup->t_data);
  	function->fn_cmin = HeapTupleHeaderGetCmin(procTup->t_data);
  	function->fn_functype = functype;
+ 	function->fn_cxt = func_cxt;
  
  	switch (functype)
  	{
  		case T_FUNCTION:
  			/*
  			 * Check for a polymorphic returntype. If found, use the
  			 * actual returntype type from the caller's FuncExpr node, if
***************
*** 398,404 ****
  				function->fn_retbyval = typeStruct->typbyval;
  				function->fn_rettyplen = typeStruct->typlen;
  				function->fn_rettypioparam = getTypeIOParam(typeTup);
! 				perm_fmgr_info(typeStruct->typinput, &(function->fn_retinput));
  
  				/*
  				 * install $0 reference, but only for polymorphic return
--- 383,389 ----
  				function->fn_retbyval = typeStruct->typbyval;
  				function->fn_rettyplen = typeStruct->typlen;
  				function->fn_rettypioparam = getTypeIOParam(typeTup);
! 				fmgr_info(typeStruct->typinput, &(function->fn_retinput));
  
  				/*
  				 * install $0 reference, but only for polymorphic return
***************
*** 407,413 ****
  				if (procStruct->prorettype == ANYARRAYOID ||
  					procStruct->prorettype == ANYELEMENTOID)
  				{
! 					(void) plpgsql_build_variable(strdup("$0"), 0,
  											 build_datatype(typeTup, -1),
  												  true);
  				}
--- 392,398 ----
  				if (procStruct->prorettype == ANYARRAYOID ||
  					procStruct->prorettype == ANYELEMENTOID)
  				{
! 					(void) plpgsql_build_variable("$0", 0,
  											 build_datatype(typeTup, -1),
  												  true);
  				}
***************
*** 449,455 ****
  								 format_type_be(argtypeid))));
  
  				/* Build variable and add to datum list */
! 				argvariable = plpgsql_build_variable(strdup(buf), 0,
  													 argdtype, false);
  
  				if (argvariable->dtype == PLPGSQL_DTYPE_VAR)
--- 434,440 ----
  								 format_type_be(argtypeid))));
  
  				/* Build variable and add to datum list */
! 				argvariable = plpgsql_build_variable(buf, 0,
  													 argdtype, false);
  
  				if (argvariable->dtype == PLPGSQL_DTYPE_VAR)
***************
*** 478,486 ****
  			break;
  
  		case T_TRIGGER:
- 
  			/*
! 			 * Trigger procedures return type is unknown yet
  			 */
  			function->fn_rettype = InvalidOid;
  			function->fn_retbyval = false;
--- 463,470 ----
  			break;
  
  		case T_TRIGGER:
  			/*
! 			 * Trigger procedure's return type is unknown yet
  			 */
  			function->fn_rettype = InvalidOid;
  			function->fn_retbyval = false;
***************
*** 490,499 ****
  			/*
  			 * Add the record for referencing NEW
  			 */
! 			rec = malloc(sizeof(PLpgSQL_rec));
! 			memset(rec, 0, sizeof(PLpgSQL_rec));
  			rec->dtype = PLPGSQL_DTYPE_REC;
! 			rec->refname = strdup("new");
  			rec->tup = NULL;
  			rec->tupdesc = NULL;
  			rec->freetup = false;
--- 474,482 ----
  			/*
  			 * Add the record for referencing NEW
  			 */
! 			rec = palloc0(sizeof(PLpgSQL_rec));
  			rec->dtype = PLPGSQL_DTYPE_REC;
! 			rec->refname = pstrdup("new");
  			rec->tup = NULL;
  			rec->tupdesc = NULL;
  			rec->freetup = false;
***************
*** 504,513 ****
  			/*
  			 * Add the record for referencing OLD
  			 */
! 			rec = malloc(sizeof(PLpgSQL_rec));
! 			memset(rec, 0, sizeof(PLpgSQL_rec));
  			rec->dtype = PLPGSQL_DTYPE_REC;
! 			rec->refname = strdup("old");
  			rec->tup = NULL;
  			rec->tupdesc = NULL;
  			rec->freetup = false;
--- 487,495 ----
  			/*
  			 * Add the record for referencing OLD
  			 */
! 			rec = palloc0(sizeof(PLpgSQL_rec));
  			rec->dtype = PLPGSQL_DTYPE_REC;
! 			rec->refname = pstrdup("old");
  			rec->tup = NULL;
  			rec->tupdesc = NULL;
  			rec->freetup = false;
***************
*** 518,524 ****
  			/*
  			 * Add the variable tg_name
  			 */
! 			var = plpgsql_build_variable(strdup("tg_name"), 0,
  									 plpgsql_build_datatype(NAMEOID, -1),
  										 true);
  			function->tg_name_varno = var->dno;
--- 500,506 ----
  			/*
  			 * Add the variable tg_name
  			 */
! 			var = plpgsql_build_variable("tg_name", 0,
  									 plpgsql_build_datatype(NAMEOID, -1),
  										 true);
  			function->tg_name_varno = var->dno;
***************
*** 526,532 ****
  			/*
  			 * Add the variable tg_when
  			 */
! 			var = plpgsql_build_variable(strdup("tg_when"), 0,
  									 plpgsql_build_datatype(TEXTOID, -1),
  										 true);
  			function->tg_when_varno = var->dno;
--- 508,514 ----
  			/*
  			 * Add the variable tg_when
  			 */
! 			var = plpgsql_build_variable("tg_when", 0,
  									 plpgsql_build_datatype(TEXTOID, -1),
  										 true);
  			function->tg_when_varno = var->dno;
***************
*** 534,540 ****
  			/*
  			 * Add the variable tg_level
  			 */
! 			var = plpgsql_build_variable(strdup("tg_level"), 0,
  									 plpgsql_build_datatype(TEXTOID, -1),
  										 true);
  			function->tg_level_varno = var->dno;
--- 516,522 ----
  			/*
  			 * Add the variable tg_level
  			 */
! 			var = plpgsql_build_variable("tg_level", 0,
  									 plpgsql_build_datatype(TEXTOID, -1),
  										 true);
  			function->tg_level_varno = var->dno;
***************
*** 542,548 ****
  			/*
  			 * Add the variable tg_op
  			 */
! 			var = plpgsql_build_variable(strdup("tg_op"), 0,
  									 plpgsql_build_datatype(TEXTOID, -1),
  										 true);
  			function->tg_op_varno = var->dno;
--- 524,530 ----
  			/*
  			 * Add the variable tg_op
  			 */
! 			var = plpgsql_build_variable("tg_op", 0,
  									 plpgsql_build_datatype(TEXTOID, -1),
  										 true);
  			function->tg_op_varno = var->dno;
***************
*** 550,556 ****
  			/*
  			 * Add the variable tg_relid
  			 */
! 			var = plpgsql_build_variable(strdup("tg_relid"), 0,
  									  plpgsql_build_datatype(OIDOID, -1),
  										 true);
  			function->tg_relid_varno = var->dno;
--- 532,538 ----
  			/*
  			 * Add the variable tg_relid
  			 */
! 			var = plpgsql_build_variable("tg_relid", 0,
  									  plpgsql_build_datatype(OIDOID, -1),
  										 true);
  			function->tg_relid_varno = var->dno;
***************
*** 558,564 ****
  			/*
  			 * Add the variable tg_relname
  			 */
! 			var = plpgsql_build_variable(strdup("tg_relname"), 0,
  									 plpgsql_build_datatype(NAMEOID, -1),
  										 true);
  			function->tg_relname_varno = var->dno;
--- 540,546 ----
  			/*
  			 * Add the variable tg_relname
  			 */
! 			var = plpgsql_build_variable("tg_relname", 0,
  									 plpgsql_build_datatype(NAMEOID, -1),
  										 true);
  			function->tg_relname_varno = var->dno;
***************
*** 566,572 ****
  			/*
  			 * Add the variable tg_nargs
  			 */
! 			var = plpgsql_build_variable(strdup("tg_nargs"), 0,
  									 plpgsql_build_datatype(INT4OID, -1),
  										 true);
  			function->tg_nargs_varno = var->dno;
--- 548,554 ----
  			/*
  			 * Add the variable tg_nargs
  			 */
! 			var = plpgsql_build_variable("tg_nargs", 0,
  									 plpgsql_build_datatype(INT4OID, -1),
  										 true);
  			function->tg_nargs_varno = var->dno;
***************
*** 584,590 ****
  	/*
  	 * Create the magic FOUND variable.
  	 */
! 	var = plpgsql_build_variable(strdup("found"), 0,
  								 plpgsql_build_datatype(BOOLOID, -1),
  								 true);
  	function->found_varno = var->dno;
--- 566,572 ----
  	/*
  	 * Create the magic FOUND variable.
  	 */
! 	var = plpgsql_build_variable("found", 0,
  								 plpgsql_build_datatype(BOOLOID, -1),
  								 true);
  	function->found_varno = var->dno;
***************
*** 611,617 ****
  	for (i = 0; i < function->fn_nargs; i++)
  		function->fn_argvarnos[i] = arg_varnos[i];
  	function->ndatums = plpgsql_nDatums;
! 	function->datums = malloc(sizeof(PLpgSQL_datum *) * plpgsql_nDatums);
  	for (i = 0; i < plpgsql_nDatums; i++)
  		function->datums[i] = plpgsql_Datums[i];
  	function->action = plpgsql_yylval.program;
--- 593,599 ----
  	for (i = 0; i < function->fn_nargs; i++)
  		function->fn_argvarnos[i] = arg_varnos[i];
  	function->ndatums = plpgsql_nDatums;
! 	function->datums = palloc(sizeof(PLpgSQL_datum *) * plpgsql_nDatums);
  	for (i = 0; i < plpgsql_nDatums; i++)
  		function->datums[i] = plpgsql_Datums[i];
  	function->action = plpgsql_yylval.program;
***************
*** 632,637 ****
--- 614,621 ----
  	plpgsql_error_funcname = NULL;
  	plpgsql_error_lineno = 0;
  
+ 	MemoryContextSwitchTo(old_cxt);
+ 
  	return function;
  }
  
***************
*** 725,735 ****
  	{
  		if (strcmp(cp[0], "tg_argv") == 0)
  		{
! 			int			save_spacescanned = plpgsql_SpaceScanned;
  			PLpgSQL_trigarg *trigarg;
  
! 			trigarg = malloc(sizeof(PLpgSQL_trigarg));
! 			memset(trigarg, 0, sizeof(PLpgSQL_trigarg));
  			trigarg->dtype = PLPGSQL_DTYPE_TRIGARG;
  
  			if (plpgsql_yylex() != '[')
--- 709,718 ----
  	{
  		if (strcmp(cp[0], "tg_argv") == 0)
  		{
! 			bool save_spacescanned = plpgsql_SpaceScanned;
  			PLpgSQL_trigarg *trigarg;
  
! 			trigarg = palloc0(sizeof(PLpgSQL_trigarg));
  			trigarg->dtype = PLPGSQL_DTYPE_TRIGARG;
  
  			if (plpgsql_yylex() != '[')
***************
*** 851,859 ****
  				 */
  				PLpgSQL_recfield *new;
  
! 				new = malloc(sizeof(PLpgSQL_recfield));
  				new->dtype = PLPGSQL_DTYPE_RECFIELD;
! 				new->fieldname = strdup(cp[1]);
  				new->recparentno = ns->itemno;
  
  				plpgsql_adddatum((PLpgSQL_datum *) new);
--- 834,842 ----
  				 */
  				PLpgSQL_recfield *new;
  
! 				new = palloc(sizeof(PLpgSQL_recfield));
  				new->dtype = PLPGSQL_DTYPE_RECFIELD;
! 				new->fieldname = pstrdup(cp[1]);
  				new->recparentno = ns->itemno;
  
  				plpgsql_adddatum((PLpgSQL_datum *) new);
***************
*** 957,965 ****
  				 */
  				PLpgSQL_recfield *new;
  
! 				new = malloc(sizeof(PLpgSQL_recfield));
  				new->dtype = PLPGSQL_DTYPE_RECFIELD;
! 				new->fieldname = strdup(cp[2]);
  				new->recparentno = ns->itemno;
  
  				plpgsql_adddatum((PLpgSQL_datum *) new);
--- 940,948 ----
  				 */
  				PLpgSQL_recfield *new;
  
! 				new = palloc(sizeof(PLpgSQL_recfield));
  				new->dtype = PLPGSQL_DTYPE_RECFIELD;
! 				new->fieldname = pstrdup(cp[2]);
  				new->recparentno = ns->itemno;
  
  				plpgsql_adddatum((PLpgSQL_datum *) new);
***************
*** 1038,1044 ****
  	pfree(cp[1]);
  
  	/*
! 	 * Do a lookup on the compilers namestack. But ensure it moves up to
  	 * the toplevel.
  	 */
  	old_nsstate = plpgsql_ns_setlocal(false);
--- 1021,1027 ----
  	pfree(cp[1]);
  
  	/*
! 	 * Do a lookup on the compiler's namestack. But ensure it moves up to
  	 * the toplevel.
  	 */
  	old_nsstate = plpgsql_ns_setlocal(false);
***************
*** 1440,1446 ****
   * to the current datum array, and optionally to the current namespace.
   */
  PLpgSQL_variable *
! plpgsql_build_variable(char *refname, int lineno, PLpgSQL_type *dtype,
  					   bool add2namespace)
  {
  	PLpgSQL_variable *result;
--- 1423,1429 ----
   * to the current datum array, and optionally to the current namespace.
   */
  PLpgSQL_variable *
! plpgsql_build_variable(const char *refname, int lineno, PLpgSQL_type *dtype,
  					   bool add2namespace)
  {
  	PLpgSQL_variable *result;
***************
*** 1452,1462 ****
  				/* Ordinary scalar datatype */
  				PLpgSQL_var *var;
  
! 				var = malloc(sizeof(PLpgSQL_var));
! 				memset(var, 0, sizeof(PLpgSQL_var));
! 
  				var->dtype = PLPGSQL_DTYPE_VAR;
! 				var->refname = refname;
  				var->lineno = lineno;
  				var->datatype = dtype;
  				/* other fields might be filled by caller */
--- 1435,1443 ----
  				/* Ordinary scalar datatype */
  				PLpgSQL_var *var;
  
! 				var = palloc0(sizeof(PLpgSQL_var));
  				var->dtype = PLPGSQL_DTYPE_VAR;
! 				var->refname = pstrdup(refname);
  				var->lineno = lineno;
  				var->datatype = dtype;
  				/* other fields might be filled by caller */
***************
*** 1482,1488 ****
  				row = build_row_var(dtype->typrelid);
  
  				row->dtype = PLPGSQL_DTYPE_ROW;
! 				row->refname = refname;
  				row->lineno = lineno;
  
  				plpgsql_adddatum((PLpgSQL_datum *) row);
--- 1463,1469 ----
  				row = build_row_var(dtype->typrelid);
  
  				row->dtype = PLPGSQL_DTYPE_ROW;
! 				row->refname = pstrdup(refname);
  				row->lineno = lineno;
  
  				plpgsql_adddatum((PLpgSQL_datum *) row);
***************
*** 1501,1511 ****
  				 */
  				PLpgSQL_rec *rec;
  
! 				rec = malloc(sizeof(PLpgSQL_rec));
! 				memset(rec, 0, sizeof(PLpgSQL_rec));
! 
  				rec->dtype = PLPGSQL_DTYPE_REC;
! 				rec->refname = refname;
  				rec->lineno = lineno;
  
  				plpgsql_adddatum((PLpgSQL_datum *) rec);
--- 1482,1490 ----
  				 */
  				PLpgSQL_rec *rec;
  
! 				rec = palloc0(sizeof(PLpgSQL_rec));
  				rec->dtype = PLPGSQL_DTYPE_REC;
! 				rec->refname = pstrdup(refname);
  				rec->lineno = lineno;
  
  				plpgsql_adddatum((PLpgSQL_datum *) rec);
***************
*** 1545,1551 ****
  	Form_pg_class classStruct;
  	const char *relname;
  	int			i;
- 	MemoryContext oldcxt;
  
  	/*
  	 * Open the relation to get info.
--- 1524,1529 ----
***************
*** 1567,1589 ****
  	 * Create a row datum entry and all the required variables that it
  	 * will point to.
  	 */
! 	row = malloc(sizeof(PLpgSQL_row));
! 	memset(row, 0, sizeof(PLpgSQL_row));
! 
  	row->dtype = PLPGSQL_DTYPE_ROW;
- 
- 	/*
- 	 * This is a bit ugly --- need a permanent copy of the rel's tupdesc.
- 	 * Someday all these mallocs should go away in favor of a per-function
- 	 * memory context ...
- 	 */
- 	oldcxt = MemoryContextSwitchTo(TopMemoryContext);
  	row->rowtupdesc = CreateTupleDescCopy(RelationGetDescr(rel));
- 	MemoryContextSwitchTo(oldcxt);
- 
  	row->nfields = classStruct->relnatts;
! 	row->fieldnames = malloc(sizeof(char *) * row->nfields);
! 	row->varnos = malloc(sizeof(int) * row->nfields);
  
  	for (i = 0; i < row->nfields; i++)
  	{
--- 1545,1556 ----
  	 * Create a row datum entry and all the required variables that it
  	 * will point to.
  	 */
! 	row = palloc0(sizeof(PLpgSQL_row));
  	row->dtype = PLPGSQL_DTYPE_ROW;
  	row->rowtupdesc = CreateTupleDescCopy(RelationGetDescr(rel));
  	row->nfields = classStruct->relnatts;
! 	row->fieldnames = palloc(sizeof(char *) * row->nfields);
! 	row->varnos = palloc(sizeof(int) * row->nfields);
  
  	for (i = 0; i < row->nfields; i++)
  	{
***************
*** 1592,1610 ****
  		/*
  		 * Get the attribute and check for dropped column
  		 */
! 		attrStruct = RelationGetDescr(rel)->attrs[i];
  
  		if (!attrStruct->attisdropped)
  		{
! 			const char *attname;
! 			char	   *refname;
  			PLpgSQL_variable *var;
  
  			attname = NameStr(attrStruct->attname);
! 			refname = malloc(strlen(relname) + strlen(attname) + 2);
! 			strcpy(refname, relname);
! 			strcat(refname, ".");
! 			strcat(refname, attname);
  
  			/*
  			 * Create the internal variable for the field
--- 1559,1574 ----
  		/*
  		 * Get the attribute and check for dropped column
  		 */
! 		attrStruct = row->rowtupdesc->attrs[i];
  
  		if (!attrStruct->attisdropped)
  		{
! 			char	   *attname;
! 			char		refname[(NAMEDATALEN * 2) + 100];
  			PLpgSQL_variable *var;
  
  			attname = NameStr(attrStruct->attname);
! 			snprintf(refname, sizeof(refname), "%s.%s", relname, attname);
  
  			/*
  			 * Create the internal variable for the field
***************
*** 1624,1630 ****
  			/*
  			 * Add the variable to the row.
  			 */
! 			row->fieldnames[i] = strdup(attname);
  			row->varnos[i] = var->dno;
  		}
  		else
--- 1588,1595 ----
  			/*
  			 * Add the variable to the row.
  			 */
! 			/* XXX: does this need to be pstrdup'd? */
! 			row->fieldnames[i] = attname;
  			row->varnos[i] = var->dno;
  		}
  		else
***************
*** 1697,1705 ****
  				 errmsg("type \"%s\" is only a shell",
  						NameStr(typeStruct->typname))));
  
! 	typ = (PLpgSQL_type *) malloc(sizeof(PLpgSQL_type));
  
! 	typ->typname = strdup(NameStr(typeStruct->typname));
  	typ->typoid = HeapTupleGetOid(typeTup);
  	switch (typeStruct->typtype)
  	{
--- 1662,1670 ----
  				 errmsg("type \"%s\" is only a shell",
  						NameStr(typeStruct->typname))));
  
! 	typ = (PLpgSQL_type *) palloc(sizeof(PLpgSQL_type));
  
! 	typ->typname = pstrdup(NameStr(typeStruct->typname));
  	typ->typoid = HeapTupleGetOid(typeTup);
  	switch (typeStruct->typtype)
  	{
***************
*** 1726,1732 ****
  	typ->typbyval = typeStruct->typbyval;
  	typ->typrelid = typeStruct->typrelid;
  	typ->typioparam = getTypeIOParam(typeTup);
! 	perm_fmgr_info(typeStruct->typinput, &(typ->typinput));
  	typ->atttypmod = typmod;
  
  	return typ;
--- 1691,1697 ----
  	typ->typbyval = typeStruct->typbyval;
  	typ->typrelid = typeStruct->typrelid;
  	typ->typioparam = getTypeIOParam(typeTup);
! 	fmgr_info(typeStruct->typinput, &(typ->typinput));
  	typ->atttypmod = typmod;
  
  	return typ;
***************
*** 1757,1763 ****
  	 */
  	if (strcmp(condname, "others") == 0)
  	{
! 		new = malloc(sizeof(PLpgSQL_condition));
  		new->sqlerrstate = 0;
  		new->condname = condname;
  		new->next = NULL;
--- 1722,1728 ----
  	 */
  	if (strcmp(condname, "others") == 0)
  	{
! 		new = palloc(sizeof(PLpgSQL_condition));
  		new->sqlerrstate = 0;
  		new->condname = condname;
  		new->next = NULL;
***************
*** 1769,1775 ****
  	{
  		if (strcmp(condname, exception_label_map[i].label) == 0)
  		{
! 			new = malloc(sizeof(PLpgSQL_condition));
  			new->sqlerrstate = exception_label_map[i].sqlerrstate;
  			new->condname = condname;
  			new->next = prev;
--- 1734,1740 ----
  	{
  		if (strcmp(condname, exception_label_map[i].label) == 0)
  		{
! 			new = palloc(sizeof(PLpgSQL_condition));
  			new->sqlerrstate = exception_label_map[i].sqlerrstate;
  			new->condname = condname;
  			new->next = prev;
***************
*** 1836,1842 ****
  	{
  		if (n > 0)
  		{
! 			*varnos = (int *) malloc(sizeof(int) * n);
  
  			n = 0;
  			for (i = datums_last; i < plpgsql_nDatums; i++)
--- 1801,1807 ----
  	{
  		if (n > 0)
  		{
! 			*varnos = (int *) palloc(sizeof(int) * n);
  
  			n = 0;
  			for (i = datums_last; i < plpgsql_nDatums; i++)
***************
*** 1930,1941 ****
--- 1895,1924 ----
  	}
  }
  
+ static void
+ delete_function(PLpgSQL_function *func)
+ {
+ 	/* remove function from hash table */
+ 	plpgsql_HashTableDelete(func);
+ 
+ 	/* release the function's storage */
+ 	MemoryContextDelete(func->fn_cxt);
+ 
+ 	/*
+ 	 * Caller should be sure not to use passed-in pointer, as it now
+ 	 * points to pfree'd storage
+ 	 */
+ }
+ 
  /* exported so we can call it from plpgsql_init() */
  void
  plpgsql_HashTableInit(void)
  {
  	HASHCTL		ctl;
  
+ 	/* don't allow double-initialization */
+ 	Assert(plpgsql_HashTable == NULL);
+ 
  	memset(&ctl, 0, sizeof(ctl));
  	ctl.keysize = sizeof(PLpgSQL_func_hashkey);
  	ctl.entrysize = sizeof(plpgsql_HashEnt);
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.127
diff -c -r1.127 pl_exec.c
*** src/pl/plpgsql/src/pl_exec.c	13 Jan 2005 23:07:34 -0000	1.127
--- src/pl/plpgsql/src/pl_exec.c	17 Jan 2005 06:50:19 -0000
***************
*** 74,86 ****
   * Local function forward declarations
   ************************************************************/
  static void plpgsql_exec_error_callback(void *arg);
  static PLpgSQL_var *copy_var(PLpgSQL_var *var);
  static PLpgSQL_rec *copy_rec(PLpgSQL_rec *rec);
  
  static int exec_stmt_block(PLpgSQL_execstate *estate,
  				PLpgSQL_stmt_block *block);
  static int exec_stmts(PLpgSQL_execstate *estate,
! 		   PLpgSQL_stmts *stmts);
  static int exec_stmt(PLpgSQL_execstate *estate,
  		  PLpgSQL_stmt *stmt);
  static int exec_stmt_assign(PLpgSQL_execstate *estate,
--- 74,87 ----
   * Local function forward declarations
   ************************************************************/
  static void plpgsql_exec_error_callback(void *arg);
+ static PLpgSQL_datum *copy_plpgsql_datum(PLpgSQL_datum *datum);
  static PLpgSQL_var *copy_var(PLpgSQL_var *var);
  static PLpgSQL_rec *copy_rec(PLpgSQL_rec *rec);
  
  static int exec_stmt_block(PLpgSQL_execstate *estate,
  				PLpgSQL_stmt_block *block);
  static int exec_stmts(PLpgSQL_execstate *estate,
! 					  List *stmts);
  static int exec_stmt(PLpgSQL_execstate *estate,
  		  PLpgSQL_stmt *stmt);
  static int exec_stmt_assign(PLpgSQL_execstate *estate,
***************
*** 212,240 ****
  	 */
  	estate.err_text = gettext_noop("during initialization of execution state");
  	for (i = 0; i < func->ndatums; i++)
! 	{
! 		switch (func->datums[i]->dtype)
! 		{
! 			case PLPGSQL_DTYPE_VAR:
! 				estate.datums[i] = (PLpgSQL_datum *)
! 					copy_var((PLpgSQL_var *) (func->datums[i]));
! 				break;
! 
! 			case PLPGSQL_DTYPE_REC:
! 				estate.datums[i] = (PLpgSQL_datum *)
! 					copy_rec((PLpgSQL_rec *) (func->datums[i]));
! 				break;
! 
! 			case PLPGSQL_DTYPE_ROW:
! 			case PLPGSQL_DTYPE_RECFIELD:
! 			case PLPGSQL_DTYPE_ARRAYELEM:
! 				estate.datums[i] = func->datums[i];
! 				break;
! 
! 			default:
! 				elog(ERROR, "unrecognized dtype: %d", func->datums[i]->dtype);
! 		}
! 	}
  
  	/*
  	 * Store the actual call argument values into the variables
--- 213,219 ----
  	 */
  	estate.err_text = gettext_noop("during initialization of execution state");
  	for (i = 0; i < func->ndatums; i++)
! 		estate.datums[i] = copy_plpgsql_datum(func->datums[i]);
  
  	/*
  	 * Store the actual call argument values into the variables
***************
*** 467,496 ****
  	 */
  	estate.err_text = gettext_noop("during initialization of execution state");
  	for (i = 0; i < func->ndatums; i++)
! 	{
! 		switch (func->datums[i]->dtype)
! 		{
! 			case PLPGSQL_DTYPE_VAR:
! 				estate.datums[i] = (PLpgSQL_datum *)
! 					copy_var((PLpgSQL_var *) (func->datums[i]));
! 				break;
! 
! 			case PLPGSQL_DTYPE_REC:
! 				estate.datums[i] = (PLpgSQL_datum *)
! 					copy_rec((PLpgSQL_rec *) (func->datums[i]));
! 				break;
! 
! 			case PLPGSQL_DTYPE_ROW:
! 			case PLPGSQL_DTYPE_RECFIELD:
! 			case PLPGSQL_DTYPE_ARRAYELEM:
! 			case PLPGSQL_DTYPE_TRIGARG:
! 				estate.datums[i] = func->datums[i];
! 				break;
! 
! 			default:
! 				elog(ERROR, "unrecognized dtype: %d", func->datums[i]->dtype);
! 		}
! 	}
  
  	/*
  	 * Put the OLD and NEW tuples into record variables
--- 446,452 ----
  	 */
  	estate.err_text = gettext_noop("during initialization of execution state");
  	for (i = 0; i < func->ndatums; i++)
! 		estate.datums[i] = copy_plpgsql_datum(func->datums[i]);
  
  	/*
  	 * Put the OLD and NEW tuples into record variables
***************
*** 758,763 ****
--- 714,748 ----
   * Support functions for copying local execution variables
   * ----------
   */
+ static PLpgSQL_datum *
+ copy_plpgsql_datum(PLpgSQL_datum *datum)
+ {
+ 	PLpgSQL_datum *result = NULL;
+ 
+ 	switch (datum->dtype)
+ 	{
+ 		case PLPGSQL_DTYPE_VAR:
+ 			result = (PLpgSQL_datum *) copy_var((PLpgSQL_var *) datum);
+ 			break;
+ 
+ 		case PLPGSQL_DTYPE_REC:
+ 			result = (PLpgSQL_datum *) copy_rec((PLpgSQL_rec *) datum);
+ 			break;
+ 
+ 		case PLPGSQL_DTYPE_ROW:
+ 		case PLPGSQL_DTYPE_RECFIELD:
+ 		case PLPGSQL_DTYPE_ARRAYELEM:
+ 		case PLPGSQL_DTYPE_TRIGARG:
+ 			result = datum;
+ 			break;
+ 
+ 		default:
+ 			elog(ERROR, "unrecognized dtype: %d", datum->dtype);
+ 	}
+ 
+ 	return result;
+ }
+ 
  static PLpgSQL_var *
  copy_var(PLpgSQL_var *var)
  {
***************
*** 920,928 ****
  		}
  		PG_CATCH();
  		{
! 			ErrorData  *edata;
! 			PLpgSQL_exceptions *exceptions;
! 			int			j;
  
  			/* Save error info */
  			MemoryContextSwitchTo(oldcontext);
--- 905,912 ----
  		}
  		PG_CATCH();
  		{
! 			ErrorData	*edata;
! 			ListCell	*e;
  
  			/* Save error info */
  			MemoryContextSwitchTo(oldcontext);
***************
*** 942,951 ****
  			SPI_restore_connection();
  
  			/* Look for a matching exception handler */
! 			exceptions = block->exceptions;
! 			for (j = 0; j < exceptions->exceptions_used; j++)
  			{
! 				PLpgSQL_exception *exception = exceptions->exceptions[j];
  
  				if (exception_matches_conditions(edata, exception->conditions))
  				{
--- 926,934 ----
  			SPI_restore_connection();
  
  			/* Look for a matching exception handler */
! 			foreach (e, block->exceptions)
  			{
! 				PLpgSQL_exception *exception = (PLpgSQL_exception *) lfirst(e);
  
  				if (exception_matches_conditions(edata, exception->conditions))
  				{
***************
*** 955,961 ****
  			}
  
  			/* If no match found, re-throw the error */
! 			if (j >= exceptions->exceptions_used)
  				ReThrowError(edata);
  			else
  				FreeErrorData(edata);
--- 938,944 ----
  			}
  
  			/* If no match found, re-throw the error */
! 			if (e == NULL)
  				ReThrowError(edata);
  			else
  				FreeErrorData(edata);
***************
*** 1005,1018 ****
   * ----------
   */
  static int
! exec_stmts(PLpgSQL_execstate *estate, PLpgSQL_stmts *stmts)
  {
! 	int			rc;
! 	int			i;
  
! 	for (i = 0; i < stmts->stmts_used; i++)
  	{
! 		rc = exec_stmt(estate, stmts->stmts[i]);
  		if (rc != PLPGSQL_RC_OK)
  			return rc;
  	}
--- 988,1001 ----
   * ----------
   */
  static int
! exec_stmts(PLpgSQL_execstate *estate, List *stmts)
  {
! 	ListCell   *s;
  
! 	foreach (s, stmts)
  	{
! 		PLpgSQL_stmt *stmt = (PLpgSQL_stmt *) lfirst(s);
! 		int rc = exec_stmt(estate, stmt);
  		if (rc != PLPGSQL_RC_OK)
  			return rc;
  	}
***************
*** 1242,1253 ****
  
  	if (!isnull && value)
  	{
! 		if (stmt->true_body != NULL)
  			return exec_stmts(estate, stmt->true_body);
  	}
  	else
  	{
! 		if (stmt->false_body != NULL)
  			return exec_stmts(estate, stmt->false_body);
  	}
  
--- 1225,1236 ----
  
  	if (!isnull && value)
  	{
! 		if (stmt->true_body != NIL)
  			return exec_stmts(estate, stmt->true_body);
  	}
  	else
  	{
! 		if (stmt->false_body != NIL)
  			return exec_stmts(estate, stmt->false_body);
  	}
  
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.38
diff -c -r1.38 pl_funcs.c
*** src/pl/plpgsql/src/pl_funcs.c	10 Oct 2004 23:37:45 -0000	1.38
--- src/pl/plpgsql/src/pl_funcs.c	18 Jan 2005 01:39:28 -0000
***************
*** 187,193 ****
   * ----------
   */
  void
! plpgsql_ns_additem(int itemtype, int itemno, char *name)
  {
  	PLpgSQL_ns *ns = ns_current;
  	PLpgSQL_nsitem *nse;
--- 187,193 ----
   * ----------
   */
  void
! plpgsql_ns_additem(int itemtype, int itemno, const char *name)
  {
  	PLpgSQL_ns *ns = ns_current;
  	PLpgSQL_nsitem *nse;
***************
*** 286,296 ****
  	int			i;
  
  	/*
! 	 * Lookup in the current namespace only
! 	 */
! 
! 	/*
! 	 * Lookup name in the namestack
  	 */
  	for (ns = ns_current; ns != NULL; ns = ns->upper)
  	{
--- 286,293 ----
  	int			i;
  
  	/*
! 	 * Lookup name in the namestack; do the lookup in the current
! 	 * namespace only.
  	 */
  	for (ns = ns_current; ns != NULL; ns = ns->upper)
  	{
***************
*** 584,603 ****
  }
  
  static void
! dump_stmts(PLpgSQL_stmts *stmts)
  {
! 	int			i;
  
  	dump_indent += 2;
! 	for (i = 0; i < stmts->stmts_used; i++)
! 		dump_stmt(stmts->stmts[i]);
  	dump_indent -= 2;
  }
  
  static void
  dump_block(PLpgSQL_stmt_block *block)
  {
- 	int			i;
  	char	   *name;
  
  	if (block->label == NULL)
--- 581,599 ----
  }
  
  static void
! dump_stmts(List *stmts)
  {
! 	ListCell *s;
  
  	dump_indent += 2;
! 	foreach (s, stmts)
! 		dump_stmt((PLpgSQL_stmt *) lfirst(s));
  	dump_indent -= 2;
  }
  
  static void
  dump_block(PLpgSQL_stmt_block *block)
  {
  	char	   *name;
  
  	if (block->label == NULL)
***************
*** 612,620 ****
  
  	if (block->exceptions)
  	{
! 		for (i = 0; i < block->exceptions->exceptions_used; i++)
  		{
! 			PLpgSQL_exception *exc = block->exceptions->exceptions[i];
  			PLpgSQL_condition *cond;
  
  			dump_ind();
--- 608,618 ----
  
  	if (block->exceptions)
  	{
! 		ListCell *e;
! 
! 		foreach (e, block->exceptions)
  		{
! 			PLpgSQL_exception *exc = (PLpgSQL_exception *) lfirst(e);
  			PLpgSQL_condition *cond;
  
  			dump_ind();
Index: src/pl/plpgsql/src/pl_handler.c
===================================================================
RCS file: /var/lib/cvs/pgsql/src/pl/plpgsql/src/pl_handler.c,v
retrieving revision 1.23
diff -c -r1.23 pl_handler.c
*** src/pl/plpgsql/src/pl_handler.c	1 Aug 2004 17:32:22 -0000	1.23
--- src/pl/plpgsql/src/pl_handler.c	18 Jan 2005 04:03:17 -0000
***************
*** 47,53 ****
  
  extern DLLIMPORT bool check_function_bodies;
  
! static int	plpgsql_firstcall = 1;
  
  static void plpgsql_init_all(void);
  
--- 47,53 ----
  
  extern DLLIMPORT bool check_function_bodies;
  
! static bool	plpgsql_firstcall = true;
  
  static void plpgsql_init_all(void);
  
***************
*** 65,74 ****
  		return;
  
  	plpgsql_HashTableInit();
- 
  	RegisterXactCallback(plpgsql_xact_cb, NULL);
! 
! 	plpgsql_firstcall = 0;
  }
  
  /*
--- 65,72 ----
  		return;
  
  	plpgsql_HashTableInit();
  	RegisterXactCallback(plpgsql_xact_cb, NULL);
! 	plpgsql_firstcall = false;
  }
  
  /*
***************
*** 78,91 ****
  plpgsql_init_all(void)
  {
  	/* Execute any postmaster-startup safe initialization */
! 	if (plpgsql_firstcall)
! 		plpgsql_init();
  
  	/*
  	 * Any other initialization that must be done each time a new backend
  	 * starts -- currently none
  	 */
- 
  }
  
  /* ----------
--- 76,87 ----
  plpgsql_init_all(void)
  {
  	/* Execute any postmaster-startup safe initialization */
! 	plpgsql_init();
  
  	/*
  	 * Any other initialization that must be done each time a new backend
  	 * starts -- currently none
  	 */
  }
  
  /* ----------
Index: src/pl/plpgsql/src/plpgsql.h
===================================================================
RCS file: /var/lib/cvs/pgsql/src/pl/plpgsql/src/plpgsql.h,v
retrieving revision 1.56
diff -c -r1.56 plpgsql.h
*** src/pl/plpgsql/src/plpgsql.h	16 Sep 2004 16:58:44 -0000	1.56
--- src/pl/plpgsql/src/plpgsql.h	17 Jan 2005 06:50:19 -0000
***************
*** 50,56 ****
   **********************************************************************/
  
  /* ----------
!  * Compilers namestack item types
   * ----------
   */
  enum
--- 50,56 ----
   **********************************************************************/
  
  /* ----------
!  * Compiler's namestack item types
   * ----------
   */
  enum
***************
*** 298,303 ****
--- 298,304 ----
  } PLpgSQL_nsitem;
  
  
+ /* XXX: consider adapting this to use List */
  typedef struct PLpgSQL_ns
  {								/* Compiler namestack level		*/
  	int			items_alloc;
***************
*** 314,327 ****
  } PLpgSQL_stmt;
  
  
- typedef struct
- {								/* List of execution nodes		*/
- 	int			stmts_alloc;	/* XXX this oughta just be a List ... */
- 	int			stmts_used;
- 	PLpgSQL_stmt **stmts;
- } PLpgSQL_stmts;
- 
- 
  typedef struct PLpgSQL_condition
  {								/* One EXCEPTION condition name */
  	int			sqlerrstate;	/* SQLSTATE code */
--- 315,320 ----
***************
*** 333,358 ****
  {								/* One EXCEPTION ... WHEN clause */
  	int			lineno;
  	PLpgSQL_condition *conditions;
! 	PLpgSQL_stmts *action;
  } PLpgSQL_exception;
  
  
  typedef struct
- {								/* List of WHEN clauses			*/
- 	int			exceptions_alloc;		/* XXX this oughta just be a List
- 										 * ... */
- 	int			exceptions_used;
- 	PLpgSQL_exception **exceptions;
- } PLpgSQL_exceptions;
- 
- 
- typedef struct
  {								/* Block of statements			*/
  	int			cmd_type;
  	int			lineno;
  	char	   *label;
! 	PLpgSQL_stmts *body;
! 	PLpgSQL_exceptions *exceptions;
  	int			n_initvars;
  	int		   *initvarnos;
  } PLpgSQL_stmt_block;
--- 326,342 ----
  {								/* One EXCEPTION ... WHEN clause */
  	int			lineno;
  	PLpgSQL_condition *conditions;
! 	List	   *action;			/* List of statements */
  } PLpgSQL_exception;
  
  
  typedef struct
  {								/* Block of statements			*/
  	int			cmd_type;
  	int			lineno;
  	char	   *label;
! 	List	   *body;			/* List of statements */
! 	List	   *exceptions;		/* List of WHEN clauses */
  	int			n_initvars;
  	int		   *initvarnos;
  } PLpgSQL_stmt_block;
***************
*** 393,400 ****
  	int			cmd_type;
  	int			lineno;
  	PLpgSQL_expr *cond;
! 	PLpgSQL_stmts *true_body;
! 	PLpgSQL_stmts *false_body;
  } PLpgSQL_stmt_if;
  
  
--- 377,384 ----
  	int			cmd_type;
  	int			lineno;
  	PLpgSQL_expr *cond;
! 	List	   *true_body;		/* List of statements */
! 	List	   *false_body;		/* List of statements */
  } PLpgSQL_stmt_if;
  
  
***************
*** 403,409 ****
  	int			cmd_type;
  	int			lineno;
  	char	   *label;
! 	PLpgSQL_stmts *body;
  } PLpgSQL_stmt_loop;
  
  
--- 387,393 ----
  	int			cmd_type;
  	int			lineno;
  	char	   *label;
! 	List	   *body;			/* List of statements */
  } PLpgSQL_stmt_loop;
  
  
***************
*** 413,419 ****
  	int			lineno;
  	char	   *label;
  	PLpgSQL_expr *cond;
! 	PLpgSQL_stmts *body;
  } PLpgSQL_stmt_while;
  
  
--- 397,403 ----
  	int			lineno;
  	char	   *label;
  	PLpgSQL_expr *cond;
! 	List	   *body;			/* List of statements */
  } PLpgSQL_stmt_while;
  
  
***************
*** 426,432 ****
  	PLpgSQL_expr *lower;
  	PLpgSQL_expr *upper;
  	int			reverse;
! 	PLpgSQL_stmts *body;
  } PLpgSQL_stmt_fori;
  
  
--- 410,416 ----
  	PLpgSQL_expr *lower;
  	PLpgSQL_expr *upper;
  	int			reverse;
! 	List	   *body;			/* List of statements */
  } PLpgSQL_stmt_fori;
  
  
***************
*** 438,444 ****
  	PLpgSQL_rec *rec;
  	PLpgSQL_row *row;
  	PLpgSQL_expr *query;
! 	PLpgSQL_stmts *body;
  } PLpgSQL_stmt_fors;
  
  
--- 422,428 ----
  	PLpgSQL_rec *rec;
  	PLpgSQL_row *row;
  	PLpgSQL_expr *query;
! 	List	   *body;			/* List of statements */
  } PLpgSQL_stmt_fors;
  
  
***************
*** 450,456 ****
  	PLpgSQL_rec *rec;
  	PLpgSQL_row *row;
  	PLpgSQL_expr *query;
! 	PLpgSQL_stmts *body;
  } PLpgSQL_stmt_dynfors;
  
  
--- 434,440 ----
  	PLpgSQL_rec *rec;
  	PLpgSQL_row *row;
  	PLpgSQL_expr *query;
! 	List	   *body;			/* List of statements */
  } PLpgSQL_stmt_dynfors;
  
  
***************
*** 577,582 ****
--- 561,567 ----
  	CommandId	fn_cmin;
  	int			fn_functype;
  	PLpgSQL_func_hashkey *fn_hashkey;	/* back-link to hashtable key */
+ 	MemoryContext fn_cxt;
  
  	Oid			fn_rettype;
  	int			fn_rettyplen;
***************
*** 649,656 ****
   * Global variable declarations
   **********************************************************************/
  
! extern int	plpgsql_DumpExecTree;
! extern int	plpgsql_SpaceScanned;
  extern int	plpgsql_nDatums;
  extern PLpgSQL_datum **plpgsql_Datums;
  
--- 634,641 ----
   * Global variable declarations
   **********************************************************************/
  
! extern bool	plpgsql_DumpExecTree;
! extern bool	plpgsql_SpaceScanned;
  extern int	plpgsql_nDatums;
  extern PLpgSQL_datum **plpgsql_Datums;
  
***************
*** 684,690 ****
  extern int	plpgsql_parse_dblwordrowtype(char *word);
  extern PLpgSQL_type *plpgsql_parse_datatype(const char *string);
  extern PLpgSQL_type *plpgsql_build_datatype(Oid typeOid, int32 typmod);
! extern PLpgSQL_variable *plpgsql_build_variable(char *refname, int lineno,
  					   PLpgSQL_type *dtype,
  					   bool add2namespace);
  extern PLpgSQL_condition *plpgsql_parse_err_condition(char *condname);
--- 669,675 ----
  extern int	plpgsql_parse_dblwordrowtype(char *word);
  extern PLpgSQL_type *plpgsql_parse_datatype(const char *string);
  extern PLpgSQL_type *plpgsql_build_datatype(Oid typeOid, int32 typmod);
! extern PLpgSQL_variable *plpgsql_build_variable(const char *refname, int lineno,
  					   PLpgSQL_type *dtype,
  					   bool add2namespace);
  extern PLpgSQL_condition *plpgsql_parse_err_condition(char *condname);
***************
*** 727,733 ****
  extern bool plpgsql_ns_setlocal(bool flag);
  extern void plpgsql_ns_push(char *label);
  extern void plpgsql_ns_pop(void);
! extern void plpgsql_ns_additem(int itemtype, int itemno, char *name);
  extern PLpgSQL_nsitem *plpgsql_ns_lookup(char *name, char *nsname);
  extern void plpgsql_ns_rename(char *oldname, char *newname);
  
--- 712,718 ----
  extern bool plpgsql_ns_setlocal(bool flag);
  extern void plpgsql_ns_push(char *label);
  extern void plpgsql_ns_pop(void);
! extern void plpgsql_ns_additem(int itemtype, int itemno, const char *name);
  extern PLpgSQL_nsitem *plpgsql_ns_lookup(char *name, char *nsname);
  extern void plpgsql_ns_rename(char *oldname, char *newname);
  
Index: src/pl/plpgsql/src/scan.l
===================================================================
RCS file: /var/lib/cvs/pgsql/src/pl/plpgsql/src/scan.l,v
retrieving revision 1.38
diff -c -r1.38 scan.l
*** src/pl/plpgsql/src/scan.l	17 Dec 2004 03:51:36 -0000	1.38
--- src/pl/plpgsql/src/scan.l	17 Jan 2005 06:50:19 -0000
***************
*** 54,60 ****
  static const char *scanstr;		/* original input string */
  
  static int	scanner_functype;
! static int	scanner_typereported;
  static int	pushback_token;
  static bool have_pushback_token;
  static int	lookahead_token;	
--- 54,60 ----
  static const char *scanstr;		/* original input string */
  
  static int	scanner_functype;
! static bool	scanner_typereported;
  static int	pushback_token;
  static bool have_pushback_token;
  static int	lookahead_token;	
***************
*** 64,70 ****
  static char    *dolqstart;      /* current $foo$ quote start string */
  static int	dolqlen;			/* signal to plpgsql_get_string_value */
  
! int	plpgsql_SpaceScanned = 0;
  %}
  
  %option 8bit
--- 64,70 ----
  static char    *dolqstart;      /* current $foo$ quote start string */
  static int	dolqlen;			/* signal to plpgsql_get_string_value */
  
! bool plpgsql_SpaceScanned = false;
  %}
  
  %option 8bit
***************
*** 114,120 ****
       * ----------
       */
      BEGIN(INITIAL);
!     plpgsql_SpaceScanned = 0;
  
      /* ----------
       * On the first call to a new source report the
--- 114,120 ----
       * ----------
       */
      BEGIN(INITIAL);
!     plpgsql_SpaceScanned = false;
  
      /* ----------
       * On the first call to a new source report the
***************
*** 123,129 ****
       */
  	if (!scanner_typereported)
  	{
! 		scanner_typereported = 1;
  		return scanner_functype;
  	}
  
--- 123,129 ----
       */
  	if (!scanner_typereported)
  	{
! 		scanner_typereported = true;
  		return scanner_functype;
  	}
  
***************
*** 255,261 ****
       * Ignore whitespaces but remember this happened
       * ----------
       */
! {space}+		{ plpgsql_SpaceScanned = 1;		}
  
      /* ----------
       * Eat up comments
--- 255,261 ----
       * Ignore whitespaces but remember this happened
       * ----------
       */
! {space}+		{ plpgsql_SpaceScanned = true;		}
  
      /* ----------
       * Eat up comments
***************
*** 266,272 ****
  \/\*			{ start_lineno = plpgsql_scanner_lineno();
  			  BEGIN(IN_COMMENT);
  			}
! <IN_COMMENT>\*\/	{ BEGIN(INITIAL); plpgsql_SpaceScanned = 1; }
  <IN_COMMENT>\n		;
  <IN_COMMENT>.		;
  <IN_COMMENT><<EOF>>	{
--- 266,272 ----
  \/\*			{ start_lineno = plpgsql_scanner_lineno();
  			  BEGIN(IN_COMMENT);
  			}
! <IN_COMMENT>\*\/	{ BEGIN(INITIAL); plpgsql_SpaceScanned = true; }
  <IN_COMMENT>\n		;
  <IN_COMMENT>.		;
  <IN_COMMENT><<EOF>>	{
***************
*** 502,508 ****
  	scanstr = str;
  
      scanner_functype = functype;
!     scanner_typereported = 0;
  
  	have_pushback_token = false;
  	have_lookahead_token = false;
--- 502,508 ----
  	scanstr = str;
  
      scanner_functype = functype;
!     scanner_typereported = false;
  
  	have_pushback_token = false;
  	have_lookahead_token = false;
