PostgreSQL'de CREATE FUNCTION bir değer (ya da satır kümesi) döndüren, sorgu içinde SELECT ile çağrılan bir yordam tanımlar; CREATE PROCEDURE ise değer döndürmeyen, tek başına CALL ile çağrılan ve gerekirse kendi içinde COMMIT veya ROLLBACK yapabilen bir yordam tanımlar. En basit hâliyle CREATE FUNCTION ad(parametre tip) RETURNS tip LANGUAGE SQL RETURN ifade; yazmanız yeterlidir.

Bu yazı SQL dilinde (LANGUAGE SQL) fonksiyon ve procedure yazmayı ele alıyor: iki gövde biçimi, parametre adları ve varsayılan değerler, OUT parametreleri, RETURNS TABLE ve SETOF, IMMUTABLE/STABLE/VOLATILE sınıfları, STRICT, aşırı yükleme tuzakları, CREATE OR REPLACE sınırları, SECURITY DEFINER ve procedure ile transaction kontrolü. Değişken, döngü ve koşul gerektiren mantık için PL/pgSQL temelleri yazısına geçebilirsiniz; serinin tamamı PostgreSQL öğrenme rehberinde.

Fonksiyon ile procedure arasındaki fark

Fonksiyon ile procedure arasındaki fark: Tanım komutu, Dönüş değeri, Çağrı, COMMIT / ROLLBACK

Kılavuz procedure'ü fonksiyona benzeyen bir nesne olarak tanımlar ve farkları tek tek sayar. Özetle:

KonuFUNCTIONPROCEDURE
Tanım komutuCREATE FUNCTIONCREATE PROCEDURE
Dönüş değeriRETURNS ile zorunlu (void olabilir)RETURNS yok, yalnızca OUT parametreleri
ÇağrıSorgu içinde: SELECT f(...)Tek başına: CALL p(...)
COMMIT / ROLLBACKYapamazCALL açık bir transaction bloğunda değilse yapabilir
STRICT, IMMUTABLE vb.VarUygulanmaz
Ortak adroutineroutine

İkisine birlikte routine denir; ALTER ROUTINE ve DROP ROUTINE komutları türünü bilmeden ikisinde de çalışır, ama CREATE ROUTINE diye bir komut yoktur. Kılavuz ayrıca void döndüren bir fonksiyon ile procedure arasındaki farkın basit durumlarda çoğunlukla üslup meselesi olduğunu, procedure'ün ise SQL standardında bulunduğunu, void dönüşün PostgreSQL eklentisi olduğunu belirtir.

İlk SQL fonksiyonu: iki gövde biçimi

SQL fonksiyonu, gövdesindeki SQL komutlarını sırayla çalıştırır ve son sorgunun sonucunu döndürür. Tek değer döndüren bir fonksiyonda son sorgunun ilk satırı döner; kılavuz, ORDER BY kullanmazsanız "ilk satırın" tanımlı olmadığını hatırlatır. Son sorgu hiç satır döndürmezse sonuç NULL olur. Gövdeyi iki şekilde yazabilirsiniz:

  • Metin gövde: AS $$ ... $$. Gövde bir metin sabitidir ve çalıştırma anında ayrıştırılır. Dolar tırnağı ($$) sayesinde içerideki tek tırnakları ikilemeniz gerekmez. Tüm dillerde kullanılabilir.
  • SQL standardı gövde: tek ifade için RETURN ifade, birden çok komut için BEGIN ATOMIC ... END. Yalnızca LANGUAGE SQL için geçerlidir, tanım anında ayrıştırılır ve gövdedeki nesnelere bağımlılık kaydı tutar.

Aşağıda kdv_dahil standart gövdeyle, stok_degeri metin gövdeyle yazıldı. İlk fonksiyonda oran parametresinin varsayılan değeri var; çağrıyı konumsal ya da ad => değer biçiminde adlı yapabilirsiniz.

sql
CREATE TABLE urun (
    id     integer PRIMARY KEY,
    ad     text NOT NULL,
    kategori text NOT NULL,
    fiyat  numeric(10,2) NOT NULL,
    stok   integer NOT NULL DEFAULT 0
);
INSERT INTO urun VALUES
    (1, 'Çay Bardağı', 'mutfak', 45.00, 120),
    (2, 'Türk Kahvesi Fincanı', 'mutfak', 180.00, 35),
    (3, 'Pamuk Havlu', 'banyo', 260.00, 0),
    (4, 'Bakır Cezve', 'mutfak', 540.00, 12),
    (5, 'Bornoz', 'banyo', 890.00, 7);

-- Gövdesi SQL standardı biçiminde (RETURN ifadesi)
CREATE FUNCTION kdv_dahil(fiyat numeric, oran numeric DEFAULT 20)
    RETURNS numeric
    LANGUAGE SQL
    IMMUTABLE
    RETURN round(fiyat * (1 + oran / 100), 2);

-- Gövdesi dolar tırnaklı metin olarak
CREATE FUNCTION stok_degeri(kat text) RETURNS numeric
    LANGUAGE SQL STABLE
AS $$
    SELECT sum(fiyat * stok) FROM urun WHERE kategori = kat;
$$;

SELECT kdv_dahil(100) AS varsayilan,
       kdv_dahil(100, 10) AS konumsal,
       kdv_dahil(oran => 1, fiyat => 100) AS adli,
       stok_degeri('mutfak') AS mutfak,
       stok_degeri('bahçe') AS bahce;
text
 varsayilan | konumsal |  adli  |  mutfak  | bahce
------------+----------+--------+----------+-------
     120.00 |   110.00 | 101.00 | 18180.00 |
(1 row)

Son sütun boş görünüyor çünkü "bahçe" kategorisinde ürün yok, sum() satır bulamayınca NULL döndü ve psql NULL değeri boş gösterir. Adlı çağrıda parametre sırasının önemsiz olduğuna dikkat edin.

Parametre adlarıyla ilgili iki kural sık karışır. Birincisi: gövdedeki bir parametre adı, aynı komuttaki bir sütun adıyla çakışırsa sütun adı kazanır. Bu yüzden yukarıda parametreye kat dedik, kategori demedik. Çakışmayı önlemenin diğer yolu parametreyi fonksiyon adıyla nitelemektir: stok_degeri.kategori. İkincisi: SQL fonksiyonu parametreleri yalnızca veri değeri olarak kullanılabilir, tablo veya sütun adı yerine geçemez; INSERT INTO $1 ... çalışmaz. Dinamik tablo adı gerekiyorsa PL/pgSQL'deki EXECUTE ile format() kullanılır ve bu durumda SQL injection önleme kurallarına dikkat etmek gerekir.

Varsayılan değerlerin bir kuralı daha var: varsayılan değeri olan bir parametreden sonra gelen tüm giriş parametrelerinin de varsayılanı olmalıdır, çünkü konumsal çağrıda yalnızca sondaki argümanlar atlanabilir. Bir de tip ayrıntısı: CREATE FUNCTION parantezli tip niteleyicilerini yok sayar; varchar(10) parametresi ile varchar parametresi aynıdır, uzunluk denetlenmez.

Birden çok değer: OUT, RETURNS TABLE, SETOF

Bir fonksiyonun birden fazla sütun döndürmesi için üç yol vardır. OUT parametreleri tek bir satır döndürür; sonuç sütunlarının adı OUT parametrelerinin adıdır. RETURNS TABLE (...) ise kılavuza göre adlandırılmış OUT parametreleri ile RETURNS SETOF birleşimine eşdeğerdir, yani satır kümesi döndürür. RETURNS SETOF tablo_adi de son sorgunun tüm satırlarını, o tablonun satır tipiyle döndürür.

sql
CREATE FUNCTION fiyat_araligi(kat text, OUT en_dusuk numeric, OUT en_yuksek numeric)
    LANGUAGE SQL STABLE
AS $$
    SELECT min(fiyat), max(fiyat) FROM urun WHERE kategori = kat;
$$;

CREATE FUNCTION kategori_urunleri(kat text)
    RETURNS TABLE (urun_adi text, kdvli numeric)
    LANGUAGE SQL STABLE
