PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Comprendre la différence entre le paramètre littéral int et le paramètre int dans la fonction PL/pgSQL

Pourquoi ?

PL/pgSQL exécute des requêtes SQL comme des instructions préparées . Le manuel sur la substitution de paramètres :

Notez le terme valeurs . Seules les valeurs réelles peuvent être paramétrées, mais pas les mots clés, les identificateurs ou les noms de type. 32 en bit(32) il a l'air comme une valeur, mais le modificateur d'un type de données n'est qu'une "valeur" en interne et ne peut pas être paramétré. SQL exige de connaître les types de données au stade de la planification, il ne peut pas attendre le stade de l'exécution.

Vous pourriez atteignez votre objectif avec SQL dynamique et EXECUTE . En tant que preuve de concept :

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;

Appel :

SELECT lpad_bits(b'1001100111000', 32);  

Notez la distinction entre sz étant utilisé comme littéral pour construire l'instruction et sa seconde occurrence où elle est utilisée comme valeur , qui peut être passé en paramètre.

Alternatives plus rapides

Une solution supérieure pour cette tâche particulière consiste simplement à utiliser lpad() comme @Abelisto a suggéré :

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;

(Plus simple que la fonction SQL simple, qui permet également l'intégration de fonctions dans le contexte de requêtes externes.)

Plusieurs fois plus rapide que la fonction ci-dessus. Un défaut mineur :nous devons caster en text et retour à varbit . Malheureusement, lpad() n'est actuellement pas implémenté pour varbit . Le manuel :

overlay() est disponible, nous pouvons avoir une fonction moins chère :

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;

Plus rapide si vous pouvez travailler avec varbit valeurs pour commencer. (L'avantage est (partiellement) annulé, si vous devez caster text en varbit de toute façon.)

Appel :

SELECT lpad_bits3(b'1001100111000', '00000000000000000000000000000000');
SELECT lpad_bits3(b'1001100111000',  repeat('0', 32)::varbit);

Nous pourrions surcharger la fonction avec une variante prenant un entier pour générer base lui-même :

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;

Appel :

SELECT lpad_bits3(b'1001100111000', 32;

Connexe :