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]

Reply via email to