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 1vi7ap-00FZYU-2E for pgsql-bugs@arkaria.postgresql.org; Tue, 20 Jan 2026 09:00:08 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1vi7ao-00HGaD-2S for pgsql-bugs@arkaria.postgresql.org; Tue, 20 Jan 2026 09:00:07 +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 1vhuu4-00EPLQ-0b for pgsql-bugs@lists.postgresql.org; Mon, 19 Jan 2026 19:27:08 +0000 Received: from mahout.postgresql.org ([2001:4800:3e1:1::227]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vhuu1-001O5r-1c for pgsql-bugs@lists.postgresql.org; Mon, 19 Jan 2026 19:27:08 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=postgresql.org; s=20171124; h=Message-ID:Date:Reply-To:Cc:From:To:Subject: Content-Transfer-Encoding:MIME-Version:Content-Type:Sender:Content-ID: Content-Description:In-Reply-To:References; bh=76Cy4WtIZUUMT+NOoT5AkDif34TlB1w+EuauqlCP2Rg=; b=35TxQd7AvyYS8Ylo55Ejn8Uduh 2TiP8DaNQrsIwyqWL2sUqyunub8nn9LUT6+qMZuJudw5y4+WYXzLYaD2AVw7Lhphxq8cB/jI17l6Z PTQqGa+h266uMkG9Vk4nGzMknnYPqAn3+km3cTootJwFfNDszylob6Nv6FnhKwHXUlKrFNSBZc2Sl 68f++eJQwtsM1A91lde3SjQivIpEL9lSwqy2adwaeOzcBTkpOaLjPVkngNs52dzfRLvknqqpmj2yn q2kS9jC5ZDf3TyYY58k6L7lup8fGtikOIGkvFjujctFxH0MibqBEiAJVOaHSlJtZGsRya6UDGo5/o Bmi6QWeA==; Received: from wrigleys.postgresql.org ([2a02:16a8:dc51::60]) by mahout.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vhutz-003mLT-0W for pgsql-bugs@lists.postgresql.org; Mon, 19 Jan 2026 19:27:04 +0000 Received: from localhost ([127.0.0.1] helo=wrigleys.postgresql.org) by wrigleys.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1vhuty-006NPh-02 for pgsql-bugs@lists.postgresql.org; Mon, 19 Jan 2026 19:27:02 +0000 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Subject: BUG #19380: Transition table in AFTER INSERT trigger misses rows from MERGE when used with INSERT in a CTE To: pgsql-bugs@lists.postgresql.org From: PG Bug reporting form Cc: dwwoelfel@gmail.com Reply-To: dwwoelfel@gmail.com, pgsql-bugs@lists.postgresql.org Date: Mon, 19 Jan 2026 19:26:32 +0000 Message-ID: <19380-4e293be2b4007248@postgresql.org> X-Auto-Response-Suppress: All Auto-Submitted: auto-generated List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk The following bug has been logged on the website: Bug reference: 19380 Logged by: Daniel Woelfel Email address: dwwoelfel@gmail.com PostgreSQL version: 17.7 Operating system: macOS (aarch64) Description: =20 In a CTE that inserts rows with both MERGE and INSERT, the transition table will not contain the rows from the MERGE. I have included a small reproduction script, which inserts 2 rows with a merge and one row with an insert. On my machine, the trigger outputs: `Row count: 1, Rows: [{"id":3,"val":"c"}]`, but I would expect it to output: `Row count: 3, Rows: [{"id": 1, "val": "a"}, {"id": 2, "val": "b"}, {"id":3,"val":"c"}]` ``` CREATE TEMP TABLE merge_bug_test (id INT PRIMARY KEY, val TEXT); -- Create trigger functions that list the IDs they see CREATE OR REPLACE FUNCTION report_insert_rows() RETURNS TRIGGER AS $$ BEGIN RAISE WARNING '[AFTER INSERT TRIGGER] Row count: %, Rows: %', (SELECT COUNT(*) FROM newrows), (SELECT COALESCE(json_agg(row_to_json(newrows))::text, 'EMPTY') FROM newrows); RETURN NULL; END; $$ LANGUAGE plpgsql; -- Create statement-level triggers for INSERT CREATE TRIGGER insert_trigger AFTER INSERT ON merge_bug_test REFERENCING NEW TABLE AS newrows FOR EACH STATEMENT EXECUTE FUNCTION report_insert_rows(); -- MERGE inserts rows, but INSERT CTE inserts nothing WITH input_triples (id, val) AS ( VALUES (1, 'a'), (2, 'b') ), insert_cte AS ( INSERT INTO merge_bug_test (id, val) values (3, 'c') RETURNING id ), -- Insert two row with merge merge_cte AS ( MERGE INTO merge_bug_test t USING input_triples s ON t.id =3D s.id WHEN NOT MATCHED THEN INSERT (id, val) VALUES (s.id, s.val) RETURNING t.id ) -- Insert one row with a regular insert SELECT id FROM merge_cte UNION ALL SELECT id FROM insert_cte; DROP TABLE merge_bug_test; DROP FUNCTION report_insert_rows; ```