sql >> Database >  >> RDS >> PostgreSQL

Zijn er ontsnappende syntaxis voor de psql-variabele in PostgreSQL-functies?

PSQL SET variabelen worden niet geïnterpoleerd in strings tussen aanhalingstekens in dollars. Ik weet dit niet zeker, maar ik denk dat er geen ontsnapping of ander bedrog is om SET in te schakelen variabele interpolatie daarin.

Je zou kunnen denken dat je een niet-geciteerde :user tussen twee in dollars genoteerde stukken PL/pgSQL om het gewenste effect te krijgen. Maar dit lijkt niet te werken... Ik denk dat de syntaxis een enkele string vereist en geen expressie die strings aaneenvoegt. Misschien vergis je je daarin.

Hoe dan ook, dat maakt niet uit. Er is een andere benadering (zoals Pasco opmerkte):schrijf de opgeslagen procedure om een ​​PL/pgSQL-argument te accepteren. Zo zou dat eruit zien.

CREATE OR REPLACE FUNCTION foo("user" TEXT) RETURNS void AS
$$
BEGIN
        EXECUTE 'GRANT SELECT ON my_table TO GROUP ' || quote_ident(user);
END;    
$$ LANGUAGE plpgsql;

Opmerkingen over deze functie:

  1. EXECUTE genereert een geschikte GRANT op elke aanroep met behulp van ons procedure-argument. De PG handleiding sectie genaamd "Dynamische commando's uitvoeren " legt uit EXECUTE in detail.
  2. Het declaratie van procedure argument user moet dubbel geciteerd worden. Dubbele aanhalingstekens dwingen het te interpreteren als een identifier.

Nadat u de functie op deze manier hebt gedefinieerd, kunt u deze aanroepen met behulp van geïnterpoleerde PSQL-variabelen. Hier is een overzicht.

  1. Voer psql --variable user="'whoever'" --file=myscript.sql uit . Enkele aanhalingstekens zijn vereist rond de gebruikersnaam!
  2. Definieer in myscript.sql de functie zoals hierboven.
  3. Plaats in myscript.sql select foo(:user); . Dit is waar we vertrouwen op die enkele aanhalingstekens die we in de waarde van user plaatsen .

Hoewel dit lijkt te werken, lijkt het me nogal eekhoornachtig. Ik dacht SET variabelen waren bedoeld voor runtime-configuratie. Gegevens meenemen in SET lijkt vreemd.

Bewerken :hier is een concrete reden om niet gebruik SET variabelen. Van de manpage:"Deze toewijzingen worden gedaan tijdens een zeer vroege fase van het opstarten, dus variabelen die zijn gereserveerd voor interne doeleinden kunnen later worden overschreven." Als Postgres besloot een variabele te gebruiken met de naam user (of wat je ook kiest), het zou je scriptargument kunnen overschrijven met iets dat je nooit van plan was. In feite neemt psql al USER voor zichzelf -- dit werkt alleen omdat SET is hoofdlettergevoelig. Dit brak bijna alles vanaf het begin!



  1. Hoe de laatste dag van vorige week in sql te krijgen?

  2. Beschermt mysql_real_escape_string() VOLLEDIG tegen SQL-injectie?

  3. Redundante externe sleutels opslaan om joins te voorkomen

  4. Hoe kan ik efficiënt tekst naar getal converteren in Oracle PL/SQL met niet-standaard NLS_NUMERIC_CHARACTERS?