了解 PL/pgSQL 函数中 int 文字与 int 参数之间的区别
Understanding difference between int literal vs int parameter in PL/pgSQL function
我有一个在 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
我一直盯着 bitstring documentation and PL/pgSQL function documentation,只是看不出这两个实现之间有什么根本不同。
解析器不允许在该位置使用变量。另一种方法是使用常量 trim 它:
select right((val::bit(128) >> (128 -length(val)))::text, sz)::bit(sz)
from (values (b'1001100111000', 32)) s(val,sz)
;
right
----------------------------------
00000000000000000001001100111000
或评论中建议的lpad
函数。
为什么?
PL/pgSQL 执行 SQL 查询,例如 准备语句 。 The manual about parameter substituion:
Prepared statements can take parameters: values that are substituted
into the statement when it is executed.
注意术语 值。只能参数化实际值,但不能参数化关键字、标识符或类型名称。 32
in bit(32)
看起来是一个值,但是数据类型的修饰符在内部只是一个"value",不能参数化。 SQL需要在计划阶段就知道数据类型,不能等到执行阶段。
您可以通过动态 SQL 和 EXECUTE
实现您的目标。作为概念验证:
CREATE OR REPLACE FUNCTION lpad_bits(val varbit, sz int = 32, OUT outval varbit) AS
$func$
BEGIN
EXECUTE format('SELECT ::bit(%s) >> ', sz) -- literal
USING val, sz - length(val) -- values
INTO outval;
END
$func$ LANGUAGE plpgsql IMMUTABLE;
致电:
SELECT lpad_bits(b'1001100111000', 32);
请注意 sz
用作 文字 以构建语句和它第二次出现的区别值,可以作为参数传递。
更快的选择
这个特定任务的一个更好的解决方案是只使用 lpad()
就像 :
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
实现。 The manual:
The following SQL-standard functions work on bit strings as well as
character strings: 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);
我们可能 覆盖 带有变体的函数采用整数生成 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 Convert bit varying to integer
- Convert hex in text representation to decimal number
我有一个在 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
我一直盯着 bitstring documentation and PL/pgSQL function documentation,只是看不出这两个实现之间有什么根本不同。
解析器不允许在该位置使用变量。另一种方法是使用常量 trim 它:
select right((val::bit(128) >> (128 -length(val)))::text, sz)::bit(sz)
from (values (b'1001100111000', 32)) s(val,sz)
;
right
----------------------------------
00000000000000000001001100111000
或评论中建议的lpad
函数。
为什么?
PL/pgSQL 执行 SQL 查询,例如 准备语句 。 The manual about parameter substituion:
Prepared statements can take parameters: values that are substituted into the statement when it is executed.
注意术语 值。只能参数化实际值,但不能参数化关键字、标识符或类型名称。 32
in bit(32)
看起来是一个值,但是数据类型的修饰符在内部只是一个"value",不能参数化。 SQL需要在计划阶段就知道数据类型,不能等到执行阶段。
您可以通过动态 SQL 和 EXECUTE
实现您的目标。作为概念验证:
CREATE OR REPLACE FUNCTION lpad_bits(val varbit, sz int = 32, OUT outval varbit) AS
$func$
BEGIN
EXECUTE format('SELECT ::bit(%s) >> ', sz) -- literal
USING val, sz - length(val) -- values
INTO outval;
END
$func$ LANGUAGE plpgsql IMMUTABLE;
致电:
SELECT lpad_bits(b'1001100111000', 32);
请注意 sz
用作 文字 以构建语句和它第二次出现的区别值,可以作为参数传递。
更快的选择
这个特定任务的一个更好的解决方案是只使用 lpad()
就像
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
实现。 The manual:
The following SQL-standard functions work on bit strings as well as character strings:
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);
我们可能 覆盖 带有变体的函数采用整数生成 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 Convert bit varying to integer
- Convert hex in text representation to decimal number