This is an automated email from the ASF dual-hosted git repository.
reshke pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudberry.git
The following commit(s) were added to refs/heads/main by this push:
new f35b3326d1f Backport: Compute aggregate argument types correctly in
transformAggregateCall(). (#1500)
f35b3326d1f is described below
commit f35b3326d1ff453e152a65aa5813107c448b3113
Author: reshke <[email protected]>
AuthorDate: Mon Dec 22 23:05:24 2025 +0500
Backport: Compute aggregate argument types correctly in
transformAggregateCall(). (#1500)
This pr fixes https://www.postgresql.org/support/security/CVE-2023-5868 in
cloudberry
https://git.postgresql.org/cgit/postgresql.git/commit/?id=3b0776fde56763c549df35ce9750f3399bc710b2
===
transformAggregateCall() captures the datatypes of the aggregate's
arguments immediately to construct the Aggref.aggargtypes list. This seems
reasonable because the arguments have already been transformed --- but there is
an edge case where they haven't been. Specifically, if we have an unknown-type
literal in an ANY argument position, nothing will have been done with it
earlier. But if we also have DISTINCT, then addTargetToGroupList() converts
the literal to "text" type, resulting [...]
To fix, move the collection of the aggargtypes list to the end of
transformAggregateCall(), after DISTINCT has been handled. This requires
slightly more code, but not a great deal.
Our thanks to Jingzhou Fu for reporting this problem.
Security: CVE-2023-5868
---
src/backend/parser/parse_agg.c | 35 ++++++++++++++++++---------
src/test/regress/expected/jsonb.out | 7 ++++++
src/test/regress/expected/jsonb_optimizer.out | 7 ++++++
src/test/regress/sql/jsonb.sql | 3 +++
4 files changed, 40 insertions(+), 12 deletions(-)
diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c
index 21709b72ba3..58a4bd68a91 100644
--- a/src/backend/parser/parse_agg.c
+++ b/src/backend/parser/parse_agg.c
@@ -115,18 +115,6 @@ transformAggregateCall(ParseState *pstate, Aggref *agg,
int save_next_resno;
ListCell *lc;
- /*
- * Before separating the args into direct and aggregated args, make a
list
- * of their data type OIDs for use later.
- */
- foreach(lc, args)
- {
- Expr *arg = (Expr *) lfirst(lc);
-
- argtypes = lappend_oid(argtypes, exprType((Node *) arg));
- }
- agg->aggargtypes = argtypes;
-
if (AGGKIND_IS_ORDERED_SET(agg->aggkind))
{
/*
@@ -238,6 +226,29 @@ transformAggregateCall(ParseState *pstate, Aggref *agg,
agg->aggorder = torder;
agg->aggdistinct = tdistinct;
+ /*
+ * Now build the aggargtypes list with the type OIDs of the direct and
+ * aggregated args, ignoring any resjunk entries that might have been
+ * added by ORDER BY/DISTINCT processing. We can't do this earlier
+ * because said processing can modify some args' data types, in
particular
+ * by resolving previously-unresolved "unknown" literals.
+ */
+ foreach(lc, agg->aggdirectargs)
+ {
+ Expr *arg = (Expr *) lfirst(lc);
+
+ argtypes = lappend_oid(argtypes, exprType((Node *) arg));
+ }
+ foreach(lc, tlist)
+ {
+ TargetEntry *tle = (TargetEntry *) lfirst(lc);
+
+ if (tle->resjunk)
+ continue; /* ignore junk */
+ argtypes = lappend_oid(argtypes, exprType((Node *) tle->expr));
+ }
+ agg->aggargtypes = argtypes;
+
check_agglevels_and_constraints(pstate, (Node *) agg);
}
diff --git a/src/test/regress/expected/jsonb.out
b/src/test/regress/expected/jsonb.out
index ebb973cb151..635016d4aad 100644
--- a/src/test/regress/expected/jsonb.out
+++ b/src/test/regress/expected/jsonb.out
@@ -1558,6 +1558,13 @@ SELECT jsonb_object_agg(name, type) FROM foo;
INSERT INTO foo VALUES (999999, NULL, 'bar');
SELECT jsonb_object_agg(name, type) FROM foo;
ERROR: field name must not be null
+-- edge case for parser
+SELECT jsonb_object_agg(DISTINCT 'a', 'abc');
+ jsonb_object_agg
+------------------
+ {"a": "abc"}
+(1 row)
+
-- jsonb_object
-- empty object, one dimension
SELECT jsonb_object('{}');
diff --git a/src/test/regress/expected/jsonb_optimizer.out
b/src/test/regress/expected/jsonb_optimizer.out
index 6250207107a..1f5510c9982 100644
--- a/src/test/regress/expected/jsonb_optimizer.out
+++ b/src/test/regress/expected/jsonb_optimizer.out
@@ -1560,6 +1560,13 @@ SELECT jsonb_object_agg(name, type) FROM foo;
INSERT INTO foo VALUES (999999, NULL, 'bar');
SELECT jsonb_object_agg(name, type) FROM foo;
ERROR: field name must not be null
+-- edge case for parser
+SELECT jsonb_object_agg(DISTINCT 'a', 'abc');
+ jsonb_object_agg
+------------------
+ {"a": "abc"}
+(1 row)
+
-- jsonb_object
-- empty object, one dimension
SELECT jsonb_object('{}');
diff --git a/src/test/regress/sql/jsonb.sql b/src/test/regress/sql/jsonb.sql
index 40cb055c11e..b1ce452a822 100644
--- a/src/test/regress/sql/jsonb.sql
+++ b/src/test/regress/sql/jsonb.sql
@@ -397,6 +397,9 @@ SELECT jsonb_object_agg(name, type) FROM foo;
INSERT INTO foo VALUES (999999, NULL, 'bar');
SELECT jsonb_object_agg(name, type) FROM foo;
+-- edge case for parser
+SELECT jsonb_object_agg(DISTINCT 'a', 'abc');
+
-- jsonb_object
-- empty object, one dimension
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]