From 7d9a90547ee251075054bfef5ec70a55a9ccacdf Mon Sep 17 00:00:00 2001
From: "Stephen R. van den Berg" <srb@cuci.nl>
Date: Mon, 11 Dec 2017 22:52:10 +0100
Subject: [PATCH] pgsql: Support binary transfer IEEE float formats.

---
 lib/modules/Sql.pmod/pgsql_util.pmod | 65 +++++++++++++++++++++++++---
 1 file changed, 59 insertions(+), 6 deletions(-)

diff --git a/lib/modules/Sql.pmod/pgsql_util.pmod b/lib/modules/Sql.pmod/pgsql_util.pmod
index 94765f25d5..43d1ec91be 100644
--- a/lib/modules/Sql.pmod/pgsql_util.pmod
+++ b/lib/modules/Sql.pmod/pgsql_util.pmod
@@ -169,7 +169,7 @@ final void throwdelayederror(sql_result|proxy parent) {
   }
 }
 
-private int oidformat(int oid) {
+private int readoidformat(int oid) {
   switch (oid) {
     case BOOLOID:
     case BYTEAOID:
@@ -177,6 +177,10 @@ private int oidformat(int oid) {
     case INT8OID:
     case INT2OID:
     case INT4OID:
+    case FLOAT4OID:
+#if !constant(__builtin.__SINGLE_PRECISION_FLOAT__)
+    case FLOAT8OID:
+#endif
     case TEXTOID:
     case OIDOID:
     case XMLOID:
@@ -190,6 +194,35 @@ private int oidformat(int oid) {
   return 0;	// text
 }
 
+private int writeoidformat(int oid, array(string|int) paramValues,
+ array(int) ai) {
+  mixed value = paramValues[ai[0]++];
+  switch (oid) {
+    case BOOLOID:
+    case BYTEAOID:
+    case CHAROID:
+    case INT8OID:
+    case INT2OID:
+    case INT4OID:
+    case TEXTOID:
+    case OIDOID:
+    case XMLOID:
+    case MACADDROID:
+    case BPCHAROID:
+    case VARCHAROID:
+    case CTIDOID:
+    case UUIDOID:
+      return 1; //binary
+    case FLOAT4OID:
+#if !constant(__builtin.__SINGLE_PRECISION_FLOAT__)
+    case FLOAT8OID:
+#endif
+      if (!stringp(value))
+        return 1;
+  }
+  return 0;	// text
+}
+
 private inline mixed callout(function(mixed ...:void) f,
  float|int delay, mixed ... args) {
   return cb_backend->call_out(f, delay, @args);
@@ -833,11 +866,18 @@ class sql_result {
         mixed value;
         switch (typ) {
           case FLOAT4OID:
-#if SIZEOF_FLOAT>=8
+#if !constant(__builtin.__SINGLE_PRECISION_FLOAT__)
           case FLOAT8OID:
 #endif
-            if (!alltext) {
-              value = (float)cr->read(collen);
+            if (_forcetext) {
+              if (!alltext) {
+                value = (float)cr->read(collen);
+                break;
+              }
+            } else {
+              [ value ] = cr->sscanf(collen == 4 ? "%4F" : "%8F");
+              if (alltext)
+                value = (string)value;
               break;
             }
           default:value = cr->read(collen);
@@ -923,7 +963,8 @@ class sql_result {
       Stdio.Buffer plugbuffer = Stdio.Buffer();
       { array dta = ({sizeof(dtoid)});
         plugbuffer->add(_portalname, 0, _preparedname, 0)
-         ->add_ints(dta + map(dtoid, oidformat) + dta, 2);
+         ->add_ints(dta
+           + map(dtoid, writeoidformat, paramValues, ({0})) + dta, 2);
       }
       string cenc = pgsqlsess.runtimeparameter[CLIENT_ENCODING];
       foreach (paramValues; int i; mixed value) {
@@ -1041,6 +1082,18 @@ class sql_result {
                 }
               }
               break;
+            case FLOAT4OID:
+#if !constant(__builtin.__SINGLE_PRECISION_FLOAT__)
+            case FLOAT8OID:
+#endif
+              if (stringp(value))
+                plugbuffer->add_hstring(value, 4);
+              else {
+                int w = dtoid[i] == FLOAT4OID ? 4 : 8;
+                plugbuffer->add_int32(w)
+                 ->sprintf(w == 4 ? "%4F" : "%8F", value);
+              }
+              break;
             case INT8OID:
               plugbuffer->add_int32(8)->add_int((int)value, 8);
               break;
@@ -1063,7 +1116,7 @@ class sql_result {
       else {
         plugbuffer->add_int16(sizeof(datarowtypes));
         if (sizeof(datarowtypes))
-          plugbuffer->add_ints(map(datarowtypes, oidformat), 2);
+          plugbuffer->add_ints(map(datarowtypes, readoidformat), 2);
         else if (syncparse < 0 && !pgsqlsess->wasparallelisable
          && !pgsqlsess->statementsinflight->drained(1)) {
           lock = pgsqlsess->shortmux->lock();
-- 
GitLab