sql >> Databasteknik >  >> RDS >> PostgreSQL

Förstå skillnaden mellan int literal vs int parameter i PL/pgSQL funktion

Varför?

PL/pgSQL kör SQL-frågor som förberedda satser . Handboken om parameterbyte:

Notera termen värden . Endast verkliga värden kan parametreras, men inte nyckelord, identifierare eller typnamn. 32 i bit(32) utseende som ett värde, men modifieraren av en datatyp är endast ett "värde" internt och kan inte parametreras. SQL kräver att känna till datatyper i planeringsstadiet, den kan inte vänta på exekveringsstadiet.

Du kunde nå ditt mål med dynamisk SQL och EXECUTE . Som proof of 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;

Ring:

SELECT lpad_bits(b'1001100111000', 32);  

Notera skillnaden mellan sz används som bokstavlig för att bygga påståendet och dess andra förekomst där det används som värde , som kan skickas som parameter.

Snabbare alternativ

En överlägsen lösning för just denna uppgift är att bara använda lpad() gillar @Abelisto föreslog :

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;

(Enklare som en vanlig SQL-funktion, som även tillåter funktionsinlining i samband med yttre frågor.)

Flera gånger snabbare än ovanstående funktion. Ett mindre fel:vi måste casta till text och tillbaka till varbit . Tyvärr, lpad() är för närvarande inte implementerat för varbit . Handboken:

overlay() finns tillgänglig kan vi ha en billigare funktion:

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;

Snabbare om du kan arbeta med varbit värden till att börja med. (Fördelen är (delvis) ogiltig om du måste casta text till varbit i alla fall.)

Ring:

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

Vi kanske överlappar funktionen med en variant som tar ett heltal för att generera base själv:

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;

Ring:

SELECT lpad_bits3(b'1001100111000', 32;

Relaterat:



  1. Kopiera användarrättigheter mellan databaser på samma server

  2. MySql logisk ordning efter

  3. php mysql visar resultat som rullgardinslista

  4. Vad är det bästa sättet att migrera en Django DB från SQLite till MySQL?