在 PostgreSQL 中将 bytea 转换为双精度
Convert bytea to double precision in PostgreSQL
我有一个数据库,其中一个 table 存储从另一个系统收集的各种通用数据的 blob (bytea
)。 bytea
字段可以包含任何内容。为了知道如何解释数据,table 还有一个格式字段。我写了一个 Java 应用程序来从数据库中读取 bytea
字段作为 byte[]
然后我可以轻松地将它转换为 double[]
或 int[]
或任何格式字段表示使用 ByteBuffer
和各种视图(DoubleBuffer
、IntBuffer
等)。
现在我遇到这样的情况,我需要在触发器函数中对数据库本身的数据进行一些操作,以保持与另一个 table 的完整性。我可以找到任何可以想象到的数据类型的转换,但我找不到从 bytea
(甚至 bit
)到 double precision
并返回的任何内容。 bytea
可以分解,转换为位,然后转换为 int
或 bigint
,但不能转换为 double precision
。例如,x'deadbeefdeadbeef'::bit(64)::bigint
将毫无问题地转换为 -2401053088876216593
,但 x'deadbeefdeadbeef'::bit(64)::double precision
失败并返回 "ERROR: cannot cast type bit to double precision" 而不是给出 -1.1885959257070704E148
.[=33 的 IEEE 754 答案=]
我找到了这个答案,它基本上实现了将位转换为双精度的 IEEE 标准,但是 PostgreSQL 中真的没有基本的转换函数可以做到这一点吗?另外,当我完成数据操作并需要更新 table 时,我还需要从 double precision
倒退到 bytea
,这个答案没有提供。
有什么想法吗?
好的,我找到了答案。在 PostgreSQL 中,您可以使用 Python 编写函数。为了启用 Python,您必须安装安装 PostgreSQL 所需的特定版本的 Python,并在 PATH 环境变量中提供它。您可以通过查看安装说明找到安装 PostgreSQL 所需的 Python 版本。我目前在 Windows 上使用 PostgreSQL 9.6.5,它需要 Python 3.3。我最初尝试了最新的 Python 3.6,但它不起作用。我为 Windows 选择了最新的 Python 3.3,即 3.3.5.
安装 Python 后,您可以通过在您的数据库上执行 CREATE EXTENSION plpython3u;
在 PostgreSQL 中启用它,如此处 https://www.postgresql.org/docs/current/static/plpython.html 所述。从那里,你可以用 Python 主体编写任何函数。
对于从 bytea
转换为 double precision[]
并返回的具体情况,我编写了以下函数:
CREATE FUNCTION bytea_to_double_array(b bytea)
RETURNS double precision[]
LANGUAGE 'plpython3u'
AS $BODY$
if 'struct' in GD:
struct = GD['struct']
else:
import struct
GD['struct'] = struct
return struct.unpack('<' + str(int(len(b) / 8)) + 'd', b)
$BODY$;
CREATE FUNCTION double_array_to_bytea(dblarray double precision[])
RETURNS bytea
LANGUAGE 'plpython3u'
AS $BODY$
if 'struct' in GD:
struct = GD['struct']
else:
import struct
GD['struct'] = struct
# dblarray here is really a list.
# PostgreSQL passes SQL arrays as Python lists
return struct.pack('<' + str(int(len(dblarray))) + 'd', *dblarray)
$BODY$;
在我的例子中,所有双打都存储在小端,所以我使用 <
。我还在全局字典中缓存了 struct
模块的导入,如 . I used GD instead of SD because I want the import available in other functions I may write. For information about GD and SD, see https://www.postgresql.org/docs/current/static/plpython-sharing.html.
中所述
知道我的数据库中的 blob 存储为小端,要查看它的运行情况,
SELECT bytea_to_double_array(decode('efbeaddeefbeadde', 'hex')), encode(double_array_to_bytea(array[-1.1885959257070704E148]), 'hex');
我得到的答案是
bytea_to_double_array | encode
double precision[] | text
-------------------------+------------------
{-1.18859592570707e+148} | efbeaddeefbeadde
其中 'efbeaddeefbeadde'
在 little endian 中是 'deadbeefdeadbeef'
。
我有一个数据库,其中一个 table 存储从另一个系统收集的各种通用数据的 blob (bytea
)。 bytea
字段可以包含任何内容。为了知道如何解释数据,table 还有一个格式字段。我写了一个 Java 应用程序来从数据库中读取 bytea
字段作为 byte[]
然后我可以轻松地将它转换为 double[]
或 int[]
或任何格式字段表示使用 ByteBuffer
和各种视图(DoubleBuffer
、IntBuffer
等)。
现在我遇到这样的情况,我需要在触发器函数中对数据库本身的数据进行一些操作,以保持与另一个 table 的完整性。我可以找到任何可以想象到的数据类型的转换,但我找不到从 bytea
(甚至 bit
)到 double precision
并返回的任何内容。 bytea
可以分解,转换为位,然后转换为 int
或 bigint
,但不能转换为 double precision
。例如,x'deadbeefdeadbeef'::bit(64)::bigint
将毫无问题地转换为 -2401053088876216593
,但 x'deadbeefdeadbeef'::bit(64)::double precision
失败并返回 "ERROR: cannot cast type bit to double precision" 而不是给出 -1.1885959257070704E148
.[=33 的 IEEE 754 答案=]
我找到了这个答案,它基本上实现了将位转换为双精度的 IEEE 标准,但是 PostgreSQL 中真的没有基本的转换函数可以做到这一点吗?另外,当我完成数据操作并需要更新 table 时,我还需要从 double precision
倒退到 bytea
,这个答案没有提供。
有什么想法吗?
好的,我找到了答案。在 PostgreSQL 中,您可以使用 Python 编写函数。为了启用 Python,您必须安装安装 PostgreSQL 所需的特定版本的 Python,并在 PATH 环境变量中提供它。您可以通过查看安装说明找到安装 PostgreSQL 所需的 Python 版本。我目前在 Windows 上使用 PostgreSQL 9.6.5,它需要 Python 3.3。我最初尝试了最新的 Python 3.6,但它不起作用。我为 Windows 选择了最新的 Python 3.3,即 3.3.5.
安装 Python 后,您可以通过在您的数据库上执行 CREATE EXTENSION plpython3u;
在 PostgreSQL 中启用它,如此处 https://www.postgresql.org/docs/current/static/plpython.html 所述。从那里,你可以用 Python 主体编写任何函数。
对于从 bytea
转换为 double precision[]
并返回的具体情况,我编写了以下函数:
CREATE FUNCTION bytea_to_double_array(b bytea)
RETURNS double precision[]
LANGUAGE 'plpython3u'
AS $BODY$
if 'struct' in GD:
struct = GD['struct']
else:
import struct
GD['struct'] = struct
return struct.unpack('<' + str(int(len(b) / 8)) + 'd', b)
$BODY$;
CREATE FUNCTION double_array_to_bytea(dblarray double precision[])
RETURNS bytea
LANGUAGE 'plpython3u'
AS $BODY$
if 'struct' in GD:
struct = GD['struct']
else:
import struct
GD['struct'] = struct
# dblarray here is really a list.
# PostgreSQL passes SQL arrays as Python lists
return struct.pack('<' + str(int(len(dblarray))) + 'd', *dblarray)
$BODY$;
在我的例子中,所有双打都存储在小端,所以我使用 <
。我还在全局字典中缓存了 struct
模块的导入,如 . I used GD instead of SD because I want the import available in other functions I may write. For information about GD and SD, see https://www.postgresql.org/docs/current/static/plpython-sharing.html.
知道我的数据库中的 blob 存储为小端,要查看它的运行情况,
SELECT bytea_to_double_array(decode('efbeaddeefbeadde', 'hex')), encode(double_array_to_bytea(array[-1.1885959257070704E148]), 'hex');
我得到的答案是
bytea_to_double_array | encode
double precision[] | text
-------------------------+------------------
{-1.18859592570707e+148} | efbeaddeefbeadde
其中 'efbeaddeefbeadde'
在 little endian 中是 'deadbeefdeadbeef'
。