根据@DanielVérité 的建议,我实现了一个plpgsql
函数,该函数将字符串替换为 type 的二进制字符串bytea
。在实现中,我只使用了二进制字符串部分的函数,所以我认为使用它应该是安全的。
这是我的代码:
CREATE OR REPLACE FUNCTION
replace_binary(input_str bytea, pattern bytea, replacement bytea)
RETURNS bytea
AS $$
DECLARE
buf bytea;
pos integer;
BEGIN
buf := '';
-- validate input
IF coalesce(length(input_str), 0) = 0 OR coalesce(length(pattern), 0) = 0
THEN
RETURN input_str;
END IF;
replacement := coalesce(replacement, '');
LOOP
-- find position of pattern in input
pos := position(pattern in input_str);
IF pos = 0 THEN
-- not found: append remaining input to buffer and return
buf := buf || substring(input_str from 1);
RETURN buf;
ELSE
-- found: append substring before pattern to buffer
buf := buf || substring(input_str from 1 for pos - 1);
-- append replacement
buf := buf || replacement;
-- go on with substring of input
input_str := substring(input_str from pos + length(pattern));
END IF;
END LOOP;
END;
$$ LANGUAGE plpgsql
IMMUTABLE;
至于我的测试用例,它工作得很好:
with input(buf, pattern, replacement) as (values
('tt'::bytea, 't'::bytea, 'ttt'::bytea),
('test'::bytea, 't'::bytea, 'ttt'::bytea),
('abcdefg'::bytea, 't'::bytea, 'ttt'::bytea),
('\000\015Hello 0orld\000\015Hello 0orld'::bytea, '0'::bytea, '1'::bytea))
select encode(replace_binary(buf, pattern, replacement), 'escape') from input;
按预期输出:
encode
------------------------------------
tttttt
tttesttt
abcdefg
\000\rHello 1orld\000\rHello 1orld
(4 rows)