sql >> Base de Datos >  >> RDS >> PostgreSQL

Insertar un número de punto flotante en una tabla usando libpq

Hay dos errores en su código:

  • Está intentando enviar datos binarios, pero no le dice a PQexecParams de qué tipo es.

    Eso no puede funcionar. Al carecer de información de tipo, PostgreSQL utilizará el tipo unknown y trátelo como una cadena. Eso significa que su representación binaria se alimentará al float8in función que convierte cadenas en valores de doble precisión, lo que fallará horriblemente. Esto es probablemente lo que estás observando.

    Tendrá que usar un cuarto parámetro con un Oid[] que contiene 701 (o FLOAT8OID si prefiere usar #define de PostgreSQL , pero tendría que #include <postgres.h> y <catalog/pg_type.h> por eso).

  • Asumes erróneamente que la representación binaria de PostgreSQL de la double precision type es el formato binario para double en uso en su máquina cliente.

    Esto podría funcionar accidentalmente si su programa se ejecuta en un big-endian máquina, ya que prácticamente todas las arquitecturas en estos días usan números de coma flotante IEEE .

    Si lee el código fuente, encontrará que el formato binario over-the-wire de PostgreSQL está definido en pq_sendfloat8 en src/backend/libpq/pqformat.c , que llama a pq_sendint64 , que convierte el valor de 8 bytes en orden de bytes de red (que es lo mismo que la representación big-endian).

Entonces tendría que definir una función de conversión similar a esta:

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

Entonces su código podría verse así:

Oid types[1];
double converted;

...

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

Pero, francamente, sería mucho más fácil usar la representación de texto. Eso hará que su código sea independiente de las partes internas de PostgreSQL y probablemente no sea mucho más lento.

No lo parece, pero si la double precision los valores se extraen de una tabla de PostgreSQL en otro lugar, puede configurar extra_float_digits = 3 para que tenga la garantía de no perder precisión cuando los valores se conviertan a su representación de cadena..