2017-02-20 8 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 유형을 사용하고 문자열로 처리합니다. 즉, 바이너리 표현은 문자열을 double precision 값으로 변환하는 float8in 함수에 전달되어 끔찍하게 실패합니다. 이것은 아마도 당신이 관찰하고있는 것입니다.

    당신은 (701)를 포함 Oid[]와 네 번째 매개 변수를 사용해야합니다 (오히려 PostgreSQL을의 #define를 사용하려는 경우 또는 FLOAT8OID,하지만 당신은 그것에 대해 #include <postgres.h><catalog/pg_type.h>해야 할 것이다).

  • PostgreSQL의 이진수 표현 double precision은 클라이언트 컴퓨터에서 사용중인 double의 이진 형식이라고 잘못 생각합니다.

    거의 모든 아키텍처가 IEEE floating point numbers을 사용하기 때문에 프로그램이 big-endian 컴퓨터에서 실행되는 경우 실수로 작동 할 수 있습니다.

    소스 코드를 읽는다면, 당신은 PostgreSQL을의 회선을 통한 바이너리 포맷 IST는 인 (바이트 순서를 네트워크에 8 바이트 값을 변환하는 pq_sendint64를 호출하는 src/backend/libpq/pqformat.cpq_sendfloat8에 정의 된 것을 확인할 수 있습니다 빅 엔디안 표현과 동일).

    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가 "백엔드가 매개 변수 유형을 추론합니다"라고 말합니다. Thatswhy 나는 그것을 생략했다. 귀하의 두 번째 포인트가 유효합니다. – Jam

+0

당신은 그것을 전달하는 4 바이트가 두 배라고 추론하는 백엔드가 어떻게 생각하십니까? [문서] (https://www.postgresql.org/docs/current/static/libpq-exec.html#LIBPQ-PQEXECPARAMS)는 다음과 같이 말합니다 : * paramTypes가 NULL이거나 배열의 특정 요소가 0이면 서버는 ** 형식화되지 않은 리터럴 문자열 **. * (emphasis mine)과 동일한 방식으로 매개 변수 심볼에 대한 데이터 유형을 추론합니다. –