plpgsql-io-function-leaks-3.patch

text/x-patch

Filename: plpgsql-io-function-leaks-3.patch
Type: text/x-patch
Part: 0
Message: Re: plpgsql leaking memory when stringifying datums

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: unified
File+
src/pl/plpgsql/src/pl_exec.c 0 0
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index bf952b62478792b5564fe2af744a318322ea197c..0b126a3f4ac0e16e4ae19b8507c5c1352842a7e2 100644
*** a/src/pl/plpgsql/src/pl_exec.c
--- b/src/pl/plpgsql/src/pl_exec.c
*************** static void exec_move_row(PLpgSQL_execst
*** 188,201 ****
  static HeapTuple make_tuple_from_row(PLpgSQL_execstate *estate,
  					PLpgSQL_row *row,
  					TupleDesc tupdesc);
! static char *convert_value_to_string(Datum value, Oid valtype);
! static Datum exec_cast_value(Datum value, Oid valtype,
  				Oid reqtype,
  				FmgrInfo *reqinput,
  				Oid reqtypioparam,
  				int32 reqtypmod,
  				bool isnull);
! static Datum exec_simple_cast_value(Datum value, Oid valtype,
  					   Oid reqtype, int32 reqtypmod,
  					   bool isnull);
  static void exec_init_tuple_store(PLpgSQL_execstate *estate);
--- 188,204 ----
  static HeapTuple make_tuple_from_row(PLpgSQL_execstate *estate,
  					PLpgSQL_row *row,
  					TupleDesc tupdesc);
! static char *convert_value_to_string(PLpgSQL_execstate *estate,
! 						Datum value, Oid valtype);
! static Datum exec_cast_value(PLpgSQL_execstate *estate,
! 				Datum value, Oid valtype,
  				Oid reqtype,
  				FmgrInfo *reqinput,
  				Oid reqtypioparam,
  				int32 reqtypmod,
  				bool isnull);
! static Datum exec_simple_cast_value(PLpgSQL_execstate *estate,
! 					   Datum value, Oid valtype,
  					   Oid reqtype, int32 reqtypmod,
  					   bool isnull);
  static void exec_init_tuple_store(PLpgSQL_execstate *estate);
*************** plpgsql_exec_function(PLpgSQL_function *
*** 295,300 ****
--- 298,305 ----
  						/* If arg is null, treat it as an empty row */
  						exec_move_row(&estate, NULL, row, NULL, NULL);
  					}
+ 					/* clean up after exec_move_row() */
+ 					exec_eval_cleanup(&estate);
  				}
  				break;
  
*************** plpgsql_exec_function(PLpgSQL_function *
*** 430,436 ****
  		else
  		{
  			/* Cast value to proper type */
! 			estate.retval = exec_cast_value(estate.retval, estate.rettype,
  											func->fn_rettype,
  											&(func->fn_retinput),
  											func->fn_rettypioparam,
--- 435,443 ----
  		else
  		{
  			/* Cast value to proper type */
! 			estate.retval = exec_cast_value(&estate,
! 											estate.retval,
! 											estate.rettype,
  											func->fn_rettype,
  											&(func->fn_retinput),
  											func->fn_rettypioparam,
*************** exec_stmt_fori(PLpgSQL_execstate *estate
*** 1757,1763 ****
  	 * Get the value of the lower bound
  	 */
  	value = exec_eval_expr(estate, stmt->lower, &isnull, &valtype);
! 	value = exec_cast_value(value, valtype, var->datatype->typoid,
  							&(var->datatype->typinput),
  							var->datatype->typioparam,
  							var->datatype->atttypmod, isnull);
--- 1764,1770 ----
  	 * Get the value of the lower bound
  	 */
  	value = exec_eval_expr(estate, stmt->lower, &isnull, &valtype);
! 	value = exec_cast_value(estate, value, valtype, var->datatype->typoid,
  							&(var->datatype->typinput),
  							var->datatype->typioparam,
  							var->datatype->atttypmod, isnull);
*************** exec_stmt_fori(PLpgSQL_execstate *estate
*** 1772,1778 ****
  	 * Get the value of the upper bound
  	 */
  	value = exec_eval_expr(estate, stmt->upper, &isnull, &valtype);
! 	value = exec_cast_value(value, valtype, var->datatype->typoid,
  							&(var->datatype->typinput),
  							var->datatype->typioparam,
  							var->datatype->atttypmod, isnull);
--- 1779,1785 ----
  	 * Get the value of the upper bound
  	 */
  	value = exec_eval_expr(estate, stmt->upper, &isnull, &valtype);
! 	value = exec_cast_value(estate, value, valtype, var->datatype->typoid,
  							&(var->datatype->typinput),
  							var->datatype->typioparam,
  							var->datatype->atttypmod, isnull);
*************** exec_stmt_fori(PLpgSQL_execstate *estate
*** 1789,1795 ****
  	if (stmt->step)
  	{
  		value = exec_eval_expr(estate, stmt->step, &isnull, &valtype);
! 		value = exec_cast_value(value, valtype, var->datatype->typoid,
  								&(var->datatype->typinput),
  								var->datatype->typioparam,
  								var->datatype->atttypmod, isnull);
--- 1796,1802 ----
  	if (stmt->step)
  	{
  		value = exec_eval_expr(estate, stmt->step, &isnull, &valtype);
! 		value = exec_cast_value(estate, value, valtype, var->datatype->typoid,
  								&(var->datatype->typinput),
  								var->datatype->typioparam,
  								var->datatype->atttypmod, isnull);
*************** exec_stmt_return_next(PLpgSQL_execstate 
*** 2440,2446 ****
  						errmsg("wrong result type supplied in RETURN NEXT")));
  
  					/* coerce type if needed */
! 					retval = exec_simple_cast_value(retval,
  													var->datatype->typoid,
  												 tupdesc->attrs[0]->atttypid,
  												tupdesc->attrs[0]->atttypmod,
--- 2447,2454 ----
  						errmsg("wrong result type supplied in RETURN NEXT")));
  
  					/* coerce type if needed */
! 					retval = exec_simple_cast_value(estate,
! 													retval,
  													var->datatype->typoid,
  												 tupdesc->attrs[0]->atttypid,
  												tupdesc->attrs[0]->atttypmod,
*************** exec_stmt_return_next(PLpgSQL_execstate 
*** 2511,2517 ****
  								&rettype);
  
  		/* coerce type if needed */
! 		retval = exec_simple_cast_value(retval,
  										rettype,
  										tupdesc->attrs[0]->atttypid,
  										tupdesc->attrs[0]->atttypmod,
--- 2519,2526 ----
  								&rettype);
  
  		/* coerce type if needed */
! 		retval = exec_simple_cast_value(estate,
! 										retval,
  										rettype,
  										tupdesc->attrs[0]->atttypid,
  										tupdesc->attrs[0]->atttypmod,
*************** exec_stmt_return_next(PLpgSQL_execstate 
*** 2519,2526 ****
  
  		tuplestore_putvalues(estate->tuple_store, tupdesc,
  							 &retval, &isNull);
- 
- 		exec_eval_cleanup(estate);
  	}
  	else
  	{
--- 2528,2533 ----
*************** exec_stmt_return_next(PLpgSQL_execstate 
*** 2537,2542 ****
--- 2544,2551 ----
  			heap_freetuple(tuple);
  	}
  
+ 	exec_eval_cleanup(estate);
+ 
  	return PLPGSQL_RC_OK;
  }
  
*************** exec_stmt_raise(PLpgSQL_execstate *estat
*** 2726,2732 ****
  				if (paramisnull)
  					extval = "<NULL>";
  				else
! 					extval = convert_value_to_string(paramvalue, paramtypeid);
  				appendStringInfoString(&ds, extval);
  				current_param = lnext(current_param);
  				exec_eval_cleanup(estate);
--- 2735,2743 ----
  				if (paramisnull)
  					extval = "<NULL>";
  				else
! 					extval = convert_value_to_string(estate,
! 													 paramvalue,
! 													 paramtypeid);
  				appendStringInfoString(&ds, extval);
  				current_param = lnext(current_param);
  				exec_eval_cleanup(estate);
*************** exec_stmt_raise(PLpgSQL_execstate *estat
*** 2764,2770 ****
  					(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
  					 errmsg("RAISE statement option cannot be null")));
  
! 		extval = convert_value_to_string(optionvalue, optiontypeid);
  
  		switch (opt->opt_type)
  		{
--- 2775,2781 ----
  					(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
  					 errmsg("RAISE statement option cannot be null")));
  
! 		extval = convert_value_to_string(estate, optionvalue, optiontypeid);
  
  		switch (opt->opt_type)
  		{
*************** exec_stmt_execsql(PLpgSQL_execstate *est
*** 3183,3188 ****
--- 3194,3200 ----
  		}
  
  		/* Clean up */
+ 		exec_eval_cleanup(estate);
  		SPI_freetuptable(SPI_tuptable);
  	}
  	else
*************** exec_stmt_dynexecute(PLpgSQL_execstate *
*** 3228,3234 ****
  				 errmsg("query string argument of EXECUTE is null")));
  
  	/* Get the C-String representation */
! 	querystr = convert_value_to_string(query, restype);
  
  	exec_eval_cleanup(estate);
  
--- 3240,3249 ----
  				 errmsg("query string argument of EXECUTE is null")));
  
  	/* Get the C-String representation */
! 	querystr = convert_value_to_string(estate, query, restype);
! 
! 	/* copy it out of the temporary context before we clean up */
! 	querystr = pstrdup(querystr);
  
  	exec_eval_cleanup(estate);
  
*************** exec_stmt_dynexecute(PLpgSQL_execstate *
*** 3361,3366 ****
--- 3376,3383 ----
  			/* Put the first result row into the target */
  			exec_move_row(estate, rec, row, tuptab->vals[0], tuptab->tupdesc);
  		}
+ 		/* clean up after exec_move_row() */
+ 		exec_eval_cleanup(estate);
  	}
  	else
  	{
*************** exec_stmt_fetch(PLpgSQL_execstate *estat
*** 3634,3639 ****
--- 3651,3657 ----
  		else
  			exec_move_row(estate, rec, row, tuptab->vals[0], tuptab->tupdesc);
  
+ 		exec_eval_cleanup(estate);
  		SPI_freetuptable(tuptab);
  	}
  	else
*************** exec_assign_c_string(PLpgSQL_execstate *
*** 3733,3739 ****
  /* ----------
   * exec_assign_value			Put a value into a target field
   *
!  * Note: in some code paths, this may leak memory in the eval_econtext;
   * we assume that will be cleaned up later by exec_eval_cleanup.  We cannot
   * call exec_eval_cleanup here for fear of destroying the input Datum value.
   * ----------
--- 3751,3757 ----
  /* ----------
   * exec_assign_value			Put a value into a target field
   *
!  * Note: in some code paths, this will leak memory in the eval_econtext;
   * we assume that will be cleaned up later by exec_eval_cleanup.  We cannot
   * call exec_eval_cleanup here for fear of destroying the input Datum value.
   * ----------
*************** exec_assign_value(PLpgSQL_execstate *est
*** 3753,3759 ****
  				PLpgSQL_var *var = (PLpgSQL_var *) target;
  				Datum		newvalue;
  
! 				newvalue = exec_cast_value(value, valtype, var->datatype->typoid,
  										   &(var->datatype->typinput),
  										   var->datatype->typioparam,
  										   var->datatype->atttypmod,
--- 3771,3780 ----
  				PLpgSQL_var *var = (PLpgSQL_var *) target;
  				Datum		newvalue;
  
! 				newvalue = exec_cast_value(estate,
! 										   value,
! 										   valtype,
! 										   var->datatype->typoid,
  										   &(var->datatype->typinput),
  										   var->datatype->typioparam,
  										   var->datatype->atttypmod,
*************** exec_assign_value(PLpgSQL_execstate *est
*** 3766,3784 ****
  									var->refname)));
  
  				/*
! 				 * If type is by-reference, make sure we have a freshly
! 				 * palloc'd copy; the originally passed value may not live as
! 				 * long as the variable!  But we don't need to re-copy if
! 				 * exec_cast_value performed a conversion; its output must
! 				 * already be palloc'd.
  				 */
  				if (!var->datatype->typbyval && !*isNull)
! 				{
! 					if (newvalue == value)
! 						newvalue = datumCopy(newvalue,
! 											 false,
! 											 var->datatype->typlen);
! 				}
  
  				/*
  				 * Now free the old value.	(We can't do this any earlier
--- 3787,3800 ----
  									var->refname)));
  
  				/*
! 				 * If type is by-reference, copy the new value (which is
! 				 * probably in the eval_econtext) into the procedure's
! 				 * memory context.
  				 */
  				if (!var->datatype->typbyval && !*isNull)
! 					newvalue = datumCopy(newvalue,
! 										 false,
! 										 var->datatype->typlen);
  
  				/*
  				 * Now free the old value.	(We can't do this any earlier
*************** exec_assign_value(PLpgSQL_execstate *est
*** 3894,3900 ****
  				Datum	   *values;
  				bool	   *nulls;
  				bool	   *replaces;
- 				void	   *mustfree;
  				bool		attisnull;
  				Oid			atttype;
  				int32		atttypmod;
--- 3910,3915 ----
*************** exec_assign_value(PLpgSQL_execstate *est
*** 3946,3952 ****
  				atttype = SPI_gettypeid(rec->tupdesc, fno + 1);
  				atttypmod = rec->tupdesc->attrs[fno]->atttypmod;
  				attisnull = *isNull;
! 				values[fno] = exec_simple_cast_value(value,
  													 valtype,
  													 atttype,
  													 atttypmod,
--- 3961,3968 ----
  				atttype = SPI_gettypeid(rec->tupdesc, fno + 1);
  				atttypmod = rec->tupdesc->attrs[fno]->atttypmod;
  				attisnull = *isNull;
! 				values[fno] = exec_simple_cast_value(estate,
! 													 value,
  													 valtype,
  													 atttype,
  													 atttypmod,
*************** exec_assign_value(PLpgSQL_execstate *est
*** 3954,3968 ****
  				nulls[fno] = attisnull;
  
  				/*
- 				 * Avoid leaking the result of exec_simple_cast_value, if it
- 				 * performed a conversion to a pass-by-ref type.
- 				 */
- 				if (!attisnull && values[fno] != value && !get_typbyval(atttype))
- 					mustfree = DatumGetPointer(values[fno]);
- 				else
- 					mustfree = NULL;
- 
- 				/*
  				 * Now call heap_modify_tuple() to create a new tuple that
  				 * replaces the old one in the record.
  				 */
--- 3970,3975 ----
*************** exec_assign_value(PLpgSQL_execstate *est
*** 3978,3985 ****
  				pfree(values);
  				pfree(nulls);
  				pfree(replaces);
- 				if (mustfree)
- 					pfree(mustfree);
  
  				break;
  			}
--- 3985,3990 ----
*************** exec_assign_value(PLpgSQL_execstate *est
*** 4002,4007 ****
--- 4007,4013 ----
  				ArrayType  *oldarrayval;
  				ArrayType  *newarrayval;
  				SPITupleTable *save_eval_tuptable;
+ 				MemoryContext oldcontext;
  
  				/*
  				 * We need to do subscript evaluation, which might require
*************** exec_assign_value(PLpgSQL_execstate *est
*** 4118,4124 ****
  				estate->eval_tuptable = save_eval_tuptable;
  
  				/* Coerce source value to match array element type. */
! 				coerced_value = exec_simple_cast_value(value,
  													   valtype,
  													   arrayelem->elemtypoid,
  													   arrayelem->arraytypmod,
--- 4124,4131 ----
  				estate->eval_tuptable = save_eval_tuptable;
  
  				/* Coerce source value to match array element type. */
! 				coerced_value = exec_simple_cast_value(estate,
! 													   value,
  													   valtype,
  													   arrayelem->elemtypoid,
  													   arrayelem->arraytypmod,
*************** exec_assign_value(PLpgSQL_execstate *est
*** 4138,4143 ****
--- 4145,4153 ----
  					(oldarrayisnull || *isNull))
  					return;
  
+ 				/* oldarrayval and newarrayval should be short-lived */
+ 				oldcontext = MemoryContextSwitchTo(estate->eval_econtext->ecxt_per_tuple_memory);
+ 
  				if (oldarrayisnull)
  					oldarrayval = construct_empty_array(arrayelem->elemtypoid);
  				else
*************** exec_assign_value(PLpgSQL_execstate *est
*** 4156,4168 ****
  										arrayelem->elemtypbyval,
  										arrayelem->elemtypalign);
  
! 				/*
! 				 * Avoid leaking the result of exec_simple_cast_value, if it
! 				 * performed a conversion to a pass-by-ref type.
! 				 */
! 				if (!*isNull && coerced_value != value &&
! 					!arrayelem->elemtypbyval)
! 					pfree(DatumGetPointer(coerced_value));
  
  				/*
  				 * Assign the new array to the base variable.  It's never NULL
--- 4166,4172 ----
  										arrayelem->elemtypbyval,
  										arrayelem->elemtypalign);
  
! 				MemoryContextSwitchTo(oldcontext);
  
  				/*
  				 * Assign the new array to the base variable.  It's never NULL
*************** exec_assign_value(PLpgSQL_execstate *est
*** 4174,4184 ****
  				exec_assign_value(estate, target,
  								  PointerGetDatum(newarrayval),
  								  arrayelem->arraytypoid, isNull);
- 
- 				/*
- 				 * Avoid leaking the modified array value, too.
- 				 */
- 				pfree(newarrayval);
  				break;
  			}
  
--- 4178,4183 ----
*************** exec_eval_integer(PLpgSQL_execstate *est
*** 4514,4520 ****
  	Oid			exprtypeid;
  
  	exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid);
! 	exprdatum = exec_simple_cast_value(exprdatum, exprtypeid,
  									   INT4OID, -1,
  									   *isNull);
  	return DatumGetInt32(exprdatum);
--- 4513,4519 ----
  	Oid			exprtypeid;
  
  	exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid);
! 	exprdatum = exec_simple_cast_value(estate, exprdatum, exprtypeid,
  									   INT4OID, -1,
  									   *isNull);
  	return DatumGetInt32(exprdatum);
*************** exec_eval_boolean(PLpgSQL_execstate *est
*** 4536,4542 ****
  	Oid			exprtypeid;
  
  	exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid);
! 	exprdatum = exec_simple_cast_value(exprdatum, exprtypeid,
  									   BOOLOID, -1,
  									   *isNull);
  	return DatumGetBool(exprdatum);
--- 4535,4541 ----
  	Oid			exprtypeid;
  
  	exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid);
! 	exprdatum = exec_simple_cast_value(estate, exprdatum, exprtypeid,
  									   BOOLOID, -1,
  									   *isNull);
  	return DatumGetBool(exprdatum);
*************** exec_for_query(PLpgSQL_execstate *estate
*** 4730,4736 ****
--- 4729,4738 ----
  	 * through with found = false.
  	 */
  	if (n <= 0)
+ 	{
  		exec_move_row(estate, rec, row, NULL, tuptab->tupdesc);
+ 		exec_eval_cleanup(estate);
+ 	}
  	else
  		found = true;			/* processed at least one tuple */
  
*************** exec_for_query(PLpgSQL_execstate *estate
*** 4747,4752 ****
--- 4749,4755 ----
  			 * Assign the tuple to the target
  			 */
  			exec_move_row(estate, rec, row, tuptab->vals[i], tuptab->tupdesc);
+ 			exec_eval_cleanup(estate);
  
  			/*
  			 * Execute the statements
*************** plpgsql_param_fetch(ParamListInfo params
*** 5138,5143 ****
--- 5141,5149 ----
  
  /* ----------
   * exec_move_row			Move one tuple's values into a record or row
+  *
+  * Since this uses exec_assign_value, caller should eventually call
+  * exec_eval_cleanup to prevent long-term memory leaks.
   * ----------
   */
  static void
*************** make_tuple_from_row(PLpgSQL_execstate *e
*** 5338,5365 ****
  /* ----------
   * convert_value_to_string			Convert a non-null Datum to C string
   *
!  * Note: callers generally assume that the result is a palloc'd string and
!  * should be pfree'd.  This is not all that safe an assumption ...
   *
   * Note: not caching the conversion function lookup is bad for performance.
   * ----------
   */
  static char *
! convert_value_to_string(Datum value, Oid valtype)
  {
  	Oid			typoutput;
  	bool		typIsVarlena;
  
  	getTypeOutputInfo(valtype, &typoutput, &typIsVarlena);
! 	return OidOutputFunctionCall(typoutput, value);
  }
  
  /* ----------
   * exec_cast_value			Cast a value if required
   * ----------
   */
  static Datum
! exec_cast_value(Datum value, Oid valtype,
  				Oid reqtype,
  				FmgrInfo *reqinput,
  				Oid reqtypioparam,
--- 5344,5387 ----
  /* ----------
   * convert_value_to_string			Convert a non-null Datum to C string
   *
!  * Note: the result is in the estate's eval_econtext, and will be cleared
!  * by the next exec_eval_cleanup() call.  The invoked output function might
!  * leave additional cruft there as well, so just pfree'ing the result string
!  * would not be enough to avoid memory leaks if we did not do it like this.
!  * In most usages the Datum being passed in is also in that context (if
!  * pass-by-reference) and so an exec_eval_cleanup() call is needed anyway.
   *
   * Note: not caching the conversion function lookup is bad for performance.
   * ----------
   */
  static char *
! convert_value_to_string(PLpgSQL_execstate *estate, Datum value, Oid valtype)
  {
+ 	char	   *result;
+ 	MemoryContext oldcontext;
  	Oid			typoutput;
  	bool		typIsVarlena;
  
+ 	oldcontext = MemoryContextSwitchTo(estate->eval_econtext->ecxt_per_tuple_memory);
  	getTypeOutputInfo(valtype, &typoutput, &typIsVarlena);
! 	result = OidOutputFunctionCall(typoutput, value);
! 	MemoryContextSwitchTo(oldcontext);
! 
! 	return result;
  }
  
  /* ----------
   * exec_cast_value			Cast a value if required
+  *
+  * Note: the estate's eval_econtext is used for temporary storage, and may
+  * also contain the result Datum if we have to do a conversion to a pass-
+  * by-reference data type.  Be sure to do an exec_eval_cleanup() call when
+  * done with the result.
   * ----------
   */
  static Datum
! exec_cast_value(PLpgSQL_execstate *estate,
! 				Datum value, Oid valtype,
  				Oid reqtype,
  				FmgrInfo *reqinput,
  				Oid reqtypioparam,
*************** exec_cast_value(Datum value, Oid valtype
*** 5367,5391 ****
  				bool isnull)
  {
  	/*
! 	 * If the type of the queries return value isn't that of the variable,
! 	 * convert it.
  	 */
  	if (valtype != reqtype || reqtypmod != -1)
  	{
  		if (!isnull)
  		{
  			char	   *extval;
  
! 			extval = convert_value_to_string(value, valtype);
  			value = InputFunctionCall(reqinput, extval,
  									  reqtypioparam, reqtypmod);
- 			pfree(extval);
  		}
  		else
  		{
  			value = InputFunctionCall(reqinput, NULL,
  									  reqtypioparam, reqtypmod);
  		}
  	}
  
  	return value;
--- 5389,5415 ----
  				bool isnull)
  {
  	/*
! 	 * If the type of the given value isn't what's requested, convert it.
  	 */
  	if (valtype != reqtype || reqtypmod != -1)
  	{
+ 		MemoryContext oldcontext;
+ 
+ 		oldcontext = MemoryContextSwitchTo(estate->eval_econtext->ecxt_per_tuple_memory);
  		if (!isnull)
  		{
  			char	   *extval;
  
! 			extval = convert_value_to_string(estate, value, valtype);
  			value = InputFunctionCall(reqinput, extval,
  									  reqtypioparam, reqtypmod);
  		}
  		else
  		{
  			value = InputFunctionCall(reqinput, NULL,
  									  reqtypioparam, reqtypmod);
  		}
+ 		MemoryContextSwitchTo(oldcontext);
  	}
  
  	return value;
*************** exec_cast_value(Datum value, Oid valtype
*** 5400,5406 ****
   * ----------
   */
  static Datum
! exec_simple_cast_value(Datum value, Oid valtype,
  					   Oid reqtype, int32 reqtypmod,
  					   bool isnull)
  {
--- 5424,5431 ----
   * ----------
   */
  static Datum
! exec_simple_cast_value(PLpgSQL_execstate *estate,
! 					   Datum value, Oid valtype,
  					   Oid reqtype, int32 reqtypmod,
  					   bool isnull)
  {
*************** exec_simple_cast_value(Datum value, Oid 
*** 5414,5420 ****
  
  		fmgr_info(typinput, &finfo_input);
  
! 		value = exec_cast_value(value,
  								valtype,
  								reqtype,
  								&finfo_input,
--- 5439,5446 ----
  
  		fmgr_info(typinput, &finfo_input);
  
! 		value = exec_cast_value(estate,
! 								value,
  								valtype,
  								reqtype,
  								&finfo_input,
*************** exec_dynquery_with_params(PLpgSQL_execst
*** 6137,6143 ****
  				 errmsg("query string argument of EXECUTE is null")));
  
  	/* Get the C-String representation */
! 	querystr = convert_value_to_string(query, restype);
  
  	exec_eval_cleanup(estate);
  
--- 6163,6172 ----
  				 errmsg("query string argument of EXECUTE is null")));
  
  	/* Get the C-String representation */
! 	querystr = convert_value_to_string(estate, query, restype);
! 
! 	/* copy it out of the temporary context before we clean up */
! 	querystr = pstrdup(querystr);
  
  	exec_eval_cleanup(estate);