*** ./src/pl/plpgsql/src/gram.y.orig	2009-05-27 12:56:10.000000000 +0200
--- ./src/pl/plpgsql/src/gram.y	2009-05-27 13:59:37.000000000 +0200
***************
*** 17,22 ****
--- 17,23 ----
  #include "plpgsql.h"
  
  #include "catalog/pg_type.h"
+ #include "lib/stringinfo.h"
  #include "parser/parser.h"
  
  
***************
*** 1978,1984 ****
  {
  	int					tok;
  	int					lno;
! 	PLpgSQL_dstring		ds;
  	int					parenlevel = 0;
  	int					nparams = 0;
  	int					params[MAX_EXPR_PARAMS];
--- 1979,1985 ----
  {
  	int					tok;
  	int					lno;
! 	StringInfoData		ds;
  	int					parenlevel = 0;
  	int					nparams = 0;
  	int					params[MAX_EXPR_PARAMS];
***************
*** 1986,1993 ****
  	PLpgSQL_expr		*expr;
  
  	lno = plpgsql_scanner_lineno();
! 	plpgsql_dstring_init(&ds);
! 	plpgsql_dstring_append(&ds, sqlstart);
  
  	for (;;)
  	{
--- 1987,1994 ----
  	PLpgSQL_expr		*expr;
  
  	lno = plpgsql_scanner_lineno();
! 	initStringInfo(&ds);
! 	appendStringInfoString(&ds, sqlstart);
  
  	for (;;)
  	{
***************
*** 2029,2035 ****
  		}
  
  		if (plpgsql_SpaceScanned)
! 			plpgsql_dstring_append(&ds, " ");
  
  		switch (tok)
  		{
--- 2030,2036 ----
  		}
  
  		if (plpgsql_SpaceScanned)
! 			appendStringInfoChar(&ds, ' ');
  
  		switch (tok)
  		{
***************
*** 2037,2061 ****
  				snprintf(buf, sizeof(buf), " $%d ",
  						 assign_expr_param(yylval.scalar->dno,
  										   params, &nparams));
! 				plpgsql_dstring_append(&ds, buf);
  				break;
  
  			case T_ROW:
  				snprintf(buf, sizeof(buf), " $%d ",
  						 assign_expr_param(yylval.row->dno,
  										   params, &nparams));
! 				plpgsql_dstring_append(&ds, buf);
  				break;
  
  			case T_RECORD:
  				snprintf(buf, sizeof(buf), " $%d ",
  						 assign_expr_param(yylval.rec->dno,
  										   params, &nparams));
! 				plpgsql_dstring_append(&ds, buf);
  				break;
  
  			default:
! 				plpgsql_dstring_append(&ds, yytext);
  				break;
  		}
  	}
--- 2038,2062 ----
  				snprintf(buf, sizeof(buf), " $%d ",
  						 assign_expr_param(yylval.scalar->dno,
  										   params, &nparams));
! 				appendStringInfoString(&ds, buf);
  				break;
  
  			case T_ROW:
  				snprintf(buf, sizeof(buf), " $%d ",
  						 assign_expr_param(yylval.row->dno,
  										   params, &nparams));
! 				appendStringInfoString(&ds, buf);
  				break;
  
  			case T_RECORD:
  				snprintf(buf, sizeof(buf), " $%d ",
  						 assign_expr_param(yylval.rec->dno,
  										   params, &nparams));
! 				appendStringInfoString(&ds, buf);
  				break;
  
  			default:
! 				appendStringInfoString(&ds, yytext);
  				break;
  		}
  	}
***************
*** 2065,2076 ****
  
  	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)
  		expr->params[nparams] = params[nparams];
! 	plpgsql_dstring_free(&ds);
  
  	if (valid_sql)
  		check_sql_expr(expr->query);
--- 2066,2077 ----
  
  	expr = palloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - sizeof(int));
  	expr->dtype			= PLPGSQL_DTYPE_EXPR;
