From 72edb1c64f95bdf30e4116869d240bd1e4f1f0cb Mon Sep 17 00:00:00 2001
From: "Stephen R. van den Berg" <srb@cuci.nl>
Date: Tue, 9 Jun 2020 09:11:34 +0200
Subject: [PATCH] pgsql: Release portals that had background-exceptions during
 bind.

---
 lib/modules/Sql.pmod/pgsql.pike      |  7 ++++---
 lib/modules/Sql.pmod/pgsql_util.pmod | 30 ++++++++++++++++++++--------
 2 files changed, 26 insertions(+), 11 deletions(-)

diff --git a/lib/modules/Sql.pmod/pgsql.pike b/lib/modules/Sql.pmod/pgsql.pike
index 0d8e47352d..602fb09b42 100644
--- a/lib/modules/Sql.pmod/pgsql.pike
+++ b/lib/modules/Sql.pmod/pgsql.pike
@@ -997,9 +997,10 @@ private void startquery(int forcetext, .pgsql_util.sql_result portal, string q,
       mixed e = catch(portal->_preparebind(tp.datatypeoid));
       if (!this)				// Already destructed?
         throw(e);
-      if (e && !portal.delayederror) {
-        portal._unnamedstatementkey = 0;	// Release early, release often
-        throw(e);
+      if (e) {
+        portal->_purgeportal();
+        if (!portal.delayederror)
+          throw(e);
       }
     }
     if (!proxy.unnamedstatement)
diff --git a/lib/modules/Sql.pmod/pgsql_util.pmod b/lib/modules/Sql.pmod/pgsql_util.pmod
index 9bf23ab616..9cede304cf 100644
--- a/lib/modules/Sql.pmod/pgsql_util.pmod
+++ b/lib/modules/Sql.pmod/pgsql_util.pmod
@@ -1970,6 +1970,26 @@ class proxy {
     procmessage();
   }
 
+  private void stasherror(int|object portal, mixed err) {
+    if (stringp(err)) {
+      if (!objectp(portal))
+        portal = this;
+      if (!portal->delayederror)
+        portal->delayederror = err;
+    }
+    if (objectp(portal))
+      portal->_purgeportal();
+  }
+
+  private void tryprepbind(sql_result portal, array dtoid) {
+    mixed err = catch(portal->_preparebind(dtoid));
+    if (err) {
+      stasherror(portal, err);
+      if (!stringp(err))
+        throw(err);
+    }
+  }
+
   private void procmessage() {
     mixed err;
     int terminating = 0;
@@ -2299,7 +2319,7 @@ class proxy {
 #endif
             if (portal._tprepared)
               portal._tprepared.datatypeoid = a;
-            Thread.Thread(portal->_preparebind, a);
+            Thread.Thread(tryprepbind, portal, a);
             break;
           }
           case 'T': {
@@ -2629,16 +2649,10 @@ class proxy {
         terminating = 1;
         err = 0;
       } else if (stringp(err)) {
-        sql_result or;
-        if (!objectp(or = portal))
-          or = this;
-        if (!or.delayederror)
-          or.delayederror = err;
 #ifdef PG_DEBUGMORE
         showportalstack("THROWN");
 #endif
-        if (objectp(portal))
-          portal->_releasesession("ERROR");
+        stasherror(portal, err);
         portal = 0;
         if (!waitforauthready)
           continue;		// Only continue if authentication did not fail
-- 
GitLab