[PATCH] automatic integer conversion - Mailing list pgsql-patches

From xeb@mail.ru
Subject [PATCH] automatic integer conversion
Date
Msg-id 200712080033.47571.xeb@mail.ru
Whole thread Raw
Responses Re: [PATCH] automatic integer conversion
List pgsql-patches
Hello!
Here is patch which makes libpq more confortable when working with binary integers.
Automatic conversion intialized by PQsetconvertint(conn,1), so old applications continues to work proper.


--------------------------------------------------------------
diff -ur postgresql-8.2.4.orig/src/interfaces/libpq/exports.txt postgresql-8.2.4/src/interfaces/libpq/exports.txt
--- postgresql-8.2.4.orig/src/interfaces/libpq/exports.txt      2006-08-18 23:52:39.000000000 +0400
+++ postgresql-8.2.4/src/interfaces/libpq/exports.txt   2007-11-26 16:23:25.000000000 +0300
@@ -136,3 +136,6 @@
 PQdescribePortal          134
 PQsendDescribePrepared    135
 PQsendDescribePortal      136
+PQsetconvertint           137
+PQisconverrtint           138
+PQexecPreparedParams      139
diff -ur postgresql-8.2.4.orig/src/interfaces/libpq/fe-exec.c postgresql-8.2.4/src/interfaces/libpq/fe-exec.c
--- postgresql-8.2.4.orig/src/interfaces/libpq/fe-exec.c        2006-10-04 04:30:13.000000000 +0400
+++ postgresql-8.2.4/src/interfaces/libpq/fe-exec.c     2007-11-26 16:20:28.000000000 +0300
@@ -12,16 +12,21 @@
  *
  *-------------------------------------------------------------------------
  */
+#include "postgres.h"
 #include "postgres_fe.h"

 #include <ctype.h>
 #include <fcntl.h>
+#include <endian.h>
+#include <byteswap.h>

 #include "libpq-fe.h"
 #include "libpq-int.h"

 #include "mb/pg_wchar.h"

+#include "catalog/pg_type.h"
+
 #ifdef WIN32
 #include "win32.h"
 #else
@@ -879,6 +884,43 @@
                                                   resultFormat);
 }

+
+/*
+ * PQsendQueryPreparedParams
+ *             Like PQsendQuery, but execute a previously prepared statement,
+ *             parameters passed as helpers for integer converting
+ */
+int
+PQsendQueryPreparedParams(PGconn *conn,
+                                       const char *stmtName,
+                                       int nParams,
+                                       const Oid *paramTypes,
+                                       const char *const * paramValues,
+                                       const int *paramLengths,
+                                       const int *paramFormats,
+                                       int resultFormat)
+{
+       if (!PQsendQueryStart(conn))
+               return 0;
+
+       if (!stmtName)
+       {
+               printfPQExpBuffer(&conn->errorMessage,
+                                       libpq_gettext("statement name is a null pointer\n"));
+               return 0;
+       }
+
+       return PQsendQueryGuts(conn,
+                                                  NULL,        /* no command to parse */
+                                                  stmtName,
+                                                  nParams,
+                                                  paramTypes,
+                                                  paramValues,
+                                                  paramLengths,
+                                                  paramFormats,
+                                                  resultFormat);
+}
+
 /*
  * Common startup code for PQsendQuery and sibling routines
  */
@@ -1003,6 +1045,13 @@
                if (paramValues && paramValues[i])
                {
                        int                     nbytes;
+                       char const *val;
+                       union
+                       {
+                           uint64 i64;
+                           uint32 i32;
+                           uint16 i16;
+                       } tmpint;

                        if (paramFormats && paramFormats[i] != 0)
                        {
@@ -1021,8 +1070,33 @@
                                /* text parameter, do not use paramLengths */
                                nbytes = strlen(paramValues[i]);
                        }
+                       #if __BYTE_ORDER == __LITTLE_ENDIAN
+                       if (conn->convert_int && paramTypes &&
+                           (paramTypes[i]==INT2OID || paramTypes[i]==INT4OID ||
+                            paramTypes[i]==INT8OID))
+                       {
+                           switch(nbytes)
+                           {
+                               case 2:
+                                   tmpint.i16=bswap_16(*(uint16*)paramValues[i]);
+                                   val=(char*)&tmpint;
+                                   break;
+                               case 4:
+                                   tmpint.i32=bswap_32(*(uint32*)paramValues[i]);
+                                   val=(char*)&tmpint;
+                                   break;
+                               case 8:
+                                   tmpint.i64=bswap_64(*(uint64*)paramValues[i]);
+                                   val=(char*)&tmpint;
+                                   break;
+                               default:
+                                   val=paramValues[i];
+                           }
+                       }else
+                       #endif
+                       val=paramValues[i];
                        if (pqPutInt(nbytes, 4, conn) < 0 ||
-                               pqPutnchar(paramValues[i], nbytes, conn) < 0)
+                               pqPutnchar(val, nbytes, conn) < 0)
                                goto sendFailed;
                }
                else
@@ -1360,6 +1434,30 @@
 }

 /*
+ * PQexecPreparedParams
+ *             Like PQexec, but execute a previously prepared statement,
+ *             parameters passed as helpers for integer convering
+ */
+PGresult *
+PQexecPreparedParams(PGconn *conn,
+                          const char *stmtName,
+                          int nParams,
+                          const Oid *paramTypes,
+                          const char *const * paramValues,
+                          const int *paramLengths,
+                          const int *paramFormats,
+                          int resultFormat)
+{
+       if (!PQexecStart(conn))
+               return NULL;
+       if (!PQsendQueryPreparedParams(conn, stmtName,
+                                                        nParams, paramTypes, paramValues, paramLengths,
+                                                        paramFormats,resultFormat))
+               return NULL;
+       return PQexecFinish(conn);
+}
+
+/*
  * Common code for PQexec and sibling routines: prepare to send command
  */
 static bool
@@ -2488,6 +2586,27 @@
 }


+/* PQsetconvertint:
+ *     returns the null status of a field value.
+ */
+int
+PQsetconvertint(PGconn *conn, int arg)
+{
+       if (!conn) return -1;
+       conn->convert_int=arg;
+       return 0;
+}
+
+/* PQsetconvertint:
+ *     returns the null status of a field value.
+ */
+int
+PQisconvertint(PGconn *conn)
+{
+       if (!conn) return -1;
+       return conn->convert_int;
+}
+
 /* PQsetnonblocking:
  *     sets the PGconn's database connection non-blocking if the arg is TRUE
  *     or makes it non-blocking if the arg is FALSE, this will not protect
diff -ur postgresql-8.2.4.orig/src/interfaces/libpq/fe-protocol3.c postgresql-8.2.4/src/interfaces/libpq/fe-protocol3.c
--- postgresql-8.2.4.orig/src/interfaces/libpq/fe-protocol3.c   2006-10-04 04:30:13.000000000 +0400
+++ postgresql-8.2.4/src/interfaces/libpq/fe-protocol3.c        2007-11-26 16:20:35.000000000 +0300
@@ -12,14 +12,19 @@
  *
  *-------------------------------------------------------------------------
  */
+#include "postgres.h"
 #include "postgres_fe.h"

 #include <ctype.h>
 #include <fcntl.h>
+#include <endian.h>
+#include <byteswap.h>

 #include "libpq-fe.h"
 #include "libpq-int.h"

+#include "catalog/pg_type.h"
+
 #include "mb/pg_wchar.h"

 #ifdef WIN32
@@ -519,6 +524,8 @@
                result->attDescs[i].typid = typid;
                result->attDescs[i].typlen = typlen;
                result->attDescs[i].atttypmod = atttypmod;
+               result->attDescs[i].is_int = typid==INT2OID || typid==INT4OID || typid==INT8OID;
+

                if (format != 1)
                        result->binary = 0;
