sql >> Database teknologi >  >> RDS >> PostgreSQL

Indsættelse af et flydende kommatal i en tabel ved hjælp af libpq

Der er to fejl i din kode:

  • Du forsøger at sende binære data, men du fortæller ikke PQexecParams hvilken type det er.

    Det kan ikke fungere. Manglende typeoplysninger vil PostgreSQL bruge typen unknown og behandle det som snor. Det betyder, at din binære repræsentation vil blive ført til float8in funktion, der konverterer strenge til dobbelte præcisionsværdier, hvilket vil fejle frygteligt. Det er sandsynligvis det, du observerer.

    Du bliver nødt til at bruge en fjerde parameter med en Oid[] der indeholder 701 (eller FLOAT8OID hvis du hellere vil bruge PostgreSQL's #define , men du skal #include <postgres.h> og <catalog/pg_type.h> for det).

  • Du antager fejlagtigt, at PostgreSQL's binære repræsentation af double precision type er det binære format for double i brug på din klientmaskine.

    Dette virker muligvis ved et uheld, hvis dit program kører på en big-endian maskine, da stort set alle arkitekturer i disse dage bruger IEEE flydende kommatal .

    Hvis du læser kildekoden, vil du opdage, at PostgreSQL's over-the-wire binære format er defineret i pq_sendfloat8 i src/backend/libpq/pqformat.c , som kalder pq_sendint64 , som konverterer 8-byte-værdien til netværksbyte-rækkefølge (hvilket er det samme som big-endian-repræsentation).

Så du bliver nødt til at definere en konverteringsfunktion, der ligner denne:

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);
}

Så kunne din kode se sådan ud:

Oid types[1];
double converted;

...

types[0] = FLOAT8OID;
to_nbo(value, &converted);
values[0] = (char *)&converted;

Men ærligt talt ville det være meget nemmere at bruge tekstgengivelsen. Det vil gøre din kode uafhængig af PostgreSQL internals og er sandsynligvis ikke så meget langsommere.

Det ser ikke sådan ud, men hvis double precision værdier hentes fra en PostgreSQL-tabel et andet sted, kan du indstille extra_float_digits = 3 så du er garanteret ikke at miste nogen præcision, når værdierne konverteres til deres strengrepræsentation.




  1. Kan ikke finde nulværdi fra JSON_EXTRACT

  2. PDO PHP bindValue virker ikke

  3. Opdater en kolonne i en tabel med en kolonne i en anden tabel i PostgreSQL

  4. Oracle 12c - yder indeks på en 'nummer'-kolonne hurtigere end indeks på 'varchar'-kolonne?