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.
