Ihr Code enthält zwei Fehler:
-
Sie versuchen, binäre Daten zu senden, aber Sie teilen
PQexecParams
nichts mit um welchen Typ es sich handelt.Das kann nicht funktionieren. Ohne Typinformationen verwendet PostgreSQL den Typ
unknown
und behandeln Sie es als Zeichenfolge. Das bedeutet, dass Ihre binäre Darstellung demfloat8in
zugeführt wird Funktion, die Zeichenfolgen in Werte mit doppelter Genauigkeit umwandelt, was schrecklich fehlschlagen wird. Dies ist wahrscheinlich das, was Sie beobachten.Sie müssen einen vierten Parameter mit einem
Oid[]
verwenden die 701 (oderFLOAT8OID
) enthält wenn Sie lieber#define
von PostgreSQL verwenden möchten , aber Sie müssten#include <postgres.h>
und<catalog/pg_type.h>
dafür). -
Sie nehmen fälschlicherweise an, dass die binäre Darstellung von PostgreSQL die
double precision
type ist das Binärformat fürdouble
auf Ihrem Client-Rechner verwendet wird.Dies könnte versehentlich funktionieren, wenn Ihr Programm auf einem Big-Endian läuft Maschine, da praktisch jede Architektur heutzutage IEEE-Gleitkommazahlen verwendet .
Wenn Sie den Quellcode lesen, werden Sie feststellen, dass das Over-the-Wire-Binärformat von PostgreSQL in
pq_sendfloat8
definiert ist insrc/backend/libpq/pqformat.c
, diepq_sendint64
aufruft , der den 8-Byte-Wert in die Netzwerk-Byte-Reihenfolge konvertiert (was der Big-Endian-Darstellung entspricht).
Sie müssten also eine Konvertierungsfunktion ähnlich der folgenden definieren:
static void to_nbo(double in, double *out) {
uint64_t *i = (uint64_t *)∈
uint32_t *r = (uint32_t *)out;
/* convert input to network byte order */
r[0] = htonl((uint32_t)((*i) >> 32));
r[1] = htonl((uint32_t)*i);
}
Dann könnte Ihr Code so aussehen:
Oid types[1];
double converted;
...
types[0] = FLOAT8OID;
to_nbo(value, &converted);
values[0] = (char *)&converted;
Aber ehrlich gesagt wäre es viel einfacher, die Textdarstellung zu verwenden. Das macht Ihren Code unabhängig von PostgreSQL-Interna und ist wahrscheinlich nicht so viel langsamer.
Es sieht nicht so aus, aber wenn die double precision
Werte aus einer PostgreSQL-Tabelle an anderer Stelle gezogen werden, könnten Sie extra_float_digits
= 3
damit Sie garantiert keine Genauigkeit verlieren, wenn die Werte in ihre String-Darstellung konvertiert werden..