errmsg("NULL cannot be assigned to variable \"%s\" declared NOT NULL",
var->refname)));
- if (var->freeval)
- {
- pfree(DatumGetPointer(var->value));
- var->freeval = false;
- }
-
/*
* If type is by-reference, make sure we have a freshly
* palloc'd copy; the originally passed value may not live
if (!var->datatype->typbyval && !*isNull)
{
if (newvalue == value)
- var->value = datumCopy(newvalue,
- false,
- var->datatype->typlen);
- else
- var->value = newvalue;
- var->freeval = true;
+ newvalue = datumCopy(newvalue,
+ false,
+ var->datatype->typlen);
}
- else
- var->value = newvalue;
+
+ /*
+ * Now free the old value. (We can't do this any earlier
+ * because of the possibility that we are assigning the
+ * var's old value to it, eg "foo := foo". We could optimize
+ * out the assignment altogether in such cases, but it's too
+ * infrequent to be worth testing for.)
+ */
+ if (var->freeval)
+ {
+ pfree(DatumGetPointer(var->value));
+ var->freeval = false;
+ }
+
+ var->value = newvalue;
var->isnull = *isNull;
+ if (!var->datatype->typbyval && !*isNull)
+ var->freeval = true;
break;
}
oldarrayisnull;
Oid arraytypeid,
arrayelemtypeid;
- int16 elemtyplen;
+ int16 arraytyplen,
+ elemtyplen;
bool elemtypbyval;
char elemtypalign;
- Datum oldarrayval,
+ Datum oldarraydatum,
coerced_value;
+ ArrayType *oldarrayval;
ArrayType *newarrayval;
/*
/* 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))
(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
}
/*
- * 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,
/*
* 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,
*/
if (rec != NULL)
{
+ /*
+ * copy input first, just in case it is pointing at variable's value
+ */
+ if (HeapTupleIsValid(tup))
+ tup = heap_copytuple(tup);
+ if (tupdesc)
+ tupdesc = CreateTupleDescCopy(tupdesc);
+
if (rec->freetup)
{
heap_freetuple(rec->tup);
if (HeapTupleIsValid(tup))
{
- rec->tup = heap_copytuple(tup);
+ rec->tup = tup;
rec->freetup = true;
}
else if (tupdesc)
if (tupdesc)
{
- rec->tupdesc = CreateTupleDescCopy(tupdesc);
+ rec->tupdesc = tupdesc;
rec->freetupdesc = true;
}
else