¿Por qué?
PL/pgSQL ejecuta consultas SQL como declaraciones preparadas . El manual sobre la sustitución de parámetros:
Tenga en cuenta el término valores . Solo se pueden parametrizar valores reales, pero no palabras clave, identificadores o nombres de tipo. 32
en bit(32)
miradas como un valor, pero el modificador de un tipo de datos es solo un "valor" internamente y no se puede parametrizar. SQL exige conocer los tipos de datos en la etapa de planificación, no puede esperar a la etapa de ejecución.
podrías logre su objetivo con SQL dinámico y EXECUTE
. Como prueba de concepto :
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;
Llamar:
SELECT lpad_bits(b'1001100111000', 32);
Tenga en cuenta la distinción entre sz
siendo usado como literal para construir la declaración y su segunda ocurrencia donde se usa como valor , que se puede pasar como parámetro.
Alternativas más rápidas
Una solución superior para esta tarea en particular es usar lpad()
Me gusta ">@Abelisto sugirió
:
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;
(Más simple que la función SQL simple, que también permite función en línea en el contexto de consultas externas).
Varias veces más rápido que la función anterior. Un defecto menor:tenemos que enviar a text
y de vuelta a varbit
. Desafortunadamente, lpad()
no está implementado actualmente para varbit
. El manual:
overlay()
está disponible, podemos tener una función más económica:
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;
Más rápido si puedes trabajar con varbit
valores para empezar. (La ventaja se anula (parcialmente), si tiene que lanzar text
a varbit
de todos modos.)
Llamar:
SELECT lpad_bits3(b'1001100111000', '00000000000000000000000000000000');
SELECT lpad_bits3(b'1001100111000', repeat('0', 32)::varbit);
Podríamos sobrecargarnos la función con una variante que toma un número entero para generar base
mismo:
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;
Llamar:
SELECT lpad_bits3(b'1001100111000', 32;
Relacionado:
- Postgresql Convertir bit variable a entero
- Convertir hexadecimal en representación de texto a número decimal