PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Insertion d'un nombre à virgule flottante dans une table à l'aide de libpq

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 au float8in 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 (ou FLOAT8OID 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 pour double 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 dans src/backend/libpq/pqformat.c , qui appelle pq_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 *)&in;
    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..