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