我必须在PostgreSQL的9.5左板位刺的函数:
CREATE OR REPLACE FUNCTION lpad_bits(val bit varying)
RETURNS bit varying as
$BODY$
BEGIN return val::bit(32) >> (32-length(val));
END;
$BODY$
LANGUAGE plpgsql IMMUTABLE;
其正常工作:
# select lpad_bits(b'1001100111000');
lpad_bits
----------------------------------
00000000000000000001001100111000
(1 row)
我的问题是,当我尝试添加一个参数来改变填充量:
CREATE OR REPLACE FUNCTION lpad_bits(val bit varying, sz integer default 1024)
RETURNS bit varying as
$BODY$
BEGIN return val::bit(sz) >> (sz-length(val));
END;
$BODY$
LANGUAGE plpgsql IMMUTABLE;
该功能现在打破:
# select lpad_bits(b'1001100111000', 32);
ERROR: invalid input syntax for integer: "sz" LINE 1: SELECT val::bit(sz) >> (sz-length(val)) ^ QUERY: SELECT val::bit(sz) >> (sz-length(val)) CONTEXT: PL/pgSQL function lpad_bits(bit varying,integer) line 2 at RETURN
我在盯着有位串的文件和PL / pgSQL函数的文档 ,我根本就没有看到的是这两种实现之间的根本不同。
为什么?
PL / pgSQL的执行像准备好的发言 SQL查询。 有关参数substituion手册:
准备的语句可以带参数:在执行时,它被代入语句的值。
此处所谓的价值观 。 只有实际值可以带参数,但不是关键词,标识符或类型名。 32
在bit(32)
看起来像一个值,而是一个数据类型的改性剂是只有一个“值”内部和不能被参数化。 SQL要求知道在规划阶段的数据类型,它不能等待执行阶段。
你可以使用动态SQL实现自己的目标和EXECUTE
。 由于概念证明 :
CREATE OR REPLACE FUNCTION lpad_bits(val varbit, sz int = 32, OUT outval varbit) AS
$func$
BEGIN
EXECUTE format('SELECT $1::bit(%s) >> $2', sz) -- literal
USING val, sz - length(val) -- values
INTO outval;
END
$func$ LANGUAGE plpgsql IMMUTABLE;
呼叫:
SELECT lpad_bits(b'1001100111000', 32);
注意区分sz
被用作字面来构建语句,并使用它的值作为它的第二次出现,可以作为参数传递。
更快的替代方案
对于这个特殊的任务比较优秀的方案是只使用lpad()
类似@Abelisto建议 :
CREATE OR REPLACE FUNCTION lpad_bits2(val varbit, sz int = 32)
RETURNS varbit AS
$func$
SELECT lpad(val::text, sz, '0')::varbit;
$func$ LANGUAGE sql IMMUTABLE;
(简单以纯SQL函数,它也允许内联函数外的查询的情况下。)
数倍于上述功能更快。 一个小小的瑕疵:我们要转换为text
,并回到varbit
。 不幸的是, lpad()
目前未实现varbit
。 手动:
:下面的SQL标准的功能对位串以及字符串的工作length
, bit_length
, octet_length
, position
, substring
, overlay
。
overlay()
是可用的,我们可以有一个更便宜的功能:
CREATE OR REPLACE FUNCTION lpad_bits3(val varbit, base varbit = '00000000000000000000000000000000')
RETURNS varbit AS
$func$
SELECT overlay(base PLACING val FROM bit_length(base) - bit_length(val))
$func$ LANGUAGE sql IMMUTABLE;
更快,如果你可以工作varbit
值开始。 (其优点是(部分)作废,如果你要投text
到varbit
反正。)
呼叫:
SELECT lpad_bits3(b'1001100111000', '00000000000000000000000000000000');
SELECT lpad_bits3(b'1001100111000', repeat('0', 32)::varbit);
我们可能overlaod功能具有一个变体将整数生成base
本身:
CREATE OR REPLACE FUNCTION lpad_bits3(val varbit, sz int = 32)
RETURNS varbit AS
$func$
SELECT overlay(repeat('0', sz)::varbit PLACING val FROM sz - bit_length(val))
$func$ LANGUAGE sql IMMUTABLE;
呼叫:
SELECT lpad_bits3(b'1001100111000', 32;
有关:
- PostgreSQL的转换位不同的整数
- 十六进制转换的文本表示十进制数
解析器不允许在该位置的变量。 另一种方法是使用一个常数,修剪:
select right((val::bit(128) >> (128 -length(val)))::text, sz)::bit(sz)
from (values (b'1001100111000', 32)) s(val,sz)
;
right
----------------------------------
00000000000000000001001100111000
或lpad
函数在评论中所建议的。
文章来源: Understanding difference between int literal vs int parameter in PL/pgSQL function