理解PL / pgSQL函数中int literal与int参数的区别

时间:2016-10-27 17:27:58

标签: postgresql plpgsql dynamic-sql function-parameter

我有一个函数来在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 documentationPL/pgSQL function documentation,根本没有看到这两种实现之间的根本区别。

2 个答案:

答案 0 :(得分:1)

解析器不允许该位置的变量。另一种方法是使用常量并修剪它:

lpad

或评论中建议的import { Component,Input } from '@angular/core'; @Component({ selector: 'my-app', template: `<h3>Angular 2 First Item in Array Missing using *ngFor</h3> <pre>{{teachers | json}}</pre> <teacher *ngFor="let t of teachers; let i = index" [teacherName]="t" [index]="i"></teacher> ` }) export class AppComponent { public teachers: string[] = [ "Erty", "Dave", "Sarah", "Walter" ]; } @Component({ selector: 'teacher', template: ` <p>Teacher {{index}}: {{teacherName}}</p> ` }) export class TeacherComponent { @Input() teacherName: string; @Input() index: number; ngOnInit() { console.log(this.teacherName); } } 功能。

答案 1 :(得分:1)

为什么?

PL / pgSQL执行SQL查询,如 预处理语句 The manual about parameter 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用作构建语句的 literal 之间的区别,以及将其用作 value <的第二次出现的区别/ em> ,可以作为参数传递。

更快的替代方案

针对此特定任务的优秀解决方案是使用 lpad() ,例如@Abelisto suggested

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()目前尚未实施varbitThe manual:

  

以下SQL标准函数适用于位字符串以及   字符串:lengthbit_lengthoctet_lengthpositionsubstringoverlay

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;

相关: