我有一个PostgreSQL表,我希望将列从bigint
更改为bytea
字节以保存更多数据。我在考虑使用以下序列:
alter table mytable add new_column
update mytable set new_column = int8send(old_column)
alter table drop old_column
alter table rename new_column to old_column
以上序列有效,唯一的问题是我希望bytea
中的字节序列反转。例如,如果old_column
中的值为0x1234567890abcdef
,则上述序列会生成\0224Vx\220\253\315\357
,但我希望它是
\357\315\253\220xV4\022
。似乎结果bytea
使用来自原始bigint
的big-endian订单。
没有编写程序,有没有简单的方法可以做到这一点?我在PostgreSQL中寻找swap64()
类函数但未能找到它。
答案 0 :(得分:3)
在十六进制表示中使用regexp提取可以在没有plpgsql代码的情况下进行字节交换。
下面是交换bigint常量的示例,假设为SET standard_conforming_strings to ON
(默认为PG 9.1)
select regexp_replace( lpad(to_hex(x'123456789abcd'::bigint),16,'0'),
'(\w\w)(\w\w)(\w\w)(\w\w)(\w\w)(\w\w)(\w\w)(\w\w)',
'\8\7\6\5\4\3\2\1');
返回cdab896745230100
。然后应用decode(value, 'hex')
将其转换为bytea。
整个类型转换实际上可以在一个SQL语句中完成:
ALTER TABLE mytable ALTER COLUMN old_column TYPE bytea
USING decode(
regexp_replace( lpad(to_hex(old_column), 16,'0'),
'(\w\w)(\w\w)(\w\w)(\w\w)(\w\w)(\w\w)(\w\w)(\w\w)',
'\8\7\6\5\4\3\2\1')
, 'hex');
答案 1 :(得分:2)
这是我编写的用于反转bytea
类型值的字节顺序的纯SQL函数:
CREATE OR REPLACE FUNCTION reverse_bytes_iter(bytes bytea, length int, midpoint int, index int)
RETURNS bytea AS
$$
SELECT CASE WHEN index >= midpoint THEN bytes ELSE
reverse_bytes_iter(
set_byte(
set_byte(bytes, index, get_byte(bytes, length-index)),
length-index, get_byte(bytes, index)
),
length, midpoint, index + 1
)
END;
$$ LANGUAGE SQL IMMUTABLE;
CREATE OR REPLACE FUNCTION reverse_bytes(bytes bytea) RETURNS bytea AS
'SELECT reverse_bytes_iter(bytes, octet_length(bytes)-1, octet_length(bytes)/2, 0)'
LANGUAGE SQL IMMUTABLE;
我昨天刚刚写了它,所以它没有经过特别好的测试和优化,但它似乎有效,至少在长度达1k的字节串上。
答案 2 :(得分:0)
This function,虽然不完全符合您的要求,但应该可以帮助您顺利前进。
该功能的源代码将在下面逐字复制。
CREATE OR REPLACE FUNCTION utils.int_littleendian(v_number integer)
RETURNS bytea AS
$BODY$
DECLARE
v_textresult bytea;
v_temp int;
v_int int;
v_i int = 0;
BEGIN
v_int = v_number;
v_textresult = '1234';
WHILE(v_i < 4) LOOP
raise notice 'loop %',v_int;
v_temp := v_int%256;
v_int := v_int - v_temp;
v_int := v_int / 256;
SELECT set_byte(v_textresult,v_i,v_temp) INTO v_textresult;
v_i := v_i + 1;
END LOOP;
return v_textresult;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE
COST 100;
答案 3 :(得分:0)
我现在正在玩pageinspect
module,我也很好奇如何更改现有bytea值的字节顺序,这非常符合你的情况。
我提出了以下功能:
CREATE OR REPLACE FUNCTION reverse(bytea) RETURNS bytea AS $reverse$
SELECT string_agg(byte,''::bytea)
FROM (
SELECT substr($1,i,1) byte
FROM generate_series(length($1),1,-1) i) s
$reverse$ LANGUAGE sql;
它很简单,与文字reverse()
功能类似:
WITH v(val) AS (
VALUES ('\xaabbccdd'::bytea),('\x0123456789abcd'::bytea)
)
SELECT val, reverse(val)
FROM v;