Hvorfor?
PL/pgSQL udfører SQL-forespørgsler som forberedte sætninger . Manualen om parametersubstitution:
Bemærk udtrykket værdier . Kun aktuelle værdier kan parametreres, men ikke nøgleord, identifikatorer eller typenavne. 32
i bit(32)
udseende som en værdi, men modifikationen af en datatype er kun en "værdi" internt og kan ikke parametreres. SQL kræver at kende datatyper på planlægningsstadiet, den kan ikke vente på udførelsesfasen.
Du kunne nå dit mål med dynamisk SQL og 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 til:
SELECT lpad_bits(b'1001100111000', 32);
Bemærk forskellen mellem sz
bliver brugt som bogstavelig at bygge sætningen og dens anden forekomst, hvor den bruges som værdi , der kan overføres som parameter.
Hurtigere alternativer
En overlegen løsning til netop denne opgave er at bruge lpad()
like @Abelisto foreslog
:
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;
(Enklere som almindelig SQL-funktion, der også tillader funktionsinlining i forbindelse med ydre forespørgsler.)
Flere gange hurtigere end ovenstående funktion. En mindre fejl:vi skal caste til text
og tilbage til varbit
. Desværre, lpad()
er i øjeblikket ikke implementeret for varbit
. Manualen:
overlay()
er tilgængelig, kan vi have en billigere 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;
Hurtigere, hvis du kan arbejde med varbit
værdier til at begynde med. (Fordelen er (delvist) annulleret, hvis du skal caste text
til varbit
alligevel.)
Ring til:
SELECT lpad_bits3(b'1001100111000', '00000000000000000000000000000000');
SELECT lpad_bits3(b'1001100111000', repeat('0', 32)::varbit);
Vi kan overlappe funktionen med en variant, der tager et heltal for at generere base
selv:
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 til:
SELECT lpad_bits3(b'1001100111000', 32;
Relateret: