Perché?
PL/pgSQL esegue query SQL come istruzioni preparate . Il manuale sulla sostituzione dei parametri:
Nota il termine valori . È possibile parametrizzare solo valori effettivi, ma non parole chiave, identificatori o nomi di tipi. 32
in bit(32)
sembra come un valore, ma il modificatore di un tipo di dati è solo un "valore" internamente e non può essere parametrizzato. SQL richiede di conoscere i tipi di dati in fase di pianificazione, non può attendere la fase di esecuzione.
Potresti raggiungi il tuo obiettivo con SQL dinamico e EXECUTE
. Come prova di concetto :
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;
Chiama:
SELECT lpad_bits(b'1001100111000', 32);
Nota la distinzione tra sz
utilizzato come letterale per creare l'istruzione e la sua seconda occorrenza dove viene utilizzata come valore , che può essere passato come parametro.
Alternative più rapide
Una soluzione superiore per questa particolare attività consiste nell'utilizzare semplicemente lpad()
come @Abelisto suggerito
:
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;
(Più semplice come una semplice funzione SQL, che consente anche inlining di funzioni nel contesto di query esterne.)
Diverse volte più veloce della funzione di cui sopra. Un piccolo difetto:dobbiamo eseguire il cast su text
e torna a varbit
. Sfortunatamente, lpad()
non è attualmente implementato per varbit
. Il manuale:
overlay()
è disponibile, possiamo avere una funzione più economica:
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;
Più veloce se puoi lavorare con varbit
valori per cominciare. (Il vantaggio è (parzialmente) annullato, se devi trasmettere text
a varbit
comunque.)
Chiama:
SELECT lpad_bits3(b'1001100111000', '00000000000000000000000000000000');
SELECT lpad_bits3(b'1001100111000', repeat('0', 32)::varbit);
Potremmo sovraccarsi la funzione con una variante che prende un intero per generare base
stesso:
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;
Chiama:
SELECT lpad_bits3(b'1001100111000', 32;
Correlati:
- Postgresql Converti bit variabile in intero
- Converti esadecimale nella rappresentazione del testo al numero decimale