public inbox for [email protected]  
help / color / mirror / Atom feed
Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL
23+ messages / 8 participants
[nested] [flat]

* Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL
@ 2026-01-19 12:08 Shruthi Gowda <[email protected]>
  2026-03-24 02:34 ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Mahendra Singh Thalor <[email protected]>
  0 siblings, 1 reply; 23+ messages in thread

From: Shruthi Gowda @ 2026-01-19 12:08 UTC (permalink / raw)
  To: Fujii Masao <[email protected]>; +Cc: Tom Lane <[email protected]>; pgsql-hackers

On Thu, Jan 8, 2026 at 9:32 PM Fujii Masao <[email protected]> wrote:

> On Thu, Jan 8, 2026 at 3:00 AM Shruthi Gowda <[email protected]> wrote:
> >
> >
> > On Mon, Dec 8, 2025 at 9:39 PM Tom Lane <[email protected]> wrote:
> >>
> >> Shruthi Gowda <[email protected]> writes:
> >> > The ECPG application crashes with a segmentation fault when calling
> >> > specific deallocation or prepared statement functions without an
> >> > established database connection. This is caused by a missing NULL
> check on
> >> > the connection handle before attempting to access it.
> >>
> >> Hmm ... poking around, I see several other places that aren't checking
> >> the result of ecpg_get_connection.  Shouldn't we tighten them all?
> >>
> >>                         regards, tom lane
> >
> >
> > I agree. I’ve reviewed all occurrences of ecpg_get_connection() and
> noted that, in most instances, it is followed by ecpg_init(), which
> validates the connection and returns immediately if the connection is NULL.
>
> Why did you add this check instead of calling ecpg_init()?
> Wouldn't it be better and sufficient to use ecpg_init() to validate
> the connection?
>
> + con = ecpg_get_connection(connection_name);
> + if (!con)
> + {
> + ecpg_raise(lineno, ECPG_NO_CONN, ECPG_SQLSTATE_CONNECTION_DOES_NOT_EXIST,
> +    connection_name ? connection_name : ecpg_gettext("NULL"));
>
>
 Thanks for the feedback, Fujii. I agree—using ecpg_init() is a more
consistent approach and aligns with how this is handled in other parts of
the code.
I have updated the patch to use ecpg_init() for validation. Please find the
revised version attached.
The patch works for MASTER and all the back branches.

Thanks & Regards,

Shruthi K C

EnterpriseDB: http://www.enterprisedb.com


Attachments:

  [application/octet-stream] v3-0001-Add-missing-connection-validation-in-ECPG.patch (2.8K, 3-v3-0001-Add-missing-connection-validation-in-ECPG.patch)
  download | inline diff:
From 3267a4da8d41761a6ddb1880e57dbfb109a3eeb3 Mon Sep 17 00:00:00 2001
From: shruthi gowda <[email protected]>
Date: Mon, 19 Jan 2026 10:32:23 +0000
Subject: [PATCH v3] Add missing connection validation in ECPG

Ensure that ECPG connections are validated before use to prevent
application crashes. This allows the system to handle disconnected
states gracefully by throwing a proper error instead of
segfaulting.
---
 src/interfaces/ecpg/ecpglib/descriptor.c |  9 +++++++--
 src/interfaces/ecpg/ecpglib/prepare.c    | 17 +++++++++++++----
 2 files changed, 20 insertions(+), 6 deletions(-)

diff --git a/src/interfaces/ecpg/ecpglib/descriptor.c b/src/interfaces/ecpg/ecpglib/descriptor.c
index 39cd5130ec9..128fddd167c 100644
--- a/src/interfaces/ecpg/ecpglib/descriptor.c
+++ b/src/interfaces/ecpg/ecpglib/descriptor.c
@@ -235,6 +235,7 @@ ECPGget_desc(int lineno, const char *desc_name, int index,...)
 {
 	va_list		args;
 	PGresult   *ECPGresult;
+	struct connection *con;
 	enum ECPGdtype type;
 	int			ntuples,
 				act_tuple;
@@ -249,8 +250,12 @@ ECPGget_desc(int lineno, const char *desc_name, int index,...)
 		return false;
 	}
 
+	con = ecpg_get_connection(NULL);
+	if (!ecpg_init(con, NULL, lineno))
+		return false;
+
 	va_start(args, index);
-	ecpg_init_sqlca(sqlca);
+
 	ECPGresult = ecpg_result_by_descriptor(lineno, desc_name);
 	if (!ECPGresult)
 	{
@@ -506,7 +511,7 @@ ECPGget_desc(int lineno, const char *desc_name, int index,...)
 #endif
 
 		/* desperate try to guess something sensible */
-		stmt.connection = ecpg_get_connection(NULL);
+		stmt.connection = con;
 		ecpg_store_result(ECPGresult, index, &stmt, &data_var);
 
 #ifdef HAVE_USELOCALE
diff --git a/src/interfaces/ecpg/ecpglib/prepare.c b/src/interfaces/ecpg/ecpglib/prepare.c
index 5c7c5397535..6bcd34cdf81 100644
--- a/src/interfaces/ecpg/ecpglib/prepare.c
+++ b/src/interfaces/ecpg/ecpglib/prepare.c
@@ -381,8 +381,13 @@ ecpg_deallocate_all_conn(int lineno, enum COMPAT_MODE c, struct connection *con)
 bool
 ECPGdeallocate_all(int lineno, int compat, const char *connection_name)
 {
-	return ecpg_deallocate_all_conn(lineno, compat,
-									ecpg_get_connection(connection_name));
+	struct connection *con;
+
+	con = ecpg_get_connection(connection_name);
+	if (!ecpg_init(con, connection_name, lineno))
+		return false;
+
+	return ecpg_deallocate_all_conn(lineno, compat, con);
 }
 
 char *
@@ -399,9 +404,13 @@ ecpg_prepared(const char *name, struct connection *con)
 char *
 ECPGprepared_statement(const char *connection_name, const char *name, int lineno)
 {
-	(void) lineno;				/* keep the compiler quiet */
+	struct connection *con;
+
+	con = ecpg_get_connection(connection_name);
+	if (!ecpg_init(con, connection_name, lineno))
+		return false;
 
-	return ecpg_prepared(name, ecpg_get_connection(connection_name));
+	return ecpg_prepared(name, con);
 }
 
 /*
-- 
2.43.0



^ permalink  raw  reply  [nested|flat] 23+ messages in thread

* Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL
  2026-01-19 12:08 Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
@ 2026-03-24 02:34 ` Mahendra Singh Thalor <[email protected]>
  2026-03-24 05:59   ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  0 siblings, 1 reply; 23+ messages in thread

From: Mahendra Singh Thalor @ 2026-03-24 02:34 UTC (permalink / raw)
  To: Shruthi Gowda <[email protected]>; +Cc: Fujii Masao <[email protected]>; Tom Lane <[email protected]>; pgsql-hackers

On Mon, 19 Jan 2026 at 17:38, Shruthi Gowda <[email protected]> wrote:
>
>
>
> On Thu, Jan 8, 2026 at 9:32 PM Fujii Masao <[email protected]> wrote:
>>
>> On Thu, Jan 8, 2026 at 3:00 AM Shruthi Gowda <[email protected]> wrote:
>> >
>> >
>> > On Mon, Dec 8, 2025 at 9:39 PM Tom Lane <[email protected]> wrote:
>> >>
>> >> Shruthi Gowda <[email protected]> writes:
>> >> > The ECPG application crashes with a segmentation fault when calling
>> >> > specific deallocation or prepared statement functions without an
>> >> > established database connection. This is caused by a missing NULL check on
>> >> > the connection handle before attempting to access it.
>> >>
>> >> Hmm ... poking around, I see several other places that aren't checking
>> >> the result of ecpg_get_connection.  Shouldn't we tighten them all?
>> >>
>> >>                         regards, tom lane
>> >
>> >
>> > I agree. I’ve reviewed all occurrences of ecpg_get_connection() and noted that, in most instances, it is followed by ecpg_init(), which validates the connection and returns immediately if the connection is NULL.
>>
>> Why did you add this check instead of calling ecpg_init()?
>> Wouldn't it be better and sufficient to use ecpg_init() to validate
>> the connection?
>>
>> + con = ecpg_get_connection(connection_name);
>> + if (!con)
>> + {
>> + ecpg_raise(lineno, ECPG_NO_CONN, ECPG_SQLSTATE_CONNECTION_DOES_NOT_EXIST,
>> +    connection_name ? connection_name : ecpg_gettext("NULL"));
>>
>
>  Thanks for the feedback, Fujii. I agree—using ecpg_init() is a more consistent approach and aligns with how this is handled in other parts of the code.
> I have updated the patch to use ecpg_init() for validation. Please find the revised version attached.
> The patch works for MASTER and all the back branches.
>
> Thanks & Regards,
>
> Shruthi K C
>
> EnterpriseDB: http://www.enterprisedb.com

Thanks Shruthi for the updated patch.

Please add a crash test case in your patch. If possible, please add a
test for connection=NULL for ECPGdeallocate_all,
ECPGprepared_statement and ECPGget_desc.

-- 
Thanks and Regards
Mahendra Singh Thalor
EnterpriseDB: http://www.enterprisedb.com





^ permalink  raw  reply  [nested|flat] 23+ messages in thread

* Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL
  2026-01-19 12:08 Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-03-24 02:34 ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Mahendra Singh Thalor <[email protected]>
@ 2026-03-24 05:59   ` Nishant Sharma <[email protected]>
  2026-04-09 10:44     ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  0 siblings, 1 reply; 23+ messages in thread

From: Nishant Sharma @ 2026-03-24 05:59 UTC (permalink / raw)
  To: Mahendra Singh Thalor <[email protected]>; +Cc: Shruthi Gowda <[email protected]>; Fujii Masao <[email protected]>; Tom Lane <[email protected]>; pgsql-hackers

Here are some review comments on v3 patch:-

   1.

   Change in descriptor.c file - In my opinion, we can use `if(conn)` with
   ecpg_raise, like other occurrence of ecpg_get_connection() call check in
   this file, and not using ecpg_init(). Three reasons: a) Consistency in
   checking conn after ecpg_get_connection() call in this file with if check.
   b) We don't need to remove 'ecpg_init_sqlca(sqlca);' line due to call to
   ecpg_init(). c) #2 comment below.
   2.

   If you agree with #1, then I see many other reasons for which
   ECPGget_desc() returns and we can avoid ecpg_get_connection() call at top
   of that function for those reasons and keep the check at the required
   location only instead of moving at top of the function.
   3.

   I see there is one more location of ecpg_get_connection() call where
   there is no check of NULL conn. In function ecpg_freeStmtCacheEntry() of
   file prepare.c? I understand it's not required for a call in
   ecpg_auto_prepare(), as the caller already validated that connection
   string. But I think, conn in ecpg_freeStmtCacheEntry() is different from
   the one that was validated.
   4.

   +1 to Mahindra, new test cases specific to the crash required for this
   change?



Regards,
Nishant Sharma,
EDB, Pune.
https://www.enterprisedb.com/


^ permalink  raw  reply  [nested|flat] 23+ messages in thread

* Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL
  2026-01-19 12:08 Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-03-24 02:34 ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Mahendra Singh Thalor <[email protected]>
  2026-03-24 05:59   ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
@ 2026-04-09 10:44     ` Shruthi Gowda <[email protected]>
  2026-04-13 10:30       ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  0 siblings, 1 reply; 23+ messages in thread

From: Shruthi Gowda @ 2026-04-09 10:44 UTC (permalink / raw)
  To: Nishant Sharma <[email protected]>; +Cc: Mahendra Singh Thalor <[email protected]>; Fujii Masao <[email protected]>; Tom Lane <[email protected]>; pgsql-hackers

On Tue, Mar 24, 2026 at 11:29 AM Nishant Sharma <
[email protected]> wrote:

> Here are some review comments on v3 patch:-
>
>    1.
>
>    Change in descriptor.c file - In my opinion, we can use `if(conn)`
>    with ecpg_raise, like other occurrence of ecpg_get_connection() call check
>    in this file, and not using ecpg_init(). Three reasons: a) Consistency in
>    checking conn after ecpg_get_connection() call in this file with if check.
>    b) We don't need to remove 'ecpg_init_sqlca(sqlca);' line due to call to
>    ecpg_init(). c) #2 comment below.
>    2.
>
>    If you agree with #1, then I see many other reasons for which
>    ECPGget_desc() returns and we can avoid ecpg_get_connection() call at top
>    of that function for those reasons and keep the check at the required
>    location only instead of moving at top of the function.
>    3.
>
>    I see there is one more location of ecpg_get_connection() call where
>    there is no check of NULL conn. In function ecpg_freeStmtCacheEntry() of
>    file prepare.c? I understand it's not required for a call in
>    ecpg_auto_prepare(), as the caller already validated that connection
>    string. But I think, conn in ecpg_freeStmtCacheEntry() is different from
>    the one that was validated.
>    4.
>
>    +1 to Mahindra, new test cases specific to the crash required for this
>    change?
>
>
>
> Regards,
> Nishant Sharma,
> EDB, Pune.
> https://www.enterprisedb.com/
>

Thanks, Nishant, for the review. I agree with points 1 and 2 and have
revised the patch accordingly. Regarding point 3, you are correct; the conn
in ecpg_freeStmtCacheEntry() differs from the one validated in the caller.
I have now added the necessary validation in the latest version.

I have also included a test case patch covering all execution paths except
for the ecpg_freeStmtCacheEntry() flow. I was unable to trigger that
specific flow, and it appears none of the existing test cases cover that
line either.

Thanks & Regards,

Shruthi K C

EnterpriseDB: http://www.enterprisedb.com


Attachments:

  [application/octet-stream] v4-0001-Add-missing-connection-validation-in-ECPG.patch (3.1K, 3-v4-0001-Add-missing-connection-validation-in-ECPG.patch)
  download | inline diff:
From 75ee6b6cb5f86139deb7b0f3caa8ab5f69455bca Mon Sep 17 00:00:00 2001
From: shruthi gowda <[email protected]>
Date: Wed, 8 Apr 2026 11:32:16 +0000
Subject: [PATCH v4] Add missing connection validation in ECPG

ECPGdeallocate_all(), ECPGprepared_statement(), ECPGget_desc(), and
ecpg_freeStmtCacheEntry() could crash or misbehave when operating on
NULL or invalid connections. Add proper connection validation to
prevent dereferencing NULL pointers.
---
 src/interfaces/ecpg/ecpglib/descriptor.c |  8 ++++++++
 src/interfaces/ecpg/ecpglib/prepare.c    | 25 ++++++++++++++++--------
 2 files changed, 25 insertions(+), 8 deletions(-)

diff --git a/src/interfaces/ecpg/ecpglib/descriptor.c b/src/interfaces/ecpg/ecpglib/descriptor.c
index 39cd5130ec9..88f1e9858b0 100644
--- a/src/interfaces/ecpg/ecpglib/descriptor.c
+++ b/src/interfaces/ecpg/ecpglib/descriptor.c
@@ -507,6 +507,14 @@ ECPGget_desc(int lineno, const char *desc_name, int index,...)
 
 		/* desperate try to guess something sensible */
 		stmt.connection = ecpg_get_connection(NULL);
+		if (stmt.connection == NULL)
+		{
+			ecpg_raise(lineno, ECPG_NO_CONN, ECPG_SQLSTATE_CONNECTION_DOES_NOT_EXIST,
+					   ecpg_gettext("NULL"));
+			va_end(args);
+			return false;
+		}
+
 		ecpg_store_result(ECPGresult, index, &stmt, &data_var);
 
 #ifdef HAVE_USELOCALE
diff --git a/src/interfaces/ecpg/ecpglib/prepare.c b/src/interfaces/ecpg/ecpglib/prepare.c
index 5c7c5397535..f9489044724 100644
--- a/src/interfaces/ecpg/ecpglib/prepare.c
+++ b/src/interfaces/ecpg/ecpglib/prepare.c
@@ -381,8 +381,12 @@ ecpg_deallocate_all_conn(int lineno, enum COMPAT_MODE c, struct connection *con)
 bool
 ECPGdeallocate_all(int lineno, int compat, const char *connection_name)
 {
-	return ecpg_deallocate_all_conn(lineno, compat,
-									ecpg_get_connection(connection_name));
+	struct connection *con = ecpg_get_connection(connection_name);
+
+	if (!ecpg_init(con, connection_name, lineno))
+		return false;
+
+	return ecpg_deallocate_all_conn(lineno, compat, con);
 }
 
 char *
@@ -395,13 +399,15 @@ ecpg_prepared(const char *name, struct connection *con)
 }
 
 /* return the prepared statement */
-/* lineno is not used here, but kept in to not break API */
 char *
 ECPGprepared_statement(const char *connection_name, const char *name, int lineno)
 {
-	(void) lineno;				/* keep the compiler quiet */
+	struct connection *con = ecpg_get_connection(connection_name);
+
+	if (!ecpg_init(con, connection_name, lineno))
+		return NULL;
 
-	return ecpg_prepared(name, ecpg_get_connection(connection_name));
+	return ecpg_prepared(name, con);
 }
 
 /*
@@ -499,9 +505,12 @@ ecpg_freeStmtCacheEntry(int lineno, int compat,
 	con = ecpg_get_connection(entry->connection);
 
 	/* free the 'prepared_statement' list entry */
-	this = ecpg_find_prepared_statement(entry->stmtID, con, &prev);
-	if (this && !deallocate_one(lineno, compat, con, prev, this))
-		return -1;
+	if (con)
+	{
+		this = ecpg_find_prepared_statement(entry->stmtID, con, &prev);
+		if (this && !deallocate_one(lineno, compat, con, prev, this))
+			return -1;
+	}
 
 	entry->stmtID[0] = '\0';
 
-- 
2.43.0



  [application/octet-stream] v1_test-0001-Tests-for-NULL-connection-validation.patch (13.0K, 4-v1_test-0001-Tests-for-NULL-connection-validation.patch)
  download | inline diff:
From 20d35849e84233c28858271655b91e09edd66863 Mon Sep 17 00:00:00 2001
From: shruthi gowda <[email protected]>
Date: Thu, 9 Apr 2026 08:37:36 +0000
Subject: [PATCH v1_test] Tests for NULL connection validation

---
 src/interfaces/ecpg/test/connect/Makefile     |   3 +-
 src/interfaces/ecpg/test/connect/meson.build  |   1 +
 .../ecpg/test/connect/test_null_connection.c  | 150 ++++++++++++++++++
 .../test/connect/test_null_connection.pgc     |  69 ++++++++
 src/interfaces/ecpg/test/ecpg_schedule        |   1 +
 .../connect-test_null_connection.stderr       |  50 ++++++
 .../connect-test_null_connection.stdout       |   8 +
 7 files changed, 281 insertions(+), 1 deletion(-)
 create mode 100644 src/interfaces/ecpg/test/connect/test_null_connection.c
 create mode 100644 src/interfaces/ecpg/test/connect/test_null_connection.pgc
 create mode 100644 src/interfaces/ecpg/test/expected/connect-test_null_connection.stderr
 create mode 100644 src/interfaces/ecpg/test/expected/connect-test_null_connection.stdout

diff --git a/src/interfaces/ecpg/test/connect/Makefile b/src/interfaces/ecpg/test/connect/Makefile
index 2602d5d286f..02151733c4c 100644
--- a/src/interfaces/ecpg/test/connect/Makefile
+++ b/src/interfaces/ecpg/test/connect/Makefile
@@ -7,6 +7,7 @@ TESTS = test1 test1.c \
         test2 test2.c \
         test3 test3.c \
         test4 test4.c \
-        test5 test5.c
+        test5 test5.c \
+        test_null_connection test_null_connection.c
 
 all: $(TESTS)
diff --git a/src/interfaces/ecpg/test/connect/meson.build b/src/interfaces/ecpg/test/connect/meson.build
index 591e04bc422..1147b4e8f51 100644
--- a/src/interfaces/ecpg/test/connect/meson.build
+++ b/src/interfaces/ecpg/test/connect/meson.build
@@ -6,6 +6,7 @@ pgc_files = [
   'test3',
   'test4',
   'test5',
+  'test_null_connection',
 ]
 
 foreach pgc_file : pgc_files
diff --git a/src/interfaces/ecpg/test/connect/test_null_connection.c b/src/interfaces/ecpg/test/connect/test_null_connection.c
new file mode 100644
index 00000000000..ef0af1fe157
--- /dev/null
+++ b/src/interfaces/ecpg/test/connect/test_null_connection.c
@@ -0,0 +1,150 @@
+/* Processed by ecpg (regression mode) */
+/* These include files are added by the preprocessor */
+#include <ecpglib.h>
+#include <ecpgerrno.h>
+#include <sqlca.h>
+/* End of automatic include section */
+#define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y))
+
+#line 1 "test_null_connection.pgc"
+/*
+ * This test verifies that ecpg functions properly handle NULL connections
+ * (i.e., when a connection name doesn't exist or has been disconnected).
+ * Before the fix, these operations would cause a segmentation fault.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+
+#line 1 "./../regression.h"
+
+
+
+
+
+
+#line 11 "test_null_connection.pgc"
+
+
+int
+main(void)
+{
+/* exec sql begin declare section */
+
+
+
+
+
+
+#line 17 "test_null_connection.pgc"
+ char * query = "SELECT 1" ;
+
+#line 18 "test_null_connection.pgc"
+ int val1output = 2 ;
+
+#line 19 "test_null_connection.pgc"
+ int val1 = 1 ;
+
+#line 20 "test_null_connection.pgc"
+ char val2 [ 5 ] = "data1" ;
+
+#line 21 "test_null_connection.pgc"
+ char * stmt1 = "SELECT * from test1 where a = $1 and b = $2" ;
+/* exec sql end declare section */
+#line 22 "test_null_connection.pgc"
+
+
+	ECPGdebug(1, stderr);
+
+	/* Connect to the database */
+	{ ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , "myconn", 0); }
+#line 27 "test_null_connection.pgc"
+
+
+	/* Test 1: Try to get descriptor on a disconnected connection */
+	printf("Test 1: Try to get descriptor on a disconnected connection \n");
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table test1 ( a int , b text )", ECPGt_EOIT, ECPGt_EORT);}
+#line 31 "test_null_connection.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into test1 ( a , b ) values ( 1 , 'data1' )", ECPGt_EOIT, ECPGt_EORT);}
+#line 32 "test_null_connection.pgc"
+
+
+	ECPGallocate_desc(__LINE__, "indesc");
+#line 34 "test_null_connection.pgc"
+
+	ECPGallocate_desc(__LINE__, "outdesc");
+#line 35 "test_null_connection.pgc"
+
+
+	{ ECPGprepare(__LINE__, NULL, 0, "foo2", stmt1);}
+#line 37 "test_null_connection.pgc"
+
+
+	{ ECPGset_desc(__LINE__, "indesc", 1,ECPGd_data,
+	ECPGt_int,&(val1),(long)1,(long)1,sizeof(int), ECPGd_EODT);
+}
+#line 39 "test_null_connection.pgc"
+
+	{ ECPGset_desc(__LINE__, "indesc", 2,ECPGd_data,
+	ECPGt_char,(val2),(long)5,(long)1,(5)*sizeof(char), ECPGd_EODT);
+}
+#line 40 "test_null_connection.pgc"
+
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_execute, "foo2",
+	ECPGt_descriptor, "indesc", 1L, 1L, 1L, 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, 
+	ECPGt_descriptor, "outdesc", 1L, 1L, 1L, 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
+#line 42 "test_null_connection.pgc"
+
+
+	{ ECPGdisconnect(__LINE__, "CURRENT");}
+#line 44 "test_null_connection.pgc"
+
+	{ ECPGget_desc(__LINE__, "outdesc", 1,ECPGd_data,
+	ECPGt_int,&(val1output),(long)1,(long)1,sizeof(int), ECPGd_EODT);
+}
+#line 45 "test_null_connection.pgc"
+
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	/* Test 2: Try to deallocate all on a non-existent connection */
+	printf("Test 2: deallocate all with non-existent connection\n");
+	{ ECPGdeallocate_all(__LINE__, 0, "nonexistent");}
+#line 50 "test_null_connection.pgc"
+
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	/* Test 3: deallocate on disconnected connection */
+	printf("Test 3: deallocate all on disconnected connection\n");
+	{ ECPGdeallocate_all(__LINE__, 0, NULL);}
+#line 55 "test_null_connection.pgc"
+
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	/* Test 4: Use prepared statement from non-existent connection */
+	printf("Test 4: Use prepared statement from non-existent connection\n");
+  	{ ECPGprepare(__LINE__, "nonexistent", 0, "stmt1", "SELECT 1");}
+#line 60 "test_null_connection.pgc"
+
+  	/* declare cur1 cursor for $1 */
+#line 61 "test_null_connection.pgc"
+
+ 	{ ECPGdo(__LINE__, 0, 1, "nonexistent", 0, ECPGst_normal, "declare cur1 cursor for $1", 
+	ECPGt_char_variable,(ECPGprepared_statement("nonexistent", "stmt1", __LINE__)),(long)1,(long)1,(1)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);}
+#line 62 "test_null_connection.pgc"
+
+
+	printf("All tests completed !\n");
+
+	{ ECPGdisconnect(__LINE__, "CURRENT");}
+#line 66 "test_null_connection.pgc"
+
+
+	return 0;
+}
diff --git a/src/interfaces/ecpg/test/connect/test_null_connection.pgc b/src/interfaces/ecpg/test/connect/test_null_connection.pgc
new file mode 100644
index 00000000000..886e4eab218
--- /dev/null
+++ b/src/interfaces/ecpg/test/connect/test_null_connection.pgc
@@ -0,0 +1,69 @@
+/*
+ * This test verifies that ecpg functions properly handle NULL connections
+ * (i.e., when a connection name doesn't exist or has been disconnected).
+ * Before the fix, these operations would cause a segmentation fault.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+exec sql include ../regression;
+
+int
+main(void)
+{
+exec sql begin declare section;
+	char *query = "SELECT 1";
+	int val1output = 2;
+	int val1 = 1;
+	char val2[5] = "data1";
+	char *stmt1 = "SELECT * from test1 where a = $1 and b = $2";
+exec sql end declare section;
+
+	ECPGdebug(1, stderr);
+
+	/* Connect to the database */
+	exec sql connect to REGRESSDB1 as myconn;
+
+	/* Test 1: Try to get descriptor on a disconnected connection */
+	printf("Test 1: Try to get descriptor on a disconnected connection \n");
+	exec sql create table test1 (a int, b text);
+	exec sql insert into test1 (a,b) values (1, 'data1');
+
+	exec sql allocate descriptor indesc;
+	exec sql allocate descriptor outdesc;
+
+	exec sql prepare foo2 from :stmt1;
+
+	exec sql set descriptor indesc value 1 DATA = :val1;
+	exec sql set descriptor indesc value 2 DATA = :val2;
+
+	exec sql execute foo2 using sql descriptor indesc into sql descriptor outdesc;
+
+	exec sql disconnect;
+	exec sql get descriptor outdesc value 1 :val1output = DATA;
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	/* Test 2: Try to deallocate all on a non-existent connection */
+	printf("Test 2: deallocate all with non-existent connection\n");
+	exec sql at nonexistent deallocate all;
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	/* Test 3: deallocate on disconnected connection */
+	printf("Test 3: deallocate all on disconnected connection\n");
+	exec sql deallocate all;
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	/* Test 4: Use prepared statement from non-existent connection */
+	printf("Test 4: Use prepared statement from non-existent connection\n");
+  	exec sql at nonexistent prepare stmt1 FROM "SELECT 1";
+  	exec sql at nonexistent declare cur1 cursor for stmt1;
+ 	exec sql at nonexistent open cur1;
+
+	printf("All tests completed !\n");
+
+	exec sql disconnect;
+
+	return 0;
+}
diff --git a/src/interfaces/ecpg/test/ecpg_schedule b/src/interfaces/ecpg/test/ecpg_schedule
index b75e16fde1e..a798f2497ab 100644
--- a/src/interfaces/ecpg/test/ecpg_schedule
+++ b/src/interfaces/ecpg/test/ecpg_schedule
@@ -13,6 +13,7 @@ test: connect/test2
 test: connect/test3
 test: connect/test4
 test: connect/test5
