PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Ikhtisar Pemrograman Sisi Server di PostgreSQL

Ada banyak cara agar server Postgres menjalankan kode yang telah ditentukan sebelumnya. Di bawah ini adalah daftar lengkap, dengan contoh, cara di mana Anda dapat membiarkan server Postgres menyimpan logika yang telah ditentukan sebelumnya, yang dapat Anda gunakan nanti dari aplikasi Anda.

Fungsi SQL

Postgres memungkinkan Anda membuat "fungsi yang ditentukan pengguna", di mana badan fungsi dapat ditulis dalam bahasa yang didukung. “Fungsi SQL” adalah fungsi yang ditentukan pengguna yang ditulis dalam SQL biasa, yang merupakan cara paling sederhana untuk merangkum kueri kompleks dan urutan pernyataan SQL.

Berikut adalah beberapa contohnya:

-- 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;

Fungsi SQL dapat menerima dan mengembalikan tipe dasar, tipe komposit, dan baris. Mereka juga mendukung jumlah variabel argumen, nilai default untuk argumen dan argumen polimorfik. Mereka bahkan dapat mengembalikan beberapa baris, meniru SELECTdari sebuah tabel. Mereka juga tidak perlu mengembalikan apa pun.

Namun, badan fungsi hanya dapat berisi pernyataan SQL. Ini berarti tidak ada pernyataan kontrol aliran (jika, sementara, ...), variabel dan sejenisnya.

Perintah CREATE FUNCTION digunakan untuk membuat fungsi. Seperti biasa, Anda dapat MENGUBAH dan MENGHENTIKAN mereka.

Ini adalah tempat yang bagus untuk mulai menggali lebih jauh:https://www.postgresql.org/docs/current/xfunc-sql.html

Fungsi C

Sementara fungsi SQL adalah yang paling mudah untuk ditulis dan paling tidak kuat, di ujung lain spektrum, fungsi dapat ditulis dalam C dan dapat melakukan banyak hal. Fungsi tersebut perlu dikodekan dalam C dan dibangun sebagai perpustakaan bersama yang dapat dimuat secara dinamis oleh Postgres.

Anda perlu memberi tahu Postgres tempat memuat pustaka bersama, nama, dan tanda tangan fungsinya:

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

Ini mengatakan bahwa perpustakaan bersama myfuncs.so , hadir dalam jalur pencarian yang telah ditentukan sebelumnya, berisi titik masuk yang dapat dipanggil oleh Postgres, dengan salah satu titik masuk adalah 'jumlah' yang dapat dipanggil sebagai fungsi.

Kode sebenarnya dalam C akan terlalu panjang untuk dimasukkan di sini, tetapi Anda dapat membaca semua tentangnya di dokumen. Dikombinasikan dengan Antarmuka Pemrograman Server (SPI), dimungkinkan untuk melakukan hampir semua operasi yang dapat Anda lakukan dengan cara lain.

Misalnya, dengan fungsi C yang didefinisikan di sini, Anda dapat melakukan permintaan HTTP:

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

Dimungkinkan juga untuk menulis pustaka bersama tersebut dalam bahasa lain seperti C++ atau Go, yang dapat membangun pustaka bersama dengan tautan "C".

Fungsi PL/pgSQL

Selain SQL dan C, Anda dapat menulis fungsi dalam bahasa prosedural . Empat bahasa tersebut didukung oleh inti PostgreSQL – pgSQL, Python, Perl dan Tcl. Dukungan untuk bahasa prosedural itu sendiri berasal dari pustaka bersama C, dan beroperasi seperti mod_perl atau mod_python dari era Apache.

pgSQL adalah bahasa kanonik, yang paling sering digunakan, seperti SQL di mana fungsi tersimpan untuk PostgreSQL ditulis. Ini tersedia secara default, karena dipasang di template1 .

PL/pgSQL adalah bahasa lengkap dengan variabel, ekspresi, dan pernyataan kontrol; dan termasuk fitur seperti kursor untuk bekerja dengan data SQL khususnya. Ini didokumentasikan secara luas di sini.

Ini contohnya:

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)

Bahasa Prosedur Inti Lainnya

Bahasa prosedural lainnya – Python, Perl, Tcl – memungkinkan pengembang untuk menggunakan bahasa yang sudah mereka kuasai. Meskipun dukungan untuk bahasa ini ada di pohon sumber Postgres, distribusi biasanya tidak menginstal binari secara default. Misalnya, di Debian Anda mungkin harus melakukan:

sudo apt install postgresql-plpython-11

untuk menginstal dukungan PL/Python untuk PostgreSQL 11.

Bahasa apa pun yang Anda gunakan untuk menulis fungsi, penelepon tidak merasakan perbedaan dalam penggunaannya.

Python

Ekstensi PL/Python mendukung fungsi penulisan di Python 2 dan Python 3. Untuk menginstalnya, lakukan:

CREATE EXTENSION plpythonu;

Berikut adalah fungsi yang ditulis dalam PL/Python:

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

Lingkungan Python tempat badan fungsi berjalan memiliki modul yang disebut plpy otomatis diimpor ke dalamnya. Modul ini berisi metode yang memungkinkan Anda menyiapkan dan menjalankan kueri, menangani transaksi, dan bekerja dengan kursor.

Informasi lebih lanjut dapat ditemukan di bab 46 dari dokumen Postgres.

Perl

Ya, Perl. Proses pengembangan, pengujian, dan pembangunan pascagres menggunakan Perlextensive, dan juga didukung sebagai bahasa prosedural. Untuk mulai menggunakannya, pastikan paket biner yang relevan untuk distro Anda sudah terinstal (contoh “postgresql-plperl-nn” untuk Debian) dan instal ekstensi “plperl”.

Berikut adalah fungsi yang ditulis dalam 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;

Dokumentasi lengkap di sini.

Tcl

Tcl adalah PL lain yang didukung oleh inti Postgres. Ini contohnya:

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;

Untuk informasi lebih lanjut, lihat dokumen di sini.

Bahasa Prosedur Non-Inti

Di luar bahasa ini, ada proyek sumber terbuka yang mengembangkan dan memelihara dukungan untuk yang lain seperti Java, Lua, R dll.

Ada daftar di sini:https://www.postgresql.org/docs/current/external-pl.html

Fungsi Agregat

Fungsi agregat beroperasi pada sekumpulan nilai, dan mengembalikan satu hasil. PostgreSQL memiliki banyak fungsi agregat bawaan (lihat daftar lengkapnya di sini). Misalnya, untuk mendapatkan deviasi standar populasi dari semua nilai dalam kolom, Anda bisa:

SELECT stddev_pop(grade) FROM students;

Anda dapat menentukan fungsi agregat Anda sendiri yang berperilaku serupa. Agregat yang ditentukan pengguna dikumpulkan dari beberapa fungsi mandiri individu yang bekerja pada keadaan internal (misalnya, keadaan internal agregat yang menghitung rata-rata dapat berupa variabel "jumlah" dan "hitung").

Berikut adalah agregat yang ditentukan pengguna yang menghitung median dari sekumpulan nilai:

-- 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='{}'
);

yang dapat dipanggil sebagai:

SELECT median(grade) FROM students;

Untuk informasi lebih lanjut, lihat dokumen tentang agregatdan pernyataan CREATE AGGREGATE.

Jenis yang ditentukan pengguna

Pustaka bersama yang ditulis dalam C yang kita lihat sebelumnya tidak hanya dapat mendefinisikan fungsi, tetapi juga tipe data. Tipe yang ditentukan pengguna ini dapat digunakan sebagai tipe data untuk kolom seperti tipe bawaan. Anda dapat menentukan fungsi untuk bekerja dengan nilai tipe yang ditentukan pengguna Anda.

Dibutuhkan sedikit kode untuk mendefinisikan tipe baru. Lihat dokumen di sini yang memandu Anda membuat tipe baru untuk mewakili bilangan kompleks. Sumber Postgres juga berisi kode tutorial untuk ini.

Operator

Operator membuat fungsi lebih mudah digunakan (misalnya, menulis 1 + 2 daripada sum(1, 2) ), dan Anda dapat menentukan operator untuk tipe yang ditentukan pengguna menggunakan pernyataan CREATE OPERATOR.

Berikut adalah contoh untuk membuat + operator yang memetakan ke fungsicomplex_add yang menambahkan dua complex nomor:

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

Informasi lebih lanjut di sini dan di sini.

Kelas Operator dan Keluarga Operator

Kelas operator memungkinkan tipe data Anda bekerja dengan B-Tree bawaan dan metode pengindeksan lainnya. Misalnya, jika Anda ingin membuat indeks B-Tree pada kolom dengan tipe "kompleks", Anda harus memberi tahu Postgres cara membandingkan dua nilai dari tipe ini untuk menentukan apakah yang satu lebih kecil, sama, atau lebih besar dari yang lain.

Akan lebih baik jika tipe kompleks dibandingkan dengan bilangan bulat atau nilai floating point, di situlah keluarga operator masuk.

Anda dapat membaca semua tentang kelas operator dan keluarga di sini.

Pemicu

Pemicu adalah mekanisme yang kuat untuk menciptakan efek samping untuk operasi normal, meskipun mereka bisa berbahaya jika digunakan secara berlebihan atau disalahgunakan. Pada dasarnya, pemicu menghubungkan peristiwa ke fungsi. Fungsi yang dirujuk dapat dipanggil:

  • sebelum atau sesudah menyisipkan/memperbarui/menghapus baris tabel
  • pada pemotongan tabel
  • bukannya menyisipkan/memperbarui/menghapus satu baris tampilan

Fungsi dapat dipanggil untuk setiap baris yang dipengaruhi oleh pernyataan, atau sekali pernyataan. Dan masih banyak lagi, seperti rangkaian pemicu, yang semuanya dijelaskan di sini.

Fungsi pemicu dapat ditulis dalam C, atau dalam salah satu fungsi PL, tetapi tidak dalam SQL. Berikut adalah contoh untuk menyisipkan baris ke dalam audit tabel, untuk setiap pembaruan yang dilakukan pada harga dari item .

