sql >> Database >  >> RDS >> PostgreSQL

Een getal met drijvende komma in een tabel invoegen met libpq

Er zijn twee fouten in uw code:

  • U probeert binaire gegevens te verzenden, maar u vertelt PQexecParams niet welk type het is.

    Dat kan niet werken. Bij gebrek aan type-informatie gebruikt PostgreSQL het type unknown en behandel het als een string. Dat betekent dat uw binaire representatie wordt ingevoerd in de float8in functie die tekenreeksen converteert naar dubbele precisiewaarden, die vreselijk zullen mislukken. Dit is waarschijnlijk wat je waarneemt.

    U moet een vierde parameter gebruiken met een Oid[] die 701 (of FLOAT8OID bevat) als je liever PostgreSQL's #define gebruikt , maar je moet #include <postgres.h> en <catalog/pg_type.h> daarvoor).

  • U neemt ten onrechte aan dat PostgreSQL's binaire representatie van de double precision type is het binaire formaat voor double in gebruik op uw clientcomputer.

    Dit kan per ongeluk werken als je programma draait op een big-endian machine, aangezien vrijwel elke architectuur tegenwoordig IEEE floating point getallen gebruikt .

    Als je de broncode leest, zul je zien dat het over-the-wire binaire formaat van PostgreSQL is gedefinieerd in pq_sendfloat8 in src/backend/libpq/pqformat.c , die pq_sendint64 . aanroept , die de 8-byte-waarde converteert naar netwerkbytevolgorde (wat hetzelfde is als big-endian-representatie).

U zou dus een conversiefunctie moeten definiëren die lijkt op deze:

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

Dan zou je code er als volgt uit kunnen zien:

Oid types[1];
double converted;

...

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

Maar eerlijk gezegd zou het veel gemakkelijker zijn om de tekstrepresentatie te gebruiken. Dat maakt je code onafhankelijk van PostgreSQL internals en is waarschijnlijk niet zo veel langzamer.

Het lijkt er niet op, maar als de double precision waarden uit een PostgreSQL-tabel ergens anders worden gehaald, kunt u extra_float_digits = 3 zodat u gegarandeerd geen precisie verliest wanneer de waarden worden geconverteerd naar hun tekenreeksweergave.




  1. Zoeken naar gegevens die geen Engelse tekst zijn

  2. Unieke geïndexeerde waarden overschrijven

  3. SQL geeft geen null-waarden weer bij een query die niet gelijk is aan?

  4. Hoe de activiteit van één database in SQL Server te analyseren