Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Fix array slicing of int2vector and oidvector values.
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 24 Nov 2013 01:04:06 +0000 (20:04 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 24 Nov 2013 01:04:06 +0000 (20:04 -0500)
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
src/backend/parser/parse_target.c
src/include/catalog/pg_type.h

index 7b5c040cb4010ce3d25f0e51936ed2f112629902..b552ddfda96dd6932be2e8705b74f1040550bfe1 100644 (file)
@@ -225,6 +225,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))
@@ -262,6 +274,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
index e818b0046ff4d1f15283cd553d921b18bd4b4ae0..98c2819369234cee23263d3a3f2b1b8244da5770 100644 (file)
@@ -817,18 +817,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)));
    }
index d72ca2342fabb33239ceed03cb85ecaeacd0fe7c..93b335189a3af0ad9800d115302f6f9af67bdc2f 100644 (file)
@@ -436,6 +436,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 - - - i x f 0 -1 0 0 _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 - - - i x f 0 -1 0 0 _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 - - - i x f 0 -1 0 0 _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 - - - i x f 0 -1 0 0 _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 - - - i x f 0 -1 0 0 _null_ _null_ ));
 #define INT4ARRAYOID       1007
@@ -443,6 +444,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 - - - i x f 0 -1 0 100 _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 - - - i x f 0 -1 0 0 _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 - - - i x f 0 -1 0 0 _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 - - - i x f 0 -1 0 0 _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 - - - i x f 0 -1 0 0 _null_ _null_ ));