sql >> Base de Datos >  >> RDS >> PostgreSQL

Comprender la diferencia entre el parámetro int literal vs int en la función PL/pgSQL

¿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: