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:
- Postgresql Converter bit variando para inteiro
- Converter hexadecimal na representação de texto para número decimal