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 1wYoM0-000WaY-0a for pgsql-bugs@arkaria.postgresql.org; Sun, 14 Jun 2026 17:10: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 1wYoLz-008ffr-0H for pgsql-bugs@arkaria.postgresql.org; Sun, 14 Jun 2026 17:10: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 1wYnLh-008cW1-1p for pgsql-bugs@lists.postgresql.org; Sun, 14 Jun 2026 16:06:13 +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.98.2) (envelope-from ) id 1wYnLc-00000000Nal-04XL for pgsql-bugs@lists.postgresql.org; Sun, 14 Jun 2026 16:06:13 +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=Rt/XfnSZRRhqAFhxwlIjqfvn7aCKx0+V/KLGm+mJL8U=; b=QlGcdE4v4E+4Ha40NOpUOtb8fe 3YsERzLyiwVZJ17yoc3f6d1rom7CkpCk7cWTHk3UkrVMA80Zz1zR3AnhEsXZMlpX180aPugdOgdge rF3447VgCJCW5LKs63OFAyFg/zXbADvMp4HqeEXLopdlAscLKrSqHXNcVCGYP4D9HkC7FtGJR7brp ACjGl66Ktv6bRYZ2sFrcppMqTGX93Nu0JnA6d3qLZWHWJFzj28BHrgsrMgaL/S8rK50TZ42gWFKAR e3ZlMZXSayYcsfp6+35yTrAApvbijQSw+IbtpEO0hm+cgRuCGuUBt6JYCXN9t8nkeCPmEUK3oB3hN r82rgcfw==; 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 1wYnLY-0015Rr-0k for pgsql-bugs@lists.postgresql.org; Sun, 14 Jun 2026 16:06:06 +0000 Received: from localhost ([127.0.0.1] helo=wrigleys.postgresql.org) by wrigleys.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wYnLW-0027cU-30 for pgsql-bugs@lists.postgresql.org; Sun, 14 Jun 2026 16:06:03 +0000 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Subject: BUG #19520: PANIC when concurrently manipulating stored procedures with pg_stat_statements and track_functions = To: pgsql-bugs@lists.postgresql.org From: PG Bug reporting form Cc: zlh21343@163.com Reply-To: zlh21343@163.com, pgsql-bugs@lists.postgresql.org Date: Sun, 14 Jun 2026 16:05:27 +0000 Message-ID: <19520-73873648d44793cf@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: 19520 Logged by: zhanglihui Email address: zlh21343@163.com PostgreSQL version: 19beta1 Operating system: Ubuntu 25.04 Description: =20 =3D=3D=3D Configuration =3D=3D=3D Enabled extensions: pg_stat_statements postgresql.conf: shared_preload_libraries =3D 'pg_stat_statements' track_functions =3D 'all' =3D=3D=3D Problem Description =3D=3D=3D PostgreSQL server throws PANIC under high concurrent create, CALL and DROP of stored procedures. This issue **only reproduces when pg_stat_statements is enabled and track_functions =3D all**. It cannot be triggered if pg_stat_statements is disabled or track_functions is set to none/pl. =3D=3D=3D Run Steps =3D=3D=3D javac -cp postgresql-42.7.5.jar -d out src/ConcurrentSqlTest.java src/ProcCrashReprodure.java # Terminal 1 =E2=80=94 Mixed DDL/DML load test (40 threads, 10000 iteration= s each) java -cp out:postgresql-42.7.5.jar ConcurrentSqlTest # Terminal 2 =E2=80=94 Pure CALL load test (20 threads, infinite loop) java -cp out:postgresql-42.7.5.jar ProcCrashReprodure # Note: If no PANIC log or core dump is generated after the execution of Terminal 1, please re-run the command repeatedly until the issue occurs. PANIC log=EF=BC=9A postgresql-2026-06-14_235441.log:2026-06-14 23:54:41.949 CST [691761] PANIC: XX000: cannot abort transaction 4166281, it was already committed postgresql-2026-06-14_235931.log:2026-06-14 23:59:31.556 CST [696980] PANIC: XX000: cannot abort transaction 4641943, it was already committed (gdb) bt #0 __pthread_kill_implementation (threadid=3D, signo=3D6, no_tid=3D0) at ./nptl/pthread_kill.c:44 #1 __pthread_kill_internal (threadid=3D, signo=3D6) at ./nptl/pthread_kill.c:89 #2 __GI___pthread_kill (threadid=3D, signo=3Dsigno@entry=3D= 6) at ./nptl/pthread_kill.c:100 #3 0x000073e62ec4579e in __GI_raise (sig=3Dsig@entry=3D6) at ../sysdeps/posix/raise.c:26 #4 0x000073e62ec288cd in __GI_abort () at ./stdlib/abort.c:73 #5 0x000056aeb574138c in errfinish (filename=3D0x56aeb57ff545 "xact.c", lineno=3D1835, funcname=3D0x56aeb5800d00 <__func__.26> "RecordTransactionAb= ort") at elog.c:621 #6 0x000056aeb4faae67 in RecordTransactionAbort (isSubXact=3Dfalse) at xact.c:1835 #7 0x000056aeb4fac19f in AbortTransaction () at xact.c:2982 #8 0x000056aeb4facc22 in AbortCurrentTransactionInternal () at xact.c:3553 #9 0x000056aeb4facb93 in AbortCurrentTransaction () at xact.c:3507 #10 0x000056aeb5525552 in PostgresMain (dbname=3D0x56aedecf30d0 "postgres", username=3D0x56aedecf30b0 "zlh_user") at postgres.c:4539 #11 0x000056aeb551b59c in BackendMain (startup_data=3D0x7fffb9501000, startup_data_len=3D24) at backend_startup.c:124 #12 0x000056aeb5405686 in postmaster_child_launch (child_type=3DB_BACKEND, child_slot=3D24, startup_data=3D0x7fffb9501000, startup_data_len=3D24, client_sock=3D0x7fffb9501060) at launch_backend.c:268 #13 0x000056aeb540c11b in BackendStartup (client_sock=3D0x7fffb9501060) at postmaster.c:3627 #14 0x000056aeb540969f in ServerLoop () at postmaster.c:1728 #15 0x000056aeb5408f7c in PostmasterMain (argc=3D1, argv=3D0x56aedeca1430) = at postmaster.c:1415 #16 0x000056aeb528ce51 in main (argc=3D1, argv=3D0x56aedeca1430) at main.c:= 231 ---- File 1: ConcurrentSqlTest.java (Mixed DDL/DML test, 40 threads =C3=97 = 10000 iterations) ---- import java.sql.*; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; /** * PostgreSQL concurrent DDL/DML stress test =E2=80=94 reproduces backend c= rash * (signal 5 / SIGTRAP) when DROP/CREATE PROCEDURE and CALL PROCEDURE * execute concurrently at high concurrency. * * Compile: javac -cp postgresql-42.7.5.jar ConcurrentSqlTest.java * Run: java -cp .:postgresql-42.7.5.jar ConcurrentSqlTest * * Optional env vars: PG_HOST, PG_PORT, PG_DATABASE, PG_USER, PG_PASSWORD */ public final class ConcurrentSqlTest { // =E2=94=80=E2=94=80 connection defaults =E2=94=80=E2=94=80 private static final String HOST =3D envOr("PG_HOST", "192.168.239.128"); private static final String PORT =3D envOr("PG_PORT", "5432"); private static final String DATABASE =3D envOr("PG_DATABASE", "postgres= "); private static final String USER =3D envOr("PG_USER", "zlh_user= "); private static final String PASSWORD =3D envOr("PG_PASSWORD", "Gauss@123"); private static final String JDBC_URL =3D "jdbc:postgresql://" + HOST + ":" + PORT + "/" + DATABASE; // =E2=94=80=E2=94=80 test parameters =E2=94=80=E2=94=80 private static final int THREADS =3D 40; private static final int ITERATIONS =3D 10_000; // =E2=94=80=E2=94=80 SQL batches =E2=94=80=E2=94=80 private static final String[] SQL =3D { "DROP PROCEDURE IF EXISTS proc_test", "CREATE OR REPLACE PROCEDURE proc_test()\n" + "LANGUAGE plpgsql\n" + "AS $$\n" + "BEGIN\n" + "END;\n" + "$$", "CALL proc_test()", }; // =E2=94=80=E2=94=80 counters =E2=94=80=E2=94=80 private static final AtomicInteger totalOk =3D new AtomicInteger(0); private static final AtomicInteger totalFail =3D new AtomicInteger(0); static { try { Class.forName("org.postgresql.Driver"); } catch (ClassNotFoundException e) { System.err.println("PostgreSQL JDBC driver not found on classpath"); System.exit(1); } } public static void main(String[] args) throws InterruptedException { System.out.println("=3D=3D=3D PostgreSQL concurrent DROP/CREATE/CALL PROCEDURE =3D=3D=3D"); System.out.println("URL: " + JDBC_URL); System.out.println("Threads: " + THREADS + " | Iterations/thread: " + ITERATIONS); System.out.println("Watch for: backend terminated by signal 5 (SIGTRAP)"); System.out.println("=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D"); long t0 =3D System.currentTimeMillis(); ExecutorService pool =3D Executors.newFixedThreadPool(THREADS); List> futures =3D new ArrayList<>(); for (int i =3D 0; i < THREADS; i++) { final int tid =3D i; futures.add(pool.submit(() -> runWorker(tid))); } Runtime.getRuntime().addShutdownHook(new Thread(() -> { System.out.println("\nShutting down..."); pool.shutdownNow(); })); // drain for (Future f : futures) { try { f.get(); } catch (ExecutionException e) { System.err.println("Thread crashed: " + e.getCause().getMessage()); } catch (CancellationException ignored) { } } pool.shutdown(); long elapsed =3D System.currentTimeMillis() - t0; System.out.println("=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D"); System.out.printf("Done. OK: %d FAIL: %d Time: %.1fs%n", totalOk.get(), totalFail.get(), elapsed / 1000.0); System.exit(totalFail.get() > 0 ? 1 : 0); } // =E2=94=80=E2=94=80 single worker (reuses one connection) =E2=94=80= =E2=94=80 private static void runWorker(int tid) { int ok =3D 0, fail =3D 0; Connection c =3D openConnection(); for (int i =3D 0; i < ITERATIONS; i++) { if (Thread.currentThread().isInterrupted()) break; try { for (String sql : SQL) { try (Statement s =3D c.createStatement()) { s.execute(sql); } } ok++; } catch (SQLException e) { fail++; if (totalFail.incrementAndGet() <=3D 10) { System.err.printf("Thread %d loop %d: [%s] %s%n", tid, i, e.getSQLState(), e.getMessage().replace('\n', ' ')); } // reconnect if server closed the connection (e.g. after crash) try { if (c.isClosed()) c =3D openConnection(); } catch (SQLException ignored) { } } } totalOk.addAndGet(ok); close(c); System.out.printf("Thread %2d: %d ok / %d fail%n", tid, ok, fail); } private static Connection openConnection() { try { Connection c =3D DriverManager.getConnection(JDBC_URL, USER, PASSWORD); c.setAutoCommit(true); return c; } catch (SQLException e) { throw new RuntimeException("Failed to connect: " + e.getMessage(), e); } } private static void close(Connection c) { try { if (c !=3D null) c.close(); } catch (SQLException ignored) { } } private static String envOr(String key, String def) { String v =3D System.getenv(key); return (v !=3D null && !v.trim().isEmpty()) ? v : def; } } ---- File 2: ProcCrashReprodure.java (Pure CALL test, 20 threads, infinite loop) ---- import java.sql.*; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicBoolean; /** * PostgreSQL concurrent CALL stress test =E2=80=94 run this together with * ConcurrentSqlTest to reproduce backend crash (signal 5 / SIGTRAP). * * This program does ONLY repeated CALL proc_test() across 20 threads * (infinite loop). ConcurrentSqlTest does DROP =E2=86=92 CREATE =E2=86=92= CALL in * a loop. Run both simultaneously. * * Compile: javac -cp postgresql-42.7.5.jar ProcCrashReprodure.java * Run: java -cp .:postgresql-42.7.5.jar ProcCrashReprodure * * Optional env vars: PG_HOST, PG_PORT, PG_DATABASE, PG_USER, PG_PASSWORD */ public final class ProcCrashReprodure { private static final String HOST =3D envOr("PG_HOST", "192.168.239.128"); private static final String PORT =3D envOr("PG_PORT", "5432"); private static final String DATABASE =3D envOr("PG_DATABASE", "postgres= "); private static final String USER =3D envOr("PG_USER", "zlh_user= "); private static final String PASSWORD =3D envOr("PG_PASSWORD", "Gauss@123"); private static final String JDBC_URL =3D "jdbc:postgresql://" + HOST + ":" + PORT + "/" + DATABASE; private static final int THREADS =3D 20; private static final AtomicBoolean stop =3D new AtomicBoolean(false); static { try { Class.forName("org.postgresql.Driver"); } catch (ClassNotFoundException e) { System.err.println("PostgreSQL JDBC driver not found on classpath"); System.exit(1); } } public static void main(String[] args) { System.out.println("=3D=3D=3D PostgreSQL CALL stress test (run ConcurrentSqlTest too) =3D=3D=3D"); System.out.println("URL: " + JDBC_URL); System.out.println("Threads: " + THREADS + " | Loop: infinite (Ctrl+C to stop)"); System.out.println("Watch for: backend terminated by signal 5 (SIGTRAP)"); System.out.println("=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D"); ExecutorService pool =3D Executors.newFixedThreadPool(THREADS); CountDownLatch latch =3D new CountDownLatch(THREADS); for (int i =3D 0; i < THREADS; i++) { final int tid =3D i; pool.submit(() -> { try { runWorker(tid); } finally { latch.countDown(); } }); } Runtime.getRuntime().addShutdownHook(new Thread(() -> { System.out.println("\nShutting down..."); stop.set(true); pool.shutdownNow(); })); try { latch.await(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } pool.shutdownNow(); System.out.println("Done."); } private static void runWorker(int tid) { while (!stop.get()) { try (Connection c =3D DriverManager.getConnection(JDBC_URL, USE= R, PASSWORD)) { c.setAutoCommit(true); while (!stop.get()) { try (CallableStatement cs =3D c.prepareCall("{ CALL proc_test() }")) { cs.execute(); } catch (SQLException e) { // expected when proc is being dropped/recreated if (c.isClosed()) break; // reconnect } } } catch (SQLException e) { // connection failure =E2=80=94 pause then reconnect try { Thread.sleep(100); } catch (InterruptedException ie) { break; } } } } private static String envOr(String key, String def) { String v =3D System.getenv(key); return (v !=3D null && !v.trim().isEmpty()) ? v : def; } }