Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wfZO9-005WGe-19 for pgsql-bugs@arkaria.postgresql.org; Fri, 03 Jul 2026 08:36:45 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wfZO5-006GcE-2c for pgsql-bugs@arkaria.postgresql.org; Fri, 03 Jul 2026 08:36:41 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wfZO5-006Gc6-1p for pgsql-bugs@lists.postgresql.org; Fri, 03 Jul 2026 08:36:41 +0000 Received: from mail-wr1-f52.google.com ([209.85.221.52]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1wfZO3-00000001I7X-1dEU for pgsql-bugs@postgresql.org; Fri, 03 Jul 2026 08:36:40 +0000 Received: by mail-wr1-f52.google.com with SMTP id ffacd0b85a97d-473ba028d46so338520f8f.1 for ; Fri, 03 Jul 2026 01:36:39 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1783067798; cv=none; d=google.com; s=arc-20260327; b=QUTqjDCYTBLkPfDCJUKEYulsDsC6r6auhXf0VzByPLBnRSjpBH88+rBId5XYTDPHvT opygllwWqs2ZmIJzEV88GUB2/iGJBPgV5ujjRPVCrFJwxUzZTXHfcR49rp2nwmlzDAHJ 8WU/fTFRdofvQfOePsNlFv/MW3o2GWn8sLXsqb5YyOpk6QKOwjiD2bVnldXfrwas3RVn CkvtgP6OvAtqqS/uUevbOdON2irpopBx1rZAQ/bQBMh8gZIjZWlGXuIfu/zYalZ6N6Av kEmrDzi/RZ2c20oWF6lcbLx5DDReHzQQ25aXlmwjXQriGyRGGdN4CaHJAwrP81bwrai2 Mi7g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20260327; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version; bh=/9QfHVue/tO1xITyeUhJWNnQo+ThvI47qfkNvklnF6A=; fh=I3eq9JLue6E0avFHTsCcomGp3fA3Ma3e1aqZSlFoqdo=; b=AgynNpJRY/1nZRMHfOspqNAB1DkKzW0pXooh3M5zgYDMyd75thOodKK+jBMuRrKdV4 D6biax2ST8Y7XiMLYHlrCWBQRDRKc66qgRpv/Bw2pepGzs5RNb5yYdEQmz8/lkMYIa07 CPqJIJVBYWASdwYhZm9o+DjGMOgUl9oxF805l/O+0qxEhU7CRvurm4HfIAs3MnRjswaW 9spXCGRZ0XP1B4q7Gy0EUm85QkkoUR55pnToHF2R59gajs9rR7+sr7pnoAqv+ST0GazX 8L0BGSKCefYfY8ajtA6NWxOtRO/PltxNligGZ7WN7aj00JfomTSwH/Fc6V53u6IFVpTi NzwA==; darn=postgresql.org ARC-Authentication-Results: i=1; mx.google.com; arc=none X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1783067798; x=1783672598; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=/9QfHVue/tO1xITyeUhJWNnQo+ThvI47qfkNvklnF6A=; b=Vs9aTeBIZ2V7Yx5VB9TLNRHW2Ot12RUB5/1FOH1EKwE0Ar0nEsEpbaBXRQHabkQRW8 jVUmtboXukJNciZDxvocOKE7k7MKBnp621W6F0CeBHQYyrxpf+7BBBgIQPOyd4Q0Onhw RftZtksKYHgOYKGajmAY76+f8Dl43Z5oLRJKmKGUUa9KOSbeeF7GkUhMWZhQv+gQEsQp +YwTCFrEKhEgRI1GCSrKWnsYmtAIZfGz3z17rE6dLB3f5MsRXkpxzebWCwVbIB9jQovW yLth8crOZCl0d8pTi0SS+JwVTHkb3vU8ribVi8CbNCM45BH5iE0l6T/vRzJL4xui/Tp7 j2OQ== X-Gm-Message-State: AOJu0Yywg9L+IIrzPc7FzK51tpzi10uTdfBzYOkifETAVwyImocJe/Rm twM7jip6gH3ld3jeCCj32em9sSuIl2AHbcf7f6yCMTwSxWFMrGUEmgs6j8gYU55mtn9Gq9Upkxy v2Zj1KcMM2cXCNvPYbzVj4JfdurFIS34= X-Gm-Gg: AfdE7cnPqOqPFJOxopLcF4mpRU38TfyLXf6qdMjvdt/Ip1HzOjTyLfgsP8OHL21AjLr dzxexb9hd+t3FCpxhcfEhBFOaKksftpJm++SLwAuTwevTeB1frPjWv0AGuL1fVkNe2wvaNFIlff pbyr0f66AZgdEQcr+LMkKZgkJf5UF490/WbYdO2jygHR+c/92/cRq5YXi1E1ixJINC5eI6W3aDC 6p8WLA/DelNgenO+ib1ofsSkMSuHGsp/PxDZHxmBZuMfBHGHqDGjbzuUkB7uCPMy/ApZJyAoftW qWrWZOaX X-Received: by 2002:a05:6000:2389:b0:475:f0c2:75a9 with SMTP id ffacd0b85a97d-4775b175d66mr14828552f8f.58.1783067797500; Fri, 03 Jul 2026 01:36:37 -0700 (PDT) MIME-Version: 1.0 References: In-Reply-To: From: Thom Brown Date: Fri, 3 Jul 2026 09:36:09 +0100 X-Gm-Features: AVVi8CfuMPTB5hBEmauWJzna4mTOOwkgStxizboBtPsR9fizPmOi-LJpFp9Z1ag Message-ID: Subject: Re: EXPLAIN (VERBOSE) fails with for JSON_ARRAYAGG/JSON_OBJECTAGG + window function To: Richard Guo Cc: pgsql-bugs Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk On Fri, 3 Jul 2026 at 04:06, Richard Guo wrote: > > On Fri, Jul 3, 2026 at 7:10=E2=80=AFAM Richard Guo wrote: > > Reproduced here. get_json_agg_constructor() expects that ctor->func > > is Aggref or WindowFunc, but what it gets here is a Var. > > > > This is because the query has both window functions and grouped > > aggregates. make_window_input_target() flattens the final tlist using > > pull_var_clause, which pulls the Aggref out of its JsonConstructorExpr > > wrapper. Then fix_upper_expr() matches that inner Aggref against the > > Agg subplan's tlist and replaces it with an OUTER Var. > > Here is the patch. It's a bit annoying that the original JSON agg > syntax then appears nowhere in the EXPLAIN output. All we get is the > bare jsonb_agg_strict Aggref. > > WindowAgg > Output: g, (jsonb_agg_strict(name)), row_number() OVER w1 > Window: w1 AS (ROWS UNBOUNDED PRECEDING) > -> HashAggregate > Output: g, jsonb_agg_strict(name) > > The reason is that the JsonConstructorExpr wrapper and the Aggref it > wraps end up in different plan nodes, and neither alone suffices to > reconstruct the syntax. > > I had an attempt to reconstruct the JSON syntax for the WindowAgg node > by leveraging resolve_special_varno(), and that works. But I don't > know how to do that for the HashAggregate node, because the > JsonConstructorExpr wrapper simply doesn't exist at that plan level. > Maybe we can hack the planner to make make_window_input_target() keep > the JsonConstructorExpr together with its Aggref. But I think that is > too invasive and it changes which node evaluates the wrapper. > > So that attempt ended up with: > > WindowAgg > Output: g, JSON_ARRAYAGG(name RETURNING jsonb), row_number() OVER w1 > Window: w1 AS (ROWS UNBOUNDED PRECEDING) > -> HashAggregate > Output: g, jsonb_agg_strict(name) > > But I don't think this is good. It fails to state the fact that the > WindowAgg doesn't compute a JSON aggregate; it passes through a value > that the HashAggregate computed. So I gave up this idea. Thanks for taking a look at this. It's unfortunate that reconstructing the syntax is problematic, because in the case of the original query that tripped on this bug, I lose the following from my original query: JSON_ARRAYAGG(i RETURNING jsonb) is instead: jsonb_agg_strict(i) And the same with: JSON_ARRAYAGG(=E2=80=A6) JSON_ARRAYAGG(i RETURNING json) is instead: json_agg_strict(i) And the same with: JSON_ARRAYAGG(i RETURNING text) WITH UNIQUE KEYS is instead: json_object_agg_unique(i,i) NULL ON NULL This isn't reconstructed I guess the relevant information can be gleaned from this, but not for JSON_ARRAYAGG(i RETURNING text) because we get the same output whether we're returning text or json. Thom