Il y a deux erreurs dans votre code :
-
Vous essayez d'envoyer des données binaires, mais vous ne dites pas à
PQexecParams
de quel type il s'agit.Cela ne peut pas fonctionner. Faute d'informations sur le type, PostgreSQL utilisera le type
unknown
et traitez-le comme une chaîne. Cela signifie que votre représentation binaire sera transmise aufloat8in
fonction qui convertit les chaînes en valeurs à double précision, ce qui échouera horriblement. C'est probablement ce que vous observez.Vous devrez utiliser un quatrième paramètre avec un
Oid[]
qui contient 701 (ouFLOAT8OID
si vous préférez utiliser le#define
de PostgreSQL , mais vous devrez#include <postgres.h>
et<catalog/pg_type.h>
pour ça). -
Vous supposez à tort que la représentation binaire de PostgreSQL de la
double precision
type est le format binaire pourdouble
en cours d'utilisation sur votre ordinateur client.Cela peut fonctionner accidentellement si votre programme s'exécute sur un big-endian machine, puisque pratiquement toutes les architectures utilisent de nos jours nombres à virgule flottante IEEE .
Si vous lisez le code source, vous constaterez que le format binaire over-the-wire de PostgreSQL est défini dans
pq_sendfloat8
danssrc/backend/libpq/pqformat.c
, qui appellepq_sendint64
, qui convertit la valeur de 8 octets dans l'ordre des octets du réseau (qui est identique à la représentation gros-boutiste).
Vous devez donc définir une fonction de conversion similaire à celle-ci :
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);
}
Votre code pourrait alors ressembler à ceci :
Oid types[1];
double converted;
...
types[0] = FLOAT8OID;
to_nbo(value, &converted);
values[0] = (char *)&converted;
Mais franchement, il serait beaucoup plus facile d'utiliser la représentation textuelle. Cela rendra votre code indépendant des composants internes de PostgreSQL et n'est probablement pas tellement plus lent.
Cela n'en a pas l'air, mais si la double precision
les valeurs sont extraites d'une table PostgreSQL ailleurs, vous pouvez définir extra_float_digits
= 3
de sorte que vous êtes assuré de ne perdre aucune précision lorsque les valeurs sont converties en leur représentation sous forme de chaîne..