! 	expr->query			= pstrdup(ds.data);
  	expr->plan			= NULL;
  	expr->nparams		= nparams;
  	while(nparams-- > 0)
  		expr->params[nparams] = params[nparams];
! 	pfree(ds.data);
  
  	if (valid_sql)
  		check_sql_expr(expr->query);
***************
*** 2082,2088 ****
  read_datatype(int tok)
  {
  	int					lno;
! 	PLpgSQL_dstring		ds;
  	char			   *type_name;
  	PLpgSQL_type		*result;
  	bool				needspace = false;
--- 2083,2089 ----
  read_datatype(int tok)
  {
  	int					lno;
! 	StringInfoData		ds;
  	char			   *type_name;
  	PLpgSQL_type		*result;
  	bool				needspace = false;
***************
*** 2100,2106 ****
  		return yylval.dtype;
  	}
  
! 	plpgsql_dstring_init(&ds);
  
  	while (tok != ';')
  	{
--- 2101,2107 ----
  		return yylval.dtype;
  	}
  
! 	initStringInfo(&ds);
  
  	while (tok != ';')
  	{
***************
*** 2122,2137 ****
  		else if (tok == ')')
  			parenlevel--;
  		if (needspace)
! 			plpgsql_dstring_append(&ds, " ");
  		needspace = true;
! 		plpgsql_dstring_append(&ds, yytext);
  
  		tok = yylex();
  	}
  
  	plpgsql_push_back_token(tok);
  
! 	type_name = plpgsql_dstring_get(&ds);
  
  	if (type_name[0] == '\0')
  		yyerror("missing data type declaration");
--- 2123,2138 ----
  		else if (tok == ')')
  			parenlevel--;
  		if (needspace)
! 			appendStringInfoChar(&ds, ' ');
  		needspace = true;
! 		appendStringInfoString(&ds, yytext);
  
  		tok = yylex();
  	}
  
  	plpgsql_push_back_token(tok);
  
! 	type_name = ds.data;
  
  	if (type_name[0] == '\0')
  		yyerror("missing data type declaration");
***************
*** 2140,2146 ****
  
  	result = plpgsql_parse_datatype(type_name);
  
! 	plpgsql_dstring_free(&ds);
  
  	return result;
  }
--- 2141,2147 ----
  
  	result = plpgsql_parse_datatype(type_name);
  
! 	pfree(ds.data);
  
  	return result;
  }
***************
*** 2148,2154 ****
  static PLpgSQL_stmt *
  make_execsql_stmt(const char *sqlstart, int lineno)
  {
! 	PLpgSQL_dstring		ds;
  	int					nparams = 0;
  	int					params[MAX_EXPR_PARAMS];
  	char				buf[32];
--- 2149,2155 ----
  static PLpgSQL_stmt *
  make_execsql_stmt(const char *sqlstart, int lineno)
  {
! 	StringInfoData		ds;
  	int					nparams = 0;
  	int					params[MAX_EXPR_PARAMS];
  	char				buf[32];
***************
*** 2161,2168 ****
  	bool				have_into = false;
  	bool				have_strict = false;
  
! 	plpgsql_dstring_init(&ds);
! 	plpgsql_dstring_append(&ds, sqlstart);
  
  	/*
  	 * We have to special-case the sequence INSERT INTO, because we don't want
--- 2162,2169 ----
  	bool				have_into = false;
  	bool				have_strict = false;
  
! 	initStringInfo(&ds);
! 	appendStringInfoString(&ds, sqlstart);
  
  	/*
  	 * We have to special-case the sequence INSERT INTO, because we don't want
***************
*** 2196,2202 ****
  		}
  
  		if (plpgsql_SpaceScanned)
! 			plpgsql_dstring_append(&ds, " ");
  
  		switch (tok)
  		{
--- 2197,2203 ----
  		}
  
  		if (plpgsql_SpaceScanned)
! 			appendStringInfoChar(&ds, ' ');
  
  		switch (tok)
  		{
***************
*** 2204,2240 ****
  				snprintf(buf, sizeof(buf), " $%d ",
  						 assign_expr_param(yylval.scalar->dno,
  										   params, &nparams));
! 				plpgsql_dstring_append(&ds, buf);
  				break;
  
  			case T_ROW:
  				snprintf(buf, sizeof(buf), " $%d ",
  						 assign_expr_param(yylval.row->dno,
  										   params, &nparams));
! 				plpgsql_dstring_append(&ds, buf);
  				break;
  
  			case T_RECORD:
  				snprintf(buf, sizeof(buf), " $%d ",
  						 assign_expr_param(yylval.rec->dno,
  										   params, &nparams));
! 				plpgsql_dstring_append(&ds, buf);
  				break;
  
  			default:
! 				plpgsql_dstring_append(&ds, yytext);
  				break;
  		}
  	}
  
  	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)
  		expr->params[nparams] = params[nparams];
! 	plpgsql_dstring_free(&ds);
  
  	check_sql_expr(expr->query);
  
--- 2205,2241 ----
  				snprintf(buf, sizeof(buf), " $%d ",
  						 assign_expr_param(yylval.scalar->dno,
  										   params, &nparams));
! 				appendStringInfoString(&ds, buf);
  				break;
  
  			case T_ROW:
  				snprintf(buf, sizeof(buf), " $%d ",
  						 assign_expr_param(yylval.row->dno,
  										   params, &nparams));
! 				appendStringInfoString(&ds, buf);
  				break;
  
  			case T_RECORD:
  				snprintf(buf, sizeof(buf), " $%d ",
  						 assign_expr_param(yylval.rec->dno,
  										   params, &nparams));
! 				appendStringInfoString(&ds, buf);
  				break;
  
  			default:
! 				appendStringInfoString(&ds, yytext);
  				break;
  		}
  	}
  
  	expr = palloc(sizeof(PLpgSQL_expr) + sizeof(int) * nparams - sizeof(int));
  	expr->dtype			= PLPGSQL_DTYPE_EXPR;
! 	expr->query			= pstrdup(ds.data);
  	expr->plan			= NULL;
  	expr->nparams		= nparams;
  	while(nparams-- > 0)
  		expr->params[nparams] = params[nparams];
! 	pfree(ds.data);
  
  	check_sql_expr(expr->query);
  
***************
*** 3023,3030 ****
  			PLpgSQL_expr *expr = cwt->expr;
  			int		nparams = expr->nparams;
  			PLpgSQL_expr *new_expr;
! 			PLpgSQL_dstring ds;
! 			char	buff[32];
  
  			/* Must add the CASE variable as an extra param to expression */
  			if (nparams >= MAX_EXPR_PARAMS)
--- 3024,3030 ----
  			PLpgSQL_expr *expr = cwt->expr;
  			int		nparams = expr->nparams;
  			PLpgSQL_expr *new_expr;
! 			StringInfoData	ds;
  
  			/* Must add the CASE variable as an extra param to expression */
  			if (nparams >= MAX_EXPR_PARAMS)
***************
*** 3041,3062 ****
  			new_expr->nparams = nparams + 1;
  			new_expr->params[nparams] = t_varno;
  
  			/* And do the string hacking */
! 			plpgsql_dstring_init(&ds);
! 
! 			plpgsql_dstring_append(&ds, "SELECT $");
! 			snprintf(buff, sizeof(buff), "%d", nparams + 1);
! 			plpgsql_dstring_append(&ds, buff);
! 			plpgsql_dstring_append(&ds, " IN (");
  
! 			/* copy expression query without SELECT keyword */
! 			Assert(strncmp(expr->query, "SELECT ", 7) == 0);
! 			plpgsql_dstring_append(&ds, expr->query + 7);
! 			plpgsql_dstring_append_char(&ds, ')');
  
! 			new_expr->query = pstrdup(plpgsql_dstring_get(&ds));
  
! 			plpgsql_dstring_free(&ds);
  			pfree(expr->query);
  			pfree(expr);
  
--- 3041,3059 ----
  			new_expr->nparams = nparams + 1;
  			new_expr->params[nparams] = t_varno;
  
+ 			/* copy expression query without SELECT keyword (expr->query + 7) */
+ 			Assert(strncmp(expr->query, "SELECT ", 7) == 0);
+ 			
  			/* And do the string hacking */
! 			initStringInfo(&ds);
  
! 			appendStringInfo(&ds, "SELECT $%d IN(%s)", 
! 								nparams + 1,
! 								expr->query + 7);
  
! 			new_expr->query = pstrdup(ds.data);
  
! 			pfree(ds.data);
  			pfree(expr->query);
  			pfree(expr);
  
*** ./src/pl/plpgsql/src/pl_exec.c.orig	2009-05-27 12:56:28.000000000 +0200
--- ./src/pl/plpgsql/src/pl_exec.c	2009-05-27 13:52:04.000000000 +0200
***************
*** 22,27 ****
--- 22,28 ----
  #include "catalog/pg_type.h"
  #include "executor/spi_priv.h"
  #include "funcapi.h"
+ #include "lib/stringinfo.h"
  #include "nodes/nodeFuncs.h"
  #include "parser/scansup.h"
  #include "storage/proc.h"
***************
*** 2388,2398 ****
  
  	if (stmt->message)
  	{
! 		PLpgSQL_dstring ds;
  		ListCell   *current_param;
  		char	   *cp;
  
! 		plpgsql_dstring_init(&ds);
  		current_param = list_head(stmt->params);
  
  		for (cp = stmt->message; *cp; cp++)
--- 2389,2399 ----
  
  	if (stmt->message)
  	{
! 		StringInfoData	ds;
  		ListCell   *current_param;
  		char	   *cp;
  
! 		initStringInfo(&ds);
  		current_param = list_head(stmt->params);
  
  		for (cp = stmt->message; *cp; cp++)
***************
*** 2410,2416 ****
  
  				if (cp[1] == '%')
  				{
! 					plpgsql_dstring_append_char(&ds, cp[1]);
  					cp++;
  					continue;
  				}
--- 2411,2417 ----
  
  				if (cp[1] == '%')
  				{
! 					appendStringInfoChar(&ds, '%');
  					cp++;
  					continue;
  				}
***************
*** 2429,2440 ****
  					extval = "<NULL>";
  				else
  					extval = convert_value_to_string(paramvalue, paramtypeid);
! 				plpgsql_dstring_append(&ds, extval);
  				current_param = lnext(current_param);
  				exec_eval_cleanup(estate);
  			}
  			else
! 				plpgsql_dstring_append_char(&ds, cp[0]);
  		}
  
  		/*
--- 2430,2441 ----
  					extval = "<NULL>";
  				else
  					extval = convert_value_to_string(paramvalue, paramtypeid);
! 				appendStringInfoString(&ds, extval);
  				current_param = lnext(current_param);
  				exec_eval_cleanup(estate);
  			}
  			else
! 				appendStringInfoChar(&ds, cp[0]);
  		}
  
  		/*
***************
*** 2446,2453 ****
  					(errcode(ERRCODE_SYNTAX_ERROR),
  					 errmsg("too many parameters specified for RAISE")));
  
! 		err_message = plpgsql_dstring_get(&ds);
! 		/* No dstring_free here, the pfree(err_message) does it */
  	}
  
  	foreach(lc, stmt->options)
--- 2447,2454 ----
  					(errcode(ERRCODE_SYNTAX_ERROR),
  					 errmsg("too many parameters specified for RAISE")));
  
