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 1w0X96-001zJf-0e for pgsql-hackers@arkaria.postgresql.org; Thu, 12 Mar 2026 03:55:36 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1w0X94-00DCUt-21 for pgsql-hackers@arkaria.postgresql.org; Thu, 12 Mar 2026 03:55:35 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1w0X94-00DCUl-16 for pgsql-hackers@lists.postgresql.org; Thu, 12 Mar 2026 03:55:34 +0000 Received: from mail-pj1-x1033.google.com ([2607:f8b0:4864:20::1033]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1w0X92-00000002F5O-1Th6 for pgsql-hackers@lists.postgresql.org; Thu, 12 Mar 2026 03:55:34 +0000 Received: by mail-pj1-x1033.google.com with SMTP id 98e67ed59e1d1-35a08ce49dcso490276a91.2 for ; Wed, 11 Mar 2026 20:55:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773287729; x=1773892529; darn=lists.postgresql.org; h=to:references:message-id:content-transfer-encoding:cc:date :in-reply-to:from:subject:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=7ArvCYaTZdgw+WKUufofGjsO3VuRC6WtOD+mYZ/t0fw=; b=X0QTJITimeC5Izr/p3tadAKCW2Jfes2rWaOTewDWo2rAIWwnCW5UH9xTgkYwugpfLm 4gn2rS3JlsBanbsXxglOKO0qY3Wk+p1h51SZZhfP5eQ2mY9pxz1PfNzzwZDSDAN9gHGO qmy/zRqs7jSv2dHuHeaasQyZBtkw+CjMQzqo1EtMP3Oob2rpC2X/pX22Y974zCbUbx0c +x1f9i82VTsVMxpfJuNx8KBcIVJ/uqTtwXVJjRtAkdJcxro0DjYJ9/KhTouETvUPlnSG 6XDuQcHIsgIJFnBhXgWDDTl6UXijdyHWeQxGYTqTSwf+mpHUUbw6HKQ7hzZ9bkQieIwo C2mg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1773287729; x=1773892529; h=to:references:message-id:content-transfer-encoding:cc:date :in-reply-to:from:subject:mime-version:x-gm-gg:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=7ArvCYaTZdgw+WKUufofGjsO3VuRC6WtOD+mYZ/t0fw=; b=ZujHoOQ0Ll/gsZFvbxrKNf9ITz+8Mvyh+NJYWEHXEIalQiFg7VmYVSpzDifskOfyyn Y5SSjMIy0OnbYaxPU7eYyjk3rZ73oR0QCWxDuAcKZkyOGXEpBAJOtq2kGiY8dJGviNWE Z6wYnJilZDiZg7Ug75O95eXuD0O2EMkoR61TkRhGUoIRssK+lS/p9Jp6bXnezkUKhjw3 SyBIMA1w1NWlhcwbV9+4lrox2EPVrwtGLt7vXhNnAD/mrhr73o3TTEvPzXZJEyB6pxeI IjlUysvOYyNEccVbHE3GWsA8JauJUESaZWOK4lBR62elp0w+MYuw8BhPzpfiHCPy4/4L 1ZyQ== X-Forwarded-Encrypted: i=1; AJvYcCVCoiku1yvMtev3HRuWiSaNKgcfaK5fQCjjP8I2vNwBNF8jAGuIYagsuAufwn+yOb5FTD2FfbuntdRybsvU@lists.postgresql.org X-Gm-Message-State: AOJu0YyW/6JXmewVUDmbkgDzUuMKoDP+Lf85QltPUTprfLqXp2m80nl/ xA5htA70qDnh2a9lOyroD9Ql6Tjt12Vn5kvJzkFbAMC4Hnh3O63IsEiI X-Gm-Gg: ATEYQzwu7tAV1ARTW1G8pcx7Vs9Oin3qU4F3fsijcKAc14XRypSmuQk1vQxdH1yOU8K U60kBnwYYvYjJWh+z/mzNc6YkbgpJ5ctzzAritkb23XHuyzVjqVuxYYLrgnPPX5e/yWEu73oIj9 OjfHiVKf0DmsyPLUMl0le1OikwNf1aiTHDLx5B5U1uTQJhF5w5pEVFOk+KcJqrXpjnpTDaR3bL5 kp8fD5fS5mJo1/qmXEpP2BdB7+DS/30KzAk7i1++C/n+27HuEYT5wAzwhJPSpRevg3tBHoreaQf ZxUaYmXJAeMK1iAFNEgeOLtbeYh92ry5uDa3sVhO7+b9LLhh/8VXdfoEBMNcHwQaDd1tF4YRSsm 8KM6ejS7zdrrbp8i5JAAQJh/LseLCt21rrxFa/ltQhq9Qij6QO3nSzwCoj59eLb/10WkjtzLdQw Zxo829ywFElHClXuVx3TBzwOJkiQIBjsY= X-Received: by 2002:a17:90b:5284:b0:359:8ed3:8a65 with SMTP id 98e67ed59e1d1-35a013200f3mr4041496a91.34.1773287728897; Wed, 11 Mar 2026 20:55:28 -0700 (PDT) Received: from smtpclient.apple ([45.32.121.103]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-35a0f6d190csm1739521a91.14.2026.03.11.20.55.26 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Wed, 11 Mar 2026 20:55:28 -0700 (PDT) Content-Type: text/plain; charset=utf-8 Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3864.400.21\)) Subject: Re: POC: PLpgSQL FOREACH IN JSON ARRAY From: Chao Li In-Reply-To: Date: Thu, 12 Mar 2026 11:54:52 +0800 Cc: Jim Jones , PostgreSQL Hackers Content-Transfer-Encoding: quoted-printable Message-Id: References: To: Pavel Stehule X-Mailer: Apple Mail (2.3864.400.21) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk > On Mar 5, 2026, at 02:50, Pavel Stehule = wrote: >=20 > Hi >=20 > st 4. 3. 2026 v 12:35 odes=C3=ADlatel Jim Jones = napsal: > I reviewed the code I have nothing to add at this point. LGTM! >=20 > The tests touch a lot of different scenarios, but for the sake of > completeness I'd like to suggest adding these three cases: >=20 > -- EXIT and CONTINUE can be triggered by LOOP_RC_PROCESSING > DO $$ > DECLARE x int; > BEGIN > FOREACH x IN JSON ARRAY '[1,2,3,4,5]' > LOOP > EXIT WHEN x =3D 3; > RAISE NOTICE '%', x; > END LOOP; > END; > $$; >=20 > DO $$ > DECLARE x int; > BEGIN > FOREACH x IN JSON ARRAY '[1,2,3,4,5]' > LOOP > CONTINUE WHEN x % 2 =3D 0; > RAISE NOTICE '%', x; > END LOOP; > END; > $$; >=20 >=20 > -- Variable instead of string > DO $$ > DECLARE x int; arr jsonb; > BEGIN > SELECT jsonb_agg(i) INTO arr > FROM generate_series(1,3) i; >=20 > FOREACH x IN JSON ARRAY arr > LOOP > RAISE NOTICE '%', x; > END LOOP; > END; > $$; >=20 >=20 > I merged these examples to tests >=20 > Thank you for review >=20 > Regards >=20 > Pavel > =20 > Thanks! >=20 > Best, Jim > I just reviewed and tested the patch. Here comes my comments: 1 - pl_gram.y ``` + = ereport(ERROR, + = (errcode(ERRCODE_SYNTAX_ERROR), + = errmsg("not zero slice is allowed only for arrays"), + = parser_errposition(@4))); ``` * () around errcode and errmsg are no longer needed. This comment is = general, and I saw other ereport() also use () in this patch. * parser_errposition should have the same indention as errmsg. 2 - pl_exec.c ``` + errdetail("Cannot iterate over a object = value."))); ``` Typo: a -> an 3 - pl_exec.c ``` + tmp_cxt =3D AllocSetContextCreate(CurrentMemoryContext, + = "FOREACH IN JSON ARRAY temporary cxt", + = ALLOCSET_DEFAULT_SIZES); ``` Do we need to destroy tmp_cxt after the loop? 4 Looks like record type of loop var is not supported: ``` evantest=3D# do $$ declare r record; begin foreach r in json array '[{"x":1,"y":"hi"},{"x":2,"y":"hello"}]=E2=80=99= loop raise notice 'x: %, y: %', r.x, r.y;=20 end loop; end; $$; ERROR: record type has not been registered CONTEXT: PL/pgSQL function inline_code_block line 5 at FOREACH over = json array ``` So, I want to check if you intentionally don=E2=80=99t want to support = that or just missed that? If it=E2=80=99s not supported, then maybe = document that. 5 I tried that composite type of loop var is supported, maybe add a test = case for that. What I tested: ``` create type t_foreach_json_row as ( x int, y text, z numeric ); do $$ declare r t_foreach_json_row; begin foreach r in json array '[{"x":1,"y":"one","z":1.5}, {"x":2,"y":"two"}, {"y":"three","z":3.14}, {}]' loop raise notice 'x=3D%, y=3D%, z=3D%', r.x, r.y, r.z; end loop; end; $$; drop type t_foreach_json_row; ``` Best regards, -- Chao Li (Evan) HighGo Software Co., Ltd. https://www.highgo.com/