Commit 2a887484 authored by Tom Lane's avatar Tom Lane

Adjust plpgsql to allow assignment to an element of an array that is

initially NULL.  For 8.0 we changed the main executor to have this
behavior in an UPDATE of an array column, but plpgsql's equivalent case
was overlooked.  Per report from Sven Willenberger.
parent 68b0e298
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* procedural language * procedural language
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.127 2005/01/13 23:07:34 tgl Exp $ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.128 2005/02/01 19:35:14 tgl Exp $
* *
* This software is copyrighted by Jan Wieck - Hamburg. * This software is copyrighted by Jan Wieck - Hamburg.
* *
...@@ -3069,11 +3069,13 @@ exec_assign_value(PLpgSQL_execstate *estate, ...@@ -3069,11 +3069,13 @@ exec_assign_value(PLpgSQL_execstate *estate,
oldarrayisnull; oldarrayisnull;
Oid arraytypeid, Oid arraytypeid,
arrayelemtypeid; arrayelemtypeid;
int16 elemtyplen; int16 arraytyplen,
elemtyplen;
bool elemtypbyval; bool elemtypbyval;
char elemtypalign; char elemtypalign;
Datum oldarrayval, Datum oldarraydatum,
coerced_value; coerced_value;
ArrayType *oldarrayval;
ArrayType *newarrayval; ArrayType *newarrayval;
/* /*
...@@ -3102,7 +3104,7 @@ exec_assign_value(PLpgSQL_execstate *estate, ...@@ -3102,7 +3104,7 @@ exec_assign_value(PLpgSQL_execstate *estate,
/* Fetch current value of array datum */ /* Fetch current value of array datum */
exec_eval_datum(estate, target, InvalidOid, exec_eval_datum(estate, target, InvalidOid,
&arraytypeid, &oldarrayval, &oldarrayisnull); &arraytypeid, &oldarraydatum, &oldarrayisnull);
arrayelemtypeid = get_element_type(arraytypeid); arrayelemtypeid = get_element_type(arraytypeid);
if (!OidIsValid(arrayelemtypeid)) if (!OidIsValid(arrayelemtypeid))
...@@ -3110,6 +3112,12 @@ exec_assign_value(PLpgSQL_execstate *estate, ...@@ -3110,6 +3112,12 @@ exec_assign_value(PLpgSQL_execstate *estate,
(errcode(ERRCODE_DATATYPE_MISMATCH), (errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("subscripted object is not an array"))); errmsg("subscripted object is not an array")));
get_typlenbyvalalign(arrayelemtypeid,
&elemtyplen,
&elemtypbyval,
&elemtypalign);
arraytyplen = get_typlen(arraytypeid);
/* /*
* Evaluate the subscripts, switch into left-to-right * Evaluate the subscripts, switch into left-to-right
* order * order
...@@ -3127,14 +3135,36 @@ exec_assign_value(PLpgSQL_execstate *estate, ...@@ -3127,14 +3135,36 @@ exec_assign_value(PLpgSQL_execstate *estate,
} }
/* /*
* Skip the assignment if we have any nulls, either in the * Skip the assignment if we have any nulls in the subscripts
* original array value, the subscripts, or the righthand * or the righthand side. This is pretty bogus but it
* side. This is pretty bogus but it corresponds to the * corresponds to the current behavior of ExecEvalArrayRef().
* current behavior of ExecEvalArrayRef().
*/ */
if (oldarrayisnull || havenullsubscript || *isNull) if (havenullsubscript || *isNull)
return; return;
/*
* If the original array is null, cons up an empty array
* so that the assignment can proceed; we'll end with a
* one-element array containing just the assigned-to
* subscript. This only works for varlena arrays, though;
* for fixed-length array types we skip the assignment.
* Again, this corresponds to the current behavior of
* ExecEvalArrayRef().
*/
if (oldarrayisnull)
{
if (arraytyplen > 0) /* fixed-length array? */
return;
oldarrayval = construct_md_array(NULL, 0, NULL, NULL,
arrayelemtypeid,
elemtyplen,
elemtypbyval,
elemtypalign);
}
else
oldarrayval = (ArrayType *) DatumGetPointer(oldarraydatum);
/* Coerce source value to match array element type. */ /* Coerce source value to match array element type. */
coerced_value = exec_simple_cast_value(value, coerced_value = exec_simple_cast_value(value,
valtype, valtype,
...@@ -3145,16 +3175,11 @@ exec_assign_value(PLpgSQL_execstate *estate, ...@@ -3145,16 +3175,11 @@ exec_assign_value(PLpgSQL_execstate *estate,
/* /*
* Build the modified array value. * Build the modified array value.
*/ */
get_typlenbyvalalign(arrayelemtypeid, newarrayval = array_set(oldarrayval,
&elemtyplen,
&elemtypbyval,
&elemtypalign);
newarrayval = array_set((ArrayType *) DatumGetPointer(oldarrayval),
nsubscripts, nsubscripts,
subscriptvals, subscriptvals,
coerced_value, coerced_value,
get_typlen(arraytypeid), arraytyplen,
elemtyplen, elemtyplen,
elemtypbyval, elemtypbyval,
elemtypalign, elemtypalign,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment