Il y a deux erreurs dans votre code :
-
Vous essayez d'envoyer des données binaires, mais vous ne dites pas à
PQexecParamsde quel type il s'agit.Cela ne peut pas fonctionner. Faute d'informations sur le type, PostgreSQL utilisera le type
unknownet traitez-le comme une chaîne. Cela signifie que votre représentation binaire sera transmise aufloat8infonction 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 (ouFLOAT8OIDsi vous préférez utiliser le#definede 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 precisiontype est le format binaire pourdoubleen 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_sendfloat8danssrc/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..