@@ -674,6 +681,23 @@
                                return EOF;
                /* we have to terminate this ourselves */
                tup[i].value[vlen] = '\0';
+               #if __BYTE_ORDER == __LITTLE_ENDIAN
+               if (conn->convert_int && result->attDescs[i].is_int)
+               {
+                   switch (tup[i].len)
+                   {
+                       case 2:
+                           *(ut16*)tup[i].value);
+                           break;
+                       case 4:
+                           *(uint32*)tup[i].value=bswap_32(*(uint32*)tup[i].value);
+                           break;
+                       case 8:
+                           *(uint64*)tup[i].value=bswap_64(*(uint64*)tup[i].value);
+                           break;
+                   }
+               }
+               #endif
        }

        /* Success!  Store the completed tuple in the result */
diff -ur postgresql-8.2.4.orig/src/interfaces/libpq/libpq-fe.h postgresql-8.2.4/src/interfaces/libpq/libpq-fe.h
--- postgresql-8.2.4.orig/src/interfaces/libpq/libpq-fe.h       2006-10-04 04:30:13.000000000 +0400
+++ postgresql-8.2.4/src/interfaces/libpq/libpq-fe.h    2007-11-26 10:17:11.000000000 +0300
@@ -322,6 +322,15 @@
                           const int *paramFormats,
                           int resultFormat);

+extern PGresult *PQexecPreparedParams(PGconn *conn,
+                          const char *stmtName,
+                          int nParams,
+                          const Oid *paramTypes,
+                          const char *const * paramValues,
+                          const int *paramLengths,
+                          const int *paramFormats,
+                          int resultFormat);
+
 /* Interface for multiple-result or asynchronous queries */
 extern int     PQsendQuery(PGconn *conn, const char *query);
 extern int PQsendQueryParams(PGconn *conn,
@@ -342,6 +351,14 @@
                                        const int *paramLengths,
                                        const int *paramFormats,
                                        int resultFormat);
+extern int PQsendQueryPreparedParams(PGconn *conn,
+                                       const char *stmtName,
+                                       int nParams,
+                                       const Oid *paramTypes,
+                                       const char *const * paramValues,
+                                       const int *paramLengths,
+                                       const int *paramFormats,
+                                       int resultFormat);
 extern PGresult *PQgetResult(PGconn *conn);

 /* Routines for managing an asynchronous query */
@@ -415,6 +432,9 @@
 extern int     PQsendDescribePrepared(PGconn *conn, const char *stmt);
 extern int     PQsendDescribePortal(PGconn *conn, const char *portal);

+extern int     PQsetconvertint(PGconn *conn, int arg);
+extern int     PQisconvertint(PGconn *conn);
+
 /* Delete a PGresult */
 extern void PQclear(PGresult *res);

diff -ur postgresql-8.2.4.orig/src/interfaces/libpq/libpq-int.h postgresql-8.2.4/src/interfaces/libpq/libpq-int.h
--- postgresql-8.2.4.orig/src/interfaces/libpq/libpq-int.h      2006-10-04 04:30:13.000000000 +0400
+++ postgresql-8.2.4/src/interfaces/libpq/libpq-int.h   2007-11-26 10:17:11.000000000 +0300
@@ -92,6 +92,7 @@
        Oid                     typid;                  /* type id */
        int                     typlen;                 /* type size */
        int                     atttypmod;              /* type-specific modifier info */
+       bool                    is_int;
 } PGresAttDesc;

 /* Data about a single parameter of a prepared statement */
@@ -358,6 +359,8 @@

        /* Buffer for receiving various parts of messages */
        PQExpBufferData workBuffer; /* expansible string */
+
+       bool convert_int;
 };

 /* PGcancel stores all data necessary to cancel a connection. A copy of this

Attachment

pgsql-patches by date:

Previous
From: Tom Lane
Date:
Subject: Re: Proposed patch to make mergejoin cost estimation more symmetric
Next
From: Gregory Stark
Date:
Subject: Re: Proposed patch to make mergejoin cost estimationmore symmetric