AS $$
    SELECT ad, kdv_dahil(fiyat) FROM urun WHERE kategori = kat ORDER BY fiyat;
$$;

CREATE FUNCTION tukenenler() RETURNS SETOF urun
    LANGUAGE SQL STABLE
AS $$
    SELECT * FROM urun WHERE stok = 0;
$$;

SELECT * FROM fiyat_araligi('banyo');
SELECT * FROM kategori_urunleri('mutfak') WHERE kdvli > 100;
SELECT id, ad, stok FROM tukenenler();
SELECT kategori_urunleri('banyo');
text
 en_dusuk | en_yuksek
----------+-----------
   260.00 |    890.00
(1 row)

       urun_adi       | kdvli
----------------------+--------
 Türk Kahvesi Fincanı | 216.00
 Bakır Cezve          | 648.00
(2 rows)

 id |     ad      | stok
----+-------------+------
  3 | Pamuk Havlu |    0
(1 row)

   kategori_urunleri
------------------------
 ("Pamuk Havlu",312.00)
 (Bornoz,1068.00)
(2 rows)

Küme döndüren fonksiyonlar en doğal hâliyle FROM içinde kullanılır ve sonuç bir tablo gibi filtrelenebilir. Son sorgu ise aynı fonksiyonu seçim listesinde çağırıyor: bu durumda her satır tek bir bileşik (composite) değer olarak, parantez içinde gelir. Sütunlara ayrı ayrı erişmek istiyorsanız fonksiyonu FROM içine alın. RETURNS TABLE ile açık OUT veya INOUT parametresi birlikte kullanılamaz; tüm çıkış sütunları TABLE listesinde olmalıdır.

Bir uyarı daha: fonksiyonun son komutu RETURNING içeren bir INSERT, UPDATE, DELETE veya MERGE ise, fonksiyon SETOF olmasa ya da çağıran tüm satırları okumasa bile komut sonuna kadar çalışır. Fazla satırlar sessizce atılır ama tablo değişiklikleri yapılmış olur. RETURNING ayrıntıları INSERT, UPDATE, DELETE ve RETURNING yazısında.

IMMUTABLE, STABLE, VOLATILE: oynaklık sınıfları

IMMUTABLE, STABLE, VOLATILE: oynaklık sınıfları: VOLATILE, STABLE, IMMUTABLE

Her fonksiyonun bir oynaklık (volatility) sınıfı vardır ve bu, planlayıcıya verilen bir sözdür. Belirtmezseniz VOLATILE varsayılır. Kılavuz en iyi sonuç için fonksiyonu geçerli olan en sıkı sınıfla işaretlemenizi önerir.

SınıfVeritabanını değiştirebilir miAynı argümanla aynı sonuçTipik örnek
VOLATILEEvetGaranti yok, her satırda yeniden çağrılırrandom(), currval(), timeofday(), setval()
STABLEHayırTek bir komut boyunca aynınow() ailesi, tablo okuyan fonksiyonlar
IMMUTABLEHayırHer zaman aynıSaf hesaplama, upper(), tamsayı toplama

Sistem kataloğu pg_proc bu bilgiyi provolatile sütununda tek harfle tutar (i, s, v). Kendi fonksiyonlarımızla yerleşik birkaç fonksiyonu karşılaştıralım:

sql
SELECT DISTINCT proname, provolatile, proisstrict
FROM pg_proc
WHERE proname IN ('kdv_dahil', 'stok_degeri', 'now', 'random', 'upper')
ORDER BY proname;
text
   proname   | provolatile | proisstrict
-------------+-------------+-------------
 kdv_dahil   | i           | f
 now         | s           | t
 random      | v           | t
 stok_degeri | s           | f
 upper       | i           | t
(5 rows)

Sınıf seçiminin pratik sonuçları şunlardır. IMMUTABLE bir fonksiyon sabit argümanlarla çağrıldığında planlama sırasında önceden hesaplanabilir; WHERE x = 2 + 2 ifadesi doğrudan x = 4 olur. STABLE bir fonksiyon indeks taraması koşulunda kullanılabilir, çünkü indeks taraması karşılaştırma değerini bir kez hesaplar; VOLATILE fonksiyonlar bu yüzden indeks koşulunda kullanılamaz. İndeks ifadesinde ise yalnızca IMMUTABLE fonksiyonlara izin verilir:

sql
CREATE TABLE kategori (ad text PRIMARY KEY, kod text NOT NULL);
INSERT INTO kategori VALUES ('mutfak', 'MTF'), ('banyo', 'BNY');
CREATE FUNCTION kategori_kodu(k text) RETURNS text
    LANGUAGE SQL
AS $$
    SELECT kod FROM public.kategori WHERE ad = k;
$$;
CREATE INDEX urun_kat_kod ON urun (kategori_kodu(kategori));

CREATE FUNCTION yarim(n integer) RETURNS integer
    LANGUAGE SQL STRICT
    RETURN n / 2;
SELECT yarim(9) AS dokuz, yarim(NULL) IS NULL AS null_mu;
text
ERROR:  functions in index expression must be marked IMMUTABLE
CREATE FUNCTION
 dokuz | null_mu
-------+---------
     4 | t
(1 row)

kategori_kodu sınıf belirtilmediği için VOLATILE sayıldı ve indeks reddedildi. Burada hatayı "fonksiyonu IMMUTABLE yapayım" diye geçiştirmek yanlış olur: fonksiyon bir tablo okuyor ve tablo içeriği değişirse sonuç da değişir. Kılavuz, IMMUTABLE bir fonksiyonun tablo okumasını genel olarak akıllıca bulmaz ve PostgreSQL'in bunu zorla engellemediğini de not eder. Yanlış işaretlenmiş bir fonksiyon, planı saklanan hazır ifadelerde ya da planı önbelleğe alan PL/pgSQL'de eski bir değerin tekrar tekrar kullanılmasına yol açabilir. Sık yapılan başka bir hata da sonucu TimeZone gibi bir ayara bağlı olan fonksiyonu IMMUTABLE işaretlemektir; böyle fonksiyonlar STABLE olmalıdır. İfade indeksleri PostgreSQL indeks türleri yazısında ayrıca anlatılıyor.

Bir ayrıntı da veri görünürlüğüyle ilgilidir: SQL ve standart prosedürel dillerde VOLATILE fonksiyonlar, kendilerini çağıran komutun yaptığı değişiklikleri görür; STABLE ve IMMUTABLE fonksiyonlar çağıran sorgunun başında alınan anlık görüntüyü (snapshot) kullanır ve bu değişiklikleri görmez. PostgreSQL, STABLE ve IMMUTABLE fonksiyonlarda SELECT dışında SQL komutuna izin vermez.

Yukarıdaki son örnekteki STRICT (eş anlamlısı RETURNS NULL ON NULL INPUT) ise başka bir şeydir: argümanlardan biri NULL ise fonksiyon hiç çalıştırılmaz, sonuç doğrudan NULL kabul edilir. Varsayılan CALLED ON NULL INPUT davranışında NULL kontrolü sizin sorumluluğunuzdadır. yarim(9) sonucunun 4 olması da tamsayı bölmesinden gelir.

Aşırı yükleme ve CREATE OR REPLACE sınırları

PostgreSQL aynı adı taşıyan, ancak giriş parametresi tipleri farklı olan birden çok fonksiyona izin verir; buna aşırı yükleme (overloading) denir. İki fonksiyon, adları ve giriş parametre tipleri aynıysa aynı sayılır; OUT parametreleri hesaba katılmaz. Kılavuzun özellikle uyardığı tuzak, varsayılan değerlerle aşırı yüklemenin birleşmesidir: tanım anında çakışma görünmez, ama çağrı belirsizleşir.

sql
CREATE FUNCTION indirim(fiyat numeric) RETURNS numeric
    LANGUAGE SQL RETURN fiyat * 0.9;
CREATE FUNCTION indirim(fiyat numeric, yuzde numeric DEFAULT 10) RETURNS numeric
    LANGUAGE SQL RETURN fiyat * (100 - yuzde) / 100;
SELECT indirim(200, 25);
SELECT indirim(200);
DROP FUNCTION indirim;

CREATE OR REPLACE FUNCTION kdv_dahil(fiyat numeric, oran numeric DEFAULT 20)
    RETURNS text
    LANGUAGE SQL IMMUTABLE
    RETURN round(fiyat * (1 + oran / 100), 2)::text;
text
       indirim
----------------------
 150.0000000000000000
(1 row)

ERROR:  function indirim(integer) is not unique
LINE 1: SELECT indirim(200);
               ^
HINT:  Could not choose a best candidate function. You might need to add explicit type casts.
ERROR:  function name "indirim" is not unique
HINT:  Specify the argument list to select the function unambiguously.
ERROR:  cannot change return type of existing function
HINT:  Use DROP FUNCTION kdv_dahil(numeric,numeric) first.

İki argümanlı çağrı yalnızca ikinci fonksiyona uydu ve çalıştı. Tek argümanlı çağrı ise her iki fonksiyona da uyduğu için reddedildi. Aynı adlı birden çok fonksiyon olduğunda DROP FUNCTION indirim da yetmez; parametre listesini yazmanız gerekir: DROP FUNCTION indirim(numeric).

Son hata CREATE OR REPLACE FUNCTION kurallarından geliyor. Bu komut var olan fonksiyonun gövdesini ve özelliklerini değiştirebilir, ama dönüş tipini değiştiremez; dönüş tipini (ve OUT parametrelerinin tiplerini) değiştirmek için fonksiyonu silip yeniden oluşturmanız gerekir. Adı veya parametre tiplerini değiştirmeye çalışırsanız komut aslında yeni, ayrı bir fonksiyon yaratır. Var olan giriş parametrelerinin adları da değiştirilemez. Değiştirme sırasında sahiplik ve yetkiler korunur. Silip yeniden oluşturduğunuzda ise yeni fonksiyon eskisiyle aynı nesne sayılmaz; fonksiyona başvuran view ve trigger gibi nesneleri de yeniden kurmanız gerekir. Bu yüzden mümkünse CREATE OR REPLACE tercih edin; sadece yardımcı özellikleri değiştirmek için ALTER FUNCTION da kullanılabilir.

CREATE PROCEDURE ve CALL

Procedure, RETURNS içermez; veriyi çağırana OUT parametreleriyle döndürebilir. CALL komutunda OUT parametreleri için de bir argüman yazılmalıdır; kılavuz bunun değerlendirilmediğini ve geleneksel olarak NULL yazıldığını söyler. Aşağıdaki procedure stok hareketini kaydedip ürün stokunu güncelliyor; gövde BEGIN ATOMIC biçiminde yazıldı:

sql
CREATE TABLE stok_hareket (
    id       integer GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    urun_id  integer NOT NULL REFERENCES urun(id),
    miktar   integer NOT NULL
);

CREATE PROCEDURE stok_ekle(p_urun integer, p_miktar integer, OUT yeni_stok integer)
    LANGUAGE SQL
BEGIN ATOMIC
    INSERT INTO stok_hareket (urun_id, miktar) VALUES (p_urun, p_miktar);
    UPDATE urun SET stok = stok + p_miktar WHERE id = p_urun RETURNING stok;
END;

CALL stok_ekle(3, 40, NULL);
SELECT stok_ekle(3, 5, NULL);
DROP TABLE stok_hareket;
text
 yeni_stok
-----------
        40
(1 row)

ERROR:  function stok_ekle(integer, integer, unknown) does not exist
LINE 1: SELECT stok_ekle(3, 5, NULL);
               ^
HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
ERROR:  cannot drop table stok_hareket because other objects depend on it
DETAIL:  function stok_ekle(integer,integer) depends on table stok_hareket
HINT:  Use DROP ... CASCADE to drop the dependent objects too.

