1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-14 18:42:34 +03:00

Support assignment to subfields of composite columns in UPDATE and INSERT.

As a side effect, cause subscripts in INSERT targetlists to do something
more or less sensible; previously we evaluated such subscripts and then
effectively ignored them.  Another side effect is that UPDATE-ing an
element or slice of an array value that is NULL now produces a non-null
result, namely an array containing just the assigned-to positions.
This commit is contained in:
Tom Lane
2004-06-09 19:08:20 +00:00
parent 3a0df651da
commit 7e64dbc6b5
27 changed files with 1468 additions and 574 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_node.c,v 1.83 2004/05/26 04:41:30 neilc Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_node.c,v 1.84 2004/06/09 19:08:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -67,6 +67,39 @@ make_var(ParseState *pstate, RangeTblEntry *rte, int attrno)
return makeVar(vnum, attrno, vartypeid, type_mod, sublevels_up);
}
/*
* transformArrayType()
* Get the element type of an array type in preparation for subscripting
*/
Oid
transformArrayType(Oid arrayType)
{
Oid elementType;
HeapTuple type_tuple_array;
Form_pg_type type_struct_array;
/* Get the type tuple for the array */
type_tuple_array = SearchSysCache(TYPEOID,
ObjectIdGetDatum(arrayType),
0, 0, 0);
if (!HeapTupleIsValid(type_tuple_array))
elog(ERROR, "cache lookup failed for type %u", arrayType);
type_struct_array = (Form_pg_type) GETSTRUCT(type_tuple_array);
/* needn't check typisdefined since this will fail anyway */
elementType = type_struct_array->typelem;
if (elementType == InvalidOid)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("cannot subscript type %s because it is not an array",
format_type_be(arrayType))));
ReleaseSysCache(type_tuple_array);
return elementType;
}
/*
* transformArraySubscripts()
* Transform array subscripting. This is used for both
@ -83,68 +116,49 @@ make_var(ParseState *pstate, RangeTblEntry *rte, int attrno)
*
* pstate Parse state
* arrayBase Already-transformed expression for the array as a whole
* (may be NULL if we are handling an INSERT)
* arrayType OID of array's datatype
* arrayTypMod typmod to be applied to array elements
* arrayType OID of array's datatype (should match type of arrayBase)
* elementType OID of array's element type (fetch with transformArrayType,
* or pass InvalidOid to do it here)
* elementTypMod typmod to be applied to array elements (if storing)
* indirection Untransformed list of subscripts (must not be NIL)
* forceSlice If true, treat subscript as array slice in all cases
* assignFrom NULL for array fetch, else transformed expression for source.
*/
ArrayRef *
transformArraySubscripts(ParseState *pstate,
Node *arrayBase,
Oid arrayType,
int32 arrayTypMod,
Oid elementType,
int32 elementTypMod,
List *indirection,
bool forceSlice,
Node *assignFrom)
{
Oid elementType,
resultType;
HeapTuple type_tuple_array;
Form_pg_type type_struct_array;
bool isSlice = forceSlice;
Oid resultType;
bool isSlice = false;
List *upperIndexpr = NIL;
List *lowerIndexpr = NIL;
ListCell *idx;
ArrayRef *aref;
/* Get the type tuple for the array */
type_tuple_array = SearchSysCache(TYPEOID,
ObjectIdGetDatum(arrayType),
0, 0, 0);
if (!HeapTupleIsValid(type_tuple_array))
elog(ERROR, "cache lookup failed for type %u", arrayType);
type_struct_array = (Form_pg_type) GETSTRUCT(type_tuple_array);
elementType = type_struct_array->typelem;
if (elementType == InvalidOid)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("cannot subscript type %s because it is not an array",
format_type_be(arrayType))));
/* Caller may or may not have bothered to determine elementType */
if (!OidIsValid(elementType))
elementType = transformArrayType(arrayType);
/*
* A list containing only single subscripts refers to a single array
* element. If any of the items are double subscripts (lower:upper),
* then the subscript expression means an array slice operation. In
* this case, we supply a default lower bound of 1 for any items that
* contain only a single subscript. The forceSlice parameter forces us
* to treat the operation as a slice, even if no lower bounds are
* mentioned. Otherwise, we have to prescan the indirection list to
* see if there are any double subscripts.
* contain only a single subscript. We have to prescan the indirection
* list to see if there are any double subscripts.
*/
if (!isSlice)
foreach(idx, indirection)
{
foreach(idx, indirection)
{
A_Indices *ai = (A_Indices *) lfirst(idx);
A_Indices *ai = (A_Indices *) lfirst(idx);
if (ai->lidx != NULL)
{
isSlice = true;
break;
}
if (ai->lidx != NULL)
{
isSlice = true;
break;
}
}
@ -166,6 +180,7 @@ transformArraySubscripts(ParseState *pstate,
A_Indices *ai = (A_Indices *) lfirst(idx);
Node *subexpr;
Assert(IsA(ai, A_Indices));
if (isSlice)
{
if (ai->lidx)
@ -209,28 +224,26 @@ transformArraySubscripts(ParseState *pstate,
/*
* If doing an array store, coerce the source value to the right type.
* (This should agree with the coercion done by updateTargetListEntry.)
*/
if (assignFrom != NULL)
{
Oid typesource = exprType(assignFrom);
Oid typeneeded = isSlice ? arrayType : elementType;
if (typesource != InvalidOid)
{
assignFrom = coerce_to_target_type(pstate,
assignFrom, typesource,
typeneeded, arrayTypMod,
COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST);
if (assignFrom == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("array assignment requires type %s"
" but expression is of type %s",
format_type_be(typeneeded),
format_type_be(typesource)),
errhint("You will need to rewrite or cast the expression.")));
}
assignFrom = coerce_to_target_type(pstate,
assignFrom, typesource,
typeneeded, elementTypMod,
COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST);
if (assignFrom == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("array assignment requires type %s"
" but expression is of type %s",
format_type_be(typeneeded),
format_type_be(typesource)),
errhint("You will need to rewrite or cast the expression.")));
}
/*
@ -245,8 +258,6 @@ transformArraySubscripts(ParseState *pstate,
aref->refexpr = (Expr *) arrayBase;
aref->refassgnexpr = (Expr *) assignFrom;
ReleaseSysCache(type_tuple_array);
return aref;
}