【问题标题】:Is it possible to get the binary (or hexadecimal) representation of a value stored as double precision in a PostgreSQL database?是否可以获得在 PostgreSQL 数据库中存储为双精度值的二进制(或十六进制)表示?
【发布时间】:2014-06-09 10:45:36
【问题描述】:

是否可以获得在 PostgreSQL 数据库中存储为双精度值的二进制(或十六进制)表示形式?

我已经尝试使用强制转换为 bit(64)(双精度存储大小为 8 个字节),但出现以下错误:

SELECT (1.031::double precision)::bit(64)
>> ERROR:  cannot cast type double precision to bit

SELECT (1024::double precision)::bit(64)
>> ERROR:  cannot cast type double precision to bit

它适用于整数:

select (1024::integer)::bit(32)
>> 00000000000000000000010000000000

select (-1024::integer)::bit(32)
>> 11111111111111111111110000000000

select (1024::bigint)::bit(64)
>> 0000000000000000000000000000000000000000000000000000010000000000

select ((17179869184+8589934592)::bigint)::bit(64)
>> 0000000000000000000000000000011000000000000000000000000000000000

官方文档似乎没有为 SQL 查询上的双精度值提供一种方法。

然而

SELECT -0::double precision AS minuszero, 0::double precision AS pluszero

在 pgAdmin III 中给出以下结果:

"minuszero";"pluszero"
-0;0

这似乎表明 pgAdmin 知道 Postgres 返回的 2 个值之间的差异(其差异仅在于 0 和 -0 的二进制表示(IEEE 标准 754)的符号位)。

不知何故,我假设 pgAdmin 在内部从数据库的回复中获取双精度值的二进制表示,并在屏幕上相应地以十进制表示显示。

【问题讨论】:

  • 你为什么要这样做?
  • psql 显示相同的结果
  • 我不希望任何 RDBMS 像您要求的那样公开其内部结构……尤其是通过 SQL,它的存在主要是为了向用户和开发人员隐藏这些内部结构。为什么需要这样的东西?
  • 在这种情况下,我对区分 -0 和 0 的可能性感兴趣。任何通常的比较平均值都会导致两个值相等(这是根据 IEEE 标准 754 的预期行为)。然而它们在内部是不同的,并且以不同的方式向用户显示“0”和“-0”。比较二进制表示将提供一种以编程方式进行区分的方法。另一个想法:为什么我可以将整数转换为二进制而不是双精度? (如果“SQL [...] 的存在主要是为了向用户和开发人员隐藏这些内部信息”)
  • 我想澄清一下,这个问题不是关于比较 -0 和 0。请不要回答将 -0 与 0 比较的方法,这不是这里的主题 ;) 从双精度转换为二进制的想法最初确实来自这个问题,但我更感兴趣的是获取 any 双精度值的二进制表示的方法。

标签: sql postgresql binary hex double


【解决方案1】:

不知何故,我假设 pgAdmin 在内部获取二进制文件 来自回复的双精度值的表示 数据库,并相应地以十进制表示形式显示在 屏幕。

不,实际上它根本不理解二进制。 -00 是来自服务器的逐字文本表示。如果 pgAdmin 理解二进制,它可以显示这个 SQL 序列的结果:

DECLARE c BINARY CURSOR WITH HOLD FOR
  SELECT -0::double precision AS minuszero, 0::double precision AS pluszero;

FETCH 1 FROM c;

事实上,它在每一列中显示一个空字符串作为输出。

psql 命令行工具也无法处理二进制,因为它不支持原始查询结果中的空字节。

这不是 C libpq 库的限制,即使是最简单的函数 PQexec()。可以使用以下代码获取原始字节并以十六进制显示:

  PGresult* res = PQexec(conn, "DECLARE c BINARY CURSOR WITH HOLD FOR "
    "SELECT -0::double precision AS minuszero, 0::double precision AS pluszero;"
    "FETCH 1 FROM c");
  if (res && PQresultStatus(res)==PGRES_TUPLES_OK) {
    for (int i=0; i<PQnfields(res); i++) {
      printf("column %s: ", PQfname(res, i));
      for (int j=0; j<PQfsize(res,0); j++)
        printf("%02x", ((unsigned char*)PQgetvalue(res, 0, i))[j]);
      printf("\n");
    }
  }

结果:

列减零:8000000000000000
列加零:0000000000000000

您最终可以将此符号位视为第一列中设置的第一个(也是唯一一个)位。它采用网络字节顺序,MSB 在前,与 x86 系列中使用的小端架构的磁盘表示形式相比,它是相反的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-02-07
    • 2010-12-15
    • 1970-01-01
    • 1970-01-01
    • 2022-01-22
    • 2011-03-31
    • 1970-01-01
    相关资源
    最近更新 更多