Proč?
PL/pgSQL provádí SQL dotazy jako připravené příkazy . Příručka o substituci parametrů:
Všimněte si termínu hodnoty . Parametrizovat lze pouze skutečné hodnoty, nikoli klíčová slova, identifikátory nebo názvy typů. 32
v bit(32)
vypadá jako hodnota, ale modifikátor datového typu je pouze interně "hodnota" a nelze ji parametrizovat. SQL vyžaduje znát datové typy ve fázi plánování, nemůže čekat na fázi provádění.
Mohli byste dosáhněte svého cíle pomocí dynamického SQL a EXECUTE
. Jakodůkaz konceptu :
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;
Volejte:
SELECT lpad_bits(b'1001100111000', 32);
Všimněte si rozdílu mezi sz
se používá jako doslova k vytvoření příkazu a jeho druhého výskytu, kde je použit jako hodnota , který lze předat jako parametr.
Rychlejší alternativy
Nejlepším řešením pro tento konkrétní úkol je použití lpad()
jako Návrh @Abelisto
:
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;
(Jednodušší jako obyčejná funkce SQL, která také umožňuje vkládání funkcí v kontextu vnějších dotazů.)
Několikanásobně rychlejší než výše uvedená funkce. Drobná chyba:musíme přetypovat do text
a zpět na varbit
. Bohužel lpad()
není aktuálně implementován pro varbit
. Příručka:
overlay()
je k dispozici, můžeme mít levnější funkci:
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;
Rychlejší, pokud můžete pracovat s varbit
hodnoty pro začátek. (Výhoda je (částečně) neplatná, pokud musíte přenést text
na varbit
stejně.)
Volejte:
SELECT lpad_bits3(b'1001100111000', '00000000000000000000000000000000');
SELECT lpad_bits3(b'1001100111000', repeat('0', 32)::varbit);
Mohli bychom se překrývat funkce s variantou, která vygeneruje base
celé číslo sám:
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;
Volejte:
SELECT lpad_bits3(b'1001100111000', 32;
Související: