如何使用libpq获取double值? [英] How to get the double value using libpq?

查看:143
本文介绍了如何使用libpq获取double值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

libpq文档中的示例显示如何获取通过将其转换为主机端表示法,该整数值。



我很好奇使用libpq(不使用libpqtyppes)获取双精度值必须做什么?我试过 reinterpret_cast ,没有运气。



另外为什么文本和字节数据不需要endian转换? / p>

数据库在Windows 7上本地运行,我使用Visual C ++ 2013。



pptr 是我正在检索的双重密码。

  #include< iostream> 
#include< memory>
#include< vector>
#include< libpq-fe.h>
#include< Winsock2.h>


static void
show_binary_results(PGresult * res)
{
int i,j;
int i_fnum,n_fnum,p_fnum;

/ *使用PQfnumber来避免对结果* /
中的字段顺序的假设b i_fnum = PQfnumber(res,id);
n_fnum = PQfnumber(res,name);
p_fnum = PQfnumber(res,price); (i = 0; i< PQntuples(res); i ++)
{
char * iptr;
char * nptr;
char * pptr;
int blen;
intival;

/ *获取字段值(我们忽略可能性为null!)* /
iptr = PQgetvalue(res,i,i_fnum);
nptr = PQgetvalue(res,i,n_fnum);
pptr = PQgetvalue(res,i,p_fnum); / *这是一个值我想要得到* /

/ *
* INT4的二进制表示是网络字节顺序,其中
*我们最好强制到本地字节顺序。
* /
ival = ntohl(*((uint32_t *)iptr));

/ *
* TEXT的二进制表示形式是文本,因为libpq
*很好,可以附加一个零字节,它只能工作罚款
*作为C字符串。
*
* BYTEA的二进制表示是一堆字节,可以
*包含嵌入的空值,所以我们必须注意字段长度。
* /
// blen = PQgetlength(res,i,b_fnum);

printf(tuple%d:got\\\
,i);
printf(i =(%d bytes)%d\\\

PQgetlength(res,i,i_fnum),ival);
printf(t =(%d bytes)'%s'\\\

PQgetlength(res,i,n_fnum),nptr);
printf(p =(%d bytes)%f\\\

PQgetlength(res,i,p_fnum),* reinterpret_cast< double *>(pptr));

printf(\\\
\\\
);
}
}


int main(int argc,char * argv [])
{
auto conn_string =postgresql:/ / postgres的:PWD @本地/分贝;
auto conn_deleter = [](PGconn * c){PQfinish(c); };
auto res_deleter = [](PGresult * r){PQclear(r); std :: cout<< 删除<<的std :: ENDL; };
std :: unique_ptr< PGconn,decltype(conn_deleter)> conn(PQconnectdb(conn_string),conn_deleter);

if(PQstatus(conn.get())!= ConnStatusType :: CONNECTION_OK)
std :: cerr<< 问题<<的std :: ENDL;

std :: vector< const char *> params {1};
std :: unique_ptr< PGresult,decltype(res_deleter)> res(PQexecParams(conn.get(),
SELECT * FROM table_with_double WHERE id = $ 1,
params.size(),/ *一个参数* /
NULL,/ * let后端推导参数类型* /
(const char * const *)& params.front(),
NULL,/ *不需要参数长度,因为文本* /
NULL, / *默认为所有文本参数* /
1),/ *请求二进制结果* /
res_deleter);

if(PQresultStatus(res.get())!= ExecStatusType :: PGRES_TUPLES_OK)
std :: cout<< SELECT failed:<< PQerrorMessage(conn.get())<<的std :: ENDL;
show_binary_results(res.get());
}


解决方案

显然,双列的数据以大字符串形式出现,必须转换成一个小字母。与ints一样。基于这个优秀的答案中的文章我使用了一个简单的函数来交换双重值。

  double double_swap(double d)
{
union
{
double d;
unsigned char bytes [8];
} src,dest;

src.d = d;
dest.bytes [0] = src.bytes [7];
dest.bytes [1] = src.bytes [6];
dest.bytes [2] = src.bytes [5];
dest.bytes [3] = src.bytes [4];
dest.bytes [4] = src.bytes [3];
dest.bytes [5] = src.bytes [2];
dest.bytes [6] = src.bytes [1];
dest.bytes [7] = src.bytes [0];
return dest.d;
}

应用此函数从DB中检索正确的值。

  printf(p =(%d bytes)%lf\\\

PQgetlength(res,i,p_fnum) double_swap(*((double *)pptr)));


