From 33c9e4ea3aa8fca50a45ea075fd35af85c9b4e77 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Wed, 12 Mar 2025 18:04:11 -0400
Subject: [PATCH v1 1/2] Fix initArrayResultAny for int2vector and oidvector.

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.  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.

There is an equivalent problem with ARRAY[] constructs, but at
least for those I've failed to demonstrate a crash.  So it might
be better not to back-patch a change for those.  This patch just
adds some test cases to document that issue.

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/utils/adt/arrayfuncs.c   |  12 ++-
 src/test/regress/expected/arrays.out | 134 +++++++++++++++++++++++++++
 src/test/regress/sql/arrays.sql      |  22 +++++
 3 files changed, 163 insertions(+), 5 deletions(-)

diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c
index d777f38ed99..c8f53c6fbe7 100644
--- a/src/backend/utils/adt/arrayfuncs.c
+++ b/src/backend/utils/adt/arrayfuncs.c
@@ -5782,9 +5782,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;
@@ -5801,9 +5806,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,
diff --git a/src/test/regress/expected/arrays.out b/src/test/regress/expected/arrays.out
index 0b61fb5bb78..5b8889cd013 100644
--- a/src/test/regress/expected/arrays.out
+++ b/src/test/regress/expected/arrays.out
@@ -2457,6 +2457,140 @@ 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[] really ought to do the same, but historically hasn't
+select pg_typeof(array['11 22 33'::int2vector]);
+ pg_typeof  
+------------
+ int2vector
+(1 row)
+
+select array['11 22 33'::int2vector];
+ array 
+-------
+ 1
+(1 row)
+
+select pg_typeof(unnest(array['11 22 33'::int2vector]));
+ pg_typeof 
+-----------
+ smallint
+ smallint
+ smallint
+(3 rows)
+
+select unnest(array['11 22 33'::int2vector]);
+ unnest 
+--------
+     11
+     22
+     33
+(3 rows)
+
+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 
+-------
+ 1
+(1 row)
+
+select pg_typeof(unnest(array['11 22 33'::oidvector]));
+ pg_typeof 
+-----------
+ oid
+ oid
+ oid
+(3 rows)
+
+select unnest(array['11 22 33'::oidvector]);
+ unnest 
+--------
+     11
+     22
+     33
+(3 rows)
+
+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);
diff --git a/src/test/regress/sql/arrays.sql b/src/test/regress/sql/arrays.sql
index 03cc8cfcd91..41a360dc18f 100644
--- a/src/test/regress/sql/arrays.sql
+++ b/src/test/regress/sql/arrays.sql
@@ -713,6 +713,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[] really ought to do the same, but historically hasn't
+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[]);
-- 
2.43.5

