Ihr Code enthält zwei Fehler:
-
Sie versuchen, binäre Daten zu senden, aber Sie teilen
PQexecParamsnichts mit um welchen Typ es sich handelt.Das kann nicht funktionieren. Ohne Typinformationen verwendet PostgreSQL den Typ
unknownund behandeln Sie es als Zeichenfolge. Das bedeutet, dass Ihre binäre Darstellung demfloat8inzugefü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#definevon 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 precisiontype ist das Binärformat fürdoubleauf 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_sendfloat8definiert ist insrc/backend/libpq/pqformat.c, diepq_sendint64aufruft , 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..