From c4d3cd3dc8514147cc8d30a648e4970a2a876ca8 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sat, 23 Nov 2013 20:04:00 -0500 Subject: [PATCH] Fix array slicing of int2vector and oidvector values. The previous coding labeled expressions such as pg_index.indkey[1:3] as being of int2vector type; which is not right because the subscript bounds of such a result don't, in general, satisfy the restrictions of int2vector. To fix, implicitly promote the result of slicing int2vector to int2[], or oidvector to oid[]. This is similar to what we've done with domains over arrays, which is a good analogy because these types are very much like restricted domains of the corresponding regular-array types. A side-effect is that we now also forbid array-element updates on such columns, eg while "update pg_index set indkey[4] = 42" would have worked before if you were superuser (and corrupted your catalogs irretrievably, no doubt) it's now disallowed. This seems like a good thing since, again, some choices of subscripting would've led to results not satisfying the restrictions of int2vector. The case of an array-slice update was rejected before, though with a different error message than you get now. We could make these cases work in future if we added a cast from int2[] to int2vector (with a cast function checking the subscript restrictions) but it seems unlikely that there's any value in that. Per report from Ronan Dunklau. Back-patch to all supported branches because of the crash risks involved. --- src/backend/parser/parse_node.c | 13 +++++++++++++ src/backend/parser/parse_target.c | 8 +++++--- src/include/catalog/pg_type.h | 2 ++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c index 6ffbd76727..e0ea43a810 100644 --- a/src/backend/parser/parse_node.c +++ b/src/backend/parser/parse_node.c @@ -226,6 +226,18 @@ transformArrayType(Oid *arrayType, int32 *arrayTypmod) */ *arrayType = getBaseTypeAndTypmod(*arrayType, arrayTypmod); + /* + * We treat int2vector and oidvector as though they were domains over + * int2[] and oid[]. This is needed because array slicing could create an + * array that doesn't satisfy the dimensionality constraints of the + * xxxvector type; so we want the result of a slice operation to be + * considered to be of the more general type. + */ + if (*arrayType == INT2VECTOROID) + *arrayType = INT2ARRAYOID; + else if (*arrayType == OIDVECTOROID) + *arrayType = OIDARRAYOID; + /* Get the type tuple for the array */ type_tuple_array = SearchSysCache1(TYPEOID, ObjectIdGetDatum(*arrayType)); if (!HeapTupleIsValid(type_tuple_array)) @@ -263,6 +275,7 @@ transformArrayType(Oid *arrayType, int32 *arrayTypmod) * For both cases, if the source array is of a domain-over-array type, * the result is of the base array type or its element type; essentially, * we must fold a domain to its base type before applying subscripting. + * (Note that int2vector and oidvector are treated as domains here.) * * pstate Parse state * arrayBase Already-transformed expression for the array as a whole diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index 9c6c202c8e..d56e00ffde 100644 --- a/src/backend/parser/parse_target.c +++ b/src/backend/parser/parse_target.c @@ -839,18 +839,20 @@ transformAssignmentSubscripts(ParseState *pstate, /* If target was a domain over array, need to coerce up to the domain */ if (arrayType != targetTypeId) { + Oid resulttype = exprType(result); + result = coerce_to_target_type(pstate, - result, exprType(result), + result, resulttype, targetTypeId, targetTypMod, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST, -1); - /* probably shouldn't fail, but check */ + /* can fail if we had int2vector/oidvector, but not for true domains */ if (result == NULL) ereport(ERROR, (errcode(ERRCODE_CANNOT_COERCE), errmsg("cannot cast type %s to %s", - format_type_be(exprType(result)), + format_type_be(resulttype), format_type_be(targetTypeId)), parser_errposition(pstate, location))); } diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h index e3822faf66..442d09e417 100644 --- a/src/include/catalog/pg_type.h +++ b/src/include/catalog/pg_type.h @@ -447,6 +447,7 @@ DATA(insert OID = 1001 ( _bytea PGNSP PGUID -1 f b A f t \054 0 17 0 array_in DATA(insert OID = 1002 ( _char PGNSP PGUID -1 f b A f t \054 0 18 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ )); DATA(insert OID = 1003 ( _name PGNSP PGUID -1 f b A f t \054 0 19 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ )); DATA(insert OID = 1005 ( _int2 PGNSP PGUID -1 f b A f t \054 0 21 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ )); +#define INT2ARRAYOID 1005 DATA(insert OID = 1006 ( _int2vector PGNSP PGUID -1 f b A f t \054 0 22 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ )); DATA(insert OID = 1007 ( _int4 PGNSP PGUID -1 f b A f t \054 0 23 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ )); #define INT4ARRAYOID 1007 @@ -454,6 +455,7 @@ DATA(insert OID = 1008 ( _regproc PGNSP PGUID -1 f b A f t \054 0 24 0 array_i DATA(insert OID = 1009 ( _text PGNSP PGUID -1 f b A f t \054 0 25 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 100 _null_ _null_ _null_ )); #define TEXTARRAYOID 1009 DATA(insert OID = 1028 ( _oid PGNSP PGUID -1 f b A f t \054 0 26 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ )); +#define OIDARRAYOID 1028 DATA(insert OID = 1010 ( _tid PGNSP PGUID -1 f b A f t \054 0 27 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ )); DATA(insert OID = 1011 ( _xid PGNSP PGUID -1 f b A f t \054 0 28 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ )); DATA(insert OID = 1012 ( _cid PGNSP PGUID -1 f b A f t \054 0 29 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ )); -- 2.40.0