-- 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();

Baca semua tentang pemicu di sini, bersama dengan dokumentasi CREATE TRIGGER.

Pemicu Peristiwa

Sementara memicu menanggapi peristiwa DML di satu tabel, pemicu peristiwa dapat menanggapi kejadian DDL pada database tertentu. Acara termasuk membuat, mengubah, menjatuhkan berbagai objek, seperti tabel, indeks, skema, tampilan, fungsi, tipe, operator, dll.

Berikut adalah pemicu peristiwa yang mencegah jatuhnya objek dari skema 'audit':

-- 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();

Informasi lebih lanjut dapat ditemukan di sini dan dalam dokumentasi CREATE EVENT TRIGGER.

Aturan

PostgreSQL hadir dengan fitur yang memungkinkan Anda menulis ulang kueri sebelum masuk ke perencana kueri. Operasi ini agak mirip dengan mengonfigurasiNginx atau Apache untuk menulis ulang URL yang masuk sebelum memprosesnya.

Berikut adalah dua contoh yang memengaruhi pernyataan INSERT pada tabel dan membuatnya melakukan hal lain:

-- 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);

Bab dari dokumentasi ini memiliki informasi lebih lanjut tentang aturan.

Prosedur Tersimpan

Dimulai dengan Postgres 11, dimungkinkan untuk membuat prosedur stored yang tersimpan juga. Dibandingkan dengan fungsi yang disimpan, hanya ada satu hal tambahan yang dapat dilakukan prosedur – kontrol transaksi.

Ini contohnya:

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);

Lihat di sini dan di sini untuk informasi lebih lanjut.

Hal-Hal Eksotis Lainnya

Pembungkus Data Asing

Pembungkus Data Asing (FDW) memungkinkan Anda berbicara dengan sumber data lain, seperti server Postgres lain, MySQL, Oracle, Cassandra, dan lainnya. Semua logika untuk mengakses server asing ditulis dalam C, sebagai pustaka bersama.

Bahkan ada toko berbentuk kolom bernama cstore_fdw berdasarkan FDW.

Anda dapat menemukan daftar implementasi PLRT Asing di Wiki Postgres dan dokumentasi lebih lanjut di sini.

Metode Akses Indeks

PostgreSQL hadir dengan tipe indeks seperti B-Tree, hash, GIN dan banyak lagi. Dimungkinkan untuk menulis jenis indeks Anda sendiri yang serupa dengan ini, sebagai pustaka bersama C. Selengkapnya di sini.

Metode Akses Tabel

Dengan PostgreSQL 12 yang akan datang, dimungkinkan untuk membuat struktur penyimpanan data Anda sendiri. Dengan mengimplementasikan antarmuka yang dijelaskan di sini, Anda dapat menyimpan data tupel secara fisik di disk dengan cara yang Anda pilih.

Plugin Replikasi Logis

Di PostgreSQL, replikasi logis diimplementasikan dengan "mendekode" isi log tulis (WAL) ke dalam format arbitrer (seperti teks SQL atau json) dan dipublikasikan ke pelanggan melalui slot replikasi. Decoding ini dilakukan melaluiplugin keluaran decoding logis , yang dapat diimplementasikan sebagai pustaka bersama C seperti yang dijelaskan di sini. Pustaka bersama “test_decoding” adalah salah satu plugin tersebut, dan Anda dapat membuatnya sendiri.

Penangan Bahasa Prosedural

Anda juga dapat menambahkan dukungan untuk bahasa pemrograman favorit Anda sebagai PL Postgres dengan membuat handler – lagi-lagi sebagai pustaka bersama C. Mulailah di sini untuk membuat PL/Go atau PL/Rust!

Ekstensi

Ekstensi adalah cara manajemen paket Postgres. Katakanlah Anda memiliki fungsi C yang melakukan sesuatu yang berguna, dan beberapa pernyataan SQL yang membuat pernyataan "CREATE FUNCTION" diperlukan untuk menyiapkannya. Anda dapat menggabungkan ini sebagai "ekstensi" yang dapat diinstal (dan dihapus) Postgres dalam satu langkah (dengan memanggil "BUAT EKSTENSI"). Saat Anda mengeluarkan versi baru, Anda juga dapat menyertakan langkah peningkatan dalam ekstensi.

Meskipun bukan pemrograman sisi server semata, ekstensi adalah cara standar dan sangat efisien untuk mengemas dan mendistribusikan kode sisi server Anda.

Informasi lebih lanjut tentang ekstensi dapat ditemukan di sini dan di sini.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Temukan baris dengan beberapa bidang duplikat dengan Rekaman Aktif, Rel &Postgres

  2. Masukkan jika tidak ada, jika tidak kembalikan id di postgresql

  3. CTE dan Paradoks Ulang Tahun

  4. Bagaimana cara melakukan kueri pemilihan di blok DO?

  5. Bagaimana cara mendapatkan kueri atribut kolom dari nama tabel menggunakan PostgreSQL?