! 		err_message = ds.data;
! 		/* No pfree(ds.data), the pfree(err_message) does it */
  	}
  
  	foreach(lc, stmt->options)
*** ./src/pl/plpgsql/src/pl_funcs.c.orig	2009-05-27 13:56:57.000000000 +0200
--- ./src/pl/plpgsql/src/pl_funcs.c	2009-05-27 13:58:44.000000000 +0200
***************
*** 29,118 ****
  
  
  /* ----------
-  * plpgsql_dstring_init			Dynamic string initialization
-  * ----------
-  */
- void
- plpgsql_dstring_init(PLpgSQL_dstring *ds)
- {
- 	ds->value = palloc(ds->alloc = 512);
- 	ds->used = 1;
- 	ds->value[0] = '\0';
- }
- 
- 
- /* ----------
-  * plpgsql_dstring_free			Dynamic string destruction
-  * ----------
-  */
- void
- plpgsql_dstring_free(PLpgSQL_dstring *ds)
- {
- 	pfree(ds->value);
- }
- 
- static void
- plpgsql_dstring_expand(PLpgSQL_dstring *ds, int needed)
- {
- 	/* Don't allow truncating the string */
- 	Assert(needed > ds->alloc);
- 	Assert(ds->used <= ds->alloc);
- 
- 	/* Might have to double more than once, if needed is large */
- 	do
- 	{
- 		ds->alloc *= 2;
- 	} while (needed > ds->alloc);
- 	ds->value = repalloc(ds->value, ds->alloc);
- }
- 
- /* ----------
-  * plpgsql_dstring_append		Dynamic string extending
-  * ----------
-  */
- void
- plpgsql_dstring_append(PLpgSQL_dstring *ds, const char *str)
- {
- 	int			len = strlen(str);
- 	int			needed = ds->used + len;
- 
- 	if (needed > ds->alloc)
- 		plpgsql_dstring_expand(ds, needed);
- 
- 	memcpy(&(ds->value[ds->used - 1]), str, len);
- 	ds->used += len;
- 	ds->value[ds->used - 1] = '\0';
- }
- 
- /* ----------
-  * plpgsql_dstring_append_char	Append a single character
-  *								to a dynamic string
-  * ----------
-  */
- void
- plpgsql_dstring_append_char(PLpgSQL_dstring *ds, char c)
- {
- 	if (ds->used == ds->alloc)
- 		plpgsql_dstring_expand(ds, ds->used + 1);
- 
- 	ds->value[ds->used - 1] = c;
- 	ds->value[ds->used] = '\0';
- 	ds->used++;
- }
- 
- 
- /* ----------
-  * plpgsql_dstring_get			Dynamic string get value
-  * ----------
-  */
- char *
- plpgsql_dstring_get(PLpgSQL_dstring *ds)
- {
- 	return ds->value;
- }
- 
- 
- /* ----------
   * plpgsql_ns_init			Initialize the namestack
   * ----------
   */
--- 29,34 ----
*** ./src/pl/plpgsql/src/plpgsql.h.orig	2009-05-27 12:56:41.000000000 +0200
--- ./src/pl/plpgsql/src/plpgsql.h	2009-05-27 13:57:55.000000000 +0200
***************
*** 148,161 ****
  
  
  typedef struct
- {								/* Dynamic string control structure */
- 	int			alloc;
- 	int			used;			/* Including NUL terminator */
- 	char	   *value;
- } PLpgSQL_dstring;
- 
- 
- typedef struct
  {								/* Postgres data type */
  	char	   *typname;		/* (simple) name of the type */
  	Oid			typoid;			/* OID of the data type */
--- 148,153 ----
***************
*** 852,867 ****
  				   SubTransactionId parentSubid, void *arg);
  
  /* ----------
-  * Functions for the dynamic string handling in pl_funcs.c
-  * ----------
-  */
- extern void plpgsql_dstring_init(PLpgSQL_dstring *ds);
- extern void plpgsql_dstring_free(PLpgSQL_dstring *ds);
- extern void plpgsql_dstring_append(PLpgSQL_dstring *ds, const char *str);
- extern void plpgsql_dstring_append_char(PLpgSQL_dstring *ds, char c);
- extern char *plpgsql_dstring_get(PLpgSQL_dstring *ds);
- 
- /* ----------
   * Functions for namestack handling in pl_funcs.c
   * ----------
   */
--- 844,849 ----
