diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index 09ecaec..97cb763 100644
*** a/src/pl/plpgsql/src/pl_comp.c
--- b/src/pl/plpgsql/src/pl_comp.c
*************** plpgsql_adddatum(PLpgSQL_datum *new)
*** 2183,2194 ****
--- 2183,2211 ----
  static void
  plpgsql_finish_datums(PLpgSQL_function *function)
  {
+ 	Size		copiable_size = 0;
  	int			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];
+ 
+ 		/* This must agree with copy_plpgsql_datums on what is copiable */
+ 		switch (function->datums[i]->dtype)
+ 		{
+ 			case PLPGSQL_DTYPE_VAR:
+ 				copiable_size += MAXALIGN(sizeof(PLpgSQL_var));
+ 				break;
+ 			case PLPGSQL_DTYPE_REC:
+ 				copiable_size += MAXALIGN(sizeof(PLpgSQL_rec));
+ 				break;
+ 			default:
+ 				break;
+ 		}
+ 	}
+ 	function->copiable_size = copiable_size;
  }
  
  
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index e119744..e2d315c 100644
*** a/src/pl/plpgsql/src/pl_exec.c
--- b/src/pl/plpgsql/src/pl_exec.c
*************** static HTAB *shared_cast_hash = NULL;
*** 235,241 ****
  static void coerce_function_result_tuple(PLpgSQL_execstate *estate,
  							 TupleDesc tupdesc);
  static void plpgsql_exec_error_callback(void *arg);
! static PLpgSQL_datum *copy_plpgsql_datum(PLpgSQL_datum *datum);
  static MemoryContext get_stmt_mcontext(PLpgSQL_execstate *estate);
  static void push_stmt_mcontext(PLpgSQL_execstate *estate);
  static void pop_stmt_mcontext(PLpgSQL_execstate *estate);
--- 235,242 ----
  static void coerce_function_result_tuple(PLpgSQL_execstate *estate,
  							 TupleDesc tupdesc);
  static void plpgsql_exec_error_callback(void *arg);
! static void copy_plpgsql_datums(PLpgSQL_execstate *estate,
! 					PLpgSQL_function *func);
  static MemoryContext get_stmt_mcontext(PLpgSQL_execstate *estate);
  static void push_stmt_mcontext(PLpgSQL_execstate *estate);
  static void pop_stmt_mcontext(PLpgSQL_execstate *estate);
*************** plpgsql_exec_function(PLpgSQL_function *
*** 458,465 ****
  	 * Make local execution copies of all the datums
  	 */
  	estate.err_text = gettext_noop("during initialization of execution state");
! 	for (i = 0; i < estate.ndatums; i++)
! 		estate.datums[i] = copy_plpgsql_datum(func->datums[i]);
  
  	/*
  	 * Store the actual call argument values into the appropriate variables
--- 459,465 ----
  	 * Make local execution copies of all the datums
  	 */
  	estate.err_text = gettext_noop("during initialization of execution state");
! 	copy_plpgsql_datums(&estate, func);
  
  	/*
  	 * Store the actual call argument values into the appropriate variables
*************** plpgsql_exec_trigger(PLpgSQL_function *f
*** 859,866 ****
  	 * Make local execution copies of all the datums
  	 */
  	estate.err_text = gettext_noop("during initialization of execution state");
! 	for (i = 0; i < estate.ndatums; i++)
! 		estate.datums[i] = copy_plpgsql_datum(func->datums[i]);
  
  	/*
  	 * Put the OLD and NEW tuples into record variables
--- 859,865 ----
  	 * Make local execution copies of all the datums
  	 */
  	estate.err_text = gettext_noop("during initialization of execution state");
! 	copy_plpgsql_datums(&estate, func);
  
  	/*
  	 * Put the OLD and NEW tuples into record variables
*************** plpgsql_exec_event_trigger(PLpgSQL_funct
*** 1153,1159 ****
  {
  	PLpgSQL_execstate estate;
  	ErrorContextCallback plerrcontext;
- 	int			i;
  	int			rc;
  	PLpgSQL_var *var;
  
--- 1152,1157 ----
*************** plpgsql_exec_event_trigger(PLpgSQL_funct
*** 1174,1181 ****
  	 * Make local execution copies of all the datums
  	 */
  	estate.err_text = gettext_noop("during initialization of execution state");
! 	for (i = 0; i < estate.ndatums; i++)
! 		estate.datums[i] = copy_plpgsql_datum(func->datums[i]);
  
  	/*
  	 * Assign the special tg_ variables
--- 1172,1178 ----
  	 * Make local execution copies of all the datums
  	 */
  	estate.err_text = gettext_noop("during initialization of execution state");
! 	copy_plpgsql_datums(&estate, func);
  
  	/*
  	 * Assign the special tg_ variables
*************** plpgsql_exec_error_callback(void *arg)
*** 1290,1346 ****
   * Support function for initializing local execution variables
   * ----------
   */
! static PLpgSQL_datum *
! copy_plpgsql_datum(PLpgSQL_datum *datum)
  {
! 	PLpgSQL_datum *result;
  
! 	switch (datum->dtype)
! 	{
! 		case PLPGSQL_DTYPE_VAR:
! 			{
! 				PLpgSQL_var *new = palloc(sizeof(PLpgSQL_var));
  
! 				memcpy(new, datum, sizeof(PLpgSQL_var));
! 				/* should be preset to null/non-freeable */
! 				Assert(new->isnull);
! 				Assert(!new->freeval);
  
! 				result = (PLpgSQL_datum *) new;
! 			}
! 			break;
  
! 		case PLPGSQL_DTYPE_REC:
! 			{
! 				PLpgSQL_rec *new = palloc(sizeof(PLpgSQL_rec));
  
! 				memcpy(new, datum, sizeof(PLpgSQL_rec));
! 				/* should be preset to empty */
! 				Assert(new->erh == NULL);
  
! 				result = (PLpgSQL_datum *) new;
! 			}
! 			break;
  
! 		case PLPGSQL_DTYPE_ROW:
! 		case PLPGSQL_DTYPE_RECFIELD:
! 		case PLPGSQL_DTYPE_ARRAYELEM:
  
! 			/*
! 			 * These datum records are read-only at runtime, so no need to
! 			 * copy them (well, RECFIELD and ARRAYELEM contain cached data,
! 			 * but we'd just as soon centralize the caching anyway)
! 			 */
! 			result = datum;
! 			break;
  
! 		default:
! 			elog(ERROR, "unrecognized dtype: %d", datum->dtype);
! 			result = NULL;		/* keep compiler quiet */
! 			break;
  	}
  
! 	return result;
  }
  
  /*
--- 1287,1359 ----
   * Support function for initializing local execution variables
   * ----------
   */
! static void
! copy_plpgsql_datums(PLpgSQL_execstate *estate,
! 					PLpgSQL_function *func)
  {
! 	int			ndatums = estate->ndatums;
! 	PLpgSQL_datum **indatums;
! 	PLpgSQL_datum **outdatums;
! 	char	   *workspace;
! 	char	   *ws_next;
! 	int			i;
  
! 	/* Allocate local datum-pointer array */
! 	estate->datums = (PLpgSQL_datum **)
! 		palloc(sizeof(PLpgSQL_datum *) * ndatums);
  
! 	/*
! 	 * To reduce palloc overhead, we make a single palloc request for all the
! 	 * space needed for locally-instantiated datums.
! 	 */
! 	workspace = palloc(func->copiable_size);
! 	ws_next = workspace;
  
! 	/* Fill datum-pointer array, copying datums into workspace as needed */
! 	indatums = func->datums;
! 	outdatums = estate->datums;
! 	for (i = 0; i < ndatums; i++)
! 	{
! 		PLpgSQL_datum *indatum = indatums[i];
! 		PLpgSQL_datum *outdatum;
  
! 		/* This must agree with plpgsql_finish_datums on what is copiable */
! 		switch (indatum->dtype)
! 		{
! 			case PLPGSQL_DTYPE_VAR:
! 				outdatum = (PLpgSQL_datum *) ws_next;
! 				memcpy(outdatum, indatum, sizeof(PLpgSQL_var));
! 				ws_next += MAXALIGN(sizeof(PLpgSQL_var));
! 				break;
  
! 			case PLPGSQL_DTYPE_REC:
! 				outdatum = (PLpgSQL_datum *) ws_next;
! 				memcpy(outdatum, indatum, sizeof(PLpgSQL_rec));
! 				ws_next += MAXALIGN(sizeof(PLpgSQL_rec));
! 				break;
  
! 			case PLPGSQL_DTYPE_ROW:
! 			case PLPGSQL_DTYPE_RECFIELD:
! 			case PLPGSQL_DTYPE_ARRAYELEM:
  
! 				/*
! 				 * These datum records are read-only at runtime, so no need to
! 				 * copy them (well, RECFIELD and ARRAYELEM contain cached
! 				 * data, but we'd just as soon centralize the caching anyway).
! 				 */
! 				outdatum = indatum;
! 				break;
  
! 			default:
! 				elog(ERROR, "unrecognized dtype: %d", indatum->dtype);
! 				outdatum = NULL;	/* keep compiler quiet */
! 				break;
! 		}
  
! 		outdatums[i] = outdatum;
  	}
  
! 	Assert(ws_next == workspace + func->copiable_size);
  }
  
  /*
*************** plpgsql_estate_setup(PLpgSQL_execstate *
*** 3504,3511 ****
  
  	estate->found_varno = func->found_varno;
  	estate->ndatums = func->ndatums;
! 	estate->datums = palloc(sizeof(PLpgSQL_datum *) * estate->ndatums);
! 	/* caller is expected to fill the datums array */
  	estate->datum_context = CurrentMemoryContext;
  
  	/* initialize our ParamListInfo with appropriate hook functions */
--- 3517,3524 ----
  
  	estate->found_varno = func->found_varno;
  	estate->ndatums = func->ndatums;
! 	estate->datums = NULL;
! 	/* the datums array will be filled by copy_plpgsql_datums() */
  	estate->datum_context = CurrentMemoryContext;
  
  	/* initialize our ParamListInfo with appropriate hook functions */
diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y
index 97c0d4f..ee943ee 100644
*** a/src/pl/plpgsql/src/pl_gram.y
--- b/src/pl/plpgsql/src/pl_gram.y
*************** decl_statement	: decl_varname decl_const
*** 564,570 ****
  
  						curname_def = palloc0(sizeof(PLpgSQL_expr));
  
- 						curname_def->dtype = PLPGSQL_DTYPE_EXPR;
  						strcpy(buf, "SELECT ");
  						cp1 = new->refname;
  						cp2 = buf + strlen(buf);
--- 564,569 ----
*************** read_sql_construct(int until,
*** 2697,2703 ****
  	}
  
  	expr = palloc0(sizeof(PLpgSQL_expr));
- 	expr->dtype			= PLPGSQL_DTYPE_EXPR;
  	expr->query			= pstrdup(ds.data);
  	expr->plan			= NULL;
  	expr->paramnos		= NULL;
--- 2696,2701 ----
*************** make_execsql_stmt(int firsttoken, int lo
*** 2944,2950 ****
  		ds.data[--ds.len] = '\0';
  
  	expr = palloc0(sizeof(PLpgSQL_expr));
- 	expr->dtype			= PLPGSQL_DTYPE_EXPR;
  	expr->query			= pstrdup(ds.data);
  	expr->plan			= NULL;
  	expr->paramnos		= NULL;
--- 2942,2947 ----
*************** read_cursor_args(PLpgSQL_var *cursor, in
*** 3816,3822 ****
  	appendStringInfoChar(&ds, ';');
  
  	expr = palloc0(sizeof(PLpgSQL_expr));
- 	expr->dtype			= PLPGSQL_DTYPE_EXPR;
  	expr->query			= pstrdup(ds.data);
  	expr->plan			= NULL;
  	expr->paramnos		= NULL;
--- 3813,3818 ----
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index d4eb67b..dadbfb5 100644
*** a/src/pl/plpgsql/src/plpgsql.h
--- b/src/pl/plpgsql/src/plpgsql.h
*************** typedef enum PLpgSQL_datum_type
*** 63,70 ****
  	PLPGSQL_DTYPE_ROW,
  	PLPGSQL_DTYPE_REC,
  	PLPGSQL_DTYPE_RECFIELD,
! 	PLPGSQL_DTYPE_ARRAYELEM,
! 	PLPGSQL_DTYPE_EXPR
  } PLpgSQL_datum_type;
  
  /*
--- 63,69 ----
  	PLPGSQL_DTYPE_ROW,
  	PLPGSQL_DTYPE_REC,
  	PLPGSQL_DTYPE_RECFIELD,
! 	PLPGSQL_DTYPE_ARRAYELEM
  } PLpgSQL_datum_type;
  
  /*
*************** typedef struct PLpgSQL_type
*** 189,226 ****
  } PLpgSQL_type;
  
  /*
-  * Generic datum array item
-  *
-  * PLpgSQL_datum is the common supertype for PLpgSQL_expr, PLpgSQL_var,
-  * PLpgSQL_row, PLpgSQL_rec, PLpgSQL_recfield, and PLpgSQL_arrayelem
-  */
- typedef struct PLpgSQL_datum
- {
- 	PLpgSQL_datum_type dtype;
- 	int			dno;
- } PLpgSQL_datum;
- 
- /*
-  * Scalar or composite variable
-  *
-  * The variants PLpgSQL_var, PLpgSQL_row, and PLpgSQL_rec share these
-  * fields
-  */
- typedef struct PLpgSQL_variable
- {
- 	PLpgSQL_datum_type dtype;
- 	int			dno;
- 	char	   *refname;
- 	int			lineno;
- } PLpgSQL_variable;
- 
- /*
   * SQL Query to plan and execute
   */
  typedef struct PLpgSQL_expr
  {
- 	PLpgSQL_datum_type dtype;
- 	int			dno;
  	char	   *query;
  	SPIPlanPtr	plan;
  	Bitmapset  *paramnos;		/* all dnos referenced by this query */
--- 188,197 ----
*************** typedef struct PLpgSQL_expr
*** 250,255 ****
--- 221,252 ----
  } PLpgSQL_expr;
  
  /*
+  * Generic datum array item
+  *
+  * PLpgSQL_datum is the common supertype for PLpgSQL_var, PLpgSQL_row,
+  * PLpgSQL_rec, PLpgSQL_recfield, and PLpgSQL_arrayelem.
+  */
+ typedef struct PLpgSQL_datum
+ {
+ 	PLpgSQL_datum_type dtype;
+ 	int			dno;
+ } PLpgSQL_datum;
+ 
+ /*
+  * Scalar or composite variable
+  *
+  * The variants PLpgSQL_var, PLpgSQL_row, and PLpgSQL_rec share these
+  * fields.
+  */
+ typedef struct PLpgSQL_variable
+ {
+ 	PLpgSQL_datum_type dtype;
+ 	int			dno;
+ 	char	   *refname;
+ 	int			lineno;
+ } PLpgSQL_variable;
+ 
+ /*
   * Scalar variable
   */
  typedef struct PLpgSQL_var
*************** typedef struct PLpgSQL_var
*** 258,268 ****
  	int			dno;
  	char	   *refname;
  	int			lineno;
  
  	PLpgSQL_type *datatype;
- 	int			isconst;
- 	int			notnull;
  	PLpgSQL_expr *default_val;
  	PLpgSQL_expr *cursor_explicit_expr;
  	int			cursor_explicit_argrow;
  	int			cursor_options;
--- 255,272 ----
  	int			dno;
  	char	   *refname;
  	int			lineno;
+ 	/* end of PLpgSQL_variable fields */
  
+ 	bool		isconst;
+ 	bool		notnull;
  	PLpgSQL_type *datatype;
  	PLpgSQL_expr *default_val;
+ 
+ 	/*
+ 	 * Variables declared as CURSOR FOR <query> are mostly like ordinary
+ 	 * scalar variables of type refcursor, but they have these additional
+ 	 * properties:
+ 	 */
  	PLpgSQL_expr *cursor_explicit_expr;
  	int			cursor_explicit_argrow;
  	int			cursor_options;
*************** typedef struct PLpgSQL_row
*** 286,291 ****
--- 290,296 ----
  	int			dno;
  	char	   *refname;
  	int			lineno;
+ 	/* end of PLpgSQL_variable fields */
  
  	/*
  	 * rowtupdesc is only set up if we might need to convert the row into a
*************** typedef struct PLpgSQL_rec
*** 308,313 ****
--- 313,320 ----
  	int			dno;
  	char	   *refname;
  	int			lineno;
+ 	/* end of PLpgSQL_variable fields */
+ 
  	Oid			rectypeid;		/* declared type of variable */
  	/* RECFIELDs for this record are chained together for easy access */
  	int			firstfield;		/* dno of first RECFIELD, or -1 if none */
*************** typedef struct PLpgSQL_recfield
*** 322,327 ****
--- 329,336 ----
  {
  	PLpgSQL_datum_type dtype;
  	int			dno;
+ 	/* end of PLpgSQL_datum fields */
+ 
  	char	   *fieldname;		/* name of field */
  	int			recparentno;	/* dno of parent record */
  	int			nextfield;		/* dno of next child, or -1 if none */
*************** typedef struct PLpgSQL_arrayelem
*** 337,342 ****
--- 346,353 ----
  {
  	PLpgSQL_datum_type dtype;
  	int			dno;
+ 	/* end of PLpgSQL_datum fields */
+ 
  	PLpgSQL_expr *subscript;
  	int			arrayparentno;	/* dno of parent array variable */
  
*************** typedef struct PLpgSQL_function
*** 884,889 ****
--- 895,901 ----
  	/* the datums representing the function's local variables */
  	int			ndatums;
  	PLpgSQL_datum **datums;
+ 	Size		copiable_size;	/* space for locally instantiated datums */
  
  	/* function body parsetree */
  	PLpgSQL_stmt_block *action;
*************** typedef struct PLpgSQL_execstate
*** 920,927 ****
  	ResourceOwner tuple_store_owner;
  	ReturnSetInfo *rsi;
  
- 	/* the datums representing the function's local variables */
  	int			found_varno;
  	int			ndatums;
  	PLpgSQL_datum **datums;
  	/* context containing variable values (same as func's SPI_proc context) */
--- 932,945 ----
  	ResourceOwner tuple_store_owner;
  	ReturnSetInfo *rsi;
  
  	int			found_varno;
+ 
+ 	/*
+ 	 * The datums representing the function's local variables.  Some of these
+ 	 * are local storage in this execstate, but some just point to the shared
+ 	 * copy belonging to the PLpgSQL_function, depending on whether or not we
+ 	 * need any per-execution state for the datum's dtype.
+ 	 */
  	int			ndatums;
  	PLpgSQL_datum **datums;
  	/* context containing variable values (same as func's SPI_proc context) */
