* procedural language
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.93.2.4 2010/07/05 09:27:57 heikki Exp $
+ * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.93.2.5 2010/08/09 18:51:12 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
*
* NB: the result of the evaluation is no longer valid after this is done,
* unless it is a pass-by-value datatype.
+ *
+ * NB: if you change this code, see also the hacks in exec_assign_value's
+ * PLPGSQL_DTYPE_ARRAYELEM case.
* ----------
*/
static void
/* ----------
* 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.
* ----------
*/
static void
Datum oldarrayval,
coerced_value;
ArrayType *newarrayval;
+ SPITupleTable *save_eval_tuptable;
HeapTuple newtup;
switch (target->dtype)
/*
* Target is an element of an array
*
+ * We need to do subscript evaluation, which might require
+ * evaluating general expressions; and the caller might have
+ * done that too in order to prepare the input Datum. We
+ * have to save and restore the caller's SPI_execute result,
+ * if any.
+ */
+ save_eval_tuptable = estate->eval_tuptable;
+ estate->eval_tuptable = NULL;
+
+ /*
* To handle constructs like x[1][2] := something, we have to be
* prepared to deal with a chain of arrayelem datums. Chase
* back to find the base array datum, and save the subscript
subscripts[nsubscripts - 1 - i],
&subisnull);
havenullsubscript |= subisnull;
+
+ /*
+ * Clean up in case the subscript expression wasn't simple.
+ * We can't do exec_eval_cleanup, but we can do this much
+ * (which is safe because the integer subscript value is
+ * surely pass-by-value), and we must do it in case the
+ * next subscript expression isn't simple either.
+ */
+ if (estate->eval_tuptable != NULL)
+ SPI_freetuptable(estate->eval_tuptable);
+ estate->eval_tuptable = NULL;
}
+ /* Now we can restore caller's SPI_execute result if any. */
+ Assert(estate->eval_tuptable == NULL);
+ estate->eval_tuptable = save_eval_tuptable;
+
/*
* Skip the assignment if we have any nulls, either in the
* original array value, the subscripts, or the righthand
(3 rows)
drop table perform_test;
+-- Test for appropriate cleanup of non-simple expression evaluations
+-- (bug in all versions prior to August 2010)
+CREATE FUNCTION nonsimple_expr_test() RETURNS text[] AS '
+DECLARE
+ arr text[];
+ lr text;
+ i integer;
+BEGIN
+ arr := array[array[''foo'',''bar''], array[''baz'', ''quux'']];
+ lr := ''fool'';
+ i := 1;
+ -- use sub-SELECTs to make expressions non-simple
+ arr[(SELECT i)][(SELECT i+1)] := (SELECT lr);
+ RETURN arr;
+END;
+' LANGUAGE plpgsql;
+SELECT nonsimple_expr_test();
+ nonsimple_expr_test
+-------------------------
+ {{foo,fool},{baz,quux}}
+(1 row)
+
+DROP FUNCTION nonsimple_expr_test();
SELECT perform_test_func();
SELECT * FROM perform_test;
-drop table perform_test;
\ No newline at end of file
+drop table perform_test;
+
+-- Test for appropriate cleanup of non-simple expression evaluations
+-- (bug in all versions prior to August 2010)
+
+CREATE FUNCTION nonsimple_expr_test() RETURNS text[] AS '
+DECLARE
+ arr text[];
+ lr text;
+ i integer;
+BEGIN
+ arr := array[array[''foo'',''bar''], array[''baz'', ''quux'']];
+ lr := ''fool'';
+ i := 1;
+ -- use sub-SELECTs to make expressions non-simple
+ arr[(SELECT i)][(SELECT i+1)] := (SELECT lr);
+ RETURN arr;
+END;
+' LANGUAGE plpgsql;
+
+SELECT nonsimple_expr_test();
+
+DROP FUNCTION nonsimple_expr_test();