From c8942cbce7e269fb85c3c37f7414b1cc6d847cea Mon Sep 17 00:00:00 2001
From: "Stephen R. van den Berg" <srb@cuci.nl>
Date: Fri, 10 Apr 2009 19:20:37 +0200
Subject: [PATCH] Improve error diagnostics with regard to parameter binding.

Rev: lib/modules/Sql.pmod/pgsql.pike:1.67
Rev: lib/modules/Sql.pmod/pgsql_util.pmod:1.19
---
 lib/modules/Sql.pmod/pgsql.pike      | 38 ++++++++++++++++++----------
 lib/modules/Sql.pmod/pgsql_util.pmod | 15 +++++------
 2 files changed, 31 insertions(+), 22 deletions(-)

diff --git a/lib/modules/Sql.pmod/pgsql.pike b/lib/modules/Sql.pmod/pgsql.pike
index caf02804fc..0ad99e0092 100644
--- a/lib/modules/Sql.pmod/pgsql.pike
+++ b/lib/modules/Sql.pmod/pgsql.pike
@@ -609,6 +609,22 @@ final int _decodemsg(void|state waitforstate)
 	PD("%O\n",msgresponse);
 	return msgresponse;
       };
+      array(string) showbindings()
+      { array(string) msgs=({});
+        array from;
+	if(from = _c.portal->_params)
+	{ array to,paramValues;
+	  [from,to,paramValues] = from;
+          if(sizeof(paramValues))
+          { string val;
+            int i;
+            string fmt=sprintf("%%%ds %%3s %%.61s",max(@map(from,sizeof)));
+            foreach(paramValues;i;val)
+               msgs+=({sprintf(fmt,from[i],to[i],sprintf("%O",val))});
+          }
+        }
+	return msgs;
+      };
       case 'R':PD("Authentication\n");
       { string sendpass;
 	int authtype;
@@ -882,8 +898,8 @@ final int _decodemsg(void|state waitforstate)
 	{ case "P0001":
 	    lastmessage=({sprintf("%s: %s",msgresponse->S,msgresponse->M)});
 	    USERERROR(a2nls(lastmessage
-	     +({pinpointerror(_c.portal->query,msgresponse->P)})));
-	    break;
+	     +({pinpointerror(_c.portal->_query,msgresponse->P)})
+	     +showbindings()));
 	  case "08P01":case "42P05":
 	    errtype=protocolerror;
 	  case "XX000":case "42883":case "42P01":
@@ -897,10 +913,11 @@ final int _decodemsg(void|state waitforstate)
 	    if(msgresponse->H)
 	      lastmessage+=({msgresponse->H});
 	    lastmessage+=({
-	     pinpointerror(_c.portal&&_c.portal->query,msgresponse->P)+
+	     pinpointerror(_c.portal&&_c.portal->_query,msgresponse->P)+
 	     pinpointerror(msgresponse->q,msgresponse->p)});
 	    if(msgresponse->W)
 	      lastmessage+=({msgresponse->W});
+	    lastmessage+=showbindings();
 	    switch(msgresponse->S)
 	    { case "PANIC":werror(a2nls(lastmessage));
 	    }
@@ -1607,12 +1624,12 @@ object big_query(string q,void|mapping(string|int:mixed) bindings,
 	ERROR("Don't know how to convert %O to %s encoding\n",q,cenc);
   }
   array(string|int) paramValues;
-  array(string) from,to;
+  array from;
   if(bindings)
   { int pi=0,rep=0;
     paramValues=allocate(sizeof(bindings));
     from=allocate(sizeof(bindings));
-    to=allocate(sizeof(bindings));
+    array(string) to=allocate(sizeof(bindings));
     foreach(bindings; mixed name; mixed value)
     { if(stringp(name))		       // Throws if mapping key is empty string
       { if(name[0]!=':')
@@ -1640,6 +1657,7 @@ object big_query(string q,void|mapping(string|int:mixed) bindings,
     if(rep--)
       q=replace(q,from=from[..rep],to=to[..rep]);
     paramValues= pi ? paramValues[..pi-1] : ({});
+    from=({from,to,paramValues});
   }
   else
     paramValues = ({});
@@ -1691,7 +1709,7 @@ object big_query(string q,void|mapping(string|int:mixed) bindings,
   }					  // pgsql_result autoassigns to portal
   else
     tp=UNDEFINED;
-  .pgsql_util.pgsql_result(this,q,_fetchlimit,portalbuffersize,_alltyped);
+  .pgsql_util.pgsql_result(this,q,_fetchlimit,portalbuffersize,_alltyped,from);
   if(unnamedportalinuse)
     portalname=PORTALPREFIX+(string)pportalcount++;
   else
@@ -1891,14 +1909,6 @@ object big_query(string q,void|mapping(string|int:mixed) bindings,
   { PD("%O\n",err);
     resync(1);
     backendstatus=UNDEFINED;
-    if(to && sizeof(to))
-    { string val;
-      int i;
-      lastmessage+=({"Parameter bindings:"});
-      foreach(to;i;val)
-	 lastmessage+=({sprintf("%16s %3s %.61s",
-	  from[i],val,sprintf("%O",paramValues[i]))});
-    }
     throw(err);
   }
   { object tportal=_c.portal;		// Make copy, because it might dislodge
diff --git a/lib/modules/Sql.pmod/pgsql_util.pmod b/lib/modules/Sql.pmod/pgsql_util.pmod
index 1bb375cf1b..6da57a40ba 100644
--- a/lib/modules/Sql.pmod/pgsql_util.pmod
+++ b/lib/modules/Sql.pmod/pgsql_util.pmod
@@ -237,7 +237,6 @@ int _qmtxkey;
 Thread.MutexKey _qmtxkey;
 #endif
 
-string query;
 string _portalname;
 
 int _bytesreceived;
@@ -245,7 +244,9 @@ int _rowsreceived;
 int _interruptable;
 int _inflight;
 int _portalbuffersize;
+array _params;
 string _statuscmdcomplete;
+string _query;
 array(array(mixed)) _datarows;
 array(mapping(string:mixed)) _datarowdesc=({});
 array(int) _datatypeoid;
@@ -260,27 +261,25 @@ protected string _sprintf(int type, void|mapping flags)
   switch(type)
   { case 'O':
       res=sprintf("pgsql_result  numrows: %d  eof: %d  querylock: %d"
-       " inflight: %d\nportalname: %O  datarows: %d\n"
-       "query: %O\n"
-       "laststatus: %s\n",
+       " inflight: %d\nportalname: %O  datarows: %d  laststatus: %s\n",
        numrows,eoffound,!!_qmtxkey,_inflight,
        _portalname,sizeof(_datarowdesc),
-       query,
        _statuscmdcomplete||"");
       break;
   }
   return res;
 }
 
-void create(object pgsqlsess,string _query,int fetchlimit,
- int portalbuffersize,int alltyped)
+void create(object pgsqlsess,string query,int fetchlimit,
+ int portalbuffersize,int alltyped,array params)
 { _pgsqlsess = pgsqlsess;
-  query = _query;
+  _query = query;
   _datarows = ({ }); numrows = UNDEFINED;
   fetchmutex = Thread.Mutex();
   _fetchlimit=fetchlimit;
   _portalbuffersize=portalbuffersize;
   _alltext = !alltyped;
+  _params = params;
   steallock();
 }
 
-- 
GitLab