aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2025-03-13 16:07:55 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2025-03-13 16:07:55 -0400
commit4618045bee4a6d3efcb489c319649d8dd9aaa738 (patch)
tree8c2cc3aa1987ed267e22d514e9b9fed72ef7845e
parentc7fc8808a91ed1b5810abb5f6043be7b6d58dbcf (diff)
downloadpostgresql-4618045bee4a6d3efcb489c319649d8dd9aaa738.tar.gz
postgresql-4618045bee4a6d3efcb489c319649d8dd9aaa738.zip
Fix ARRAY_SUBLINK and ARRAY[] for int2vector and oidvector input.
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
-rw-r--r--src/backend/parser/parse_expr.c14
-rw-r--r--src/backend/utils/adt/arrayfuncs.c12
-rw-r--r--src/test/regress/expected/arrays.out126
-rw-r--r--src/test/regress/sql/arrays.sql22
4 files changed, 166 insertions, 8 deletions
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index bad1df732ea..9caf1e481a2 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -2053,10 +2053,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);
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..7afd7356bbe 100644
--- a/src/test/regress/expected/arrays.out
+++ b/src/test/regress/expected/arrays.out
@@ -2457,6 +2457,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);
diff --git a/src/test/regress/sql/arrays.sql b/src/test/regress/sql/arrays.sql
index 03cc8cfcd91..399a0797f3b 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[] 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[]);