Üç şey görülüyor. CALL, OUT parametresini bir sonuç satırı olarak döndürdü. Procedure'ü SELECT ile çağırmak işe yaramadı: PostgreSQL bu adla bir fonksiyon aradı ve bulamadı; kılavuz da fonksiyon çağırmak için SELECT, procedure çağırmak için CALL kullanılacağını belirtir. Son olarak BEGIN ATOMIC gövdesi tabloya bağımlılık kaydı bıraktığı için DROP TABLE engellendi. Kılavuza göre metin gövdeli fonksiyonlarda bu takip yapılmaz; tablo silinebilir ve geride çalışmayan bir fonksiyon kalabilir. Buna karşılık standart gövde tanım anında ayrıştırıldığı için polimorfik argüman tiplerini desteklemez.

Procedure'ün asıl ayırt edici özelliği transaction kontrolüdür. SQL dilindeki fonksiyon ve procedure'lerde COMMIT kullanılamaz, bu yüzden aşağıdaki örnek PL/pgSQL ile yazıldı. Procedure döngü içinde her iki satırda bir commit ediyor:

sql
CREATE TABLE log_kayit (id integer, zaman timestamptz DEFAULT now());

CREATE PROCEDURE toplu_ekle(adet integer)
    LANGUAGE plpgsql
AS $$
BEGIN
    FOR i IN 1..adet LOOP
        INSERT INTO log_kayit (id) VALUES (i);
        IF i % 2 = 0 THEN
            COMMIT;
        END IF;
    END LOOP;
END;
$$;

CALL toplu_ekle(5);
SELECT count(*) FROM log_kayit;

BEGIN;
CALL toplu_ekle(2);
ROLLBACK;
text
CALL
 count
-------
     5
(1 row)

BEGIN
ERROR:  invalid transaction termination
CONTEXT:  PL/pgSQL function toplu_ekle(integer) line 6 at COMMIT
ROLLBACK

İlk CALL kendi başına çalıştığı için COMMIT yapabildi. İkinci çağrı BEGIN ile açılmış bir transaction bloğunun içinde yapıldı ve invalid transaction termination hatası verdi. Kılavuz bu kuralı açıkça yazar: transaction kontrolü yalnızca CALL kendi transaction'ında çalıştırıldığında mümkündür. Ayrıca SECURITY DEFINER olan ya da SET yan tümcesi taşıyan bir procedure de COMMIT/ROLLBACK yapamaz. Transaction kavramının kendisi BEGIN, COMMIT ve ROLLBACK yazısında anlatılıyor.

SECURITY DEFINER ve SET search_path

SECURITY DEFINER ve SET search_path: search_path sabitlenmeli, PUBLIC yetkisi kaldırılmalı

Varsayılan SECURITY INVOKER modunda fonksiyon, onu çağıran kullanıcının yetkileriyle çalışır. SECURITY DEFINER ile fonksiyon, sahibinin yetkileriyle çalışır; böylece kullanıcıya tabloya doğrudan yazma yetkisi vermeden yalnızca belirli bir işlemi yapma izni verebilirsiniz. Kılavuz bu gücün kötüye kullanılmaması için iki önlem ister:

  • search_path sabitlenmeli: güvenilmeyen kullanıcıların yazabildiği şemalar arama yolunda olmamalı. Varsayılan olarak ilk aranan geçici tablo şeması herkesçe yazılabilir; bu yüzden pg_temp en sona yazılmalıdır. Aksi hâlde kötü niyetli biri aynı adla geçici bir tablo oluşturup fonksiyonu kandırabilir.
  • PUBLIC yetkisi kaldırılmalı: yeni fonksiyonlarda EXECUTE yetkisi varsayılan olarak PUBLIC rolüne verilir. Kılavuz, fonksiyonun bir an bile herkese açık kalmaması için oluşturma ve yetki ayarını tek bir transaction içinde yapmayı önerir.
sql
BEGIN;
CREATE FUNCTION fiyat_guncelle(p_id integer, p_fiyat numeric) RETURNS numeric
    LANGUAGE SQL
    SECURITY DEFINER
    SET search_path = public, pg_temp
AS $$
    UPDATE urun SET fiyat = p_fiyat WHERE id = p_id RETURNING fiyat;
$$;
REVOKE ALL ON FUNCTION fiyat_guncelle(integer, numeric) FROM PUBLIC;
COMMIT;

SELECT proname, prosecdef, proconfig, proacl
FROM pg_proc WHERE proname = 'fiyat_guncelle';
text
    proname     | prosecdef |            proconfig            |        proacl
----------------+-----------+---------------------------------+-----------------------
 fiyat_guncelle | t         | {"search_path=public, pg_temp"} | {postgres=X/postgres}
(1 row)

proacl sütununda artık yalnızca sahibin EXECUTE (X) yetkisi görünüyor. Gerçek kullanımda bunun ardından GRANT EXECUTE ON FUNCTION ... TO rol ile yetkiyi seçili rollere verirsiniz; ayrıntılar GRANT ve REVOKE ve rol yönetimi yazılarında. SET yan tümcesi, fonksiyona girerken ayarı değiştirir ve çıkarken eski değere döndürür.

PostgreSQL 18 sürüm notları SQL dilindeki fonksiyonların plan önbelleğinin iyileştirildiğini ve psql'in \df+ çıktısına fonksiyonun LEAKPROOF bilgisinin eklendiğini belirtir. LEAKPROOF işaretini yalnızca süper kullanıcı verebilir ve security_barrier view ile RLS sorgularının nasıl çalıştırılacağını etkiler.

Sık yapılan hatalar

  • Procedure'ü SELECT ile çağırmak: "function ... does not exist" hatası alırsınız; CALL kullanın.
  • Parametreye sütunla aynı adı vermek: SQL fonksiyonunda sütun adı kazanır ve sorgu sessizce yanlış sonuç verebilir.
  • Oynaklığı yanlış işaretlemek: tablo okuyan veya ayarlara bağlı fonksiyonu IMMUTABLE yapmak, eski değerlerin kullanılmasına yol açabilir; yan etkili fonksiyonlar VOLATILE kalmalıdır.
  • Varsayılanlı aşırı yükleme: f(int) ve f(int, int DEFAULT ...) birlikte belirsiz çağrı üretir.
  • Dönüş tipini CREATE OR REPLACE ile değiştirmeye çalışmak: önce DROP FUNCTION gerekir ve bağımlı nesneler etkilenir.
  • SECURITY DEFINER fonksiyonda search_path ayarlamamak ve PUBLIC yetkisini kaldırmamak.
  • Transaction bloğu içinden COMMIT yapan procedure çağırmak: invalid transaction termination hatası alırsınız.

Sık Sorulan Sorular

LANGUAGE SQL mi, plpgsql mi seçmeliyim?

Fonksiyon tek bir sorgu veya ifadeden oluşuyorsa SQL dili yeterlidir ve standart gövdeyle bağımlılık takibi de kazanırsınız. Değişken, döngü, koşul veya hata yakalama gerekiyorsa PL/pgSQL kullanın; ayrıntılar PL/pgSQL temelleri ve PL/pgSQL hata yakalama yazılarında.

Fonksiyonun tanımını nasıl görürüm?

psql içinde \df ad fonksiyonları listeler, \df+ ad ayrıntıları gösterir, \sf ad tanımı yazdırır. Komutlar için psql komutları yazısına bakın.

Fonksiyon trigger olarak kullanılabilir mi?

Trigger fonksiyonları özel bir tür olan trigger döndürür ve SQL diliyle değil, PL/pgSQL gibi prosedürel bir dille yazılır. Konu PostgreSQL trigger oluşturma yazısında.

Değişken sayıda argüman alabilir miyim?

Evet, son parametreyi VARIADIC ve dizi tipinde tanımlarsınız; fazladan argümanlar bir diziye toplanır. Hazır bir diziyi geçirmek için çağrıda VARIADIC ARRAY[...] yazılır. Dizi işlemleri PostgreSQL dizi tipi yazısında.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: PostgreSQL öğrenme rehberi · PL/pgSQL temelleri · Trigger oluşturma · İndeks türleri · GRANT ve REVOKE · SQL injection önleme