sql >> Databáze >  >> RDS >> PostgreSQL

Pochopení rozdílu mezi int literálem a parametrem int ve funkci PL/pgSQL

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



  1. mysql_real_escape_string a array_map vrátí prázdné řetězce?

  2. php mysql_connect Varování zakázat

  3. Nezpracovaný dotaz PostgreSQL se zablokuje při spuštění pomocí TypeOrm

  4. Hranice slov MySQL REGEXP [[:<:]] [[:>:]] a dvojité uvozovky