PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Comprensione della differenza tra il parametro int literal e int nella funzione PL/pgSQL

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: