Ci sono due errori nel tuo codice:
-
Stai tentando di inviare dati binari, ma non dici a
PQexecParams
che tipo è.Non può funzionare. In mancanza di informazioni sul tipo, PostgreSQL utilizzerà il tipo
unknown
e trattalo come una stringa. Ciò significa che la tua rappresentazione binaria verrà inviata afloat8in
funzione 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 (oFLOAT8OID
se preferisci usare#define
di PostgreSQL , ma dovresti#include <postgres.h>
e<catalog/pg_type.h>
per quello). -
Si presume erroneamente che la rappresentazione binaria di PostgreSQL della
double precision
type è il formato binario perdouble
in 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_sendfloat8
insrc/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..