sql >> Databáze >  >> RDS >> PostgreSQL

Vložení čísla s plovoucí desetinnou čárkou do tabulky pomocí libpq

Ve vašem kódu jsou dvě chyby:

  • Pokoušíte se odeslat binární data, ale neříkáte PQexecParams o jaký typ se jedná.

    To nemůže fungovat. Bez informací o typu bude PostgreSQL používat typ unknown a zacházet s ním jako s provázkem. To znamená, že vaše binární reprezentace bude přiváděna do float8in funkce, která převádí řetězce na hodnoty s dvojnásobnou přesností, což selže. To je pravděpodobně to, co pozorujete.

    Budete muset použít čtvrtý parametr s Oid[] který obsahuje 701 (nebo FLOAT8OID pokud byste raději použili #define PostgreSQL , ale museli byste #include <postgres.h> a <catalog/pg_type.h> za to).

  • Mylně předpokládáte, že binární reprezentace PostgreSQL double precision type je binární formát pro double na vašem klientském počítači.

    To může náhodně fungovat, pokud váš program běží na big-endian počítač, protože prakticky každá architektura v dnešní době používá čísla IEEE s plovoucí desetinnou čárkou .

    Pokud si přečtete zdrojový kód, zjistíte, že binární formát PostgreSQL over-the-wire je definován v pq_sendfloat8 v src/backend/libpq/pqformat.c , který volá pq_sendint64 , který převádí 8bajtovou hodnotu na síťové pořadí bajtů (což je stejné jako reprezentace big-endian).

Takže byste museli definovat konverzní funkci podobnou této:

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

Pak by váš kód mohl vypadat takto:

Oid types[1];
double converted;

...

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

Ale upřímně řečeno, bylo by mnohem jednodušší použít reprezentaci textu. Díky tomu bude váš kód nezávislý na vnitřních částech PostgreSQL a pravděpodobně nebude o tolik pomalejší.

Nezdá se to, ale pokud je double precision hodnoty jsou získávány z tabulky PostgreSQL někde jinde, můžete nastavit extra_float_digits = 3 takže je zaručeno, že neztratíte žádnou přesnost, když se hodnoty převedou na jejich řetězcovou reprezentaci..




  1. Nejjednodušší způsob migrace projektu Django z MySQL do PostgreSQL

  2. Jak kombinovat datum z jednoho pole s časem z jiného pole - MS SQL Server

  3. mysqli - Opravdu musím udělat $result->close(); &$mysqli->close();?

  4. Laravel Eloquent vybere všechny řádky s max. created_at