PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Wstawianie liczby zmiennoprzecinkowej do tabeli za pomocą libpq

W Twoim kodzie są dwa błędy:

  • Próbujesz wysłać dane binarne, ale nie mówisz PQexecParams jaki to jest typ.

    To nie może działać. Brak informacji o typie PostgreSQL użyje typu unknown i traktuj to jako ciąg. Oznacza to, że twoja binarna reprezentacja zostanie przekazana do float8in funkcja, która konwertuje ciągi na wartości podwójnej precyzji, co strasznie się nie powiedzie. To jest prawdopodobnie to, co obserwujesz.

    Będziesz musiał użyć czwartego parametru z Oid[] który zawiera 701 (lub FLOAT8OID jeśli wolisz używać #define PostgreSQLa , ale musiałbyś #include <postgres.h> i <catalog/pg_type.h> za to).

  • Błędnie zakładasz, że binarna reprezentacja PostgreSQL double precision type to format binarny dla double w użyciu na komputerze klienckim.

    Może to przypadkowo zadziałać, jeśli Twój program działa na big-endian maszyny, ponieważ obecnie praktycznie każda architektura używa liczby zmiennoprzecinkowe IEEE .

    Jeśli przeczytasz kod źródłowy, odkryjesz, że format binarny PostgreSQL jest zdefiniowany w pq_sendfloat8 w src/backend/libpq/pqformat.c , który wywołuje pq_sendint64 , który konwertuje wartość 8-bajtową na sieciowy porządek bajtów (który jest taki sam jak reprezentacja big-endian).

Musisz więc zdefiniować funkcję konwersji podobną do tej:

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

Wtedy Twój kod może wyglądać tak:

Oid types[1];
double converted;

...

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

Ale szczerze mówiąc, znacznie łatwiej byłoby użyć reprezentacji tekstowej. To sprawi, że Twój kod będzie niezależny od wewnętrznych elementów PostgreSQL i prawdopodobnie nie będzie dużo wolniejszy.

Nie wygląda na to, ale jeśli double precision wartości są pobierane z tabeli PostgreSQL gdzie indziej, możesz ustawić extra_float_digits = 3 dzięki czemu masz gwarancję, że nie stracisz precyzji, gdy wartości zostaną przekonwertowane na ich reprezentację w postaci ciągu.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Rails:wdrażanie do Heroku, wiele problemów

  2. jak poprzedzić ciąg przed sekwencją wygenerowaną przez postgresql?

  3. Postgis SQL dla najbliższych sąsiadów

  4. Alias ​​odniesienia w klauzuli WHERE

  5. Jak dodać kolumnę w tabeli za pomocą migracji laravel 5 bez utraty jej danych?