]> granicus.if.org Git - postgresql/commitdiff
Adjust plpgsql to allow assignment to an element of an array that is
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 1 Feb 2005 19:35:14 +0000 (19:35 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 1 Feb 2005 19:35:14 +0000 (19:35 +0000)
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.

src/pl/plpgsql/src/pl_exec.c

index bd2c6a00bed87cce3f660ba2b6dc6c061b6619ed..1f3d4c4ab2caa94d974e42fcfd90551ff2bd370e 100644 (file)
@@ -3,7 +3,7 @@
  *                       procedural language
  *
  * 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.
  *
@@ -3069,11 +3069,13 @@ exec_assign_value(PLpgSQL_execstate *estate,
                                                        oldarrayisnull;
                                Oid                     arraytypeid,
                                                        arrayelemtypeid;
-                               int16           elemtyplen;
+                               int16           arraytyplen,
+                                                       elemtyplen;
                                bool            elemtypbyval;
                                char            elemtypalign;
-                               Datum           oldarrayval,
+                               Datum           oldarraydatum,
                                                        coerced_value;
+                               ArrayType  *oldarrayval;
                                ArrayType  *newarrayval;
 
                                /*
@@ -3102,7 +3104,7 @@ exec_assign_value(PLpgSQL_execstate *estate,
 
                                /* Fetch current value of array datum */
                                exec_eval_datum(estate, target, InvalidOid,
-                                                       &arraytypeid, &oldarrayval, &oldarrayisnull);
+                                                               &arraytypeid, &oldarraydatum, &oldarrayisnull);
 
                                arrayelemtypeid = get_element_type(arraytypeid);
                                if (!OidIsValid(arrayelemtypeid))
@@ -3110,6 +3112,12 @@ exec_assign_value(PLpgSQL_execstate *estate,
                                                        (errcode(ERRCODE_DATATYPE_MISMATCH),
                                                  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
                                 * order
@@ -3127,14 +3135,36 @@ exec_assign_value(PLpgSQL_execstate *estate,
                                }
 
                                /*
-                                * Skip the assignment if we have any nulls, either in the
-                                * original array value, the subscripts, or the righthand
-                                * side. This is pretty bogus but it corresponds to the
-                                * current behavior of ExecEvalArrayRef().
+                                * Skip the assignment if we have any nulls in the subscripts
+                                * or the righthand side. This is pretty bogus but it
+                                * corresponds to the current behavior of ExecEvalArrayRef().
                                 */
-                               if (oldarrayisnull || havenullsubscript || *isNull)
+                               if (havenullsubscript || *isNull)
                                        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. */
                                coerced_value = exec_simple_cast_value(value,
                                                                                                           valtype,
@@ -3145,16 +3175,11 @@ exec_assign_value(PLpgSQL_execstate *estate,
                                /*
                                 * Build the modified array value.
                                 */
-                               get_typlenbyvalalign(arrayelemtypeid,
-                                                                        &elemtyplen,
-                                                                        &elemtypbyval,
-                                                                        &elemtypalign);
-
-                               newarrayval = array_set((ArrayType *) DatumGetPointer(oldarrayval),
+                               newarrayval = array_set(oldarrayval,
                                                                                nsubscripts,
                                                                                subscriptvals,
                                                                                coerced_value,
-                                                                               get_typlen(arraytypeid),
+                                                                               arraytyplen,
                                                                                elemtyplen,
                                                                                elemtypbyval,
                                                                                elemtypalign,