+test: connect/test_null_connection
 test: pgtypeslib/dt_test
 test: pgtypeslib/dt_test2
 test: pgtypeslib/num_test
diff --git a/src/interfaces/ecpg/test/expected/connect-test_null_connection.stderr b/src/interfaces/ecpg/test/expected/connect-test_null_connection.stderr
new file mode 100644
index 00000000000..f4bc2a07924
--- /dev/null
+++ b/src/interfaces/ecpg/test/expected/connect-test_null_connection.stderr
@@ -0,0 +1,50 @@
+[NO_PID]: ECPGdebug: set to 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ECPGconnect: opening database ecpg1_regression on <DEFAULT> port <DEFAULT>  
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 31: query: create table test1 ( a int , b text ); with 0 parameter(s) on connection myconn
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 31: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 31: OK: CREATE TABLE
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 32: query: insert into test1 ( a , b ) values ( 1 , 'data1' ); with 0 parameter(s) on connection myconn
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 32: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 32: OK: INSERT 0 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: prepare_common on line 37: name foo2; query: "SELECT * from test1 where a = $1 and b = $2"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 42: query: SELECT * from test1 where a = $1 and b = $2; with 2 parameter(s) on connection myconn
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 42: using PQexecPrepared for "SELECT * from test1 where a = $1 and b = $2"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_free_params on line 42: parameter 1 = 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_free_params on line 42: parameter 2 = data1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 42: correctly got 1 tuples with 2 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 42: putting result (1 tuples) into descriptor outdesc
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: deallocate_one on line 0: name foo2
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_finish: connection myconn closed
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ECPGget_desc: reading items for tuple 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: raising sqlcode -220 on line 45: connection "NULL" does not exist on line 45
+[NO_PID]: sqlca: code: -220, state: 08003
+[NO_PID]: raising sqlcode -220 on line 50: connection "nonexistent" does not exist on line 50
+[NO_PID]: sqlca: code: -220, state: 08003
+[NO_PID]: raising sqlcode -220 on line 55: connection "NULL" does not exist on line 55
+[NO_PID]: sqlca: code: -220, state: 08003
+[NO_PID]: raising sqlcode -220 on line 60: connection "nonexistent" does not exist on line 60
+[NO_PID]: sqlca: code: -220, state: 08003
+[NO_PID]: raising sqlcode -220 on line 63: connection "nonexistent" does not exist on line 63
+[NO_PID]: sqlca: code: -220, state: 08003
+[NO_PID]: raising sqlcode -220 on line 62: connection "nonexistent" does not exist on line 62
+[NO_PID]: sqlca: code: -220, state: 08003
+[NO_PID]: raising sqlcode -220 on line 66: connection "CURRENT" does not exist on line 66
+[NO_PID]: sqlca: code: -220, state: 08003
diff --git a/src/interfaces/ecpg/test/expected/connect-test_null_connection.stdout b/src/interfaces/ecpg/test/expected/connect-test_null_connection.stdout
new file mode 100644
index 00000000000..a845c736a0a
--- /dev/null
+++ b/src/interfaces/ecpg/test/expected/connect-test_null_connection.stdout
@@ -0,0 +1,8 @@
+Test 1: Try to get descriptor on a disconnected connection 
+sqlca.sqlcode = -220
+Test 2: deallocate all with non-existent connection
+sqlca.sqlcode = -220
+Test 3: deallocate all on disconnected connection
+sqlca.sqlcode = -220
+Test 4: Use prepared statement from non-existent connection
+All tests completed !
-- 
2.43.0



^ permalink  raw  reply  [nested|flat] 23+ messages in thread

* Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL
  2026-01-19 12:08 Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-03-24 02:34 ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Mahendra Singh Thalor <[email protected]>
  2026-03-24 05:59   ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-09 10:44     ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
@ 2026-04-13 10:30       ` Nishant Sharma <[email protected]>
  2026-04-13 10:32         ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-15 09:56         ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  0 siblings, 2 replies; 23+ messages in thread

From: Nishant Sharma @ 2026-04-13 10:30 UTC (permalink / raw)
  To: Shruthi Gowda <[email protected]>; +Cc: Mahendra Singh Thalor <[email protected]>; Fujii Masao <[email protected]>; Tom Lane <[email protected]>; pgsql-hackers

Thanks Shruthi, for the new patches!


Here are some review comments:-
1. I think we should rename "test_null_connection.pgc" to "test6.pgc", and
make other required changes appropriately. We can see existing test files
uses test1.pgc, test2.pgc ..., test5.pgc as naming convention, and has test
description inside the file.
2. No need to add test_null_connection.c as commit file in
src/interfaces/ecpg/test/connect/ folder, we don't see such C src files for
other existing test files like test1.c, test2.c ..., test5.c. It is part of
src/interfaces/ecpg/test/connect/.gitignore. So, need to add test6.c and
its executable test6 like others in
src/interfaces/ecpg/test/connect/.gitignore
3. After doing #2 above make sure to create the test9.c C src file as
src/interfaces/ecpg/test/expected/connect-test6.c, I can see other existing
connect tests C src files in src/interfaces/ecpg/test/expected/ folder.
3. Not able to run "make -j 8 installcheck" on my setup, fails due to #3.
4. Extra space at the end (don't see that in other tested cases prints) :
printf("Test 1: Try to get descriptor on a disconnected connection \n");
5. char *query = "SELECT 1" -- unused in new test file added.
6. "if (stmt.connection == NULL)" --> "if (!stmt.connection)"?
7. Should we return -1 in else of new fix added in
ecpg_freeStmtCacheEntry()? If 'con' is NULL, why clean up the cache? Is
returning -1 more defensive than cleaning the cache?
8. Do we need to clean up "stmt.oldlocale = ecpg_strdup(...)" and undo
setlocale() before returning from the newly added fix in ECPGget_desc()?


Regards,
Nishant Sharma,
EDB, Pune.
https://www.enterprisedb.com/

On Thu, Apr 9, 2026 at 4:14 PM Shruthi Gowda <[email protected]> wrote:

>
>
> On Tue, Mar 24, 2026 at 11:29 AM Nishant Sharma <
> [email protected]> wrote:
>
>> Here are some review comments on v3 patch:-
>>
>>    1.
>>
>>    Change in descriptor.c file - In my opinion, we can use `if(conn)`
>>    with ecpg_raise, like other occurrence of ecpg_get_connection() call check
>>    in this file, and not using ecpg_init(). Three reasons: a) Consistency in
>>    checking conn after ecpg_get_connection() call in this file with if check.
>>    b) We don't need to remove 'ecpg_init_sqlca(sqlca);' line due to call to
>>    ecpg_init(). c) #2 comment below.
>>    2.
>>
>>    If you agree with #1, then I see many other reasons for which
>>    ECPGget_desc() returns and we can avoid ecpg_get_connection() call at top
>>    of that function for those reasons and keep the check at the required
>>    location only instead of moving at top of the function.
>>    3.
>>
>>    I see there is one more location of ecpg_get_connection() call where
>>    there is no check of NULL conn. In function ecpg_freeStmtCacheEntry() of
>>    file prepare.c? I understand it's not required for a call in
>>    ecpg_auto_prepare(), as the caller already validated that connection
>>    string. But I think, conn in ecpg_freeStmtCacheEntry() is different from
>>    the one that was validated.
>>    4.
>>
>>    +1 to Mahindra, new test cases specific to the crash required for
>>    this change?
>>
>>
>>
>> Regards,
>> Nishant Sharma,
>> EDB, Pune.
>> https://www.enterprisedb.com/
>>
>
> Thanks, Nishant, for the review. I agree with points 1 and 2 and have
> revised the patch accordingly. Regarding point 3, you are correct; the
> conn in ecpg_freeStmtCacheEntry() differs from the one validated in the
> caller. I have now added the necessary validation in the latest version.
>
> I have also included a test case patch covering all execution paths except
> for the ecpg_freeStmtCacheEntry() flow. I was unable to trigger that
> specific flow, and it appears none of the existing test cases cover that
> line either.
>
> Thanks & Regards,
>
> Shruthi K C
>
> EnterpriseDB: http://www.enterprisedb.com
>
>


^ permalink  raw  reply  [nested|flat] 23+ messages in thread

* Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL
  2026-01-19 12:08 Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-03-24 02:34 ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Mahendra Singh Thalor <[email protected]>
  2026-03-24 05:59   ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-09 10:44     ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-13 10:30       ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
@ 2026-04-13 10:32         ` Nishant Sharma <[email protected]>
  1 sibling, 0 replies; 23+ messages in thread

From: Nishant Sharma @ 2026-04-13 10:32 UTC (permalink / raw)
  To: Shruthi Gowda <[email protected]>; +Cc: Mahendra Singh Thalor <[email protected]>; Fujii Masao <[email protected]>; Tom Lane <[email protected]>; pgsql-hackers

Apologies, I top posted my previous review comments.


^ permalink  raw  reply  [nested|flat] 23+ messages in thread

* Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL
  2026-01-19 12:08 Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-03-24 02:34 ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Mahendra Singh Thalor <[email protected]>
  2026-03-24 05:59   ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-09 10:44     ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-13 10:30       ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
@ 2026-04-15 09:56         ` Shruthi Gowda <[email protected]>
  2026-04-16 07:04           ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  1 sibling, 1 reply; 23+ messages in thread

From: Shruthi Gowda @ 2026-04-15 09:56 UTC (permalink / raw)
  To: Nishant Sharma <[email protected]>; +Cc: Mahendra Singh Thalor <[email protected]>; Fujii Masao <[email protected]>; Tom Lane <[email protected]>; pgsql-hackers

On Mon, Apr 13, 2026 at 4:00 PM Nishant Sharma <
[email protected]> wrote:

> Thanks Shruthi, for the new patches!
>
>
> Here are some review comments:-
> 1. I think we should rename "test_null_connection.pgc" to "test6.pgc", and
> make other required changes appropriately. We can see existing test files
> uses test1.pgc, test2.pgc ..., test5.pgc as naming convention, and has test
> description inside the file.
> 2. No need to add test_null_connection.c as commit file in
> src/interfaces/ecpg/test/connect/ folder, we don't see such C src files for
> other existing test files like test1.c, test2.c ..., test5.c. It is part of
> src/interfaces/ecpg/test/connect/.gitignore. So, need to add test6.c and
> its executable test6 like others in
> src/interfaces/ecpg/test/connect/.gitignore
> 3. After doing #2 above make sure to create the test9.c C src file as
> src/interfaces/ecpg/test/expected/connect-test6.c, I can see other existing
> connect tests C src files in src/interfaces/ecpg/test/expected/ folder.
> 3. Not able to run "make -j 8 installcheck" on my setup, fails due to #3.
> 4. Extra space at the end (don't see that in other tested cases prints) :
> printf("Test 1: Try to get descriptor on a disconnected connection \n");
> 5. char *query = "SELECT 1" -- unused in new test file added.
> 6. "if (stmt.connection == NULL)" --> "if (!stmt.connection)"?
> 7. Should we return -1 in else of new fix added in
> ecpg_freeStmtCacheEntry()? If 'con' is NULL, why clean up the cache? Is
> returning -1 more defensive than cleaning the cache?
> 8. Do we need to clean up "stmt.oldlocale = ecpg_strdup(...)" and undo
> setlocale() before returning from the newly added fix in ECPGget_desc()?
>
>
> Regards,
> Nishant Sharma,
> EDB, Pune.
> https://www.enterprisedb.com/
>
> On Thu, Apr 9, 2026 at 4:14 PM Shruthi Gowda <[email protected]> wrote:
>
>>
>>
>> On Tue, Mar 24, 2026 at 11:29 AM Nishant Sharma <
>> [email protected]> wrote:
>>
>>> Here are some review comments on v3 patch:-
>>>
>>>    1.
>>>
>>>    Change in descriptor.c file - In my opinion, we can use `if(conn)`
>>>    with ecpg_raise, like other occurrence of ecpg_get_connection() call check
>>>    in this file, and not using ecpg_init(). Three reasons: a) Consistency in
>>>    checking conn after ecpg_get_connection() call in this file with if check.
>>>    b) We don't need to remove 'ecpg_init_sqlca(sqlca);' line due to call to
>>>    ecpg_init(). c) #2 comment below.
>>>    2.
>>>
>>>    If you agree with #1, then I see many other reasons for which
>>>    ECPGget_desc() returns and we can avoid ecpg_get_connection() call at top
>>>    of that function for those reasons and keep the check at the required
>>>    location only instead of moving at top of the function.
>>>    3.
>>>
>>>    I see there is one more location of ecpg_get_connection() call where
>>>    there is no check of NULL conn. In function ecpg_freeStmtCacheEntry() of
>>>    file prepare.c? I understand it's not required for a call in
>>>    ecpg_auto_prepare(), as the caller already validated that connection
>>>    string. But I think, conn in ecpg_freeStmtCacheEntry() is different from
>>>    the one that was validated.
>>>    4.
>>>
>>>    +1 to Mahindra, new test cases specific to the crash required for
>>>    this change?
>>>
>>>
>>>
>>> Regards,
>>> Nishant Sharma,
>>> EDB, Pune.
>>> https://www.enterprisedb.com/
>>>
>>
>> Thanks, Nishant, for the review. I agree with points 1 and 2 and have
>> revised the patch accordingly. Regarding point 3, you are correct; the
>> conn in ecpg_freeStmtCacheEntry() differs from the one validated in the
>> caller. I have now added the necessary validation in the latest version.
>>
>> I have also included a test case patch covering all execution paths
>> except for the ecpg_freeStmtCacheEntry() flow. I was unable to trigger
>> that specific flow, and it appears none of the existing test cases cover
>> that line either.
>>
>> Thanks & Regards,
>>
>> Shruthi K C
>>
>> EnterpriseDB: http://www.enterprisedb.com
>>
>

Thanks for the review Nishant. I have updated the test case patch to
address comments 1–5. Regarding points 6–8, please see my detailed
responses below:
6. "if (stmt.connection == NULL)" --> "if (!stmt.connection)"?
    --> Both formats are used interchangeably in the ecpg code. I’d prefer
to stick with the explicit null check here

7. Should we return -1 in else of new fix added in
ecpg_freeStmtCacheEntry()? If 'con' is NULL, why clean up the cache? Is
returning -1 more defensive than cleaning the cache?
 --> The cache entry cleanup must happen regardless of whether the
connection exists, because:
  - The cache slot is being reclaimed for a new statement
  - Memory must be freed to avoid leaks

  - A disconnected connection means the entry is stale and must be cleaned
   The NULL check protects against crashes while still performing necessary
cleanup.

8. Do we need to clean up "stmt.oldlocale = ecpg_strdup(...)" and undo
setlocale() before returning from the newly added fix in ECPGget_desc()?
    Great point! To avoid this cleanup complexity, I moved the connection
check before the locale setup so the early return happens before any
resources are allocated.

Thanks & Regards,

Shruthi K C

EnterpriseDB: http://www.enterprisedb.com


Attachments:

  [application/octet-stream] v5-0001-Add-missing-connection-validation-in-ECPG.patch (3.5K, 3-v5-0001-Add-missing-connection-validation-in-ECPG.patch)
  download | inline diff:
From 858e2bc8ecde70b704173d28993a977410136dab Mon Sep 17 00:00:00 2001
From: shruthi gowda <[email protected]>
Date: Wed, 15 Apr 2026 08:34:18 +0000
Subject: [PATCH v5] Add missing connection validation in ECPG

ECPGdeallocate_all(), ECPGprepared_statement(), ECPGget_desc(), and
ecpg_freeStmtCacheEntry() could crash or misbehave when operating on
NULL or invalid connections. Add proper connection validation to
prevent dereferencing NULL pointers.
---
 src/interfaces/ecpg/ecpglib/descriptor.c | 12 ++++++++++--
 src/interfaces/ecpg/ecpglib/prepare.c    | 25 ++++++++++++++++--------
 2 files changed, 27 insertions(+), 10 deletions(-)

diff --git a/src/interfaces/ecpg/ecpglib/descriptor.c b/src/interfaces/ecpg/ecpglib/descriptor.c
index 39cd5130ec9..1ad5f2d88cc 100644
--- a/src/interfaces/ecpg/ecpglib/descriptor.c
+++ b/src/interfaces/ecpg/ecpglib/descriptor.c
@@ -476,6 +476,16 @@ ECPGget_desc(int lineno, const char *desc_name, int index,...)
 		memset(&stmt, 0, sizeof stmt);
 		stmt.lineno = lineno;
 
+		/* desperate try to guess something sensible */
+		stmt.connection = ecpg_get_connection(NULL);
+		if (stmt.connection == NULL)
+		{
+			ecpg_raise(lineno, ECPG_NO_CONN, ECPG_SQLSTATE_CONNECTION_DOES_NOT_EXIST,
+					   ecpg_gettext("NULL"));
+			va_end(args);
+			return false;
+		}
+
 		/* Make sure we do NOT honor the locale for numeric input */
 		/* since the database gives the standard decimal point */
 		/* (see comments in execute.c) */
@@ -505,8 +515,6 @@ ECPGget_desc(int lineno, const char *desc_name, int index,...)
 		setlocale(LC_NUMERIC, "C");
 #endif
 
-		/* desperate try to guess something sensible */
-		stmt.connection = ecpg_get_connection(NULL);
 		ecpg_store_result(ECPGresult, index, &stmt, &data_var);
 
 #ifdef HAVE_USELOCALE
diff --git a/src/interfaces/ecpg/ecpglib/prepare.c b/src/interfaces/ecpg/ecpglib/prepare.c
index 5c7c5397535..f9489044724 100644
--- a/src/interfaces/ecpg/ecpglib/prepare.c
+++ b/src/interfaces/ecpg/ecpglib/prepare.c
@@ -381,8 +381,12 @@ ecpg_deallocate_all_conn(int lineno, enum COMPAT_MODE c, struct connection *con)
 bool
 ECPGdeallocate_all(int lineno, int compat, const char *connection_name)
 {
-	return ecpg_deallocate_all_conn(lineno, compat,
-									ecpg_get_connection(connection_name));
+	struct connection *con = ecpg_get_connection(connection_name);
+
+	if (!ecpg_init(con, connection_name, lineno))
+		return false;
+
+	return ecpg_deallocate_all_conn(lineno, compat, con);
 }
 
 char *
@@ -395,13 +399,15 @@ ecpg_prepared(const char *name, struct connection *con)
 }
 
 /* return the prepared statement */
-/* lineno is not used here, but kept in to not break API */
 char *
 ECPGprepared_statement(const char *connection_name, const char *name, int lineno)
 {
-	(void) lineno;				/* keep the compiler quiet */
+	struct connection *con = ecpg_get_connection(connection_name);
+
+	if (!ecpg_init(con, connection_name, lineno))
+		return NULL;
 
-	return ecpg_prepared(name, ecpg_get_connection(connection_name));
+	return ecpg_prepared(name, con);
 }
 
 /*
@@ -499,9 +505,12 @@ ecpg_freeStmtCacheEntry(int lineno, int compat,
 	con = ecpg_get_connection(entry->connection);
 
 	/* free the 'prepared_statement' list entry */
-	this = ecpg_find_prepared_statement(entry->stmtID, con, &prev);
-	if (this && !deallocate_one(lineno, compat, con, prev, this))
-		return -1;
+	if (con)
+	{
+		this = ecpg_find_prepared_statement(entry->stmtID, con, &prev);
+		if (this && !deallocate_one(lineno, compat, con, prev, this))
+			return -1;
+	}
 
 	entry->stmtID[0] = '\0';
 
-- 
2.43.0



  [application/octet-stream] v2_test-0001-Tests-for-NULL-connection-validation.patch (12.7K, 4-v2_test-0001-Tests-for-NULL-connection-validation.patch)
  download | inline diff:
From b6714c710e66d17bed41dfb165b8048d52d3c396 Mon Sep 17 00:00:00 2001
From: shruthi gowda <[email protected]>
Date: Wed, 15 Apr 2026 08:58:09 +0000
Subject: [PATCH v2_test] Tests for NULL connection validation

---
 src/interfaces/ecpg/test/connect/.gitignore   |   2 +
 src/interfaces/ecpg/test/connect/Makefile     |   3 +-
 src/interfaces/ecpg/test/connect/meson.build  |   1 +
 src/interfaces/ecpg/test/connect/test6.pgc    |  68 ++++++++
 src/interfaces/ecpg/test/ecpg_schedule        |   1 +
 .../ecpg/test/expected/connect-test6.c        | 146 ++++++++++++++++++
 .../ecpg/test/expected/connect-test6.stderr   |  50 ++++++
 .../ecpg/test/expected/connect-test6.stdout   |   8 +
 8 files changed, 278 insertions(+), 1 deletion(-)
 create mode 100644 src/interfaces/ecpg/test/connect/test6.pgc
 create mode 100644 src/interfaces/ecpg/test/expected/connect-test6.c
 create mode 100644 src/interfaces/ecpg/test/expected/connect-test6.stderr
 create mode 100644 src/interfaces/ecpg/test/expected/connect-test6.stdout

diff --git a/src/interfaces/ecpg/test/connect/.gitignore b/src/interfaces/ecpg/test/connect/.gitignore
index e0639f3c8d1..02236847444 100644
--- a/src/interfaces/ecpg/test/connect/.gitignore
+++ b/src/interfaces/ecpg/test/connect/.gitignore
@@ -8,3 +8,5 @@
 /test4.c
 /test5
 /test5.c
+/test6
+/test6.c
diff --git a/src/interfaces/ecpg/test/connect/Makefile b/src/interfaces/ecpg/test/connect/Makefile
index 2602d5d286f..17fa2667bf7 100644
--- a/src/interfaces/ecpg/test/connect/Makefile
+++ b/src/interfaces/ecpg/test/connect/Makefile
@@ -7,6 +7,7 @@ TESTS = test1 test1.c \
         test2 test2.c \
         test3 test3.c \
         test4 test4.c \
-        test5 test5.c
+        test5 test5.c \
+        test6 test6.c
 
 all: $(TESTS)
diff --git a/src/interfaces/ecpg/test/connect/meson.build b/src/interfaces/ecpg/test/connect/meson.build
index 591e04bc422..1cc0a928309 100644
--- a/src/interfaces/ecpg/test/connect/meson.build
+++ b/src/interfaces/ecpg/test/connect/meson.build
@@ -6,6 +6,7 @@ pgc_files = [
   'test3',
   'test4',
   'test5',
+  'test6',
 ]
 
 foreach pgc_file : pgc_files
diff --git a/src/interfaces/ecpg/test/connect/test6.pgc b/src/interfaces/ecpg/test/connect/test6.pgc
new file mode 100644
index 00000000000..da30a37d885
--- /dev/null
+++ b/src/interfaces/ecpg/test/connect/test6.pgc
@@ -0,0 +1,68 @@
+/*
+ * This test verifies that ecpg functions properly handle NULL connections
+ * (i.e., when a connection name doesn't exist or has been disconnected).
+ * Before the fix, these operations would cause a segmentation fault.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+exec sql include ../regression;
+
+int
+main(void)
+{
+exec sql begin declare section;
+	int val1output = 2;
+	int val1 = 1;
+	char val2[5] = "data1";
+	char *stmt1 = "SELECT * from test1 where a = $1 and b = $2";
+exec sql end declare section;
+
+	ECPGdebug(1, stderr);
+
+	/* Connect to the database */
+	exec sql connect to REGRESSDB1 as myconn;
+
+	/* Test 1: Try to get descriptor on a disconnected connection */
+	printf("Test 1: Try to get descriptor on a disconnected connection\n");
+	exec sql create table test1 (a int, b text);
+	exec sql insert into test1 (a,b) values (1, 'data1');
+
+	exec sql allocate descriptor indesc;
+	exec sql allocate descriptor outdesc;
+
+	exec sql prepare foo2 from :stmt1;
+
+	exec sql set descriptor indesc value 1 DATA = :val1;
+	exec sql set descriptor indesc value 2 DATA = :val2;
+
+	exec sql execute foo2 using sql descriptor indesc into sql descriptor outdesc;
+
+	exec sql disconnect;
+	exec sql get descriptor outdesc value 1 :val1output = DATA;
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	/* Test 2: Try to deallocate all on a non-existent connection */
+	printf("Test 2: deallocate all with non-existent connection\n");
+	exec sql at nonexistent deallocate all;
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	/* Test 3: deallocate on disconnected connection */
+	printf("Test 3: deallocate all on disconnected connection\n");
+	exec sql deallocate all;
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	/* Test 4: Use prepared statement from non-existent connection */
+	printf("Test 4: Use prepared statement from non-existent connection\n");
+	exec sql at nonexistent prepare stmt1 FROM "SELECT 1";
+	exec sql at nonexistent declare cur1 cursor for stmt1;
+	exec sql at nonexistent open cur1;
+
+	printf("All tests completed !\n");
+
+	exec sql disconnect;
+
+	return 0;
+}
diff --git a/src/interfaces/ecpg/test/ecpg_schedule b/src/interfaces/ecpg/test/ecpg_schedule
index b75e16fde1e..d1f5d9452b7 100644
--- a/src/interfaces/ecpg/test/ecpg_schedule
+++ b/src/interfaces/ecpg/test/ecpg_schedule
@@ -13,6 +13,7 @@ test: connect/test2
 test: connect/test3
 test: connect/test4
 test: connect/test5
+test: connect/test6
 test: pgtypeslib/dt_test
 test: pgtypeslib/dt_test2
 test: pgtypeslib/num_test
diff --git a/src/interfaces/ecpg/test/expected/connect-test6.c b/src/interfaces/ecpg/test/expected/connect-test6.c
new file mode 100644
index 00000000000..29cf70a2e9b
--- /dev/null
+++ b/src/interfaces/ecpg/test/expected/connect-test6.c
@@ -0,0 +1,146 @@
+/* Processed by ecpg (regression mode) */
+/* These include files are added by the preprocessor */
+#include <ecpglib.h>
+#include <ecpgerrno.h>
+#include <sqlca.h>
+/* End of automatic include section */
+#define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y))
+
+#line 1 "test6.pgc"
+/*
+ * This test verifies that ecpg functions properly handle NULL connections
+ * (i.e., when a connection name doesn't exist or has been disconnected).
+ * Before the fix, these operations would cause a segmentation fault.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+
+#line 1 "regression.h"
+
+
+
+
+
+
+#line 11 "test6.pgc"
+
+
+int
+main(void)
+{
+/* exec sql begin declare section */
+	   
+	   
+	   
+	   
+
+#line 17 "test6.pgc"
+ int val1output = 2 ;
+ 
+#line 18 "test6.pgc"
+ int val1 = 1 ;
+ 
+#line 19 "test6.pgc"
+ char val2 [ 5 ] = "data1" ;
+ 
+#line 20 "test6.pgc"
+ char * stmt1 = "SELECT * from test1 where a = $1 and b = $2" ;
+/* exec sql end declare section */
+#line 21 "test6.pgc"
+
+
+	ECPGdebug(1, stderr);
+
+	/* Connect to the database */
+	{ ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , "myconn", 0); }
+#line 26 "test6.pgc"
+
+
+	/* Test 1: Try to get descriptor on a disconnected connection */
+	printf("Test 1: Try to get descriptor on a disconnected connection\n");
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table test1 ( a int , b text )", ECPGt_EOIT, ECPGt_EORT);}
+#line 30 "test6.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into test1 ( a , b ) values ( 1 , 'data1' )", ECPGt_EOIT, ECPGt_EORT);}
+#line 31 "test6.pgc"
+
+
+	ECPGallocate_desc(__LINE__, "indesc");
+#line 33 "test6.pgc"
+
+	ECPGallocate_desc(__LINE__, "outdesc");
+#line 34 "test6.pgc"
+
+
+	{ ECPGprepare(__LINE__, NULL, 0, "foo2", stmt1);}
+#line 36 "test6.pgc"
+
+
+	{ ECPGset_desc(__LINE__, "indesc", 1,ECPGd_data,
+	ECPGt_int,&(val1),(long)1,(long)1,sizeof(int), ECPGd_EODT);
+}
+#line 38 "test6.pgc"
+
+	{ ECPGset_desc(__LINE__, "indesc", 2,ECPGd_data,
+	ECPGt_char,(val2),(long)5,(long)1,(5)*sizeof(char), ECPGd_EODT);
+}
+#line 39 "test6.pgc"
+
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_execute, "foo2", 
+	ECPGt_descriptor, "indesc", 1L, 1L, 1L, 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, 
+	ECPGt_descriptor, "outdesc", 1L, 1L, 1L, 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
+#line 41 "test6.pgc"
+
+
+	{ ECPGdisconnect(__LINE__, "CURRENT");}
+#line 43 "test6.pgc"
+
+	{ ECPGget_desc(__LINE__, "outdesc", 1,ECPGd_data,
+	ECPGt_int,&(val1output),(long)1,(long)1,sizeof(int), ECPGd_EODT);
+}
+#line 44 "test6.pgc"
+
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	/* Test 2: Try to deallocate all on a non-existent connection */
+	printf("Test 2: deallocate all with non-existent connection\n");
+	{ ECPGdeallocate_all(__LINE__, 0, "nonexistent");}
+#line 49 "test6.pgc"
+
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	/* Test 3: deallocate on disconnected connection */
+	printf("Test 3: deallocate all on disconnected connection\n");
+	{ ECPGdeallocate_all(__LINE__, 0, NULL);}
+#line 54 "test6.pgc"
+
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	/* Test 4: Use prepared statement from non-existent connection */
+	printf("Test 4: Use prepared statement from non-existent connection\n");
+	{ ECPGprepare(__LINE__, "nonexistent", 0, "stmt1", "SELECT 1");}
+#line 59 "test6.pgc"
+
+	/* declare cur1 cursor for $1 */
+#line 60 "test6.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, "nonexistent", 0, ECPGst_normal, "declare cur1 cursor for $1", 
+	ECPGt_char_variable,(ECPGprepared_statement("nonexistent", "stmt1", __LINE__)),(long)1,(long)1,(1)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);}
+#line 61 "test6.pgc"
+
+
+	printf("All tests completed !\n");
+
+	{ ECPGdisconnect(__LINE__, "CURRENT");}
+#line 65 "test6.pgc"
+
+
+	return 0;
+}
diff --git a/src/interfaces/ecpg/test/expected/connect-test6.stderr b/src/interfaces/ecpg/test/expected/connect-test6.stderr
new file mode 100644
index 00000000000..fba91a8f257
--- /dev/null
+++ b/src/interfaces/ecpg/test/expected/connect-test6.stderr
@@ -0,0 +1,50 @@
+[NO_PID]: ECPGdebug: set to 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ECPGconnect: opening database ecpg1_regression on <DEFAULT> port <DEFAULT>  
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 30: query: create table test1 ( a int , b text ); with 0 parameter(s) on connection myconn
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 30: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 30: OK: CREATE TABLE
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 31: query: insert into test1 ( a , b ) values ( 1 , 'data1' ); with 0 parameter(s) on connection myconn
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 31: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 31: OK: INSERT 0 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: prepare_common on line 36: name foo2; query: "SELECT * from test1 where a = $1 and b = $2"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 41: query: SELECT * from test1 where a = $1 and b = $2; with 2 parameter(s) on connection myconn
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 41: using PQexecPrepared for "SELECT * from test1 where a = $1 and b = $2"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_free_params on line 41: parameter 1 = 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_free_params on line 41: parameter 2 = data1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 41: correctly got 1 tuples with 2 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 41: putting result (1 tuples) into descriptor outdesc
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: deallocate_one on line 0: name foo2
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_finish: connection myconn closed
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ECPGget_desc: reading items for tuple 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: raising sqlcode -220 on line 44: connection "NULL" does not exist on line 44
+[NO_PID]: sqlca: code: -220, state: 08003
+[NO_PID]: raising sqlcode -220 on line 49: connection "nonexistent" does not exist on line 49
+[NO_PID]: sqlca: code: -220, state: 08003
+[NO_PID]: raising sqlcode -220 on line 54: connection "NULL" does not exist on line 54
+[NO_PID]: sqlca: code: -220, state: 08003
+[NO_PID]: raising sqlcode -220 on line 59: connection "nonexistent" does not exist on line 59
+[NO_PID]: sqlca: code: -220, state: 08003
+[NO_PID]: raising sqlcode -220 on line 62: connection "nonexistent" does not exist on line 62
+[NO_PID]: sqlca: code: -220, state: 08003
+[NO_PID]: raising sqlcode -220 on line 61: connection "nonexistent" does not exist on line 61
+[NO_PID]: sqlca: code: -220, state: 08003
+[NO_PID]: raising sqlcode -220 on line 65: connection "CURRENT" does not exist on line 65
+[NO_PID]: sqlca: code: -220, state: 08003
diff --git a/src/interfaces/ecpg/test/expected/connect-test6.stdout b/src/interfaces/ecpg/test/expected/connect-test6.stdout
new file mode 100644
index 00000000000..c83136c77e0
--- /dev/null
+++ b/src/interfaces/ecpg/test/expected/connect-test6.stdout
@@ -0,0 +1,8 @@
+Test 1: Try to get descriptor on a disconnected connection
+sqlca.sqlcode = -220
+Test 2: deallocate all with non-existent connection
+sqlca.sqlcode = -220
+Test 3: deallocate all on disconnected connection
+sqlca.sqlcode = -220
+Test 4: Use prepared statement from non-existent connection
+All tests completed !
-- 
2.43.0



^ permalink  raw  reply  [nested|flat] 23+ messages in thread

* Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL
  2026-01-19 12:08 Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-03-24 02:34 ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Mahendra Singh Thalor <[email protected]>
  2026-03-24 05:59   ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-09 10:44     ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-13 10:30       ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-15 09:56         ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
@ 2026-04-16 07:04           ` Nishant Sharma <[email protected]>
  2026-04-18 16:20             ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  0 siblings, 1 reply; 23+ messages in thread

From: Nishant Sharma @ 2026-04-16 07:04 UTC (permalink / raw)
  To: Shruthi Gowda <[email protected]>; +Cc: Mahendra Singh Thalor <[email protected]>; Fujii Masao <[email protected]>; Tom Lane <[email protected]>; pgsql-hackers

Thanks Shruthi for the new patches!

I can apply v5 on all active branches (i.e master, REL_18, REL_17, REL_16,
REL_15, REL_14).
I checked PG's ECPG regression with v5 and v2_test on master, REL_18,
REL_17, and REL_16 using both make and meson.

The v5 patch looks good to me now. I only have a few observations on
v2_test patch.

Review comments on v2_test:
1. Not able to apply the v2 test patch on PG15 and PG14 branch, appears
meson.build for test is not there on these branches. Need to remove all
meson related changes for these branches.
2. char val2[5] = "data1"; --> val2's size will not be able to fit '\0' for
the string. As size of val2 and number of characters in "data1" are exactly
same?
3. "exec sql disconnect;" - Do we need this at the end as we have already
disconnected before Test 2.
3. Minor - Do we need "printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);"? I
see all others have it, but not Test 4?


Regards,
Nishant Sharma,
Pune, EDB.
https://www.enterprisedb.com/

>


^ permalink  raw  reply  [nested|flat] 23+ messages in thread

* Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL
  2026-01-19 12:08 Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-03-24 02:34 ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Mahendra Singh Thalor <[email protected]>
  2026-03-24 05:59   ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-09 10:44     ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-13 10:30       ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-15 09:56         ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-16 07:04           ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
@ 2026-04-18 16:20             ` Shruthi Gowda <[email protected]>
  2026-04-20 06:01               ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  0 siblings, 1 reply; 23+ messages in thread

From: Shruthi Gowda @ 2026-04-18 16:20 UTC (permalink / raw)
  To: Nishant Sharma <[email protected]>; +Cc: Mahendra Singh Thalor <[email protected]>; Fujii Masao <[email protected]>; Tom Lane <[email protected]>; pgsql-hackers

On Thu, Apr 16, 2026 at 12:34 PM Nishant Sharma <
[email protected]> wrote:

> Thanks Shruthi for the new patches!
>
> I can apply v5 on all active branches (i.e master, REL_18, REL_17, REL_16,
> REL_15, REL_14).
> I checked PG's ECPG regression with v5 and v2_test on master, REL_18,
> REL_17, and REL_16 using both make and meson.
>
> The v5 patch looks good to me now. I only have a few observations on
> v2_test patch.
>
> Review comments on v2_test:
> 1. Not able to apply the v2 test patch on PG15 and PG14 branch, appears
> meson.build for test is not there on these branches. Need to remove all
> meson related changes for these branches.
> 2. char val2[5] = "data1"; --> val2's size will not be able to fit '\0'
> for the string. As size of val2 and number of characters in "data1" are
> exactly same?
> 3. "exec sql disconnect;" - Do we need this at the end as we have already
> disconnected before Test 2.
> 3. Minor - Do we need "printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);"? I
> see all others have it, but not Test 4?
>
>
> Regards,
> Nishant Sharma,
> Pune, EDB.
> https://www.enterprisedb.com/
>

Thanks Nishant for the review on the latest patch. I have taken care of all
the review comments for the test patch. Please find the latest test patches
for master to REL_16 (v3_test) and V15 to v14 (v3_test_v15) respectively.



Thanks & Regards,

Shruthi K C

EnterpriseDB: http://www.enterprisedb.com


Attachments:

  [application/octet-stream] v3_test-0001-Tests-for-NULL-connection-validation.patch (12.6K, 3-v3_test-0001-Tests-for-NULL-connection-validation.patch)
  download | inline diff:
From b02c0a7c9311ebae16af6e209f42b044fa1e2522 Mon Sep 17 00:00:00 2001
From: shruthi gowda <[email protected]>
Date: Fri, 17 Apr 2026 13:46:15 +0000
Subject: [PATCH v3_test] Tests for NULL connection validation

---
 src/interfaces/ecpg/test/connect/.gitignore   |   2 +
 src/interfaces/ecpg/test/connect/Makefile     |   3 +-
 src/interfaces/ecpg/test/connect/meson.build  |   1 +
 src/interfaces/ecpg/test/connect/test6.pgc    |  67 ++++++++
 src/interfaces/ecpg/test/ecpg_schedule        |   1 +
 .../ecpg/test/expected/connect-test6.c        | 143 ++++++++++++++++++
 .../ecpg/test/expected/connect-test6.stderr   |  48 ++++++
 .../ecpg/test/expected/connect-test6.stdout   |   9 ++
 8 files changed, 273 insertions(+), 1 deletion(-)
 create mode 100644 src/interfaces/ecpg/test/connect/test6.pgc
 create mode 100644 src/interfaces/ecpg/test/expected/connect-test6.c
 create mode 100644 src/interfaces/ecpg/test/expected/connect-test6.stderr
 create mode 100644 src/interfaces/ecpg/test/expected/connect-test6.stdout

diff --git a/src/interfaces/ecpg/test/connect/.gitignore b/src/interfaces/ecpg/test/connect/.gitignore
index e0639f3c8d1..02236847444 100644
--- a/src/interfaces/ecpg/test/connect/.gitignore
+++ b/src/interfaces/ecpg/test/connect/.gitignore
@@ -8,3 +8,5 @@
 /test4.c
 /test5
 /test5.c
+/test6
+/test6.c
diff --git a/src/interfaces/ecpg/test/connect/Makefile b/src/interfaces/ecpg/test/connect/Makefile
index 2602d5d286f..17fa2667bf7 100644
--- a/src/interfaces/ecpg/test/connect/Makefile
+++ b/src/interfaces/ecpg/test/connect/Makefile
@@ -7,6 +7,7 @@ TESTS = test1 test1.c \
         test2 test2.c \
         test3 test3.c \
         test4 test4.c \
-        test5 test5.c
+        test5 test5.c \
+        test6 test6.c
 
 all: $(TESTS)
diff --git a/src/interfaces/ecpg/test/connect/meson.build b/src/interfaces/ecpg/test/connect/meson.build
index 591e04bc422..1cc0a928309 100644
--- a/src/interfaces/ecpg/test/connect/meson.build
+++ b/src/interfaces/ecpg/test/connect/meson.build
@@ -6,6 +6,7 @@ pgc_files = [
   'test3',
   'test4',
   'test5',
+  'test6',
 ]
 
 foreach pgc_file : pgc_files
diff --git a/src/interfaces/ecpg/test/connect/test6.pgc b/src/interfaces/ecpg/test/connect/test6.pgc
new file mode 100644
index 00000000000..0f7dc355ffc
--- /dev/null
+++ b/src/interfaces/ecpg/test/connect/test6.pgc
@@ -0,0 +1,67 @@
+/*
+ * This test verifies that ecpg functions properly handle NULL connections
+ * (i.e., when a connection name doesn't exist or has been disconnected).
+ * Before the fix, these operations would cause a segmentation fault.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+exec sql include ../regression;
+
+int
+main(void)
+{
+exec sql begin declare section;
+	int val1output = 2;
+	int val1 = 1;
+	char val2[6] = "data1";
+	char *stmt1 = "SELECT * from test1 where a = $1 and b = $2";
+exec sql end declare section;
+
+	ECPGdebug(1, stderr);
+
+	/* Connect to the database */
+	exec sql connect to REGRESSDB1 as myconn;
+
+	/* Test 1: Try to get descriptor on a disconnected connection */
+	printf("Test 1: Try to get descriptor on a disconnected connection\n");
+	exec sql create table test1 (a int, b text);
+	exec sql insert into test1 (a,b) values (1, 'data1');
+
+	exec sql allocate descriptor indesc;
+	exec sql allocate descriptor outdesc;
+
+	exec sql prepare foo2 from :stmt1;
+
+	exec sql set descriptor indesc value 1 DATA = :val1;
+	exec sql set descriptor indesc value 2 DATA = :val2;
+
+	exec sql execute foo2 using sql descriptor indesc into sql descriptor outdesc;
+
+	exec sql disconnect;
+	exec sql get descriptor outdesc value 1 :val1output = DATA;
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	/* Test 2: Try to deallocate all on a non-existent connection */
+	printf("Test 2: deallocate all with non-existent connection\n");
+	exec sql at nonexistent deallocate all;
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	/* Test 3: deallocate on disconnected connection */
+	printf("Test 3: deallocate all on disconnected connection\n");
+	exec sql deallocate all;
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	/* Test 4: Use prepared statement from non-existent connection */
+	printf("Test 4: Use prepared statement from non-existent connection\n");
+	exec sql at nonexistent prepare stmt1 FROM "SELECT 1";
+	exec sql at nonexistent declare cur1 cursor for stmt1;
+	exec sql at nonexistent open cur1;
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	printf("All tests completed !\n");
+
+	return 0;
+}
diff --git a/src/interfaces/ecpg/test/ecpg_schedule b/src/interfaces/ecpg/test/ecpg_schedule
index b75e16fde1e..d1f5d9452b7 100644
--- a/src/interfaces/ecpg/test/ecpg_schedule
+++ b/src/interfaces/ecpg/test/ecpg_schedule
@@ -13,6 +13,7 @@ test: connect/test2
 test: connect/test3
 test: connect/test4
 test: connect/test5
+test: connect/test6
 test: pgtypeslib/dt_test
 test: pgtypeslib/dt_test2
 test: pgtypeslib/num_test
diff --git a/src/interfaces/ecpg/test/expected/connect-test6.c b/src/interfaces/ecpg/test/expected/connect-test6.c
new file mode 100644
index 00000000000..072293faf01
--- /dev/null
+++ b/src/interfaces/ecpg/test/expected/connect-test6.c
@@ -0,0 +1,143 @@
+/* Processed by ecpg (regression mode) */
+/* These include files are added by the preprocessor */
+#include <ecpglib.h>
+#include <ecpgerrno.h>
+#include <sqlca.h>
+/* End of automatic include section */
+#define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y))
+
+#line 1 "test6.pgc"
+/*
+ * This test verifies that ecpg functions properly handle NULL connections
+ * (i.e., when a connection name doesn't exist or has been disconnected).
+ * Before the fix, these operations would cause a segmentation fault.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+
+#line 1 "regression.h"
+
+
+
+
+
+
+#line 11 "test6.pgc"
+
+
+int
+main(void)
+{
+/* exec sql begin declare section */
+	   
+	   
+	   
+	   
+
+#line 17 "test6.pgc"
+ int val1output = 2 ;
+ 
+#line 18 "test6.pgc"
+ int val1 = 1 ;
+ 
+#line 19 "test6.pgc"
+ char val2 [ 6 ] = "data1" ;
+ 
+#line 20 "test6.pgc"
+ char * stmt1 = "SELECT * from test1 where a = $1 and b = $2" ;
+/* exec sql end declare section */
+#line 21 "test6.pgc"
+
+
+	ECPGdebug(1, stderr);
+
+	/* Connect to the database */
+	{ ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , "myconn", 0); }
+#line 26 "test6.pgc"
+
+
+	/* Test 1: Try to get descriptor on a disconnected connection */
+	printf("Test 1: Try to get descriptor on a disconnected connection\n");
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table test1 ( a int , b text )", ECPGt_EOIT, ECPGt_EORT);}
+#line 30 "test6.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into test1 ( a , b ) values ( 1 , 'data1' )", ECPGt_EOIT, ECPGt_EORT);}
+#line 31 "test6.pgc"
+
+
+	ECPGallocate_desc(__LINE__, "indesc");
+#line 33 "test6.pgc"
+
+	ECPGallocate_desc(__LINE__, "outdesc");
+#line 34 "test6.pgc"
+
+
+	{ ECPGprepare(__LINE__, NULL, 0, "foo2", stmt1);}
+#line 36 "test6.pgc"
+
+
+	{ ECPGset_desc(__LINE__, "indesc", 1,ECPGd_data,
+	ECPGt_int,&(val1),(long)1,(long)1,sizeof(int), ECPGd_EODT);
+}
+#line 38 "test6.pgc"
+
+	{ ECPGset_desc(__LINE__, "indesc", 2,ECPGd_data,
+	ECPGt_char,(val2),(long)6,(long)1,(6)*sizeof(char), ECPGd_EODT);
+}
+#line 39 "test6.pgc"
+
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_execute, "foo2", 
+	ECPGt_descriptor, "indesc", 1L, 1L, 1L, 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, 
+	ECPGt_descriptor, "outdesc", 1L, 1L, 1L, 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
+#line 41 "test6.pgc"
+
+
+	{ ECPGdisconnect(__LINE__, "CURRENT");}
+#line 43 "test6.pgc"
+
+	{ ECPGget_desc(__LINE__, "outdesc", 1,ECPGd_data,
+	ECPGt_int,&(val1output),(long)1,(long)1,sizeof(int), ECPGd_EODT);
+}
+#line 44 "test6.pgc"
+
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	/* Test 2: Try to deallocate all on a non-existent connection */
+	printf("Test 2: deallocate all with non-existent connection\n");
+	{ ECPGdeallocate_all(__LINE__, 0, "nonexistent");}
+#line 49 "test6.pgc"
+
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	/* Test 3: deallocate on disconnected connection */
+	printf("Test 3: deallocate all on disconnected connection\n");
+	{ ECPGdeallocate_all(__LINE__, 0, NULL);}
+#line 54 "test6.pgc"
+
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	/* Test 4: Use prepared statement from non-existent connection */
+	printf("Test 4: Use prepared statement from non-existent connection\n");
+	{ ECPGprepare(__LINE__, "nonexistent", 0, "stmt1", "SELECT 1");}
+#line 59 "test6.pgc"
+
+	/* declare cur1 cursor for $1 */
+#line 60 "test6.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, "nonexistent", 0, ECPGst_normal, "declare cur1 cursor for $1", 
+	ECPGt_char_variable,(ECPGprepared_statement("nonexistent", "stmt1", __LINE__)),(long)1,(long)1,(1)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);}
+#line 61 "test6.pgc"
+
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	printf("All tests completed !\n");
+
+	return 0;
+}
diff --git a/src/interfaces/ecpg/test/expected/connect-test6.stderr b/src/interfaces/ecpg/test/expected/connect-test6.stderr
new file mode 100644
index 00000000000..38d3590d65c
--- /dev/null
+++ b/src/interfaces/ecpg/test/expected/connect-test6.stderr
@@ -0,0 +1,48 @@
+[NO_PID]: ECPGdebug: set to 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ECPGconnect: opening database ecpg1_regression on <DEFAULT> port <DEFAULT>  
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 30: query: create table test1 ( a int , b text ); with 0 parameter(s) on connection myconn
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 30: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 30: OK: CREATE TABLE
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 31: query: insert into test1 ( a , b ) values ( 1 , 'data1' ); with 0 parameter(s) on connection myconn
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 31: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 31: OK: INSERT 0 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: prepare_common on line 36: name foo2; query: "SELECT * from test1 where a = $1 and b = $2"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 41: query: SELECT * from test1 where a = $1 and b = $2; with 2 parameter(s) on connection myconn
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 41: using PQexecPrepared for "SELECT * from test1 where a = $1 and b = $2"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_free_params on line 41: parameter 1 = 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_free_params on line 41: parameter 2 = data1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 41: correctly got 1 tuples with 2 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 41: putting result (1 tuples) into descriptor outdesc
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: deallocate_one on line 0: name foo2
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_finish: connection myconn closed
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ECPGget_desc: reading items for tuple 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: raising sqlcode -220 on line 44: connection "NULL" does not exist on line 44
+[NO_PID]: sqlca: code: -220, state: 08003
+[NO_PID]: raising sqlcode -220 on line 49: connection "nonexistent" does not exist on line 49
+[NO_PID]: sqlca: code: -220, state: 08003
+[NO_PID]: raising sqlcode -220 on line 54: connection "NULL" does not exist on line 54
+[NO_PID]: sqlca: code: -220, state: 08003
+[NO_PID]: raising sqlcode -220 on line 59: connection "nonexistent" does not exist on line 59
+[NO_PID]: sqlca: code: -220, state: 08003
+[NO_PID]: raising sqlcode -220 on line 62: connection "nonexistent" does not exist on line 62
+[NO_PID]: sqlca: code: -220, state: 08003
+[NO_PID]: raising sqlcode -220 on line 61: connection "nonexistent" does not exist on line 61
+[NO_PID]: sqlca: code: -220, state: 08003
diff --git a/src/interfaces/ecpg/test/expected/connect-test6.stdout b/src/interfaces/ecpg/test/expected/connect-test6.stdout
new file mode 100644
index 00000000000..bf9a2e91051
--- /dev/null
+++ b/src/interfaces/ecpg/test/expected/connect-test6.stdout
@@ -0,0 +1,9 @@
+Test 1: Try to get descriptor on a disconnected connection
+sqlca.sqlcode = -220
+Test 2: deallocate all with non-existent connection
+sqlca.sqlcode = -220
+Test 3: deallocate all on disconnected connection
+sqlca.sqlcode = -220
+Test 4: Use prepared statement from non-existent connection
+sqlca.sqlcode = -220
+All tests completed !
-- 
2.43.0



  [application/octet-stream] v3_test_v15-0001-Tests-for-NULL-connection-validation-for.patch (12.2K, 4-v3_test_v15-0001-Tests-for-NULL-connection-validation-for.patch)
  download | inline diff:
From c1db801c37eeff6ad726ab66d5afe3d14b0dbc37 Mon Sep 17 00:00:00 2001
From: shruthi gowda <[email protected]>
Date: Sat, 18 Apr 2026 16:13:37 +0000
Subject: [PATCH v3_test_v15] Tests for NULL connection validation for V15

---
 src/interfaces/ecpg/test/connect/.gitignore   |   2 +
 src/interfaces/ecpg/test/connect/Makefile     |   3 +-
 src/interfaces/ecpg/test/connect/test6.pgc    |  67 ++++++++
 src/interfaces/ecpg/test/ecpg_schedule        |   1 +
 .../ecpg/test/expected/connect-test6.c        | 143 ++++++++++++++++++
 .../ecpg/test/expected/connect-test6.stderr   |  48 ++++++
 .../ecpg/test/expected/connect-test6.stdout   |   9 ++
 7 files changed, 272 insertions(+), 1 deletion(-)
 create mode 100644 src/interfaces/ecpg/test/connect/test6.pgc
 create mode 100644 src/interfaces/ecpg/test/expected/connect-test6.c
 create mode 100644 src/interfaces/ecpg/test/expected/connect-test6.stderr
 create mode 100644 src/interfaces/ecpg/test/expected/connect-test6.stdout

diff --git a/src/interfaces/ecpg/test/connect/.gitignore b/src/interfaces/ecpg/test/connect/.gitignore
index e0639f3c8d1..02236847444 100644
--- a/src/interfaces/ecpg/test/connect/.gitignore
+++ b/src/interfaces/ecpg/test/connect/.gitignore
@@ -8,3 +8,5 @@
 /test4.c
 /test5
 /test5.c
+/test6
+/test6.c
diff --git a/src/interfaces/ecpg/test/connect/Makefile b/src/interfaces/ecpg/test/connect/Makefile
index 2602d5d286f..17fa2667bf7 100644
--- a/src/interfaces/ecpg/test/connect/Makefile
+++ b/src/interfaces/ecpg/test/connect/Makefile
@@ -7,6 +7,7 @@ TESTS = test1 test1.c \
         test2 test2.c \
         test3 test3.c \
         test4 test4.c \
-        test5 test5.c
+        test5 test5.c \
+        test6 test6.c
 
 all: $(TESTS)
diff --git a/src/interfaces/ecpg/test/connect/test6.pgc b/src/interfaces/ecpg/test/connect/test6.pgc
new file mode 100644
index 00000000000..0f7dc355ffc
--- /dev/null
+++ b/src/interfaces/ecpg/test/connect/test6.pgc
@@ -0,0 +1,67 @@
+/*
+ * This test verifies that ecpg functions properly handle NULL connections
+ * (i.e., when a connection name doesn't exist or has been disconnected).
+ * Before the fix, these operations would cause a segmentation fault.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+exec sql include ../regression;
+
+int
+main(void)
+{
+exec sql begin declare section;
+	int val1output = 2;
+	int val1 = 1;
+	char val2[6] = "data1";
+	char *stmt1 = "SELECT * from test1 where a = $1 and b = $2";
+exec sql end declare section;
+
+	ECPGdebug(1, stderr);
+
+	/* Connect to the database */
+	exec sql connect to REGRESSDB1 as myconn;
+
+	/* Test 1: Try to get descriptor on a disconnected connection */
+	printf("Test 1: Try to get descriptor on a disconnected connection\n");
+	exec sql create table test1 (a int, b text);
+	exec sql insert into test1 (a,b) values (1, 'data1');
+
+	exec sql allocate descriptor indesc;
+	exec sql allocate descriptor outdesc;
+
+	exec sql prepare foo2 from :stmt1;
+
+	exec sql set descriptor indesc value 1 DATA = :val1;
+	exec sql set descriptor indesc value 2 DATA = :val2;
+
+	exec sql execute foo2 using sql descriptor indesc into sql descriptor outdesc;
+
+	exec sql disconnect;
+	exec sql get descriptor outdesc value 1 :val1output = DATA;
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	/* Test 2: Try to deallocate all on a non-existent connection */
+	printf("Test 2: deallocate all with non-existent connection\n");
+	exec sql at nonexistent deallocate all;
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	/* Test 3: deallocate on disconnected connection */
+	printf("Test 3: deallocate all on disconnected connection\n");
+	exec sql deallocate all;
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	/* Test 4: Use prepared statement from non-existent connection */
+	printf("Test 4: Use prepared statement from non-existent connection\n");
+	exec sql at nonexistent prepare stmt1 FROM "SELECT 1";
+	exec sql at nonexistent declare cur1 cursor for stmt1;
+	exec sql at nonexistent open cur1;
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	printf("All tests completed !\n");
+
+	return 0;
+}
diff --git a/src/interfaces/ecpg/test/ecpg_schedule b/src/interfaces/ecpg/test/ecpg_schedule
index 363eced2dfb..c5d5939bd46 100644
--- a/src/interfaces/ecpg/test/ecpg_schedule
+++ b/src/interfaces/ecpg/test/ecpg_schedule
@@ -13,6 +13,7 @@ test: connect/test2
 test: connect/test3
 test: connect/test4
 test: connect/test5
+test: connect/test6
 test: pgtypeslib/dt_test
 test: pgtypeslib/dt_test2
 test: pgtypeslib/num_test
diff --git a/src/interfaces/ecpg/test/expected/connect-test6.c b/src/interfaces/ecpg/test/expected/connect-test6.c
new file mode 100644
index 00000000000..072293faf01
--- /dev/null
+++ b/src/interfaces/ecpg/test/expected/connect-test6.c
@@ -0,0 +1,143 @@
+/* Processed by ecpg (regression mode) */
+/* These include files are added by the preprocessor */
+#include <ecpglib.h>
+#include <ecpgerrno.h>
+#include <sqlca.h>
+/* End of automatic include section */
+#define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y))
+
+#line 1 "test6.pgc"
+/*
+ * This test verifies that ecpg functions properly handle NULL connections
+ * (i.e., when a connection name doesn't exist or has been disconnected).
+ * Before the fix, these operations would cause a segmentation fault.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+
+#line 1 "regression.h"
+
+
+
+
+
+
+#line 11 "test6.pgc"
+
+
+int
+main(void)
+{
+/* exec sql begin declare section */
+	   
+	   
+	   
+	   
+
+#line 17 "test6.pgc"
+ int val1output = 2 ;
+ 
+#line 18 "test6.pgc"
+ int val1 = 1 ;
+ 
+#line 19 "test6.pgc"
+ char val2 [ 6 ] = "data1" ;
+ 
+#line 20 "test6.pgc"
+ char * stmt1 = "SELECT * from test1 where a = $1 and b = $2" ;
+/* exec sql end declare section */
+#line 21 "test6.pgc"
+
+
+	ECPGdebug(1, stderr);
+
+	/* Connect to the database */
+	{ ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , "myconn", 0); }
+#line 26 "test6.pgc"
+
+
+	/* Test 1: Try to get descriptor on a disconnected connection */
+	printf("Test 1: Try to get descriptor on a disconnected connection\n");
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table test1 ( a int , b text )", ECPGt_EOIT, ECPGt_EORT);}
+#line 30 "test6.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into test1 ( a , b ) values ( 1 , 'data1' )", ECPGt_EOIT, ECPGt_EORT);}
+#line 31 "test6.pgc"
+
+
+	ECPGallocate_desc(__LINE__, "indesc");
+#line 33 "test6.pgc"
+
+	ECPGallocate_desc(__LINE__, "outdesc");
+#line 34 "test6.pgc"
+
+
+	{ ECPGprepare(__LINE__, NULL, 0, "foo2", stmt1);}
+#line 36 "test6.pgc"
+
+
+	{ ECPGset_desc(__LINE__, "indesc", 1,ECPGd_data,
+	ECPGt_int,&(val1),(long)1,(long)1,sizeof(int), ECPGd_EODT);
+}
+#line 38 "test6.pgc"
+
+	{ ECPGset_desc(__LINE__, "indesc", 2,ECPGd_data,
+	ECPGt_char,(val2),(long)6,(long)1,(6)*sizeof(char), ECPGd_EODT);
+}
+#line 39 "test6.pgc"
+
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_execute, "foo2", 
+	ECPGt_descriptor, "indesc", 1L, 1L, 1L, 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, 
+	ECPGt_descriptor, "outdesc", 1L, 1L, 1L, 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
+#line 41 "test6.pgc"
+
+
+	{ ECPGdisconnect(__LINE__, "CURRENT");}
+#line 43 "test6.pgc"
+
+	{ ECPGget_desc(__LINE__, "outdesc", 1,ECPGd_data,
+	ECPGt_int,&(val1output),(long)1,(long)1,sizeof(int), ECPGd_EODT);
+}
+#line 44 "test6.pgc"
+
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	/* Test 2: Try to deallocate all on a non-existent connection */
+	printf("Test 2: deallocate all with non-existent connection\n");
+	{ ECPGdeallocate_all(__LINE__, 0, "nonexistent");}
+#line 49 "test6.pgc"
+
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	/* Test 3: deallocate on disconnected connection */
+	printf("Test 3: deallocate all on disconnected connection\n");
+	{ ECPGdeallocate_all(__LINE__, 0, NULL);}
+#line 54 "test6.pgc"
+
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	/* Test 4: Use prepared statement from non-existent connection */
+	printf("Test 4: Use prepared statement from non-existent connection\n");
+	{ ECPGprepare(__LINE__, "nonexistent", 0, "stmt1", "SELECT 1");}
+#line 59 "test6.pgc"
+
+	/* declare cur1 cursor for $1 */
+#line 60 "test6.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, "nonexistent", 0, ECPGst_normal, "declare cur1 cursor for $1", 
+	ECPGt_char_variable,(ECPGprepared_statement("nonexistent", "stmt1", __LINE__)),(long)1,(long)1,(1)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);}
+#line 61 "test6.pgc"
+
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	printf("All tests completed !\n");
+
+	return 0;
+}
diff --git a/src/interfaces/ecpg/test/expected/connect-test6.stderr b/src/interfaces/ecpg/test/expected/connect-test6.stderr
new file mode 100644
index 00000000000..38d3590d65c
--- /dev/null
+++ b/src/interfaces/ecpg/test/expected/connect-test6.stderr
@@ -0,0 +1,48 @@
+[NO_PID]: ECPGdebug: set to 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ECPGconnect: opening database ecpg1_regression on <DEFAULT> port <DEFAULT>  
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 30: query: create table test1 ( a int , b text ); with 0 parameter(s) on connection myconn
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 30: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 30: OK: CREATE TABLE
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 31: query: insert into test1 ( a , b ) values ( 1 , 'data1' ); with 0 parameter(s) on connection myconn
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 31: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 31: OK: INSERT 0 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: prepare_common on line 36: name foo2; query: "SELECT * from test1 where a = $1 and b = $2"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 41: query: SELECT * from test1 where a = $1 and b = $2; with 2 parameter(s) on connection myconn
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 41: using PQexecPrepared for "SELECT * from test1 where a = $1 and b = $2"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_free_params on line 41: parameter 1 = 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_free_params on line 41: parameter 2 = data1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 41: correctly got 1 tuples with 2 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 41: putting result (1 tuples) into descriptor outdesc
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: deallocate_one on line 0: name foo2
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_finish: connection myconn closed
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ECPGget_desc: reading items for tuple 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: raising sqlcode -220 on line 44: connection "NULL" does not exist on line 44
+[NO_PID]: sqlca: code: -220, state: 08003
+[NO_PID]: raising sqlcode -220 on line 49: connection "nonexistent" does not exist on line 49
+[NO_PID]: sqlca: code: -220, state: 08003
+[NO_PID]: raising sqlcode -220 on line 54: connection "NULL" does not exist on line 54
+[NO_PID]: sqlca: code: -220, state: 08003
+[NO_PID]: raising sqlcode -220 on line 59: connection "nonexistent" does not exist on line 59
+[NO_PID]: sqlca: code: -220, state: 08003
+[NO_PID]: raising sqlcode -220 on line 62: connection "nonexistent" does not exist on line 62
+[NO_PID]: sqlca: code: -220, state: 08003
+[NO_PID]: raising sqlcode -220 on line 61: connection "nonexistent" does not exist on line 61
+[NO_PID]: sqlca: code: -220, state: 08003
diff --git a/src/interfaces/ecpg/test/expected/connect-test6.stdout b/src/interfaces/ecpg/test/expected/connect-test6.stdout
new file mode 100644
index 00000000000..bf9a2e91051
--- /dev/null
+++ b/src/interfaces/ecpg/test/expected/connect-test6.stdout
@@ -0,0 +1,9 @@
+Test 1: Try to get descriptor on a disconnected connection
+sqlca.sqlcode = -220
+Test 2: deallocate all with non-existent connection
+sqlca.sqlcode = -220
+Test 3: deallocate all on disconnected connection
+sqlca.sqlcode = -220
+Test 4: Use prepared statement from non-existent connection
+sqlca.sqlcode = -220
+All tests completed !
-- 
2.43.0



^ permalink  raw  reply  [nested|flat] 23+ messages in thread

* Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL
  2026-01-19 12:08 Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-03-24 02:34 ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Mahendra Singh Thalor <[email protected]>
  2026-03-24 05:59   ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-09 10:44     ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-13 10:30       ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-15 09:56         ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-16 07:04           ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-18 16:20             ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
@ 2026-04-20 06:01               ` Nishant Sharma <[email protected]>
  2026-04-21 07:09                 ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  0 siblings, 1 reply; 23+ messages in thread

From: Nishant Sharma @ 2026-04-20 06:01 UTC (permalink / raw)
  To: Shruthi Gowda <[email protected]>; +Cc: Mahendra Singh Thalor <[email protected]>; Fujii Masao <[email protected]>; Tom Lane <[email protected]>; pgsql-hackers

Thanks Shruthi for the new test patches!

I can apply v3_test_v15 on both REL_15 and REL_14.

I only have the following concern in the test patches now:-
1. The test1 table in the test case is not being cleaned up.


Regards,
Nishant Sharma,
EDB, Pune.
https://www.enterprisedb.com/


^ permalink  raw  reply  [nested|flat] 23+ messages in thread

* Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL
  2026-01-19 12:08 Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-03-24 02:34 ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Mahendra Singh Thalor <[email protected]>
  2026-03-24 05:59   ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-09 10:44     ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-13 10:30       ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-15 09:56         ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-16 07:04           ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-18 16:20             ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-20 06:01               ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
@ 2026-04-21 07:09                 ` Shruthi Gowda <[email protected]>
  2026-04-22 04:27                   ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  0 siblings, 1 reply; 23+ messages in thread

From: Shruthi Gowda @ 2026-04-21 07:09 UTC (permalink / raw)
  To: Nishant Sharma <[email protected]>; +Cc: Mahendra Singh Thalor <[email protected]>; Fujii Masao <[email protected]>; Tom Lane <[email protected]>; pgsql-hackers

On Mon, Apr 20, 2026 at 11:31 AM Nishant Sharma <
[email protected]> wrote:

> Thanks Shruthi for the new test patches!
>
> I can apply v3_test_v15 on both REL_15 and REL_14.
>
> I only have the following concern in the test patches now:-
> 1. The test1 table in the test case is not being cleaned up.
>
>
> Regards,
> Nishant Sharma,
> EDB, Pune.
> https://www.enterprisedb.com/
>


Hi Nishant, I have updated the test patches by adding a ROLLBACK command
before DISCONNECT. Please find the latest test patches for master through
REL_16 (v4_test) and REL_15 through REL_14 (v4_test_v15).

I am also reattaching the v5 source code patch, which is applicable to all
active branches (master, REL_18, REL_17, REL_16, REL_15, and REL_14).


Attachments:

  [application/octet-stream] v4_test-0001-Tests-for-NULL-connection-validation.patch (12.8K, 3-v4_test-0001-Tests-for-NULL-connection-validation.patch)
  download | inline diff:
From 9f4007c7e370060714a1a0b177bba1b7e79044af Mon Sep 17 00:00:00 2001
From: shruthi gowda <[email protected]>
Date: Tue, 21 Apr 2026 06:14:49 +0000
Subject: [PATCH v4_test] Tests for NULL connection validation

---
 src/interfaces/ecpg/test/connect/.gitignore   |   2 +
 src/interfaces/ecpg/test/connect/Makefile     |   3 +-
 src/interfaces/ecpg/test/connect/meson.build  |   1 +
 src/interfaces/ecpg/test/connect/test6.pgc    |  68 ++++++++
 src/interfaces/ecpg/test/ecpg_schedule        |   1 +
 .../ecpg/test/expected/connect-test6.c        | 146 ++++++++++++++++++
 .../ecpg/test/expected/connect-test6.stderr   |  50 ++++++
 .../ecpg/test/expected/connect-test6.stdout   |   9 ++
 8 files changed, 279 insertions(+), 1 deletion(-)
 create mode 100644 src/interfaces/ecpg/test/connect/test6.pgc
 create mode 100644 src/interfaces/ecpg/test/expected/connect-test6.c
 create mode 100644 src/interfaces/ecpg/test/expected/connect-test6.stderr
 create mode 100644 src/interfaces/ecpg/test/expected/connect-test6.stdout

diff --git a/src/interfaces/ecpg/test/connect/.gitignore b/src/interfaces/ecpg/test/connect/.gitignore
index e0639f3c8d1..02236847444 100644
--- a/src/interfaces/ecpg/test/connect/.gitignore
+++ b/src/interfaces/ecpg/test/connect/.gitignore
@@ -8,3 +8,5 @@
 /test4.c
 /test5
 /test5.c
+/test6
+/test6.c
diff --git a/src/interfaces/ecpg/test/connect/Makefile b/src/interfaces/ecpg/test/connect/Makefile
index 2602d5d286f..17fa2667bf7 100644
--- a/src/interfaces/ecpg/test/connect/Makefile
+++ b/src/interfaces/ecpg/test/connect/Makefile
@@ -7,6 +7,7 @@ TESTS = test1 test1.c \
         test2 test2.c \
         test3 test3.c \
         test4 test4.c \
-        test5 test5.c
+        test5 test5.c \
+        test6 test6.c
 
 all: $(TESTS)
diff --git a/src/interfaces/ecpg/test/connect/meson.build b/src/interfaces/ecpg/test/connect/meson.build
index 591e04bc422..1cc0a928309 100644
--- a/src/interfaces/ecpg/test/connect/meson.build
+++ b/src/interfaces/ecpg/test/connect/meson.build
@@ -6,6 +6,7 @@ pgc_files = [
   'test3',
   'test4',
   'test5',
+  'test6',
 ]
 
 foreach pgc_file : pgc_files
diff --git a/src/interfaces/ecpg/test/connect/test6.pgc b/src/interfaces/ecpg/test/connect/test6.pgc
new file mode 100644
index 00000000000..d2c10dffb03
--- /dev/null
+++ b/src/interfaces/ecpg/test/connect/test6.pgc
@@ -0,0 +1,68 @@
+/*
+ * This test verifies that ecpg functions properly handle NULL connections
+ * (i.e., when a connection name doesn't exist or has been disconnected).
+ * Before the fix, these operations would cause a segmentation fault.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+exec sql include ../regression;
+
+int
+main(void)
+{
+exec sql begin declare section;
+	int val1output = 2;
+	int val1 = 1;
+	char val2[6] = "data1";
+	char *stmt1 = "SELECT * from test1 where a = $1 and b = $2";
+exec sql end declare section;
+
+	ECPGdebug(1, stderr);
+
+	/* Connect to the database */
+	exec sql connect to REGRESSDB1 as myconn;
+
+	/* Test 1: Try to get descriptor on a disconnected connection */
+	printf("Test 1: Try to get descriptor on a disconnected connection\n");
+	exec sql create table test1 (a int, b text);
+	exec sql insert into test1 (a,b) values (1, 'data1');
+
+	exec sql allocate descriptor indesc;
+	exec sql allocate descriptor outdesc;
+
+	exec sql prepare foo2 from :stmt1;
+
+	exec sql set descriptor indesc value 1 DATA = :val1;
+	exec sql set descriptor indesc value 2 DATA = :val2;
+
+	exec sql execute foo2 using sql descriptor indesc into sql descriptor outdesc;
+
+	exec sql rollback;
+	exec sql disconnect;
+	exec sql get descriptor outdesc value 1 :val1output = DATA;
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	/* Test 2: Try to deallocate all on a non-existent connection */
+	printf("Test 2: deallocate all with non-existent connection\n");
+	exec sql at nonexistent deallocate all;
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	/* Test 3: deallocate on disconnected connection */
+	printf("Test 3: deallocate all on disconnected connection\n");
+	exec sql deallocate all;
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	/* Test 4: Use prepared statement from non-existent connection */
+	printf("Test 4: Use prepared statement from non-existent connection\n");
+	exec sql at nonexistent prepare stmt1 FROM "SELECT 1";
+	exec sql at nonexistent declare cur1 cursor for stmt1;
+	exec sql at nonexistent open cur1;
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	printf("All tests completed !\n");
+
+	return 0;
+}
diff --git a/src/interfaces/ecpg/test/ecpg_schedule b/src/interfaces/ecpg/test/ecpg_schedule
index b75e16fde1e..d1f5d9452b7 100644
--- a/src/interfaces/ecpg/test/ecpg_schedule
+++ b/src/interfaces/ecpg/test/ecpg_schedule
@@ -13,6 +13,7 @@ test: connect/test2
 test: connect/test3
 test: connect/test4
 test: connect/test5
+test: connect/test6
 test: pgtypeslib/dt_test
 test: pgtypeslib/dt_test2
 test: pgtypeslib/num_test
diff --git a/src/interfaces/ecpg/test/expected/connect-test6.c b/src/interfaces/ecpg/test/expected/connect-test6.c
new file mode 100644
index 00000000000..eed3c46a38c
--- /dev/null
+++ b/src/interfaces/ecpg/test/expected/connect-test6.c
@@ -0,0 +1,146 @@
+/* Processed by ecpg (regression mode) */
+/* These include files are added by the preprocessor */
+#include <ecpglib.h>
+#include <ecpgerrno.h>
+#include <sqlca.h>
+/* End of automatic include section */
+#define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y))
+
+#line 1 "test6.pgc"
+/*
+ * This test verifies that ecpg functions properly handle NULL connections
+ * (i.e., when a connection name doesn't exist or has been disconnected).
+ * Before the fix, these operations would cause a segmentation fault.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+
+#line 1 "regression.h"
+
+
+
+
+
+
+#line 11 "test6.pgc"
+
+
+int
+main(void)
+{
+/* exec sql begin declare section */
+	   
+	   
+	   
+	   
+
+#line 17 "test6.pgc"
+ int val1output = 2 ;
+ 
+#line 18 "test6.pgc"
+ int val1 = 1 ;
+ 
+#line 19 "test6.pgc"
+ char val2 [ 6 ] = "data1" ;
+ 
+#line 20 "test6.pgc"
+ char * stmt1 = "SELECT * from test1 where a = $1 and b = $2" ;
+/* exec sql end declare section */
+#line 21 "test6.pgc"
+
+
+	ECPGdebug(1, stderr);
+
+	/* Connect to the database */
+	{ ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , "myconn", 0); }
+#line 26 "test6.pgc"
+
+
+	/* Test 1: Try to get descriptor on a disconnected connection */
+	printf("Test 1: Try to get descriptor on a disconnected connection\n");
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table test1 ( a int , b text )", ECPGt_EOIT, ECPGt_EORT);}
+#line 30 "test6.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into test1 ( a , b ) values ( 1 , 'data1' )", ECPGt_EOIT, ECPGt_EORT);}
+#line 31 "test6.pgc"
+
+
+	ECPGallocate_desc(__LINE__, "indesc");
+#line 33 "test6.pgc"
+
+	ECPGallocate_desc(__LINE__, "outdesc");
+#line 34 "test6.pgc"
+
+
+	{ ECPGprepare(__LINE__, NULL, 0, "foo2", stmt1);}
+#line 36 "test6.pgc"
+
+
+	{ ECPGset_desc(__LINE__, "indesc", 1,ECPGd_data,
+	ECPGt_int,&(val1),(long)1,(long)1,sizeof(int), ECPGd_EODT);
+}
+#line 38 "test6.pgc"
+
+	{ ECPGset_desc(__LINE__, "indesc", 2,ECPGd_data,
+	ECPGt_char,(val2),(long)6,(long)1,(6)*sizeof(char), ECPGd_EODT);
+}
+#line 39 "test6.pgc"
+
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_execute, "foo2", 
+	ECPGt_descriptor, "indesc", 1L, 1L, 1L, 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, 
+	ECPGt_descriptor, "outdesc", 1L, 1L, 1L, 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
+#line 41 "test6.pgc"
+
+
+	{ ECPGtrans(__LINE__, NULL, "rollback");}
+#line 43 "test6.pgc"
+
+	{ ECPGdisconnect(__LINE__, "CURRENT");}
+#line 44 "test6.pgc"
+
+	{ ECPGget_desc(__LINE__, "outdesc", 1,ECPGd_data,
+	ECPGt_int,&(val1output),(long)1,(long)1,sizeof(int), ECPGd_EODT);
+}
+#line 45 "test6.pgc"
+
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	/* Test 2: Try to deallocate all on a non-existent connection */
+	printf("Test 2: deallocate all with non-existent connection\n");
+	{ ECPGdeallocate_all(__LINE__, 0, "nonexistent");}
+#line 50 "test6.pgc"
+
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	/* Test 3: deallocate on disconnected connection */
+	printf("Test 3: deallocate all on disconnected connection\n");
+	{ ECPGdeallocate_all(__LINE__, 0, NULL);}
+#line 55 "test6.pgc"
+
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	/* Test 4: Use prepared statement from non-existent connection */
+	printf("Test 4: Use prepared statement from non-existent connection\n");
+	{ ECPGprepare(__LINE__, "nonexistent", 0, "stmt1", "SELECT 1");}
+#line 60 "test6.pgc"
+
+	/* declare cur1 cursor for $1 */
+#line 61 "test6.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, "nonexistent", 0, ECPGst_normal, "declare cur1 cursor for $1", 
+	ECPGt_char_variable,(ECPGprepared_statement("nonexistent", "stmt1", __LINE__)),(long)1,(long)1,(1)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);}
+#line 62 "test6.pgc"
+
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	printf("All tests completed !\n");
+
+	return 0;
+}
diff --git a/src/interfaces/ecpg/test/expected/connect-test6.stderr b/src/interfaces/ecpg/test/expected/connect-test6.stderr
new file mode 100644
index 00000000000..8784d5a9d40
--- /dev/null
+++ b/src/interfaces/ecpg/test/expected/connect-test6.stderr
@@ -0,0 +1,50 @@
+[NO_PID]: ECPGdebug: set to 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ECPGconnect: opening database ecpg1_regression on <DEFAULT> port <DEFAULT>  
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 30: query: create table test1 ( a int , b text ); with 0 parameter(s) on connection myconn
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 30: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 30: OK: CREATE TABLE
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 31: query: insert into test1 ( a , b ) values ( 1 , 'data1' ); with 0 parameter(s) on connection myconn
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 31: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 31: OK: INSERT 0 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: prepare_common on line 36: name foo2; query: "SELECT * from test1 where a = $1 and b = $2"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 41: query: SELECT * from test1 where a = $1 and b = $2; with 2 parameter(s) on connection myconn
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 41: using PQexecPrepared for "SELECT * from test1 where a = $1 and b = $2"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_free_params on line 41: parameter 1 = 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_free_params on line 41: parameter 2 = data1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 41: correctly got 1 tuples with 2 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 41: putting result (1 tuples) into descriptor outdesc
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ECPGtrans on line 43: action "rollback"; connection "myconn"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: deallocate_one on line 0: name foo2
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_finish: connection myconn closed
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ECPGget_desc: reading items for tuple 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: raising sqlcode -220 on line 45: connection "NULL" does not exist on line 45
+[NO_PID]: sqlca: code: -220, state: 08003
+[NO_PID]: raising sqlcode -220 on line 50: connection "nonexistent" does not exist on line 50
+[NO_PID]: sqlca: code: -220, state: 08003
+[NO_PID]: raising sqlcode -220 on line 55: connection "NULL" does not exist on line 55
+[NO_PID]: sqlca: code: -220, state: 08003
+[NO_PID]: raising sqlcode -220 on line 60: connection "nonexistent" does not exist on line 60
+[NO_PID]: sqlca: code: -220, state: 08003
+[NO_PID]: raising sqlcode -220 on line 63: connection "nonexistent" does not exist on line 63
+[NO_PID]: sqlca: code: -220, state: 08003
+[NO_PID]: raising sqlcode -220 on line 62: connection "nonexistent" does not exist on line 62
+[NO_PID]: sqlca: code: -220, state: 08003
diff --git a/src/interfaces/ecpg/test/expected/connect-test6.stdout b/src/interfaces/ecpg/test/expected/connect-test6.stdout
new file mode 100644
index 00000000000..bf9a2e91051
--- /dev/null
+++ b/src/interfaces/ecpg/test/expected/connect-test6.stdout
@@ -0,0 +1,9 @@
+Test 1: Try to get descriptor on a disconnected connection
+sqlca.sqlcode = -220
+Test 2: deallocate all with non-existent connection
+sqlca.sqlcode = -220
+Test 3: deallocate all on disconnected connection
+sqlca.sqlcode = -220
+Test 4: Use prepared statement from non-existent connection
+sqlca.sqlcode = -220
+All tests completed !
-- 
2.43.0



  [application/octet-stream] v4_test_v15-0001-Tests-for-NULL-connection-validation-for.patch (12.4K, 4-v4_test_v15-0001-Tests-for-NULL-connection-validation-for.patch)
  download | inline diff:
From fbaf5515fb9f72871885bcf571396bae25f92c25 Mon Sep 17 00:00:00 2001
From: shruthi gowda <[email protected]>
Date: Tue, 21 Apr 2026 07:00:49 +0000
Subject: [PATCH v4_test_v15] Tests for NULL connection validation for V15

---
 src/interfaces/ecpg/test/connect/.gitignore   |   2 +
 src/interfaces/ecpg/test/connect/Makefile     |   3 +-
 src/interfaces/ecpg/test/connect/test6.pgc    |  68 ++++++++
 src/interfaces/ecpg/test/ecpg_schedule        |   1 +
 .../ecpg/test/expected/connect-test6.c        | 146 ++++++++++++++++++
 .../ecpg/test/expected/connect-test6.stderr   |  50 ++++++
 .../ecpg/test/expected/connect-test6.stdout   |   9 ++
 7 files changed, 278 insertions(+), 1 deletion(-)
 create mode 100644 src/interfaces/ecpg/test/connect/test6.pgc
 create mode 100644 src/interfaces/ecpg/test/expected/connect-test6.c
 create mode 100644 src/interfaces/ecpg/test/expected/connect-test6.stderr
 create mode 100644 src/interfaces/ecpg/test/expected/connect-test6.stdout

diff --git a/src/interfaces/ecpg/test/connect/.gitignore b/src/interfaces/ecpg/test/connect/.gitignore
index e0639f3c8d1..02236847444 100644
--- a/src/interfaces/ecpg/test/connect/.gitignore
+++ b/src/interfaces/ecpg/test/connect/.gitignore
@@ -8,3 +8,5 @@
 /test4.c
 /test5
 /test5.c
+/test6
+/test6.c
diff --git a/src/interfaces/ecpg/test/connect/Makefile b/src/interfaces/ecpg/test/connect/Makefile
index 2602d5d286f..17fa2667bf7 100644
--- a/src/interfaces/ecpg/test/connect/Makefile
+++ b/src/interfaces/ecpg/test/connect/Makefile
@@ -7,6 +7,7 @@ TESTS = test1 test1.c \
         test2 test2.c \
         test3 test3.c \
         test4 test4.c \
-        test5 test5.c
+        test5 test5.c \
+        test6 test6.c
 
 all: $(TESTS)
diff --git a/src/interfaces/ecpg/test/connect/test6.pgc b/src/interfaces/ecpg/test/connect/test6.pgc
new file mode 100644
index 00000000000..d2c10dffb03
--- /dev/null
+++ b/src/interfaces/ecpg/test/connect/test6.pgc
@@ -0,0 +1,68 @@
+/*
+ * This test verifies that ecpg functions properly handle NULL connections
+ * (i.e., when a connection name doesn't exist or has been disconnected).
+ * Before the fix, these operations would cause a segmentation fault.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+exec sql include ../regression;
+
+int
+main(void)
+{
+exec sql begin declare section;
+	int val1output = 2;
+	int val1 = 1;
+	char val2[6] = "data1";
+	char *stmt1 = "SELECT * from test1 where a = $1 and b = $2";
+exec sql end declare section;
+
+	ECPGdebug(1, stderr);
+
+	/* Connect to the database */
+	exec sql connect to REGRESSDB1 as myconn;
+
+	/* Test 1: Try to get descriptor on a disconnected connection */
+	printf("Test 1: Try to get descriptor on a disconnected connection\n");
+	exec sql create table test1 (a int, b text);
+	exec sql insert into test1 (a,b) values (1, 'data1');
+
+	exec sql allocate descriptor indesc;
+	exec sql allocate descriptor outdesc;
+
+	exec sql prepare foo2 from :stmt1;
+
+	exec sql set descriptor indesc value 1 DATA = :val1;
+	exec sql set descriptor indesc value 2 DATA = :val2;
+
+	exec sql execute foo2 using sql descriptor indesc into sql descriptor outdesc;
+
+	exec sql rollback;
+	exec sql disconnect;
+	exec sql get descriptor outdesc value 1 :val1output = DATA;
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	/* Test 2: Try to deallocate all on a non-existent connection */
+	printf("Test 2: deallocate all with non-existent connection\n");
+	exec sql at nonexistent deallocate all;
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	/* Test 3: deallocate on disconnected connection */
+	printf("Test 3: deallocate all on disconnected connection\n");
+	exec sql deallocate all;
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	/* Test 4: Use prepared statement from non-existent connection */
+	printf("Test 4: Use prepared statement from non-existent connection\n");
+	exec sql at nonexistent prepare stmt1 FROM "SELECT 1";
+	exec sql at nonexistent declare cur1 cursor for stmt1;
+	exec sql at nonexistent open cur1;
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	printf("All tests completed !\n");
+
+	return 0;
+}
diff --git a/src/interfaces/ecpg/test/ecpg_schedule b/src/interfaces/ecpg/test/ecpg_schedule
index 363eced2dfb..c5d5939bd46 100644
--- a/src/interfaces/ecpg/test/ecpg_schedule
+++ b/src/interfaces/ecpg/test/ecpg_schedule
@@ -13,6 +13,7 @@ test: connect/test2
 test: connect/test3
 test: connect/test4
 test: connect/test5
+test: connect/test6
 test: pgtypeslib/dt_test
 test: pgtypeslib/dt_test2
 test: pgtypeslib/num_test
diff --git a/src/interfaces/ecpg/test/expected/connect-test6.c b/src/interfaces/ecpg/test/expected/connect-test6.c
new file mode 100644
index 00000000000..eed3c46a38c
--- /dev/null
+++ b/src/interfaces/ecpg/test/expected/connect-test6.c
@@ -0,0 +1,146 @@
+/* Processed by ecpg (regression mode) */
+/* These include files are added by the preprocessor */
+#include <ecpglib.h>
+#include <ecpgerrno.h>
+#include <sqlca.h>
+/* End of automatic include section */
+#define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y))
+
+#line 1 "test6.pgc"
+/*
+ * This test verifies that ecpg functions properly handle NULL connections
+ * (i.e., when a connection name doesn't exist or has been disconnected).
+ * Before the fix, these operations would cause a segmentation fault.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+
+#line 1 "regression.h"
+
+
+
+
+
+
+#line 11 "test6.pgc"
+
+
+int
+main(void)
+{
+/* exec sql begin declare section */
+	   
+	   
+	   
+	   
+
+#line 17 "test6.pgc"
+ int val1output = 2 ;
+ 
+#line 18 "test6.pgc"
+ int val1 = 1 ;
+ 
+#line 19 "test6.pgc"
+ char val2 [ 6 ] = "data1" ;
+ 
+#line 20 "test6.pgc"
+ char * stmt1 = "SELECT * from test1 where a = $1 and b = $2" ;
+/* exec sql end declare section */
+#line 21 "test6.pgc"
+
+
+	ECPGdebug(1, stderr);
+
+	/* Connect to the database */
+	{ ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , "myconn", 0); }
+#line 26 "test6.pgc"
+
+
+	/* Test 1: Try to get descriptor on a disconnected connection */
+	printf("Test 1: Try to get descriptor on a disconnected connection\n");
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table test1 ( a int , b text )", ECPGt_EOIT, ECPGt_EORT);}
+#line 30 "test6.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into test1 ( a , b ) values ( 1 , 'data1' )", ECPGt_EOIT, ECPGt_EORT);}
+#line 31 "test6.pgc"
+
+
+	ECPGallocate_desc(__LINE__, "indesc");
+#line 33 "test6.pgc"
+
+	ECPGallocate_desc(__LINE__, "outdesc");
+#line 34 "test6.pgc"
+
+
+	{ ECPGprepare(__LINE__, NULL, 0, "foo2", stmt1);}
+#line 36 "test6.pgc"
+
+
+	{ ECPGset_desc(__LINE__, "indesc", 1,ECPGd_data,
+	ECPGt_int,&(val1),(long)1,(long)1,sizeof(int), ECPGd_EODT);
+}
+#line 38 "test6.pgc"
+
+	{ ECPGset_desc(__LINE__, "indesc", 2,ECPGd_data,
+	ECPGt_char,(val2),(long)6,(long)1,(6)*sizeof(char), ECPGd_EODT);
+}
+#line 39 "test6.pgc"
+
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_execute, "foo2", 
+	ECPGt_descriptor, "indesc", 1L, 1L, 1L, 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, 
+	ECPGt_descriptor, "outdesc", 1L, 1L, 1L, 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);}
+#line 41 "test6.pgc"
+
+
+	{ ECPGtrans(__LINE__, NULL, "rollback");}
+#line 43 "test6.pgc"
+
+	{ ECPGdisconnect(__LINE__, "CURRENT");}
+#line 44 "test6.pgc"
+
+	{ ECPGget_desc(__LINE__, "outdesc", 1,ECPGd_data,
+	ECPGt_int,&(val1output),(long)1,(long)1,sizeof(int), ECPGd_EODT);
+}
+#line 45 "test6.pgc"
+
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	/* Test 2: Try to deallocate all on a non-existent connection */
+	printf("Test 2: deallocate all with non-existent connection\n");
+	{ ECPGdeallocate_all(__LINE__, 0, "nonexistent");}
+#line 50 "test6.pgc"
+
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	/* Test 3: deallocate on disconnected connection */
+	printf("Test 3: deallocate all on disconnected connection\n");
+	{ ECPGdeallocate_all(__LINE__, 0, NULL);}
+#line 55 "test6.pgc"
+
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	/* Test 4: Use prepared statement from non-existent connection */
+	printf("Test 4: Use prepared statement from non-existent connection\n");
+	{ ECPGprepare(__LINE__, "nonexistent", 0, "stmt1", "SELECT 1");}
+#line 60 "test6.pgc"
+
+	/* declare cur1 cursor for $1 */
+#line 61 "test6.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, "nonexistent", 0, ECPGst_normal, "declare cur1 cursor for $1", 
+	ECPGt_char_variable,(ECPGprepared_statement("nonexistent", "stmt1", __LINE__)),(long)1,(long)1,(1)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, ECPGt_EORT);}
+#line 62 "test6.pgc"
+
+	printf("sqlca.sqlcode = %ld\n", sqlca.sqlcode);
+
+	printf("All tests completed !\n");
+
+	return 0;
+}
diff --git a/src/interfaces/ecpg/test/expected/connect-test6.stderr b/src/interfaces/ecpg/test/expected/connect-test6.stderr
new file mode 100644
index 00000000000..8784d5a9d40
--- /dev/null
+++ b/src/interfaces/ecpg/test/expected/connect-test6.stderr
@@ -0,0 +1,50 @@
+[NO_PID]: ECPGdebug: set to 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ECPGconnect: opening database ecpg1_regression on <DEFAULT> port <DEFAULT>  
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 30: query: create table test1 ( a int , b text ); with 0 parameter(s) on connection myconn
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 30: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 30: OK: CREATE TABLE
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 31: query: insert into test1 ( a , b ) values ( 1 , 'data1' ); with 0 parameter(s) on connection myconn
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 31: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 31: OK: INSERT 0 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: prepare_common on line 36: name foo2; query: "SELECT * from test1 where a = $1 and b = $2"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 41: query: SELECT * from test1 where a = $1 and b = $2; with 2 parameter(s) on connection myconn
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 41: using PQexecPrepared for "SELECT * from test1 where a = $1 and b = $2"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_free_params on line 41: parameter 1 = 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_free_params on line 41: parameter 2 = data1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 41: correctly got 1 tuples with 2 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 41: putting result (1 tuples) into descriptor outdesc
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ECPGtrans on line 43: action "rollback"; connection "myconn"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: deallocate_one on line 0: name foo2
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_finish: connection myconn closed
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ECPGget_desc: reading items for tuple 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: raising sqlcode -220 on line 45: connection "NULL" does not exist on line 45
+[NO_PID]: sqlca: code: -220, state: 08003
+[NO_PID]: raising sqlcode -220 on line 50: connection "nonexistent" does not exist on line 50
+[NO_PID]: sqlca: code: -220, state: 08003
+[NO_PID]: raising sqlcode -220 on line 55: connection "NULL" does not exist on line 55
+[NO_PID]: sqlca: code: -220, state: 08003
+[NO_PID]: raising sqlcode -220 on line 60: connection "nonexistent" does not exist on line 60
+[NO_PID]: sqlca: code: -220, state: 08003
+[NO_PID]: raising sqlcode -220 on line 63: connection "nonexistent" does not exist on line 63
+[NO_PID]: sqlca: code: -220, state: 08003
+[NO_PID]: raising sqlcode -220 on line 62: connection "nonexistent" does not exist on line 62
+[NO_PID]: sqlca: code: -220, state: 08003
diff --git a/src/interfaces/ecpg/test/expected/connect-test6.stdout b/src/interfaces/ecpg/test/expected/connect-test6.stdout
new file mode 100644
index 00000000000..bf9a2e91051
--- /dev/null
+++ b/src/interfaces/ecpg/test/expected/connect-test6.stdout
@@ -0,0 +1,9 @@
+Test 1: Try to get descriptor on a disconnected connection
+sqlca.sqlcode = -220
+Test 2: deallocate all with non-existent connection
+sqlca.sqlcode = -220
+Test 3: deallocate all on disconnected connection
+sqlca.sqlcode = -220
+Test 4: Use prepared statement from non-existent connection
+sqlca.sqlcode = -220
+All tests completed !
-- 
2.43.0



  [application/octet-stream] v5-0001-Add-missing-connection-validation-in-ECPG.patch (3.5K, 5-v5-0001-Add-missing-connection-validation-in-ECPG.patch)
  download | inline diff:
From 858e2bc8ecde70b704173d28993a977410136dab Mon Sep 17 00:00:00 2001
From: shruthi gowda <[email protected]>
Date: Wed, 15 Apr 2026 08:34:18 +0000
Subject: [PATCH v5] Add missing connection validation in ECPG

ECPGdeallocate_all(), ECPGprepared_statement(), ECPGget_desc(), and
ecpg_freeStmtCacheEntry() could crash or misbehave when operating on
NULL or invalid connections. Add proper connection validation to
prevent dereferencing NULL pointers.
---
 src/interfaces/ecpg/ecpglib/descriptor.c | 12 ++++++++++--
 src/interfaces/ecpg/ecpglib/prepare.c    | 25 ++++++++++++++++--------
 2 files changed, 27 insertions(+), 10 deletions(-)

diff --git a/src/interfaces/ecpg/ecpglib/descriptor.c b/src/interfaces/ecpg/ecpglib/descriptor.c
index 39cd5130ec9..1ad5f2d88cc 100644
--- a/src/interfaces/ecpg/ecpglib/descriptor.c
+++ b/src/interfaces/ecpg/ecpglib/descriptor.c
@@ -476,6 +476,16 @@ ECPGget_desc(int lineno, const char *desc_name, int index,...)
 		memset(&stmt, 0, sizeof stmt);
 		stmt.lineno = lineno;
 
+		/* desperate try to guess something sensible */
+		stmt.connection = ecpg_get_connection(NULL);
+		if (stmt.connection == NULL)
+		{
+			ecpg_raise(lineno, ECPG_NO_CONN, ECPG_SQLSTATE_CONNECTION_DOES_NOT_EXIST,
+					   ecpg_gettext("NULL"));
+			va_end(args);
+			return false;
+		}
+
 		/* Make sure we do NOT honor the locale for numeric input */
 		/* since the database gives the standard decimal point */
 		/* (see comments in execute.c) */
@@ -505,8 +515,6 @@ ECPGget_desc(int lineno, const char *desc_name, int index,...)
 		setlocale(LC_NUMERIC, "C");
 #endif
 
-		/* desperate try to guess something sensible */
-		stmt.connection = ecpg_get_connection(NULL);
 		ecpg_store_result(ECPGresult, index, &stmt, &data_var);
 
 #ifdef HAVE_USELOCALE
diff --git a/src/interfaces/ecpg/ecpglib/prepare.c b/src/interfaces/ecpg/ecpglib/prepare.c
index 5c7c5397535..f9489044724 100644
--- a/src/interfaces/ecpg/ecpglib/prepare.c
+++ b/src/interfaces/ecpg/ecpglib/prepare.c
@@ -381,8 +381,12 @@ ecpg_deallocate_all_conn(int lineno, enum COMPAT_MODE c, struct connection *con)
 bool
 ECPGdeallocate_all(int lineno, int compat, const char *connection_name)
 {
-	return ecpg_deallocate_all_conn(lineno, compat,
-									ecpg_get_connection(connection_name));
+	struct connection *con = ecpg_get_connection(connection_name);
+
+	if (!ecpg_init(con, connection_name, lineno))
+		return false;
+
+	return ecpg_deallocate_all_conn(lineno, compat, con);
 }
 
 char *
@@ -395,13 +399,15 @@ ecpg_prepared(const char *name, struct connection *con)
 }
 
 /* return the prepared statement */
-/* lineno is not used here, but kept in to not break API */
 char *
 ECPGprepared_statement(const char *connection_name, const char *name, int lineno)
 {
-	(void) lineno;				/* keep the compiler quiet */
+	struct connection *con = ecpg_get_connection(connection_name);
+
+	if (!ecpg_init(con, connection_name, lineno))
+		return NULL;
 
-	return ecpg_prepared(name, ecpg_get_connection(connection_name));
+	return ecpg_prepared(name, con);
 }
 
 /*
@@ -499,9 +505,12 @@ ecpg_freeStmtCacheEntry(int lineno, int compat,
 	con = ecpg_get_connection(entry->connection);
 
 	/* free the 'prepared_statement' list entry */
-	this = ecpg_find_prepared_statement(entry->stmtID, con, &prev);
-	if (this && !deallocate_one(lineno, compat, con, prev, this))
-		return -1;
+	if (con)
+	{
+		this = ecpg_find_prepared_statement(entry->stmtID, con, &prev);
+		if (this && !deallocate_one(lineno, compat, con, prev, this))
+			return -1;
+	}
 
 	entry->stmtID[0] = '\0';
 
-- 
2.43.0



^ permalink  raw  reply  [nested|flat] 23+ messages in thread

* Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL
  2026-01-19 12:08 Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-03-24 02:34 ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Mahendra Singh Thalor <[email protected]>
  2026-03-24 05:59   ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-09 10:44     ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-13 10:30       ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-15 09:56         ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-16 07:04           ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-18 16:20             ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-20 06:01               ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-21 07:09                 ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
@ 2026-04-22 04:27                   ` Nishant Sharma <[email protected]>
  2026-05-01 19:20                     ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Andrew Dunstan <[email protected]>
  0 siblings, 1 reply; 23+ messages in thread

From: Nishant Sharma @ 2026-04-22 04:27 UTC (permalink / raw)
  To: Shruthi Gowda <[email protected]>; +Cc: Mahendra Singh Thalor <[email protected]>; Fujii Masao <[email protected]>; Tom Lane <[email protected]>; pgsql-hackers

Thanks Shruthi!

v5 code, v4_test and v4_test_15 patches look good to me.

I checked ECPG regression on master, REL_18, REL_17, REL_16, REL_15, REL_14
using both make and meson.

I have finished my review work on the patches. Thank you!


Regards,
Nishant Sharma,
EDB, Pune.
https://www.enterprisedb.com/


^ permalink  raw  reply  [nested|flat] 23+ messages in thread

* Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL
  2026-01-19 12:08 Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-03-24 02:34 ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Mahendra Singh Thalor <[email protected]>
  2026-03-24 05:59   ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-09 10:44     ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-13 10:30       ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-15 09:56         ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-16 07:04           ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-18 16:20             ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-20 06:01               ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-21 07:09                 ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-22 04:27                   ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
@ 2026-05-01 19:20                     ` Andrew Dunstan <[email protected]>
  2026-05-05 20:00                       ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Alexander Lakhin <[email protected]>
  2026-05-05 20:32                       ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Tom Lane <[email protected]>
  2026-05-23 18:59                       ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL SATYANARAYANA NARLAPURAM <[email protected]>
  0 siblings, 3 replies; 23+ messages in thread

From: Andrew Dunstan @ 2026-05-01 19:20 UTC (permalink / raw)
  To: Nishant Sharma <[email protected]>; +Cc: Shruthi Gowda <[email protected]>; Mahendra Singh Thalor <[email protected]>; Fujii Masao <[email protected]>; Tom Lane <[email protected]>; pgsql-hackers

On Wed, Apr 22, 2026 at 12:27 AM Nishant Sharma <
[email protected]> wrote:

> Thanks Shruthi!
>
> v5 code, v4_test and v4_test_15 patches look good to me.
>
> I checked ECPG regression on master, REL_18, REL_17, REL_16, REL_15,
> REL_14 using both make and meson.
>
> I have finished my review work on the patches. Thank you!
>
>
>
>
Thanks, everybody, pushed (as combined patches)

cheers

andrew


^ permalink  raw  reply  [nested|flat] 23+ messages in thread

* Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL
  2026-01-19 12:08 Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-03-24 02:34 ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Mahendra Singh Thalor <[email protected]>
  2026-03-24 05:59   ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-09 10:44     ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-13 10:30       ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-15 09:56         ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-16 07:04           ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-18 16:20             ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-20 06:01               ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-21 07:09                 ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-22 04:27                   ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-05-01 19:20                     ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Andrew Dunstan <[email protected]>
@ 2026-05-05 20:00                       ` Alexander Lakhin <[email protected]>
  2 siblings, 0 replies; 23+ messages in thread

From: Alexander Lakhin @ 2026-05-05 20:00 UTC (permalink / raw)
  To: Andrew Dunstan <[email protected]>; Nishant Sharma <[email protected]>; +Cc: Shruthi Gowda <[email protected]>; Mahendra Singh Thalor <[email protected]>; Fujii Masao <[email protected]>; Tom Lane <[email protected]>; pgsql-hackers

Hello hackers,

01.05.2026 22:20, Andrew Dunstan wrote:
>
> On Wed, Apr 22, 2026 at 12:27 AM Nishant Sharma <[email protected]> wrote:
>
>     Thanks Shruthi!
>
>     v5 code, v4_test and v4_test_15 patches look good to me.
>
>     I checked ECPG regression on master, REL_18, REL_17, REL_16, REL_15, REL_14 using both make and meson.
>
>     I have finished my review work on the patches. Thank you!
>
>
> Thanks, everybody, pushed (as combined patches)

Despite this improvement committed, dikkop keeps producing segfaults
during ecpg test, e.g., [1], [2]:
ok 62        - thread/thread_implicit                    224 ms
not ok 63    - thread/prep                               116 ms
# (test process was terminated by signal 11: Segmentation fault)
ok 64        - thread/alloc                              406 ms

There is no other useful information in the log, so it's not clear what's
wrong with that animal (no other gives us such failures), but I could
produce something similar (on FreeBSD and Linux) with:
echo "max_connections = 10" >/tmp/temp.config; TEMP_CONFIG=/tmp/temp.config gmake -s check -C src/interfaces/ecpg/test

not ok 64    - thread/prep                                29 ms
# (test process was terminated by signal 11: Segmentation fault)

not ok 65    - thread/alloc                               27 ms
# (test process was terminated by signal 11: Segmentation fault)

gdb src/interfaces/ecpg/test/thread/prep src/interfaces/ecpg/test/core.3371028
Core was generated by `.../src/interfaces/ecpg/test/thread/prep'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x00007478ad3a8301 in deallocate_one (lineno=lineno@entry=45, c=c@entry=ECPG_COMPAT_PGSQL, 
con=con@entry=0x747888000ca0, prev=0x0, this=0x74788800ad40)
     at prepare.c:313
313 this->stmt->connection->connection,
[Current thread is 1 (Thread 0x7478a1c006c0 (LWP 3371041))]
(gdb) bt
#0  0x00007478ad3a8301 in deallocate_one (lineno=lineno@entry=45, c=c@entry=ECPG_COMPAT_PGSQL, 
con=con@entry=0x747888000ca0, prev=0x0, this=0x74788800ad40)
     at prepare.c:313
#1  0x00007478ad3a8a32 in ECPGprepare (lineno=lineno@entry=45, connection_name=connection_name@entry=0x0, 
questionmarks=questionmarks@entry=false,
     name=name@entry=0x5d934a41b024 "i", variable=variable@entry=0x7478a1bffdb0 "INSERT INTO T VALUES ( ? )") at 
prepare.c:264
#2  0x00005d934a41a536 in fn (arg=<optimized out>) at .../src/interfaces/ecpg/test/thread/prep.pgc:45
#3  0x00007478ad09caa4 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:447
#4  0x00007478ad129c3c in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:78

(gdb) p this->stmt
$1 = (struct statement *) 0x242028205345554c
(gdb) p this->stmt->connection
Cannot access memory at address 0x2420282053455564

gdb src/interfaces/ecpg/test/thread/alloc src/interfaces/ecpg/test/core.3371068
Core was generated by `.../src/interfaces/ecpg/test/thread/alloc'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  pqRowProcessor (conn=conn@entry=0x7962f4000d60, errmsgp=errmsgp@entry=0x7963151ffbd0) at fe-exec.c:1226
1226            int                     nfields = res->numAttributes;
[Current thread is 1 (Thread 0x7963152006c0 (LWP 3371075))]
(gdb) bt
#0  pqRowProcessor (conn=conn@entry=0x7962f4000d60, errmsgp=errmsgp@entry=0x7963151ffbd0) at fe-exec.c:1226
#1  0x00007963188e9d44 in getAnotherTuple (conn=conn@entry=0x7962f4000d60, msgLength=14) at fe-protocol3.c:849
#2  0x00007963188eb42b in pqParseInput3 (conn=conn@entry=0x7962f4000d60) at fe-protocol3.c:388
#3  0x00007963188e0e69 in parseInput (conn=conn@entry=0x7962f4000d60) at fe-exec.c:2039
#4  0x00007963188e3d74 in PQgetResult (conn=conn@entry=0x7962f4000d60) at fe-exec.c:2125
#5  0x00007963188e3fec in PQexecStart (conn=conn@entry=0x7962f4000d60) at fe-exec.c:2386
#6  0x00007963188e40a7 in PQexec (conn=0x7962f4000d60, query=0x7962e8000ca0 "select relname from pg_class where relname 
= 'pg_class'") at fe-exec.c:2281
#7  0x0000796318948620 in ecpg_execute (stmt=0x7962e8009e60) at execute.c:1619
#8  0x00007963189494fc in ecpg_do (lineno=<optimized out>, compat=<optimized out>, force_indicator=<optimized out>, 
connection_name=<optimized out>,
     questionmarks=questionmarks@entry=false, st=<optimized out>, query=0x5a5947b97028 "select relname from pg_class 
where relname = 'pg_class'",
     args=0x7963151ffcf0) at execute.c:2273
#9  0x00007963189495b7 in ECPGdo (lineno=lineno@entry=45, compat=compat@entry=0, force_indicator=force_indicator@entry=1,
     connection_name=connection_name@entry=0x0, questionmarks=questionmarks@entry=false, st=st@entry=0,
     query=0x5a5947b97028 "select relname from pg_class where relname = 'pg_class'") at execute.c:2298
#10 0x00005a5947b963b8 in fn (arg=<optimized out>) at .../src/interfaces/ecpg/test/thread/alloc.pgc:45
#11 0x000079631869caa4 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:447
#12 0x0000796318729c3c in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:78
(gdb) p conn
$1 = (PGconn *) 0x7962f4000d60
(gdb) p conn->result
$2 = (PGresult *) 0x0

Could you please look if such crashes can be prevented too?

[1] https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=dikkop&dt=2026-05-04%2010%3A00%3A10
[2] https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=dikkop&dt=2026-05-03%2021%3A25%3A17

Best regards,
Alexander

^ permalink  raw  reply  [nested|flat] 23+ messages in thread

* Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL
  2026-01-19 12:08 Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-03-24 02:34 ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Mahendra Singh Thalor <[email protected]>
  2026-03-24 05:59   ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-09 10:44     ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-13 10:30       ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-15 09:56         ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-16 07:04           ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-18 16:20             ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-20 06:01               ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-21 07:09                 ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-22 04:27                   ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-05-01 19:20                     ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Andrew Dunstan <[email protected]>
@ 2026-05-05 20:32                       ` Tom Lane <[email protected]>
  2026-05-05 21:36                         ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Andrew Dunstan <[email protected]>
  2 siblings, 1 reply; 23+ messages in thread

From: Tom Lane @ 2026-05-05 20:32 UTC (permalink / raw)
  To: Alexander Lakhin <[email protected]>; +Cc: Andrew Dunstan <[email protected]>; Nishant Sharma <[email protected]>; Shruthi Gowda <[email protected]>; Mahendra Singh Thalor <[email protected]>; Fujii Masao <[email protected]>; pgsql-hackers

Alexander Lakhin <[email protected]> writes:
> There is no other useful information in the log, so it's not clear what's
> wrong with that animal (no other gives us such failures), but I could
> produce something similar (on FreeBSD and Linux) with:
> echo "max_connections = 10" >/tmp/temp.config; TEMP_CONFIG=/tmp/temp.config gmake -s check -C src/interfaces/ecpg/test

Yes, I can also reproduce problems with the ecpg tests at
max_connections = 10.  For me, thread/prep segfaults but thread/alloc
just seems to hang indefinitely.  (thread/prep sometimes does too.)
These issues are not new; v18 does the same.  The reporting is a
bit different but I think that's from pg_regress changes not ecpg.

Looking at the postmaster log, I see

2026-05-05 16:11:06.509 EDT [682116] FATAL:  sorry, too many clients already

which is unsurprising in this situation, but apparently these tests
don't handle a connection failure well at all.

There's no such message in dikkop's log, so that may be an unrelated problem.

BTW, reducing max_connections to 5 causes several other tests to fail,
but in unsurprising ways, like

# +SQL error: could not connect to database "ecpg1_regression" on line 107
# +SQL error: could not connect to database "ecpg1_regression" on line 107
# +SQL error: could not connect to database "ecpg1_regression" on line 107
# +SQL error: could not connect to database "ecpg1_regression" on line 107


			regards, tom lane





^ permalink  raw  reply  [nested|flat] 23+ messages in thread

* Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL
  2026-01-19 12:08 Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-03-24 02:34 ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Mahendra Singh Thalor <[email protected]>
  2026-03-24 05:59   ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-09 10:44     ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-13 10:30       ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-15 09:56         ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-16 07:04           ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-18 16:20             ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-20 06:01               ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-21 07:09                 ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-22 04:27                   ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-05-01 19:20                     ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Andrew Dunstan <[email protected]>
  2026-05-05 20:32                       ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Tom Lane <[email protected]>
@ 2026-05-05 21:36                         ` Andrew Dunstan <[email protected]>
  2026-05-06 11:55                           ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Andrew Dunstan <[email protected]>
  2026-05-06 14:58                           ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Tom Lane <[email protected]>
  0 siblings, 2 replies; 23+ messages in thread

From: Andrew Dunstan @ 2026-05-05 21:36 UTC (permalink / raw)
  To: Tom Lane <[email protected]>; Alexander Lakhin <[email protected]>; +Cc: Nishant Sharma <[email protected]>; Shruthi Gowda <[email protected]>; Mahendra Singh Thalor <[email protected]>; Fujii Masao <[email protected]>; pgsql-hackers


On 2026-05-05 Tu 4:32 PM, Tom Lane wrote:
> Alexander Lakhin <[email protected]> writes:
>> There is no other useful information in the log, so it's not clear what's
>> wrong with that animal (no other gives us such failures), but I could
>> produce something similar (on FreeBSD and Linux) with:
>> echo "max_connections = 10" >/tmp/temp.config; TEMP_CONFIG=/tmp/temp.config gmake -s check -C src/interfaces/ecpg/test
> Yes, I can also reproduce problems with the ecpg tests at
> max_connections = 10.  For me, thread/prep segfaults but thread/alloc
> just seems to hang indefinitely.  (thread/prep sometimes does too.)
> These issues are not new; v18 does the same.  The reporting is a
> bit different but I think that's from pg_regress changes not ecpg.
>
> Looking at the postmaster log, I see
>
> 2026-05-05 16:11:06.509 EDT [682116] FATAL:  sorry, too many clients already
>
> which is unsurprising in this situation, but apparently these tests
> don't handle a connection failure well at all.
>
> There's no such message in dikkop's log, so that may be an unrelated problem.
>
> BTW, reducing max_connections to 5 causes several other tests to fail,
> but in unsurprising ways, like
>
> # +SQL error: could not connect to database "ecpg1_regression" on line 107
> # +SQL error: could not connect to database "ecpg1_regression" on line 107
> # +SQL error: could not connect to database "ecpg1_regression" on line 107
> # +SQL error: could not connect to database "ecpg1_regression" on line 107
>
>
> 			


Ugh. I will do some digging.


cheers


andrew


--
Andrew Dunstan
EDB: https://www.enterprisedb.com






^ permalink  raw  reply  [nested|flat] 23+ messages in thread

* Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL
  2026-01-19 12:08 Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-03-24 02:34 ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Mahendra Singh Thalor <[email protected]>
  2026-03-24 05:59   ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-09 10:44     ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-13 10:30       ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-15 09:56         ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-16 07:04           ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-18 16:20             ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-20 06:01               ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-21 07:09                 ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-22 04:27                   ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-05-01 19:20                     ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Andrew Dunstan <[email protected]>
  2026-05-05 20:32                       ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Tom Lane <[email protected]>
  2026-05-05 21:36                         ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Andrew Dunstan <[email protected]>
@ 2026-05-06 11:55                           ` Andrew Dunstan <[email protected]>
  1 sibling, 0 replies; 23+ messages in thread

From: Andrew Dunstan @ 2026-05-06 11:55 UTC (permalink / raw)
  To: Tom Lane <[email protected]>; Alexander Lakhin <[email protected]>; +Cc: Nishant Sharma <[email protected]>; Shruthi Gowda <[email protected]>; Mahendra Singh Thalor <[email protected]>; Fujii Masao <[email protected]>; pgsql-hackers


On 2026-05-05 Tu 5:36 PM, Andrew Dunstan wrote:
>
> On 2026-05-05 Tu 4:32 PM, Tom Lane wrote:
>> Alexander Lakhin <[email protected]> writes:
>>> There is no other useful information in the log, so it's not clear 
>>> what's
>>> wrong with that animal (no other gives us such failures), but I could
>>> produce something similar (on FreeBSD and Linux) with:
>>> echo "max_connections = 10" >/tmp/temp.config; 
>>> TEMP_CONFIG=/tmp/temp.config gmake -s check -C src/interfaces/ecpg/test
>> Yes, I can also reproduce problems with the ecpg tests at
>> max_connections = 10.  For me, thread/prep segfaults but thread/alloc
>> just seems to hang indefinitely.  (thread/prep sometimes does too.)
>> These issues are not new; v18 does the same.  The reporting is a
>> bit different but I think that's from pg_regress changes not ecpg.
>>
>> Looking at the postmaster log, I see
>>
>> 2026-05-05 16:11:06.509 EDT [682116] FATAL:  sorry, too many clients 
>> already
>>
>> which is unsurprising in this situation, but apparently these tests
>> don't handle a connection failure well at all.
>>
>> There's no such message in dikkop's log, so that may be an unrelated 
>> problem.
>>
>> BTW, reducing max_connections to 5 causes several other tests to fail,
>> but in unsurprising ways, like
>>
>> # +SQL error: could not connect to database "ecpg1_regression" on 
>> line 107
>> # +SQL error: could not connect to database "ecpg1_regression" on 
>> line 107
>> # +SQL error: could not connect to database "ecpg1_regression" on 
>> line 107
>> # +SQL error: could not connect to database "ecpg1_regression" on 
>> line 107
>>
>>
>>
>
>
> Ugh. I will do some digging.
>
>
>

OK, first this is orthogonal to the issue fixed earlier in this thread.

It's a 22 yer old bug where a connection failure results in a thread 
falling back to a sibling's connection. The fix is to keep track of 
which thread opened which connection and only fall back to the global 
actual_connection if it was started by our thread.

There was an unresolved report of these symptoms in 2006[1]. 
Essentially, the user was holding the lock the docs told him to hold, 
and ecpglib still corrupted state because the corruption window was 
inside ecpglib, not inside the libpq calls he was trying to serialize. 
It's not an easy problem to diagnose, however, so there could well have 
been more cases.

Attached is a patch with the fix, courtesy of claude. It's a slight 
behaviour change:

After the patch, programs in this category fail loudly with ECPG_NO_CONN:

- Pattern that breaks: main thread calls EXEC SQL CONNECT, spawns 
workers, workers issue EXEC SQL ... with no connection name and no 
per-thread SET CONNECTION, relying on their own mutex to serialize the 
libpq calls.
- Migration: one of two existing supported patterns. Either name the 
connection explicitly per statement (EXEC SQL AT con1 SELECT ...) or set 
the per-thread default once at thread start (EXEC SQL SET CONNECTION 
con1;). The
   latter still works under the patch because it explicitly populates 
the per-thread slot, and the patch only owner-checks the global 
fallback, not the per-thread slot.

So I guess the question is whether or not we backpatch it (or some other 
fix)?


cheers


andrew



[1] 
https://www.postgresql.org/message-id/[email protected]


--
Andrew Dunstan
EDB: https://www.enterprisedb.com


Attachments:

  [text/x-patch] Prevent-thread-unsafe-sharing-of-an-ECPG-default-connection.patch (19.0K, 2-Prevent-thread-unsafe-sharing-of-an-ECPG-default-connection.patch)
  download | inline diff:
From 530249a06d2173ea54d9e3af4a6e56921bf4471b Mon Sep 17 00:00:00 2001
From: Andrew Dunstan <[email protected]>
Date: Wed, 6 May 2026 07:39:28 -0400
Subject: [PATCH] Prevent thread-unsafe sharing of an ECPG default connection

ECPGconnect() published the new struct connection into all_connections,
the calling thread's per-thread default-connection slot (held in
thread-specific data via actual_connection_key), and the global
actual_connection before calling PQconnectdbParams().  If
PQconnectdbParams() then failed, ecpg_finish() removed the dead struct
from the list and -- by the same logic that ecpg_finish() uses for
DISCONNECT -- repointed the failing thread's per-thread slot at whatever
now headed all_connections, which is typically a sibling thread's
already-open connection.

After such a failed CONNECT the caller's whenever-sqlerror handler often
just logs and lets the thread continue; the next EXEC SQL statement
issued without an explicit connection name then resolved through the
poisoned per-thread slot or the actual_connection global default and ran
libpq calls on the sibling's PGconn concurrently with the sibling thread
itself.  libpq is not thread-safe at the per-connection level, so the
shared prep_stmts list got corrupted (segv in deallocate_one), the
connection input buffer got reallocated underneath an in-flight reader
(heap abort in pqCheckInBufferSpace), and conn->result occasionally went
NULL while another thread was mid-row-processing.

This was reproducible by running thread/prep and thread/alloc against a
server with max_connections set low enough to refuse some of the worker
threads' CONNECTs, e.g.

  max_connections = 10

in a TEMP_CONFIG passed to "make -C src/interfaces/ecpg/test check",
and is the family of crashes Alexander Lakhin observed on the dikkop
buildfarm animal.

Fix:

* Record on each successful CONNECT which thread opened that connection
  (new owner_thread field on struct connection).  When an EXEC SQL
  statement is issued without a connection name and the calling thread
  has nothing in its per-thread default-connection slot, only fall back
  to actual_connection if its owner matches the caller; otherwise return
  NULL so ecpg_init() raises ECPG_NO_CONN cleanly.  Threads that
  genuinely want to share a connection must do so explicitly by name (or
  via SET CONNECTION) and provide their own synchronization.

* In ECPGconnect()'s failure path, snapshot the prior per-thread slot
  value and global default before publishing the unopened struct, and
  restore them after ecpg_finish() returns.  This prevents the failing
  thread's slot from being aliased to a sibling's open connection.

A new ecpg_thread_id abstraction (pthread_t on POSIX, DWORD on Win32)
keeps ECPG_GET_THREAD_ID()/ECPG_THREAD_ID_EQUAL() portable across
threading models.

A new test thread/connfail forces a deterministic CONNECT failure (by
naming a database that does not exist) and verifies that the worker
thread's subsequent unnamed PREPARE returns ECPG_NO_CONN instead of
silently using the main thread's connection.

Reported-by: Alexander Lakhin <[email protected]>
Discussion: https://postgr.es/m/[email protected]
---
 src/interfaces/ecpg/ecpglib/connect.c         |  73 +++++--
 src/interfaces/ecpg/ecpglib/ecpglib_extern.h  |   2 +
 .../ecpg/include/ecpg-pthread-win32.h         |  17 ++
 src/interfaces/ecpg/test/ecpg_schedule        |   1 +
 .../ecpg/test/expected/thread-connfail.c      | 192 ++++++++++++++++++
 .../ecpg/test/expected/thread-connfail.stderr |   0
 .../ecpg/test/expected/thread-connfail.stdout |   2 +
 src/interfaces/ecpg/test/thread/Makefile      |   3 +-
 src/interfaces/ecpg/test/thread/connfail.pgc  |  89 ++++++++
 src/interfaces/ecpg/test/thread/meson.build   |   1 +
 10 files changed, 359 insertions(+), 21 deletions(-)
 create mode 100644 src/interfaces/ecpg/test/expected/thread-connfail.c
 create mode 100644 src/interfaces/ecpg/test/expected/thread-connfail.stderr
 create mode 100644 src/interfaces/ecpg/test/expected/thread-connfail.stdout
 create mode 100644 src/interfaces/ecpg/test/thread/connfail.pgc

diff --git a/src/interfaces/ecpg/ecpglib/connect.c b/src/interfaces/ecpg/ecpglib/connect.c
index 78de9f298ba..e09f728a379 100644
--- a/src/interfaces/ecpg/ecpglib/connect.c
+++ b/src/interfaces/ecpg/ecpglib/connect.c
@@ -32,6 +32,30 @@ ecpg_pthreads_init(void)
 	pthread_once(&actual_connection_key_once, ecpg_actual_connection_init);
 }
 
+/*
+ * Resolve actual_connection as the implicit default for an unnamed EXEC SQL,
+ * but only if it was opened by the calling thread.  Otherwise we'd let one
+ * thread silently issue libpq calls on another thread's PGconn, which is
+ * not safe.  Threads that want to share a connection must do so explicitly
+ * by name (or via SET CONNECTION) and provide their own synchronization.
+ */
+static struct connection *
+ecpg_default_connection(void)
+{
+	struct connection *ret;
+
+	ret = pthread_getspecific(actual_connection_key);
+	if (ret != NULL)
+		return ret;
+
+	if (actual_connection != NULL &&
+		ECPG_THREAD_ID_EQUAL(actual_connection->owner_thread,
+							 ECPG_GET_THREAD_ID()))
+		return actual_connection;
+
+	return NULL;
+}
+
 static struct connection *
 ecpg_get_connection_nr(const char *connection_name)
 {
@@ -41,16 +65,7 @@ ecpg_get_connection_nr(const char *connection_name)
 	{
 		ecpg_pthreads_init();	/* ensure actual_connection_key is valid */
 
-		ret = pthread_getspecific(actual_connection_key);
-
-		/*
-		 * if no connection in TSD for this thread, get the global default
-		 * connection and hope the user knows what they're doing (i.e. using
-		 * their own mutex to protect that connection from concurrent accesses
-		 */
-		if (ret == NULL)
-			/* no TSD connection, going for global */
-			ret = actual_connection;
+		ret = ecpg_default_connection();
 	}
 	else
 	{
@@ -81,16 +96,7 @@ ecpg_get_connection(const char *connection_name)
 	{
 		ecpg_pthreads_init();	/* ensure actual_connection_key is valid */
 
-		ret = pthread_getspecific(actual_connection_key);
-
-		/*
-		 * if no connection in TSD for this thread, get the global default
-		 * connection and hope the user knows what they're doing (i.e. using
-		 * their own mutex to protect that connection from concurrent accesses
-		 */
-		if (ret == NULL)
-			/* no TSD connection here either, using global */
-			ret = actual_connection;
+		ret = ecpg_default_connection();
 	}
 	else
 	{
@@ -262,6 +268,8 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p
 	struct sqlca_t *sqlca = ECPGget_sqlca();
 	enum COMPAT_MODE compat = c;
 	struct connection *this;
+	struct connection *prev_actual_connection;
+	struct connection *prev_thread_connection;
 	int			i,
 				connect_params = 0;
 	bool		alloc_failed = (sqlca == NULL);
@@ -540,12 +548,25 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p
 
 	this->cache_head = NULL;
 	this->prep_stmts = NULL;
+	this->owner_thread = ECPG_GET_THREAD_ID();
 
 	if (all_connections == NULL)
 		this->next = NULL;
 	else
 		this->next = all_connections;
 
+	/*
+	 * Snapshot this thread's per-thread default connection (kept in
+	 * thread-specific data via actual_connection_key) and the global default,
+	 * so we can restore them if PQconnectdbParams() fails below.  Without
+	 * this, ecpg_finish() would re-point this thread's slot at whatever then
+	 * heads all_connections -- typically a sibling thread's already-open
+	 * PGconn, which would later be returned by ecpg_get_connection(NULL) and
+	 * used by libpq concurrently from two threads.
+	 */
+	prev_actual_connection = actual_connection;
+	prev_thread_connection = pthread_getspecific(actual_connection_key);
+
 	all_connections = this;
 	pthread_setspecific(actual_connection_key, all_connections);
 	actual_connection = all_connections;
@@ -668,6 +689,18 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p
 		ecpg_log("ECPGconnect: %s", errmsg);
 
 		ecpg_finish(this);
+
+		/*
+		 * Restore this thread's per-thread default connection and the global
+		 * default to whatever they were before we published "this".
+		 * ecpg_finish() reset them to the new head of all_connections, but
+		 * that may be a different thread's open connection -- letting our
+		 * failed attempt aim this thread's slot at a sibling's PGconn would
+		 * be unsafe.
+		 */
+		pthread_setspecific(actual_connection_key, prev_thread_connection);
+		actual_connection = prev_actual_connection;
+
 		pthread_mutex_unlock(&connections_mutex);
 
 		ecpg_raise(lineno, ECPG_CONNECT, ECPG_SQLSTATE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION, db);
diff --git a/src/interfaces/ecpg/ecpglib/ecpglib_extern.h b/src/interfaces/ecpg/ecpglib/ecpglib_extern.h
index c92f0aa1081..b6c391bf717 100644
--- a/src/interfaces/ecpg/ecpglib/ecpglib_extern.h
+++ b/src/interfaces/ecpg/ecpglib/ecpglib_extern.h
@@ -4,6 +4,7 @@
 #define _ECPG_ECPGLIB_EXTERN_H
 
 #include "ecpg_config.h"
+#include "ecpg-pthread-win32.h"
 #include "ecpgtype.h"
 #include "libpq-fe.h"
 #include "sqlca.h"
@@ -103,6 +104,7 @@ struct connection
 	char	   *name;
 	PGconn	   *connection;
 	bool		autocommit;
+	ecpg_thread_id owner_thread;	/* thread that opened this connection */
 	struct ECPGtype_information_cache *cache_head;
 	struct prepared_statement *prep_stmts;
 	struct connection *next;
diff --git a/src/interfaces/ecpg/include/ecpg-pthread-win32.h b/src/interfaces/ecpg/include/ecpg-pthread-win32.h
index 7b6ba46b349..c742bb5232b 100644
--- a/src/interfaces/ecpg/include/ecpg-pthread-win32.h
+++ b/src/interfaces/ecpg/include/ecpg-pthread-win32.h
@@ -8,8 +8,25 @@
 #ifndef WIN32
 
 #include <pthread.h>
+
+/*
+ * Abstraction for capturing and comparing a thread identity.  Used by
+ * ecpglib to record which thread owns a given connection so that an
+ * unnamed EXEC SQL statement issued from a different thread (whose own
+ * CONNECT may have failed) does not silently fall through to it via the
+ * actual_connection global default -- libpq is not thread-safe at the
+ * per-connection level.
+ */
+typedef pthread_t ecpg_thread_id;
+#define ECPG_GET_THREAD_ID()			pthread_self()
+#define ECPG_THREAD_ID_EQUAL(a, b)		pthread_equal((a), (b))
+
 #else
 
+typedef DWORD ecpg_thread_id;
+#define ECPG_GET_THREAD_ID()			GetCurrentThreadId()
+#define ECPG_THREAD_ID_EQUAL(a, b)		((a) == (b))
+
 typedef struct pthread_mutex_t
 {
 	/* initstate = 0: not initialized; 1: init done; 2: init in progress */
diff --git a/src/interfaces/ecpg/test/ecpg_schedule b/src/interfaces/ecpg/test/ecpg_schedule
index d1f5d9452b7..d2c254fe9f3 100644
--- a/src/interfaces/ecpg/test/ecpg_schedule
+++ b/src/interfaces/ecpg/test/ecpg_schedule
@@ -64,3 +64,4 @@ test: thread/thread_implicit
 test: thread/prep
 test: thread/alloc
 test: thread/descriptor
+test: thread/connfail
diff --git a/src/interfaces/ecpg/test/expected/thread-connfail.c b/src/interfaces/ecpg/test/expected/thread-connfail.c
new file mode 100644
index 00000000000..53d8865e9a8
--- /dev/null
+++ b/src/interfaces/ecpg/test/expected/thread-connfail.c
@@ -0,0 +1,192 @@
+/* Processed by ecpg (regression mode) */
+/* These include files are added by the preprocessor */
+#include <ecpglib.h>
+#include <ecpgerrno.h>
+#include <sqlca.h>
+/* End of automatic include section */
+#define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y))
+
+#line 1 "connfail.pgc"
+/*
+ * Verify that an EXEC SQL statement issued without a connection name from
+ * a worker thread whose own EXEC SQL CONNECT failed does not silently fall
+ * back to another thread's open PGconn.  Before the corresponding ecpglib
+ * fix, ecpg_get_connection(NULL) would return the global default
+ * connection regardless of which thread had opened it, letting the worker
+ * issue libpq calls on the main thread's connection concurrently with the
+ * main thread itself -- libpq is not thread-safe at the per-connection
+ * level, so cross-thread sharing must be opt-in by name, not implicit.
+ *
+ * The test forces a deterministic CONNECT failure (target database does
+ * not exist), then issues an unnamed EXEC SQL.  With the fix the unnamed
+ * statement must error with sqlcode = ECPG_NO_CONN (-220); without the
+ * fix it would silently succeed against the main thread's connection
+ * (or, under load, crash from concurrent libpq access).
+ */
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "ecpg_config.h"
+
+#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <process.h>
+#else
+#include <pthread.h>
+#endif
+
+
+#line 1 "sqlca.h"
+#ifndef POSTGRES_SQLCA_H
+#define POSTGRES_SQLCA_H
+
+#ifndef PGDLLIMPORT
+#if  defined(WIN32) || defined(__CYGWIN__)
+#define PGDLLIMPORT __declspec (dllimport)
+#else
+#define PGDLLIMPORT
+#endif							/* __CYGWIN__ */
+#endif							/* PGDLLIMPORT */
+
+#define SQLERRMC_LEN	150
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+struct sqlca_t
+{
+	char		sqlcaid[8];
+	long		sqlabc;
+	long		sqlcode;
+	struct
+	{
+		int			sqlerrml;
+		char		sqlerrmc[SQLERRMC_LEN];
+	}			sqlerrm;
+	char		sqlerrp[8];
+	long		sqlerrd[6];
+	/* Element 0: empty						*/
+	/* 1: OID of processed tuple if applicable			*/
+	/* 2: number of rows processed				*/
+	/* after an INSERT, UPDATE or				*/
+	/* DELETE statement					*/
+	/* 3: empty						*/
+	/* 4: empty						*/
+	/* 5: empty						*/
+	char		sqlwarn[8];
+	/* Element 0: set to 'W' if at least one other is 'W'	*/
+	/* 1: if 'W' at least one character string		*/
+	/* value was truncated when it was			*/
+	/* stored into a host variable.             */
+
+	/*
+	 * 2: if 'W' a (hopefully) non-fatal notice occurred
+	 */	/* 3: empty */
+	/* 4: empty						*/
+	/* 5: empty						*/
+	/* 6: empty						*/
+	/* 7: empty						*/
+
+	char		sqlstate[5];
+};
+
+struct sqlca_t *ECPGget_sqlca(void);
+
+#ifndef POSTGRES_ECPG_INTERNAL
+#define sqlca (*ECPGget_sqlca())
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#line 30 "connfail.pgc"
+
+
+#line 1 "regression.h"
+
+
+
+
+
+
+#line 31 "connfail.pgc"
+
+
+#ifdef WIN32
+static unsigned __stdcall
+fn(void *arg)
+#else
+static void *
+fn(void *arg)
+#endif
+{
+	/* exec sql begin declare section */
+		     
+	
+#line 42 "connfail.pgc"
+ char * query = "SELECT 1" ;
+/* exec sql end declare section */
+#line 43 "connfail.pgc"
+
+
+	(void) arg;
+
+	/*
+	 * Connect to a database name that the test instance does not have.
+	 * This is guaranteed to fail with ECPG_CONNECT.
+	 */
+	{ ECPGconnect(__LINE__, 0, "nonexistent_xyzzy_db" , NULL, NULL , NULL, 0); }
+#line 51 "connfail.pgc"
+
+	printf("worker connect sqlcode = %ld\n", sqlca.sqlcode);
+
+	/*
+	 * After our own connect failed, an unnamed EXEC SQL must fail with
+	 * ECPG_NO_CONN (-220), NOT silently use the main thread's connection.
+	 */
+	{ ECPGprepare(__LINE__, NULL, 0, "iworker", query);}
+#line 58 "connfail.pgc"
+
+	printf("worker prepare sqlcode = %ld\n", sqlca.sqlcode);
+
+	return 0;
+}
+
+int
+main(void)
+{
+#ifdef WIN32
+	HANDLE		t;
+	unsigned	id;
+#else
+	pthread_t	t;
+#endif
+
+	{ ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , NULL, 0); }
+#line 74 "connfail.pgc"
+
+	{ ECPGsetcommit(__LINE__, "on", NULL);}
+#line 75 "connfail.pgc"
+
+
+#ifdef WIN32
+	t = (HANDLE) _beginthreadex(NULL, 0, fn, NULL, 0, &id);
+	WaitForSingleObject(t, INFINITE);
+	CloseHandle(t);
+#else
+	pthread_create(&t, NULL, fn, NULL);
+	pthread_join(t, NULL);
+#endif
+
+	{ ECPGdisconnect(__LINE__, "CURRENT");}
+#line 86 "connfail.pgc"
+
+
+	return 0;
+}
diff --git a/src/interfaces/ecpg/test/expected/thread-connfail.stderr b/src/interfaces/ecpg/test/expected/thread-connfail.stderr
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/src/interfaces/ecpg/test/expected/thread-connfail.stdout b/src/interfaces/ecpg/test/expected/thread-connfail.stdout
new file mode 100644
index 00000000000..9d91f3f7358
--- /dev/null
+++ b/src/interfaces/ecpg/test/expected/thread-connfail.stdout
@@ -0,0 +1,2 @@
+worker connect sqlcode = -402
+worker prepare sqlcode = -220
diff --git a/src/interfaces/ecpg/test/thread/Makefile b/src/interfaces/ecpg/test/thread/Makefile
index 1b4ddcff61b..04b600420d9 100644
--- a/src/interfaces/ecpg/test/thread/Makefile
+++ b/src/interfaces/ecpg/test/thread/Makefile
@@ -8,6 +8,7 @@ TESTS = thread_implicit thread_implicit.c \
         thread thread.c \
         prep prep.c \
         descriptor descriptor.c \
-        alloc alloc.c
+        alloc alloc.c \
+        connfail connfail.c
 
 all: $(TESTS)
diff --git a/src/interfaces/ecpg/test/thread/connfail.pgc b/src/interfaces/ecpg/test/thread/connfail.pgc
new file mode 100644
index 00000000000..3e2e5271d47
--- /dev/null
+++ b/src/interfaces/ecpg/test/thread/connfail.pgc
@@ -0,0 +1,89 @@
+/*
+ * Verify that an EXEC SQL statement issued without a connection name from
+ * a worker thread whose own EXEC SQL CONNECT failed does not silently fall
+ * back to another thread's open PGconn.  Before the corresponding ecpglib
+ * fix, ecpg_get_connection(NULL) would return the global default
+ * connection regardless of which thread had opened it, letting the worker
+ * issue libpq calls on the main thread's connection concurrently with the
+ * main thread itself -- libpq is not thread-safe at the per-connection
+ * level, so cross-thread sharing must be opt-in by name, not implicit.
+ *
+ * The test forces a deterministic CONNECT failure (target database does
+ * not exist), then issues an unnamed EXEC SQL.  With the fix the unnamed
+ * statement must error with sqlcode = ECPG_NO_CONN (-220); without the
+ * fix it would silently succeed against the main thread's connection
+ * (or, under load, crash from concurrent libpq access).
+ */
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "ecpg_config.h"
+
+#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <process.h>
+#else
+#include <pthread.h>
+#endif
+
+exec sql include sqlca;
+exec sql include ../regression;
+
+#ifdef WIN32
+static unsigned __stdcall
+fn(void *arg)
+#else
+static void *
+fn(void *arg)
+#endif
+{
+	exec sql begin declare section;
+	char	   *query = "SELECT 1";
+	exec sql end declare section;
+
+	(void) arg;
+
+	/*
+	 * Connect to a database name that the test instance does not have.
+	 * This is guaranteed to fail with ECPG_CONNECT.
+	 */
+	exec sql connect to nonexistent_xyzzy_db;
+	printf("worker connect sqlcode = %ld\n", sqlca.sqlcode);
+
+	/*
+	 * After our own connect failed, an unnamed EXEC SQL must fail with
+	 * ECPG_NO_CONN (-220), NOT silently use the main thread's connection.
+	 */
+	exec sql prepare iworker from :query;
+	printf("worker prepare sqlcode = %ld\n", sqlca.sqlcode);
+
+	return 0;
+}
+
+int
+main(void)
+{
+#ifdef WIN32
+	HANDLE		t;
+	unsigned	id;
+#else
+	pthread_t	t;
+#endif
+
+	exec sql connect to REGRESSDB1;
+	exec sql set autocommit to on;
+
+#ifdef WIN32
+	t = (HANDLE) _beginthreadex(NULL, 0, fn, NULL, 0, &id);
+	WaitForSingleObject(t, INFINITE);
+	CloseHandle(t);
+#else
+	pthread_create(&t, NULL, fn, NULL);
+	pthread_join(t, NULL);
+#endif
+
+	exec sql disconnect;
+
+	return 0;
+}
diff --git a/src/interfaces/ecpg/test/thread/meson.build b/src/interfaces/ecpg/test/thread/meson.build
index b23289730b7..3af4604b90c 100644
--- a/src/interfaces/ecpg/test/thread/meson.build
+++ b/src/interfaces/ecpg/test/thread/meson.build
@@ -6,6 +6,7 @@ pgc_files = [
   'prep',
   'descriptor',
   'alloc',
+  'connfail',
 ]
 
 foreach pgc_file : pgc_files
-- 
2.43.0



^ permalink  raw  reply  [nested|flat] 23+ messages in thread

* Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL
  2026-01-19 12:08 Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-03-24 02:34 ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Mahendra Singh Thalor <[email protected]>
  2026-03-24 05:59   ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-09 10:44     ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-13 10:30       ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-15 09:56         ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-16 07:04           ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-18 16:20             ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-20 06:01               ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-21 07:09                 ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-22 04:27                   ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-05-01 19:20                     ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Andrew Dunstan <[email protected]>
  2026-05-05 20:32                       ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Tom Lane <[email protected]>
  2026-05-05 21:36                         ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Andrew Dunstan <[email protected]>
@ 2026-05-06 14:58                           ` Tom Lane <[email protected]>
  2026-05-06 15:50                             ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Andrew Dunstan <[email protected]>
  1 sibling, 1 reply; 23+ messages in thread

From: Tom Lane @ 2026-05-06 14:58 UTC (permalink / raw)
  To: Andrew Dunstan <[email protected]>; +Cc: Alexander Lakhin <[email protected]>; Nishant Sharma <[email protected]>; Shruthi Gowda <[email protected]>; Mahendra Singh Thalor <[email protected]>; Fujii Masao <[email protected]>; pgsql-hackers

Andrew Dunstan <[email protected]> writes:
> Attached is a patch with the fix, courtesy of claude. It's a slight 
> behaviour change:

Yeah.  So we could either do something like this, or say that the
test case is buggy and needs to provide its own mutexes, per the
existing comment

-         * if no connection in TSD for this thread, get the global default
-         * connection and hope the user knows what they're doing (i.e. using
-         * their own mutex to protect that connection from concurrent accesses

On the whole I think I favor the behavior change.  We might get some
complaints, but it just seems a lot safer to redefine it like this.

Either way, it seems like some documentation adjustments are called
for.

As far as the patch itself goes, I'd be inclined to pull the
preparatory step

         ecpg_pthreads_init();    /* ensure actual_connection_key is valid */

into the new ecpg_default_connection() subroutine, especially since
its proposed comment doesn't mention that prerequisite.

			regards, tom lane





^ permalink  raw  reply  [nested|flat] 23+ messages in thread

* Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL
  2026-01-19 12:08 Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-03-24 02:34 ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Mahendra Singh Thalor <[email protected]>
  2026-03-24 05:59   ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-09 10:44     ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-13 10:30       ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-15 09:56         ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-16 07:04           ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-18 16:20             ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-20 06:01               ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-21 07:09                 ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-22 04:27                   ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-05-01 19:20                     ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Andrew Dunstan <[email protected]>
  2026-05-05 20:32                       ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Tom Lane <[email protected]>
  2026-05-05 21:36                         ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Andrew Dunstan <[email protected]>
  2026-05-06 14:58                           ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Tom Lane <[email protected]>
@ 2026-05-06 15:50                             ` Andrew Dunstan <[email protected]>
  2026-05-06 16:02                               ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Tom Lane <[email protected]>
  0 siblings, 1 reply; 23+ messages in thread

From: Andrew Dunstan @ 2026-05-06 15:50 UTC (permalink / raw)
  To: Tom Lane <[email protected]>; +Cc: Alexander Lakhin <[email protected]>; Nishant Sharma <[email protected]>; Shruthi Gowda <[email protected]>; Mahendra Singh Thalor <[email protected]>; Fujii Masao <[email protected]>; pgsql-hackers


On 2026-05-06 We 10:58 AM, Tom Lane wrote:
> Andrew Dunstan <[email protected]> writes:
>> Attached is a patch with the fix, courtesy of claude. It's a slight
>> behaviour change:
> Yeah.  So we could either do something like this, or say that the
> test case is buggy and needs to provide its own mutexes, per the
> existing comment
>
> -         * if no connection in TSD for this thread, get the global default
> -         * connection and hope the user knows what they're doing (i.e. using
> -         * their own mutex to protect that connection from concurrent accesses
>
> On the whole I think I favor the behavior change.  We might get some
> complaints, but it just seems a lot safer to redefine it like this.


I agree.


>
> Either way, it seems like some documentation adjustments are called
> for.
>
> As far as the patch itself goes, I'd be inclined to pull the
> preparatory step
>
>           ecpg_pthreads_init();    /* ensure actual_connection_key is valid */
>
> into the new ecpg_default_connection() subroutine, especially since
> its proposed comment doesn't mention that prerequisite.
>
> 			


Right.


Given the lack of field complaints, maybe we should wait until after 
next week's releases?


cheers


andrew


--
Andrew Dunstan
EDB: https://www.enterprisedb.com






^ permalink  raw  reply  [nested|flat] 23+ messages in thread

* Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL
  2026-01-19 12:08 Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-03-24 02:34 ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Mahendra Singh Thalor <[email protected]>
  2026-03-24 05:59   ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-09 10:44     ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-13 10:30       ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-15 09:56         ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-16 07:04           ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-18 16:20             ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-20 06:01               ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-21 07:09                 ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-22 04:27                   ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-05-01 19:20                     ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Andrew Dunstan <[email protected]>
  2026-05-05 20:32                       ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Tom Lane <[email protected]>
  2026-05-05 21:36                         ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Andrew Dunstan <[email protected]>
  2026-05-06 14:58                           ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Tom Lane <[email protected]>
  2026-05-06 15:50                             ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Andrew Dunstan <[email protected]>
@ 2026-05-06 16:02                               ` Tom Lane <[email protected]>
  0 siblings, 0 replies; 23+ messages in thread

From: Tom Lane @ 2026-05-06 16:02 UTC (permalink / raw)
  To: Andrew Dunstan <[email protected]>; +Cc: Alexander Lakhin <[email protected]>; Nishant Sharma <[email protected]>; Shruthi Gowda <[email protected]>; Mahendra Singh Thalor <[email protected]>; Fujii Masao <[email protected]>; pgsql-hackers

Andrew Dunstan <[email protected]> writes:
> Given the lack of field complaints, maybe we should wait until after 
> next week's releases?

Yeah, given that this bug has gone almost undetected for decades,
I don't think there's a rush.  Let's sit on it another week.

			regards, tom lane






^ permalink  raw  reply  [nested|flat] 23+ messages in thread

* Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL
  2026-01-19 12:08 Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-03-24 02:34 ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Mahendra Singh Thalor <[email protected]>
  2026-03-24 05:59   ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-09 10:44     ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-13 10:30       ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-15 09:56         ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-16 07:04           ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-18 16:20             ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-20 06:01               ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-21 07:09                 ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-22 04:27                   ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-05-01 19:20                     ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Andrew Dunstan <[email protected]>
@ 2026-05-23 18:59                       ` SATYANARAYANA NARLAPURAM <[email protected]>
  2026-05-25 07:46                         ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2 siblings, 1 reply; 23+ messages in thread

From: SATYANARAYANA NARLAPURAM @ 2026-05-23 18:59 UTC (permalink / raw)
  To: Andrew Dunstan <[email protected]>; +Cc: Nishant Sharma <[email protected]>; Shruthi Gowda <[email protected]>; Mahendra Singh Thalor <[email protected]>; Fujii Masao <[email protected]>; Tom Lane <[email protected]>; pgsql-hackers

Hi

On Fri, May 1, 2026 at 12:21 PM Andrew Dunstan <[email protected]> wrote:

>
>
> On Wed, Apr 22, 2026 at 12:27 AM Nishant Sharma <
> [email protected]> wrote:
>
>> Thanks Shruthi!
>>
>> v5 code, v4_test and v4_test_15 patches look good to me.
>>
>> I checked ECPG regression on master, REL_18, REL_17, REL_16, REL_15,
>> REL_14 using both make and meson.
>>
>> I have finished my review work on the patches. Thank you!
>>
>>
>>
>>
> Thanks, everybody, pushed (as combined patches)
>

Looks like this committed a case, attached a patch to fix this.

Thanks,
Satya


Attachments:

  [application/octet-stream] 0006-ecpg-fix-null-deref-in-ecpg_auto_prepare.patch (667B, 3-0006-ecpg-fix-null-deref-in-ecpg_auto_prepare.patch)
  download | inline diff:
diff --git a/src/interfaces/ecpg/ecpglib/prepare.c b/src/interfaces/ecpg/ecpglib/prepare.c
index 3874a64ae8e..7a9036bcfc0 100644
--- a/src/interfaces/ecpg/ecpglib/prepare.c
+++ b/src/interfaces/ecpg/ecpglib/prepare.c
@@ -620,6 +620,11 @@ ecpg_auto_prepare(int lineno, const char *connection_name, const int compat, cha
 			return false;
 
 		con = ecpg_get_connection(connection_name);
+		if (!ecpg_init(con, connection_name, lineno))
+		{
+			ecpg_free(*name);
+			return false;
+		}
 		prep = ecpg_find_prepared_statement(stmtID, con, NULL);
 		/* This prepared name doesn't exist on this connection. */
 		if (!prep && !prepare_common(lineno, con, stmtID, query))


^ permalink  raw  reply  [nested|flat] 23+ messages in thread

* Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL
  2026-01-19 12:08 Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-03-24 02:34 ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Mahendra Singh Thalor <[email protected]>
  2026-03-24 05:59   ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-09 10:44     ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-13 10:30       ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-15 09:56         ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-16 07:04           ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-18 16:20             ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-20 06:01               ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-21 07:09                 ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-22 04:27                   ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-05-01 19:20                     ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Andrew Dunstan <[email protected]>
  2026-05-23 18:59                       ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL SATYANARAYANA NARLAPURAM <[email protected]>
@ 2026-05-25 07:46                         ` Shruthi Gowda <[email protected]>
  2026-05-25 23:34                           ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Michael Paquier <[email protected]>
  0 siblings, 1 reply; 23+ messages in thread

From: Shruthi Gowda @ 2026-05-25 07:46 UTC (permalink / raw)
  To: SATYANARAYANA NARLAPURAM <[email protected]>; +Cc: Andrew Dunstan <[email protected]>; Nishant Sharma <[email protected]>; Mahendra Singh Thalor <[email protected]>; Fujii Masao <[email protected]>; Tom Lane <[email protected]>; pgsql-hackers

On Sun, May 24, 2026 at 12:29 AM SATYANARAYANA NARLAPURAM <
[email protected]> wrote:

> Hi
>
> On Fri, May 1, 2026 at 12:21 PM Andrew Dunstan <[email protected]>
> wrote:
>
>>
>>
>> On Wed, Apr 22, 2026 at 12:27 AM Nishant Sharma <
>> [email protected]> wrote:
>>
>>> Thanks Shruthi!
>>>
>>> v5 code, v4_test and v4_test_15 patches look good to me.
>>>
>>> I checked ECPG regression on master, REL_18, REL_17, REL_16, REL_15,
>>> REL_14 using both make and meson.
>>>
>>> I have finished my review work on the patches. Thank you!
>>>
>>>
>>>
>>>
>> Thanks, everybody, pushed (as combined patches)
>>
>
> Looks like this committed a case, attached a patch to fix this.
>
> Thanks,
> Satya
>
>
Thanks Satya for looking into this. However, we don't need to add the
validation here because the caller ecpg_do_prologue*()* has already taken
care of it. Adding it again would be redundant. What do you think?

Thanks & Regards,

Shruthi K C

EnterpriseDB: http://www.enterprisedb.com


^ permalink  raw  reply  [nested|flat] 23+ messages in thread

* Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL
  2026-01-19 12:08 Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-03-24 02:34 ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Mahendra Singh Thalor <[email protected]>
  2026-03-24 05:59   ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-09 10:44     ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-13 10:30       ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-15 09:56         ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-16 07:04           ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-18 16:20             ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-20 06:01               ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-04-21 07:09                 ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
  2026-04-22 04:27                   ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Nishant Sharma <[email protected]>
  2026-05-01 19:20                     ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Andrew Dunstan <[email protected]>
  2026-05-23 18:59                       ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL SATYANARAYANA NARLAPURAM <[email protected]>
  2026-05-25 07:46                         ` Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
@ 2026-05-25 23:34                           ` Michael Paquier <[email protected]>
  0 siblings, 0 replies; 23+ messages in thread

From: Michael Paquier @ 2026-05-25 23:34 UTC (permalink / raw)
  To: Shruthi Gowda <[email protected]>; +Cc: SATYANARAYANA NARLAPURAM <[email protected]>; Andrew Dunstan <[email protected]>; Nishant Sharma <[email protected]>; Mahendra Singh Thalor <[email protected]>; Fujii Masao <[email protected]>; Tom Lane <[email protected]>; pgsql-hackers

On Mon, May 25, 2026 at 01:16:20PM +0530, Shruthi Gowda wrote:
> Thanks Satya for looking into this. However, we don't need to add the
> validation here because the caller ecpg_do_prologue*()* has already taken
> care of it. Adding it again would be redundant. What do you think?

Right, but I think that this points at a different issue: it is
wasteful to call a second time ecpg_get_connection() to get a
connection while ecpg_do_prologue() has already done a cache lookup
for the connection.

Wouldn't it be better to pass directly the connection obtained by the
first call of ecpg_get_connection() as a function argument of
ecpg_auto_prepare(), replacing the connection name?  If we need the
extra init() at the end, please show if this can go wrong in the shape
of a regression test.
--
Michael


Attachments:

  [application/pgp-signature] signature.asc (833B, 2-signature.asc)
  download

^ permalink  raw  reply  [nested|flat] 23+ messages in thread


end of thread, other threads:[~2026-05-25 23:34 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2026-01-19 12:08 Re: [BUG] CRASH: ECPGprepared_statement() and ECPGdeallocate_all() when connection is NULL Shruthi Gowda <[email protected]>
2026-03-24 02:34 ` Mahendra Singh Thalor <[email protected]>
2026-03-24 05:59   ` Nishant Sharma <[email protected]>
2026-04-09 10:44     ` Shruthi Gowda <[email protected]>
2026-04-13 10:30       ` Nishant Sharma <[email protected]>
2026-04-13 10:32         ` Nishant Sharma <[email protected]>
2026-04-15 09:56         ` Shruthi Gowda <[email protected]>
2026-04-16 07:04           ` Nishant Sharma <[email protected]>
2026-04-18 16:20             ` Shruthi Gowda <[email protected]>
2026-04-20 06:01               ` Nishant Sharma <[email protected]>
2026-04-21 07:09                 ` Shruthi Gowda <[email protected]>
2026-04-22 04:27                   ` Nishant Sharma <[email protected]>
2026-05-01 19:20                     ` Andrew Dunstan <[email protected]>
2026-05-05 20:00                       ` Alexander Lakhin <[email protected]>
2026-05-05 20:32                       ` Tom Lane <[email protected]>
2026-05-05 21:36                         ` Andrew Dunstan <[email protected]>
2026-05-06 11:55                           ` Andrew Dunstan <[email protected]>
2026-05-06 14:58                           ` Tom Lane <[email protected]>
2026-05-06 15:50                             ` Andrew Dunstan <[email protected]>
2026-05-06 16:02                               ` Tom Lane <[email protected]>
2026-05-23 18:59                       ` SATYANARAYANA NARLAPURAM <[email protected]>
2026-05-25 07:46                         ` Shruthi Gowda <[email protected]>
2026-05-25 23:34                           ` Michael Paquier <[email protected]>

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox