2017-02-20 77 views
2

我使用libpq在表中插入浮点数。我得到这个错误INSERT failed: ERROR: insufficient data left in message使用libpq在表中插入浮点数

这里是我的代码库对应的摘录:

printf ("Enter write parameter_value"); 
scanf("%f", &parameter_value); 

char *stm = "INSERT INTO write_reg_set (parameter_value) VALUES ($1::double precision)"; 

int nparam = 1; 

//set the values to use 
const char *values[1] = {(char *)&parameter_value}; 

//calculate the lengths of each of the values 
int lengths[1] = {sizeof(parameter_value)}; 

//state which parameters are binary 
int binary[1] = {1}; 

PGresult *res = PQexecParams(conn, 
        stm, 
        nparam, //number of parameters 
        NULL, //ignore the Oid field 
        values, //values to substitute $1 and $2 and so on 
        lengths, //the lengths, in bytes, of each of the parameter values 
        binary, //whether the values are binary or not 
        0);  //we want the result in text format 

if (PQresultStatus(res) != PGRES_COMMAND_OK) { 
    fprintf(stderr, "INSERT failed: %s", PQerrorMessage(conn)); 
    exit_nicely(conn,res); 
} 
PQclear(res); 

回答

1

有两个错误在你的代码:

  • 您尝试发送二进制数据,但你不知道PQexecParams它是哪种类型。

    这是行不通的。缺少类型信息,PostgreSQL将使用类型unknown并将其视为字符串。这意味着您的二进制表示将被馈送到float8in函数,该函数将字符串转换为双精度值,这会导致可怕的失败。这可能是你正在观察的。

    你将不得不使用第四个参数与包含701 Oid[](或FLOAT8OID如果你宁愿使用PostgreSQL的#define,但你必须#include <postgres.h><catalog/pg_type.h>为)。

  • 您错误地认为PostgreSQL的double precision类型的二进制表示形式是您客户机器上使用的double的二进制格式。

    如果您的程序在big-endian机器上运行,这可能会意外地起作用,因为几乎每个架构现在都使用IEEE floating point numbers

    如果你读了源代码,你会发现,在pq_sendfloat8定义的 PostgreSQL的过度的电线二进制格式IST,这就要求pq_sendint64,其中8个字节的值转换为网络字节顺序(这是与大端表示法相同)。

所以你必须定义一个类似的转换功能:

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

那么你的代码看起来是这样的:

Oid types[1]; 
double converted; 

... 

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

但坦率地说,这将是更更容易使用文本表示。这将使你的代码独立于PostgreSQL内部,并且可能不会太慢​​。

它看起来并不像它,但如果double precision值从一个PostgreSQL表别的地方拉,你可以设置extra_float_digits= 3,让你保证不会丢失任何精度当值转换为他们的字符串表示..

+0

第一点:testlibpq2.c说ergarding OID“让后端推断参数类型”为二进制和文本的例子。这就是我省略它。你的第二点是有效的。 – Jam

+0

你认为后端应该推断出你传递的4个字节是双精度? [文档](https://www.postgresql.org/docs/current/static/libpq-exec.html#LIBPQ-PQEXECPARAMS)说:*如果paramTypes为NULL,或者数组中的任何特定元素为零,则服务器推断参数符号的数据类型的方式与它对**无类型文字字符串**。(强调我的) –