PostgreSQL

Alle prozeduralen Sprachen von PostgreSQL, mit denen man Funktionen und Prozeduren innerhalb der Datenbank schreiben kann, haben die Fähigkeit, beliebige SQL-Anweisungen auszuführen.

PL/pgSQL

Die sicherste Weise, SQL innerhalb einer PL/pgSQL-Anweisung auszuführen:

CREATE OR REPLACE FUNCTION user_access (
    p_uname TEXT
) RETURNS timestamp language plpgsql AS $$
BEGIN
    RETURN accessed_at FROM users WHERE username = p_uname;
END;
$$;

In so einem einfachen Fall schreibt man besser eine reine SQL-Funktion:

CREATE OR REPLACE FUNCTION user_access (
    p_uname TEXT
) RETURNS timestamp language sql AS $$
    SELECT accessed_at FROM users WHERE username = $1;
$$;

Aber manchmal möchte man kompliziertere Sachen machen wie z.B. WHERE-Teilausdrücke dynamisch je nach Eingabedaten hinzuzufügen. In diesem Fall benutzt man die EXECUTE-Syntax von PL/pgSQL. Ein Beispiel mit einer Gefährdung durch SQL-Einschleusung:

CREATE OR REPLACE FUNCTION get_users(
    p_column TEXT,
    p_value  TEXT
) RETURNS SETOF users LANGUAGE plpgsql AS $$
DECLARE
    query TEXT := 'SELECT * FROM users';
BEGIN
    IF p_column IS NOT NULL THEN
        query := query || ' WHERE ' || p_column
              || $_$ = '$_$ || p_value || $_$'$_$;
    END IF;
    RETURN QUERY EXECUTE query;
END;
$$;

Die Argumente p_column und p_value sind beide angreifbar. Um das Problem zu vermeiden, wird die Funktion quote_ident() verwendet, um einen SQL-Bezeichner (hier: p_column) zu maskieren und quote_literal(), um einen Literalwert zu maskieren:

CREATE OR REPLACE FUNCTION get_users(
    p_column TEXT,
    p_value  TEXT
) RETURNS SETOF users LANGUAGE plpgsql AS $$
DECLARE
    query TEXT := 'SELECT * FROM users';
BEGIN
    IF p_column IS NOT NULL THEN
        query := query || ' WHERE ' || quote_ident(p_column)
              || ' = ' || quote_literal(p_value);
    END IF;
    RETURN QUERY EXECUTE query;
END;
$$;

So ist es auch viel leichter zu lesen!

PL/Perl

In Vorbereitung.

PL/Python

In Vorbereitung.

PL/Tcl

In Vorbereitung.

Mach auf GitHub mit