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 dofloat8in
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 (neboFLOAT8OID
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 prodouble
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
vsrc/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 *)∈
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..