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.94.2) (envelope-from ) id 1tw9FI-00BBKB-LK for pgsql-general@arkaria.postgresql.org; Sun, 23 Mar 2025 00:31:20 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1tw9FG-005WiD-DJ for pgsql-general@arkaria.postgresql.org; Sun, 23 Mar 2025 00:31:18 +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.94.2) (envelope-from ) id 1tw9FG-005WeG-26 for pgsql-general@lists.postgresql.org; Sun, 23 Mar 2025 00:31:18 +0000 Received: from smtp91.iad3a.emailsrvr.com ([173.203.187.91]) by magus.postgresql.org with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1tw9FD-000aX0-2D for pgsql-general@postgresql.org; Sun, 23 Mar 2025 00:31:17 +0000 X-Auth-ID: xof@thebuild.com Received: by smtp12.relay.iad3a.emailsrvr.com (Authenticated sender: xof-AT-thebuild.com) with ESMTPSA id 1949D25EA3; Sat, 22 Mar 2025 20:31:13 -0400 (EDT) Content-Type: text/plain; charset=us-ascii Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3776.700.51.11.1\)) Subject: Re: Nested Stored Procedures - ERROR: invalid transaction termination 2D000 From: Christophe Pettus In-Reply-To: Date: Sat, 22 Mar 2025 22:18:07 +0000 Cc: Tom Lane , "pgsql-general@postgresql.org" Content-Transfer-Encoding: quoted-printable Message-Id: References: <12B83964-7B3B-4345-9952-F8FE61727CB5@thebuild.com> <1830668.1742655550@sss.pgh.pa.us> To: Kevin Stephenson X-Mailer: Apple Mail (2.3776.700.51.11.1) X-Classification-ID: 10053e3e-e84f-4498-9d2d-39ab832b746f-1-1 List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk > On Mar 22, 2025, at 21:37, Kevin Stephenson = wrote: >=20 > Christophe and Tom, thank you for your responses, but I'm still a bit = confused. In my original email, the Test 2 case is allowing a ROLLBACK = in the EXCEPTION clause without throwing an error. Is it a NOP ROLLBACK = being applied to an aborted subTX, a real full ROLLBACK, or something = else? Please advise. That's an interesting question. It appears to be a no-op, although a = quick scan of the code doesn't reveal why. Here's an illustrative test = case: xof=3D# CREATE OR REPLACE PROCEDURE outer() AS $$ BEGIN INSERT INTO t VALUES(3); BEGIN CALL inner(); PERFORM 1/0; EXCEPTION WHEN OTHERS THEN RAISE NOTICE 'in outer exception handler'; END; END; $$ language plpgsql; CREATE PROCEDURE xof=3D# create or replace procedure inner() as $$ BEGIN BEGIN INSERT INTO t VALUES(1); PERFORM 1/0; EXCEPTION WHEN OTHERS THEN ROLLBACK; =20 INSERT INTO t VALUES(2); END; END; =20 $$ language plpgsql; CREATE PROCEDURE xof=3D# call outer(); NOTICE: in outer exception handler CALL xof=3D# table t; i =20 --- 3 (1 row) xof=3D# truncate t; TRUNCATE TABLE xof=3D# call inner(); CALL xof=3D# table t; i =20 --- 2 (1 row) It clearly doesn't roll back the outer transaction. The savepoint that = BEGIN ... EXCEPTION creates is released upon entry into the EXCEPTION = block, so there's no savepoint in that context to roll back to. Pragmatically, the answer is: don't put top-level transaction control = statements in procedures where they might be invoked within an EXCEPTION = block, either directly or indirectly.=