]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Fix ARRAY_SUBLINK and ARRAY[] for int2vector and oidvector input.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 13 Mar 2025 20:07:55 +0000 (16:07 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 13 Mar 2025 20:07:55 +0000 (16:07 -0400)
If the given input_type yields valid results from both
get_element_type and get_array_type, initArrayResultAny believed the
former and treated the input as an array type.  However this is
inconsistent with what get_promoted_array_type does, leading to
situations where the output of an ARRAY() subquery is labeled with
the wrong type: it's labeled as oidvector[] but is really a 2-D
array of OID.  That at least results in strange output, and can
result in crashes if further processing such as unnest() is applied.
AFAIK this is only possible with the int2vector and oidvector
types, which are special-cased to be treated mostly as true arrays
even though they aren't quite.

Fix by switching the logic to match get_promoted_array_type by
testing get_array_type not get_element_type, and remove an Assert
thereby made pointless.  (We need not introduce a symmetrical
check for get_element_type in the other if-branch, because
initArrayResultArr will check it.)  This restores the behavior
that existed before bac27394a introduced initArrayResultAny:
the output really is int2vector[] or oidvector[].

Comparable confusion exists when an input of an ARRAY[] construct
is int2vector or oidvector: transformArrayExpr decides it's dealing
with a multidimensional array constructor, and we end up with
something that's a multidimensional OID array but is alleged to be
of type oidvector.  I have not found a crashing case here, but it's
easy to demonstrate totally-wrong results.  Adjust that code so
that what you get is an oidvector[] instead, for consistency with
ARRAY() subqueries.  (This change also makes these types work like
domains-over-arrays in this context, which seems correct.)

Bug: #18840
Reported-by: yang lei <ylshiyu@126.com>
Author: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/18840-fbc9505f066e50d6@postgresql.org
Backpatch-through: 13

src/backend/parser/parse_expr.c
src/backend/utils/adt/arrayfuncs.c
src/test/regress/expected/arrays.out
src/test/regress/sql/arrays.sql

index 312d2c7ebaf40a0ab4f618557440c4544112305a..2e0a5b797a10bbd5f426092be5db0ec24749c840 100644 (file)
@@ -1966,10 +1966,18 @@ transformArrayExpr(ParseState *pstate, A_ArrayExpr *a,
 
                        /*
                         * Check for sub-array expressions, if we haven't already found
-                        * one.
+                        * one.  Note we don't accept domain-over-array as a sub-array,
+                        * nor int2vector nor oidvector; those have constraints that don't
+                        * map well to being treated as a sub-array.
                         */
-                       if (!newa->multidims && type_is_array(exprType(newe)))
-                               newa->multidims = true;
+                       if (!newa->multidims)
+                       {
+                               Oid                     newetype = exprType(newe);
+
+                               if (newetype != INT2VECTOROID && newetype != OIDVECTOROID &&
+                                       type_is_array(newetype))
+                                       newa->multidims = true;
+                       }
                }
 
                newelems = lappend(newelems, newe);
index 5049fb79f68a9c0e649c8f8b382952ca541278e5..78ae2b5299cf4c89866860f15c06ab97b48c4180 100644 (file)
@@ -5603,9 +5603,14 @@ ArrayBuildStateAny *
 initArrayResultAny(Oid input_type, MemoryContext rcontext, bool subcontext)
 {
        ArrayBuildStateAny *astate;
-       Oid                     element_type = get_element_type(input_type);
 
-       if (OidIsValid(element_type))
+       /*
+        * int2vector and oidvector will satisfy both get_element_type and
+        * get_array_type.  We prefer to treat them as scalars, to be consistent
+        * with get_promoted_array_type.  Hence, check get_array_type not
+        * get_element_type.
+        */
+       if (!OidIsValid(get_array_type(input_type)))
        {
                /* Array case */
                ArrayBuildStateArr *arraystate;
@@ -5622,9 +5627,6 @@ initArrayResultAny(Oid input_type, MemoryContext rcontext, bool subcontext)
                /* Scalar case */
                ArrayBuildState *scalarstate;
 
-               /* Let's just check that we have a type that can be put into arrays */
-               Assert(OidIsValid(get_array_type(input_type)));
-
                scalarstate = initArrayResult(input_type, rcontext, subcontext);
                astate = (ArrayBuildStateAny *)
                        MemoryContextAlloc(scalarstate->mcontext,
index 666d892969c1c2edd47ea72a1999524ba406b911..281aa3769c4df6970d2846e8e53493e78333a57a 100644 (file)
@@ -2276,6 +2276,132 @@ select array(select array['Hello', i::text] from generate_series(9,11) i);
  {{Hello,9},{Hello,10},{Hello,11}}
 (1 row)
 
+-- int2vector and oidvector should be treated as scalar types for this purpose
+select pg_typeof(array(select '11 22 33'::int2vector from generate_series(1,5)));
+  pg_typeof   
+--------------
+ int2vector[]
+(1 row)
+
+select array(select '11 22 33'::int2vector from generate_series(1,5));
+                          array                           
+----------------------------------------------------------
+ {"11 22 33","11 22 33","11 22 33","11 22 33","11 22 33"}
+(1 row)
+
+select unnest(array(select '11 22 33'::int2vector from generate_series(1,5)));
+  unnest  
+----------
+ 11 22 33
+ 11 22 33
+ 11 22 33
+ 11 22 33
+ 11 22 33
+(5 rows)
+
+select pg_typeof(array(select '11 22 33'::oidvector from generate_series(1,5)));
+  pg_typeof  
+-------------
+ oidvector[]
+(1 row)
+
+select array(select '11 22 33'::oidvector from generate_series(1,5));
+                          array                           
+----------------------------------------------------------
+ {"11 22 33","11 22 33","11 22 33","11 22 33","11 22 33"}
+(1 row)
+
+select unnest(array(select '11 22 33'::oidvector from generate_series(1,5)));
+  unnest  
+----------
+ 11 22 33
+ 11 22 33
+ 11 22 33
+ 11 22 33
+ 11 22 33
+(5 rows)
+
+-- array[] should do the same
+select pg_typeof(array['11 22 33'::int2vector]);
+  pg_typeof   
+--------------
+ int2vector[]
+(1 row)
+
+select array['11 22 33'::int2vector];
+    array     
+--------------
+ {"11 22 33"}
+(1 row)
+
+select pg_typeof(unnest(array['11 22 33'::int2vector]));
+ pg_typeof  
+------------
+ int2vector
+(1 row)
+
+select unnest(array['11 22 33'::int2vector]);
+  unnest  
+----------
+ 11 22 33
+(1 row)
+
+select pg_typeof(unnest('11 22 33'::int2vector));
+ pg_typeof 
+-----------
+ smallint
+ smallint
+ smallint
+(3 rows)
+
+select unnest('11 22 33'::int2vector);
+ unnest 
+--------
+     11
+     22
+     33
+(3 rows)
+
+select pg_typeof(array['11 22 33'::oidvector]);
+  pg_typeof  
+-------------
+ oidvector[]
+(1 row)
+
+select array['11 22 33'::oidvector];
+    array     
+--------------
+ {"11 22 33"}
+(1 row)
+
+select pg_typeof(unnest(array['11 22 33'::oidvector]));
+ pg_typeof 
+-----------
+ oidvector
+(1 row)
+
+select unnest(array['11 22 33'::oidvector]);
+  unnest  
+----------
+ 11 22 33
+(1 row)
+
+select pg_typeof(unnest('11 22 33'::oidvector));
+ pg_typeof 
+-----------
+ oid
+ oid
+ oid
+(3 rows)
+
+select unnest('11 22 33'::oidvector);
+ unnest 
+--------
+     11
+     22
+     33
+(3 rows)
+
 -- Insert/update on a column that is array of composite
 create temp table t1 (f1 int8_tbl[]);
 insert into t1 (f1[5].q1) values(42);
index dea76ffed1172a919206ff0a5fb4d88047087ee3..dd15d6174efc862ba3c1215488f7791c933af75d 100644 (file)
@@ -676,6 +676,28 @@ select array_replace(array['AB',NULL,'CDE'],NULL,'12');
 select array(select array[i,i/2] from generate_series(1,5) i);
 select array(select array['Hello', i::text] from generate_series(9,11) i);
 
+-- int2vector and oidvector should be treated as scalar types for this purpose
+select pg_typeof(array(select '11 22 33'::int2vector from generate_series(1,5)));
+select array(select '11 22 33'::int2vector from generate_series(1,5));
+select unnest(array(select '11 22 33'::int2vector from generate_series(1,5)));
+select pg_typeof(array(select '11 22 33'::oidvector from generate_series(1,5)));
+select array(select '11 22 33'::oidvector from generate_series(1,5));
+select unnest(array(select '11 22 33'::oidvector from generate_series(1,5)));
+
+-- array[] should do the same
+select pg_typeof(array['11 22 33'::int2vector]);
+select array['11 22 33'::int2vector];
+select pg_typeof(unnest(array['11 22 33'::int2vector]));
+select unnest(array['11 22 33'::int2vector]);
+select pg_typeof(unnest('11 22 33'::int2vector));
+select unnest('11 22 33'::int2vector);
+select pg_typeof(array['11 22 33'::oidvector]);
+select array['11 22 33'::oidvector];
+select pg_typeof(unnest(array['11 22 33'::oidvector]));
+select unnest(array['11 22 33'::oidvector]);
+select pg_typeof(unnest('11 22 33'::oidvector));
+select unnest('11 22 33'::oidvector);
+
 -- Insert/update on a column that is array of composite
 
 create temp table t1 (f1 int8_tbl[]);