我使用libpq
在表格中插入浮点数。我收到此错误INSERT failed: ERROR: insufficient data left in message
。
以下是我的代码库中的相应代码段:
printf ("Enter write parameter_value");
scanf("%f", ¶meter_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 *)¶meter_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);
答案 0 :(得分:1)
您的代码中有两个错误:
您正在尝试发送二进制数据,但您没有告诉PQexecParams
它是哪种类型。
那不行。缺少类型信息,PostgreSQL将使用类型unknown
并将其视为字符串。这意味着您的二进制表示将被馈送到float8in
函数,该函数将字符串转换为双精度值,这将失败。这可能就是你所观察到的。
你必须使用包含701的Oid[]
的第四个参数(或者如果您更喜欢使用PostgreSQL的FLOAT8OID
,则使用#define
,但是您必须{{1} }}和#include <postgres.h>
。)
您错误地认为PostgreSQL的<catalog/pg_type.h>
类型的二进制表示形式是客户端计算机上使用的double precision
的二进制格式。
如果您的程序在big-endian计算机上运行,这可能会无意中发生,因为现在几乎每个架构都使用IEEE floating point numbers。
如果您阅读了源代码,您会发现PostgreSQL的线上二进制格式是在double
pq_sendfloat8
中定义的,src/backend/libpq/pqformat.c
调用pq_sendint64
,后者转换为8 - 网络字节顺序的字节值(与big-endian表示相同)。
所以你必须定义一个类似于此的转换函数:
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);
}
然后你的代码看起来像这样:
Oid types[1];
double converted;
...
types[0] = FLOAT8OID;
to_nbo(value, &converted);
values[0] = (char *)&converted;
但坦率地说,使用文本表示会更容易。这将使您的代码独立于PostgreSQL内部,并且可能不会那么慢。
它看起来不像,但如果从其他地方的PostgreSQL表中提取double precision
值,您可以设置extra_float_digits
= 3
,以确保不会丢失将值转换为字符串表示形式时的任何精度。