sql >> Databasteknik >  >> RDS >> PostgreSQL

Infoga ett flyttal i en tabell med hjälp av libpq

Det finns två fel i din kod:

  • Du försöker skicka binär data, men du berättar inte för PQexecParams vilken typ det är.

    Det kan inte fungera. I brist på typinformation kommer PostgreSQL att använda typen unknown och behandla det som ett snöre. Det betyder att din binära representation kommer att matas till float8in funktion som omvandlar strängar till dubbla precisionsvärden, vilket kommer att misslyckas fruktansvärt. Detta är förmodligen vad du observerar.

    Du måste använda en fjärde parameter med en Oid[] som innehåller 701 (eller FLOAT8OID om du hellre vill använda PostgreSQL:s #define , men du måste #include <postgres.h> och <catalog/pg_type.h> för det).

  • Du antar felaktigt att PostgreSQL:s binära representation av double precision typ är det binära formatet för double som används på din klientdator.

    Detta kan fungera av misstag om ditt program körs på en big-endian maskin, eftersom praktiskt taget alla arkitekturer nuförtiden använder IEEE-flyttal .

    Om du läser källkoden kommer du att upptäcka att PostgreSQL:s binära format över tråden är definierat i pq_sendfloat8 i src/backend/libpq/pqformat.c , som anropar pq_sendint64 , som konverterar 8-byte-värdet till nätverksbyteordning (vilket är samma som big-endian-representation).

Så du måste definiera en konverteringsfunktion som liknar denna:

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

Då kan din kod se ut så här:

Oid types[1];
double converted;

...

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

Men ärligt talat skulle det vara mycket lättare att använda textrepresentationen. Det kommer att göra din kod oberoende av PostgreSQL-interna funktioner och är förmodligen inte så mycket långsammare.

Det ser inte ut som det, men om double precision värden hämtas från en PostgreSQL-tabell någon annanstans kan du ställa in extra_float_digits = 3 så att du garanterat inte förlorar någon precision när värdena konverteras till deras strängrepresentation.




  1. Hur man skriver lagrade procedurer för professionella SSRS-rapporter

  2. Använder du kraften i kluster i samband med databaser?

  3. SQL Server främmande nyckel till flera tabeller

  4. MySQL Deadlock med en insert som höjer en trigger