Ci sono due errori nel tuo codice:
-
Stai tentando di inviare dati binari, ma non dici a
PQexecParamsche tipo è.Non può funzionare. In mancanza di informazioni sul tipo, PostgreSQL utilizzerà il tipo
unknowne trattalo come una stringa. Ciò significa che la tua rappresentazione binaria verrà inviata afloat8infunzione che converte le stringhe in valori a doppia precisione, che falliranno in modo orribile. Questo è probabilmente ciò che stai osservando.Dovrai usare un quarto parametro con un
Oid[]che contiene 701 (oFLOAT8OIDse preferisci usare#definedi PostgreSQL , ma dovresti#include <postgres.h>e<catalog/pg_type.h>per quello). -
Si presume erroneamente che la rappresentazione binaria di PostgreSQL della
double precisiontype è il formato binario perdoublein uso sul tuo computer client.Questo potrebbe funzionare accidentalmente se il tuo programma è in esecuzione su un big-endian macchina, dal momento che praticamente ogni architettura oggigiorno utilizza numeri in virgola mobile IEEE .
Se leggi il codice sorgente, scoprirai che il formato binario over-the-wire di PostgreSQL è definito in
pq_sendfloat8insrc/backend/libpq/pqformat.c, che chiamapq_sendint64, che converte il valore a 8 byte nell'ordine dei byte di rete (che è lo stesso della rappresentazione big-endian).
Quindi dovresti definire una funzione di conversione simile a questa:
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);
}
Quindi il tuo codice potrebbe assomigliare a questo:
Oid types[1];
double converted;
...
types[0] = FLOAT8OID;
to_nbo(value, &converted);
values[0] = (char *)&converted;
Ma francamente, sarebbe molto più semplice utilizzare la rappresentazione testuale. Ciò renderà il tuo codice indipendente dagli interni di PostgreSQL e probabilmente non sarà molto più lento.
Non sembra, ma se la double precision i valori vengono estratti da una tabella PostgreSQL da qualche altra parte, è possibile impostare extra_float_digits
= 3 in modo che tu abbia la garanzia di non perdere alcuna precisione quando i valori vengono convertiti nella loro rappresentazione di stringa..