The examples in the libpq documentation show how to get the the integer value by converting it to the host-endian representation.

I am curious what must be done to get the double precision value using libpq (without libpqtyppes)? I have tried reinterpret_cast with no luck.

Also why text and byte data doesn't need endian conversions?

The DB runs locally on Windows 7, I am using Visual C++ 2013.

pptr is a double vaule I am trying to retrieve.

#include <iostream>
#include <memory>
#include <vector>
#include <libpq-fe.h>
#include <Winsock2.h>


static void
show_binary_results(PGresult *res)
{
    int i, j;
    int i_fnum, n_fnum, p_fnum;

    /* Use PQfnumber to avoid assumptions about field order in result */
    i_fnum = PQfnumber(res, "id");
    n_fnum = PQfnumber(res, "name");
    p_fnum = PQfnumber(res, "price");

    for (i = 0; i < PQntuples(res); i++)
    {
        char* iptr;
        char* nptr;
        char* pptr;
        int         blen;
        int         ival;

        /* Get the field values (we ignore possibility they are null!) */
        iptr = PQgetvalue(res, i, i_fnum);
        nptr = PQgetvalue(res, i, n_fnum);
        pptr = PQgetvalue(res, i, p_fnum); /*THIS IS A VALUE I AM TRYING TO GET*/

        /*
        * The binary representation of INT4 is in network byte order, which
        * we'd better coerce to the local byte order.
        */
        ival = ntohl(*((uint32_t *) iptr));

        /*
        * The binary representation of TEXT is, well, text, and since libpq
        * was nice enough to append a zero byte to it, it'll work just fine
        * as a C string.
        *
        * The binary representation of BYTEA is a bunch of bytes, which could
        * include embedded nulls so we have to pay attention to field length.
        */
        //blen = PQgetlength(res, i, b_fnum);

        printf("tuple %d: got\n", i);
        printf(" i = (%d bytes) %d\n",
            PQgetlength(res, i, i_fnum), ival);
        printf(" t = (%d bytes) '%s'\n",
            PQgetlength(res, i, n_fnum), nptr);
        printf(" p = (%d bytes) %f\n",
            PQgetlength(res, i, p_fnum), *reinterpret_cast<double*>(pptr));

        printf("\n\n");
    }
}


int main(int argc, char* argv [])
{
    auto conn_string = "postgresql://postgres:pwd@localhost/db";
    auto conn_deleter = [](PGconn* c) { PQfinish(c); };
    auto res_deleter = [](PGresult* r) { PQclear(r); std::cout << "deleted" << std::endl; };
    std::unique_ptr<PGconn, decltype(conn_deleter)> conn(PQconnectdb(conn_string), conn_deleter);

    if (PQstatus(conn.get()) != ConnStatusType::CONNECTION_OK)
        std::cerr << "Problem" << std::endl;

    std::vector<const char *> params{ "1" };
    std::unique_ptr < PGresult, decltype(res_deleter)> res(PQexecParams(conn.get(),
        "SELECT * FROM table_with_double WHERE id = $1",
        params.size(),       /* one param */
        NULL,    /* let the backend deduce param type */
        (const char * const *)&params.front(),
        NULL,    /* don't need param lengths since text */
        NULL,    /* default to all text params */
        1), /* ask for binary results */
        res_deleter);      

    if (PQresultStatus(res.get()) != ExecStatusType::PGRES_TUPLES_OK)
        std::cout << "SELECT failed: " << PQerrorMessage(conn.get()) << std::endl;
    show_binary_results(res.get());
}

解决方案

Apparently data for a double column comes in as big endian and has to be converted to a little endian. Same as ints. Based on this excellent article from this answer I have used a simple function to swap the double value.

double double_swap(double d)
{
    union
    {
        double d;
        unsigned char bytes[8];
    } src, dest;

    src.d = d;
    dest.bytes[0] = src.bytes[7];
    dest.bytes[1] = src.bytes[6];
    dest.bytes[2] = src.bytes[5];
    dest.bytes[3] = src.bytes[4];
    dest.bytes[4] = src.bytes[3];
    dest.bytes[5] = src.bytes[2];
    dest.bytes[6] = src.bytes[1];
    dest.bytes[7] = src.bytes[0];
    return dest.d;
}

Applying this function a correct value is retrieved from the DB.

printf(" p = (%d bytes) %lf\n",
            PQgetlength(res, i, p_fnum), double_swap(*((double*) pptr)));

这篇关于如何使用libpq获取double值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