PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Entendendo a diferença entre int literal vs parâmetro int na função PL/pgSQL

Por quê?


PL/pgSQL executa consultas SQL como instruções preparadas . O manual sobre substituição de parâmetros:

Observe o termo valores . Somente valores reais podem ser parametrizados, mas não palavras-chave, identificadores ou nomes de tipo. 32 em bit(32) aparência como um valor, mas o modificador de um tipo de dados é apenas um "valor" internamente e não pode ser parametrizado. O SQL exige conhecer os tipos de dados no estágio de planejamento, ele não pode esperar pelo estágio de execução.

Você poderia alcance seu objetivo com SQL dinâmico e EXECUTE . Como prova de conceito :
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;

Ligar:
SELECT lpad_bits(b'1001100111000', 32);  

Observe a distinção entre sz sendo usado como literal para construir a declaração e sua segunda ocorrência onde ela é usada como valor , que pode ser passado como parâmetro.

Alternativas mais rápidas


Uma solução superior para esta tarefa específica é usar apenas lpad() como @Abelisto sugerido :
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;

(Mais simples como função SQL simples, que também permite função embutida no contexto de consultas externas.)

Várias vezes mais rápido do que a função acima. Uma pequena falha:temos que converter para text e de volta para varbit . Infelizmente, lpad() não está implementado atualmente para varbit . O manual:

overlay() está disponível, podemos ter uma função mais barata:
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;

Mais rápido se você puder trabalhar com varbit valores para começar. (A vantagem é (parcialmente) anulada, se você tiver que converter text para varbit de qualquer forma.)

Ligar:
SELECT lpad_bits3(b'1001100111000', '00000000000000000000000000000000');
SELECT lpad_bits3(b'1001100111000',  repeat('0', 32)::varbit);

Podemos sobrepor a função com uma variante que recebe um inteiro para gerar base em si:
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;

Ligar:
SELECT lpad_bits3(b'1001100111000', 32;

Relacionado: