PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Przegląd programowania po stronie serwera w PostgreSQL

Istnieje wiele sposobów, dzięki którym serwer Postgres może uruchomić wstępnie zdefiniowany kod. Poniżej znajduje się wyczerpująca lista wraz z przykładami sposobów, w jakie serwer Postgres może przechowywać wstępnie zdefiniowaną logikę, którą można później wykorzystać w swojej aplikacji.

Funkcje SQL

Postgres pozwala tworzyć „funkcje zdefiniowane przez użytkownika”, w których treść funkcji może być napisana w obsługiwanym języku. „Funkcje SQL” to zdefiniowane przez użytkownika funkcje napisane w zwykłym języku SQL, co jest najprostszym sposobem enkapsulacji złożonych zapytań i sekwencji instrukcji SQL.

Oto kilka przykładów:

-- update item price and record the change
CREATE FUNCTION update_price(item text, newprice numeric) RETURNS void AS $$
    UPDATE items SET price=$2 WHERE name=$1;
    INSERT INTO audit (event, new_price, at, item)
      VALUES ('price changed', $2, now(), $1);
$$ LANGUAGE SQL;

-- a function from uuid-osp
CREATE FUNCTION uuid_timestamp_bits(uuid) RETURNS varbit AS
$$ SELECT ('x' || substr($1::text, 15, 4) || substr($1::text, 10, 4) ||
           substr($1::text, 1, 8) || substr($1::text, 20, 4))::bit(80)
          & x'0FFFFFFFFFFFFFFF3FFF' $$
LANGUAGE SQL STRICT IMMUTABLE;

Funkcje SQL mogą akceptować i zwracać typy podstawowe, typy złożone i wiersze. Obsługują również zmienną liczbę argumentów, domyślne wartości argumentów i argumenty polimorficzne. Mogą nawet zwrócić wiele wierszy, naśladując SELECT z tabeli. Nie jest również konieczne, aby w ogóle niczego zwracali.

Treść funkcji może jednak zawierać tylko instrukcje SQL. Oznacza to, że nie ma instrukcji kontroli przepływu (jeśli, while, …), zmiennych i tym podobnych.

Polecenie CREATE FUNCTION służy do tworzenia funkcji. Jak zwykle możesz je ZMIENIĆ i UPUŚĆ.

To świetne miejsce, aby zacząć dalej kopać:https://www.postgresql.org/docs/current/xfunc-sql.html

Funkcje C

Podczas gdy funkcje SQL są najłatwiejsze do napisania i najmniej wydajne, na drugim końcu spektrum funkcje mogą być napisane w C i mogą praktycznie wszystko. Takie funkcje muszą być zakodowane w C i zbudowane jako biblioteka współdzielona, ​​którą Postgres może dynamicznie ładować.

Musisz powiedzieć Postgresowi, gdzie ma załadować bibliotekę współdzieloną, nazwę i podpis funkcji:

CREATE FUNCTION sum(integer, integer) RETURNS integer
    AS 'myfuncs', 'sum'
    LANGUAGE C STRICT;

To mówi, że współdzielona biblioteka myfuncs.so , obecny we wstępnie zdefiniowanej ścieżce wyszukiwania, zawiera punkty wejścia, które mogą być wywoływane przez Postgres, przy czym jednym z punktów wejścia jest „suma”, która może być wywołana jako funkcja.

Rzeczywisty kod w języku C byłby zbyt długi, aby go tu zamieścić, ale możesz o nim przeczytać w dokumentacji. W połączeniu z interfejsem programowania serwera (SPI) można wykonać prawie każdą operację, którą można wykonać w inny sposób.

Na przykład, ze zdefiniowanymi tutaj funkcjami C, możesz wykonywać żądania HTTP:

SELECT status, content_type FROM http_get('https://postgresql.org/');

Możliwe jest również napisanie takich bibliotek dzielonych w innych językach, takich jak C++ lub Go, które mogą budować biblioteki dzielone z linkami „C”.

Funkcje PL/pgSQL

Oprócz SQL i C możesz pisać funkcje w językach proceduralnych . Cztery takie języki są obsługiwane przez rdzeń PostgreSQL – pgSQL, Python, Perl i Tcl. Wsparcie dla każdego języka proceduralnego pochodzi ze współdzielonej biblioteki C i działa podobnie jak mod_perl lub mod_python z ery Apaczów.

pgSQL jest kanonicznym, najczęściej używanym językiem podobnym do SQL, w którym napisane są przechowywane funkcje dla PostgreSQL. Jest dostępny domyślnie dzięki uprzejmości instalacji w template1 .

PL/pgSQL jest pełnoprawnym językiem ze zmiennymi, wyrażeniami i instrukcjami kontrolnymi; i zawiera funkcje, takie jak kursory do pracy w szczególności z danymi SQL. Jest to obszernie udokumentowane tutaj.

Oto przykład:

CREATE FUNCTION repeat(times integer, s text)
    RETURNS text
    AS $$
DECLARE
    result text;
BEGIN
    result := '';
    FOR i IN 1..times LOOP
        result := result || s;
    END LOOP;
    RETURN result;
END;
$$
LANGUAGE plpgsql
IMMUTABLE;

-- psql> SELECT repeat(10, '*');
--    repeat
-- ------------
--  **********
-- (1 row)

Inne podstawowe języki proceduralne

Inne języki proceduralne — Python, Perl, Tcl — pozwalają programistom na używanie języka, z którym są już zaznajomieni. Chociaż obsługa tych języków znajduje się w drzewie źródłowym Postgresa, dystrybucje zwykle domyślnie nie instalują plików binarnych. Na przykład w Debianie być może będziesz musiał zrobić:

sudo apt install postgresql-plpython-11

zainstalować obsługę PL/Pythona dla PostgreSQL 11.

Bez względu na język, w jakim piszesz funkcję, osoba wywołująca nie dostrzega żadnych różnic w jej użyciu.

Python

Rozszerzenie PL/Python obsługuje pisanie funkcji w Python 2 i Python 3. Aby je zainstalować, wykonaj:

CREATE EXTENSION plpythonu;

Oto funkcja napisana w PL/Python:

CREATE FUNCTION pymax (a integer, b integer)
  RETURNS integer
AS $$
  if a > b:
    return a
  return b
$$ LANGUAGE plpythonu;

Środowisko Pythona, w którym działa treść funkcji, ma moduł o nazwie plpy automatycznie importowane do niego. Ten moduł zawiera metody, które pozwalają przygotowywać i uruchamiać zapytania, obsługiwać transakcje i pracować z kursorami.

Więcej informacji można znaleźć w rozdziale 46 dokumentacji Postgres.

Perl

No tak, Perlu. Procesy rozwoju, testowania i budowania Postgresa wykorzystują Perlextensively, a także jest obsługiwany jako język proceduralny. Aby zacząć go używać, upewnij się, że wszystkie odpowiednie pakiety binarne dla twojej dystrybucji zostały zainstalowane (na przykład „postgresql-plperl-nn” dla Debiana) i zainstaluj rozszerzenie „plperl”.

Oto funkcja napisana w PL/Perl:

CREATE FUNCTION perl_max (integer, integer) RETURNS integer AS $$
    my ($x, $y) = @_;
    if (not defined $x) {
        return undef if not defined $y;
        return $y;
    }
    return $x if not defined $y;
    return $x if $x > $y;
    return $y;
$$ LANGUAGE plperl;

Pełna dokumentacja tutaj.

Tcl

Tcl to kolejny PL wspierany przez Core Postgres. Oto przykład:

CREATE FUNCTION tcl_max(integer, integer) RETURNS integer AS $$
    if {[argisnull 1]} {
        if {[argisnull 2]} { return_null }
        return $2
    }
    if {[argisnull 2]} { return $1 }
    if {$1 > $2} {return $1}
    return $2
$$ LANGUAGE pltcl;

Aby uzyskać więcej informacji, zapoznaj się z dokumentacją tutaj.

Niepodstawowe języki proceduralne

Poza tymi językami istnieją projekty open source, które rozwijają i utrzymują wsparcie dla innych, takich jak Java, Lua, R itp.

Lista znajduje się tutaj:https://www.postgresql.org/docs/current/external-pl.html

Funkcje agregujące

Funkcje agregujące działają na zbiorze wartości i zwracają pojedynczy wynik. PostgreSQL ma kilka wbudowanych funkcji agregujących (zobacz pełną listę tutaj). Na przykład, aby uzyskać odchylenie standardowe populacji wszystkich wartości w kolumnie, może:

SELECT stddev_pop(grade) FROM students;

Możesz zdefiniować własne funkcje agregujące, które zachowują się w podobny sposób. Agregat zdefiniowany przez użytkownika składa się z kilku indywidualnych samodzielnych funkcji, które działają w stanie wewnętrznym (na przykład stanem wewnętrznym agregatu obliczającego średnią może być zmienne „suma” i „liczba”).

Oto agregat zdefiniowany przez użytkownika, który oblicza medianę zbioru wartości:

-- from https://wiki.postgresql.org/wiki/Aggregate_Median
CREATE OR REPLACE FUNCTION _final_median(NUMERIC[])
   RETURNS NUMERIC AS
$$
   SELECT AVG(val)
   FROM (
     SELECT val
     FROM unnest($1) val
     ORDER BY 1
     LIMIT  2 - MOD(array_upper($1, 1), 2)
     OFFSET CEIL(array_upper($1, 1) / 2.0) - 1
   ) sub;
$$
LANGUAGE 'sql' IMMUTABLE;
 
CREATE AGGREGATE median(NUMERIC) (
  SFUNC=array_append,
  STYPE=NUMERIC[],
  FINALFUNC=_final_median,
  INITCOND='{}'
);

które można wywołać jako:

SELECT median(grade) FROM students;

Aby uzyskać więcej informacji, zapoznaj się z dokumentacją dotyczącą agregatów oraz oświadczeniem CREATE AGGREGATE.

Typy zdefiniowane przez użytkownika

Współdzielone biblioteki napisane w C, które widzieliśmy wcześniej, mogą nie tylko definiować funkcje, ale także typy danych. Te typy zdefiniowane przez użytkownika mogą być używane jako typy danych dla kolumn, podobnie jak typy wbudowane. Możesz zdefiniować funkcje do pracy z wartościami typów zdefiniowanych przez użytkownika.

Zdefiniowanie nowego typu zajmuje trochę kodu. Zapoznaj się z dokumentami, które przeprowadzą Cię przez proces tworzenia nowego typu do reprezentowania liczb zespolonych. Źródło ThePostgres zawiera również kod samouczka do tego.

Operatorzy

Operatory ułatwiają korzystanie z funkcji (na przykład pisanie 1 + 2 zamiast sum(1, 2) ) i możesz zdefiniować operatory dla typów zdefiniowanych przez użytkownika za pomocą instrukcji CREATE OPERATOR.

Oto przykład tworzenia + operator, który mapuje do funkcjicomplex_add który dodaje dwa complex numery:

CREATE OPERATOR + (
    leftarg = complex,
    rightarg = complex,
    function = complex_add,
    commutator = +
);

Więcej informacji tutaj i tutaj.

Klasy operatorów i rodziny operatorów

Klasy operatorów umożliwiają pracę typu danych z wbudowanymi metodami B-Tree i innymi metodami indeksowania. Na przykład, jeśli chcesz utworzyć indeks B-Tree w kolumnie typu „złożony”, musisz powiedzieć Postgresowi, jak porównać dwie wartości tego typu, aby określić, czy jedna jest mniejsza, równa lub większa od drugiej.

Byłoby dobrze, aby typy złożone były porównywane z liczbami całkowitymi lub wartościami zmiennoprzecinkowymi, do których wkraczają rodziny operatorów.

Możesz przeczytać wszystko o klasach i rodzinach operatorów tutaj.

Wyzwalacze

Wyzwalacze są potężnym mechanizmem tworzenia efektów ubocznych dla normalnych operacji, chociaż mogą być niebezpieczne, jeśli są nadużywane lub nadużywane. Zasadniczo wyzwalacze łączą zdarzenia z funkcjami. Funkcja, do której się odwołuje, może zostać wywołana:

  • przed lub po wstawieniu/aktualizacji/usunięciu wiersza tabeli
  • przy obcięciu tabeli
  • zamiast wstawiania/aktualizowania/usuwania wiersza widoku

Funkcja może być wywoływana dla każdego wiersza, na który ma wpływ instrukcja, lub jednorazowo. Jest jeszcze więcej rzeczy, takich jak kaskada wyzwalaczy, z których wszystkie wyjaśniono tutaj.

Funkcje wyzwalaczy można napisać w języku C lub w dowolnej funkcji PL, ale nie w języku SQL. Oto przykład wstawienia wiersza do audytu tabela, za każdą aktualizację ceny przedmiotu .

-- first create the function
CREATE FUNCTION log_update() RETURNS TRIGGER AS $$
    INSERT INTO audit (event, new_price, at, item)
      VALUES ('price changed', NEW.price, now(), OLD.item);
$$
LANGUAGE plpgsql;

-- then create the trigger
CREATE TRIGGER audit_price_changes
    AFTER UPDATE ON items
    FOR EACH ROW
    WHEN (OLD.price IS DISTINCT FROM NEW.price)
    EXECUTE FUNCTION log_update();

Przeczytaj wszystko o wyzwalaczach tutaj, wraz z dokumentacją CREATE TRIGGER.

Wyzwalacze zdarzeń

Podczas gdy wyzwalacze odpowiadać na zdarzenia DML na jednej tabeli, wyzwalacze zdarzeń może odpowiadać na zdarzenia DDL w określonej bazie danych. Zdarzenia obejmują tworzenie, zmianę, upuszczanie różnych obiektów, takich jak tabele, indeksy, schematy, widoki, funkcje, typy, operatory itp.

Oto wyzwalacz zdarzenia, który zapobiega upuszczaniu obiektów ze schematu audytu:

-- create function first
CREATE FUNCTION nodrop() RETURNS event_trigger LANGUAGE plpgsql AS $$
BEGIN
    IF EXISTS(
      SELECT 1
      FROM pg_event_trigger_dropped_objects() AS T
      WHERE T.schema_name = 'audit')
    THEN
      RAISE EXCEPTION 'not allowed to drop objects in audit schema';
    END IF;
END $$;

-- create event trigger
CREATE EVENT TRIGGER trigger_nodrop
    ON sql_drop
    EXECUTE FUNCTION nodrop();

Więcej informacji można znaleźć tutaj oraz w dokumentacji UTWÓRZ WYZWALANIE ZDARZEŃ.

Zasady

PostgreSQL jest wyposażony w funkcję, która pozwala przepisać zapytania, zanim trafi do planera zapytań. Operacja jest nieco podobna do konfigurowania Nginx lub Apache w celu przepisania przychodzącego adresu URL przed jego przetworzeniem.

Oto dwa przykłady, które wpływają na polecenia INSERT w tabeli i sprawiają, że robią coś innego:

-- make inserts into "items" table a no-op
CREATE RULE rule1 AS ON INSERT TO items DO INSTEAD NOTHING;

-- make inserts go elsewhere
CREATE RULE rule2 AS ON INSERT TO items DO INSTEAD
    INSERT INTO items_pending_review VALUES (NEW.name, NEW.price);

Ten rozdział z dokumentacji zawiera więcej informacji o zasadach.

Procedury przechowywane

Począwszy od Postgres 11, możliwe jest tworzenie zapisanych procedur W porównaniu z funkcjami przechowywanymi jest tylko jedna dodatkowa rzecz, którą mogą zrobić procedury – kontrola transakcji.

Oto przykład:

CREATE PROCEDURE check_commit(v integer)
LANGUAGE plpgsql AS $$
BEGIN
    IF v % 2 = 0 THEN
        COMMIT;
    ELSE
        ROLLBACK;
    END IF;
END $$;

-- call it
CALL check_commit(10);

Zobacz tutaj i tutaj, aby uzyskać więcej informacji.

Inne egzotyczne rzeczy

Obce opakowania danych

Zagraniczne opakowania danych (FDW) umożliwiają komunikację z innymi źródłami danych, takimi jak inny serwer Postgres, MySQL, Oracle, Cassandra i inne. Cała logika dostępu do obcego serwera jest napisana w C jako biblioteka współdzielona.

Istnieje nawet sklep kolumnowy o nazwie cstore_fdw oparty na FDW.

Listę implementacji FDW można znaleźć w Postgres Wiki i więcej dokumentacji tutaj.

Metody dostępu do indeksu

PostgreSQL zawiera typy indeksów, takie jak B-Tree, hash, GIN i inne. Możliwe jest napisanie własnego typu indeksu podobnego do tego, jako biblioteki współdzielonej C. Więcej szczegółów tutaj.

Metody dostępu do tabel

Wraz z nadchodzącym PostgreSQL 12, możliwe będzie stworzenie własnej struktury przechowywania danych. Implementując opisany tutaj interfejs, możesz przechowywać dane krotki fizycznie na dysku w wybrany przez siebie sposób.

Wtyczki replikacji logicznej

W PostgreSQL replikacja logiczna jest implementowana przez „dekodowanie” zawartości dziennika zapisu z wyprzedzeniem (WAL) do dowolnego formatu (takiego jak tekst SQL lub json) i publikowana dla subskrybentów przez szczeliny replikacji. To dekodowanie odbywa się za pomocąwtyczki wyjścia dekodowania logicznego , która może być zaimplementowana jako biblioteka współdzielona C, jak opisano tutaj. Biblioteka współdzielona „test_decoding” jest jedną z takich wtyczek i możesz zbudować własną.

Proceduralny program obsługi języka

Możesz także dodać obsługę swojego ulubionego języka programowania jako Postgres PL, tworząc program obsługi – ponownie jako bibliotekę współdzieloną C. Zacznij tutaj, aby tworzyć PL/Go lub PL/Rust!

Rozszerzenia

Rozszerzenia to sposób zarządzania pakietami Postgresa. Załóżmy, że masz funkcję C, która robi coś użytecznego, i kilka instrukcji SQL, które sprawiają, że do jej skonfigurowania niezbędne są instrukcje „CREATE FUNCTION”. Możesz połączyć te „rozszerzenia”, które Postgres może zainstalować (i odinstalować) w jednym kroku (wywołując „UTWÓRZ ROZSZERZENIE”). Kiedy wydajesz nową wersję, możesz również uwzględnić kroki aktualizacji również w rozszerzeniu.

Chociaż nie jest to programowanie po stronie serwera samo w sobie, rozszerzenia są standardowym i bardzo wydajnym sposobem pakowania i dystrybucji kodu po stronie serwera.

Więcej informacji o rozszerzeniach można znaleźć tutaj i tutaj.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. plik wejściowy wygląda na zrzut w formacie tekstowym. Proszę użyć psql

  2. Wstaw, jeśli nie istnieje, w przeciwnym razie zwróć identyfikator w postgresql

  3. Nie można usunąć bazy danych

  4. Jaka jest różnica między LATERAL JOIN a podzapytanie w PostgreSQL?

  5. Jak działa pg_sleep_for() w PostgreSQL