Function yaratish — RETURNS, LANGUAGE, SECURITY DEFINER
Muammodan boshlaylik
Oldingi darsda DO bloki bilan PL/pgSQL ni sinab ko'rdik. Lekin DO bloki bir martalik — tugagandan keyin yo'qoladi. Agar bir xil kodni bir necha joyda ishlatish kerak bo'lsa — har safar qaytadan yozish kerak.
Masalan: foydalanuvchi balansini tekshirib, yetarli bo'lsa pul yechish. Bu logika bir necha yerda kerak — buyurtma berishda, pul o'tkazishda, obuna yangilashda. Har joyda bir xil kodni takrorlash — xatoga moyil, o'zgartirishda ko'p joy topib yangilash kerak.
Function — bu kodni bir joyda yozib, keyin nomini chaqirish. Bir marta yozing, istalgan joydan foydalaning.
Function nima?
Function — nom berilgan, parametr qabul qiladigan, natija qaytaradigan kod bloki. Yozgandan keyin jadval kabi bazada saqlanadi — o'chirilmaguncha ishlaydi.
Hayotiy o'xshatma: kafe menyusidagi taom. Oshpaz "kofeni qanday tayyorlash" retseptini bir marta yozadi. Har safar "bir kafe" deb buyurtma berilganda, retsept qaytadan o'qiladi va bajariladi. Function — shu retsept. Siz faqat nomini chaqirasiz — ichida nima bo'lishini bilmasan ham bo'ladi.
DO bloki: Function:
───────────────────────── ──────────────────────────────
Bir martalik Saqlanib qoladi
Qayta ishlatib bo'lmaydi Istalgan joydan chaqirish mumkin
Parametr yo'q Parametr qabul qiladi
Eng oddiy function
CREATE OR REPLACE FUNCTION salomlash(ism TEXT)
RETURNS TEXT
LANGUAGE plpgsql
AS $
BEGIN
RETURN 'Salom, ' || ism || '!';
END;
$;
Chaqirish:
SELECT salomlash('Ali'); -- 'Salom, Ali!'
SELECT salomlash('Vali'); -- 'Salom, Vali!'
CREATE OR REPLACE — allaqachon bor bo'lsa, yangilaydi. Yo'q bo'lsa, yaratadi.
RETURNS TEXT — funksiya nima qaytarishini bildiradi.
LANGUAGE plpgsql — qaysi tilda yozilgani.
AS $ ... $ — funksiya tanasi.
Sintaksis to'liq ko'rinishi
CREATE OR REPLACE FUNCTION funksiya_nomi(
parametr1 tur1,
parametr2 tur2 DEFAULT standart_qiymat
)
RETURNS qaytish_turi
LANGUAGE plpgsql
AS $
DECLARE
-- o'zgaruvchilar
BEGIN
-- kod
RETURN natija;
END;
$;
Parametrlar
Oddiy parametrlar
CREATE OR REPLACE FUNCTION ikki_son_yig(a NUMERIC, b NUMERIC)
RETURNS NUMERIC
LANGUAGE plpgsql
AS $
BEGIN
RETURN a + b;
END;
$;
SELECT ikki_son_yig(15, 27); -- 42
SELECT ikki_son_yig(100, 200); -- 300
DEFAULT qiymat
Ba'zi parametrlar ixtiyoriy bo'lishi mumkin — berilmasa standart qiymat ishlatiladi:
CREATE OR REPLACE FUNCTION chegirma_hisobla(
narx NUMERIC,
foiz NUMERIC DEFAULT 10 -- berilmasa 10% chegirma
)
RETURNS NUMERIC
LANGUAGE plpgsql
AS $
BEGIN
RETURN narx * (1 - foiz / 100.0);
END;
$;
SELECT chegirma_hisobla(1000000); -- 900000 (10% chegirma)
SELECT chegirma_hisobla(1000000, 20); -- 800000 (20% chegirma)
SELECT chegirma_hisobla(narx := 1000000, foiz := 15); -- 850000 (nom bilan)
Qaytish turlari
Bitta qiymat
RETURNS INT
RETURNS TEXT
RETURNS NUMERIC
RETURNS BOOLEAN
RETURNS VOID -- hech narsa qaytarmaydi
Jadval qatori — RETURNS TABLE
Funksiya bir nechta ustunli natija qaytarishi kerak bo'lsa:
CREATE OR REPLACE FUNCTION faol_foydalanuvchilar(min_buyurtma INT DEFAULT 1)
RETURNS TABLE (
id INT,
ism TEXT,
soni BIGINT
)
LANGUAGE plpgsql
AS $
BEGIN
RETURN QUERY
SELECT
f.id,
f.ism,
COUNT(b.id)::BIGINT
FROM foydalanuvchilar f
JOIN buyurtmalar b ON f.id = b.foydalanuvchi_id
GROUP BY f.id, f.ism
HAVING COUNT(b.id) >= min_buyurtma
ORDER BY COUNT(b.id) DESC;
END;
$;
Chaqirish — oddiy jadval kabi:
SELECT * FROM faol_foydalanuvchilar();
SELECT * FROM faol_foydalanuvchilar(min_buyurtma := 3);
SELECT ism FROM faol_foydalanuvchilar(2) WHERE soni > 5;
RETURN QUERY — so'rov natijasini funksiya natijasi sifatida qaytaradi.
LANGUAGE SQL — sodda funksiyalar uchun
Agar funksiya faqat SQL so'rovidan iborat bo'lsa — PL/pgSQL kerak emas, LANGUAGE sql yetarli. Tezroq va soddaroq:
CREATE OR REPLACE FUNCTION foydalanuvchi_buyurtmalari(foy_id INT)
RETURNS TABLE (mahsulot TEXT, summa NUMERIC)
LANGUAGE sql
AS $
SELECT mahsulot, summa
FROM buyurtmalar
WHERE foydalanuvchi_id = foy_id
ORDER BY summa DESC;
$;
PL/pgSQL kerak bo'lganda: shartlar, sikllar, o'zgaruvchilar, xatolarni ushlash kerak bo'lsa. Aks holda — LANGUAGE sql yetarli.
SECURITY DEFINER — kim nomidan ishlash
Bu parametr funksiyaning huquqlarini belgilaydi.
Standart — SECURITY INVOKER: Funksiya uni chaqirgan foydalanuvchi nomidan ishlaydi. Chaqiruvchi foydalanuvchilar jadvalini ko'ra olmasa — funksiya ham ko'ra olmaydi.
SECURITY DEFINER: Funksiya uni yaratgan foydalanuvchi nomidan ishlaydi. Chaqiruvchi jadvalga to'g'ridan-to'g'ri kirish huquqi bo'lmasa ham, funksiya orqali ishlay oladi.
SECURITY INVOKER: SECURITY DEFINER:
───────────────────────────────── ─────────────────────────────────
Chaqiruvchi kim? → uning huquqi Yaratuvchi kim? → uning huquqi
Ali chaqirsa → Ali huquqi Admin yaratgan → Admin huquqi
Vali chaqirsa → Vali huquqi Ali yoki Vali chaqirsa → Admin huquqi
Hayotiy o'xshatma: kompaniya direktori imzolagan hujjat. Xodim direktorsiz hujjatni imzolay olmaydi. Lekin direktorning "muhrli" funksiyasi orqali hujjat rasmiy hisoblanadi. SECURITY DEFINER — o'sha muhur.
CREATE OR REPLACE FUNCTION umumiy_hisobot()
RETURNS TABLE (ism TEXT, jami NUMERIC)
LANGUAGE sql
SECURITY DEFINER -- admin huquqi bilan ishlaydi
AS $
SELECT f.ism, SUM(b.summa)
FROM foydalanuvchilar f
JOIN buyurtmalar b ON f.id = b.foydalanuvchi_id
GROUP BY f.ism;
$;
-- Oddiy foydalanuvchi jadvalga kira olmaydi
-- Lekin funksiyani chaqira oladi — funksiya admin nomidan ishlaydi
GRANT EXECUTE ON FUNCTION umumiy_hisobot() TO oddiy_foydalanuvchi;
⚠️ Diqqat:
SECURITY DEFINER— kuchli, lekin xavfli. Funksiya ichiga foydalanuvchi kiritgan matn to'g'ridan-to'g'ri SQL ga qo'shilmaydi — har doim parameterized query ishlatilsin.
Funksiyani ko'rish va o'chirish
-- Funksiya ta'rifini ko'rish
\df+ funksiya_nomi -- psql da
SELECT prosrc FROM pg_proc WHERE proname = 'salomlash';
-- O'chirish
DROP FUNCTION salomlash(TEXT);
-- Parametr turi ko'rsatilishi shart — bir xil nomli bir nechta funksiya bo'lishi mumkin
-- Mavjud bo'lsa o'chirish
DROP FUNCTION IF EXISTS salomlash(TEXT);
Amaliy misol — to'liq funksiya
Foydalanuvchi ro'yxatdan o'tishi: email tekshirish, yaratish, profil yaratish — hammasi bitta funksiyada:
CREATE OR REPLACE FUNCTION foydalanuvchi_yaratish(
p_ism TEXT,
p_email TEXT,
p_parol TEXT
)
RETURNS INT -- yangi foydalanuvchi ID si
LANGUAGE plpgsql
AS $
DECLARE
yangi_id INT;
BEGIN
-- Email ni normallashtirish
p_email := LOWER(TRIM(p_email));
-- Minimal validatsiya
IF LENGTH(p_parol) < 8 THEN
RAISE EXCEPTION 'Parol kamida 8 belgi bo''lishi kerak';
END IF;
-- Foydalanuvchi yaratish
INSERT INTO foydalanuvchilar (ism, email, parol)
VALUES (TRIM(p_ism), p_email, p_parol)
RETURNING id INTO yangi_id;
-- Profil yaratish
INSERT INTO profillar (foydalanuvchi_id)
VALUES (yangi_id);
RETURN yangi_id;
EXCEPTION
WHEN unique_violation THEN
RAISE EXCEPTION 'Bu email allaqachon ro''yxatdan o''tgan: %', p_email;
END;
$;
Chaqirish:
SELECT foydalanuvchi_yaratish('Ali Karimov', 'ali@mail.com', 'parol123');
-- 1 (yangi ID)
SELECT foydalanuvchi_yaratish('Ali', 'ali@mail.com', 'boshqaparol');
-- ERROR: Bu email allaqachon ro'yxatdan o'tgan: ali@mail.com
Tez-tez uchraydigan xatolar
Bir xil nomli funksiyani o'chirishda parametr turini ko'rsatmaslik:
-- ❌ — qaysi salomlash? TEXT mi, INT mi?
DROP FUNCTION salomlash;
-- ERROR: function name "salomlash" is not unique
-- ✅ — parametr turi bilan aniq
DROP FUNCTION salomlash(TEXT);
PostgreSQL da bir xil nomli lekin har xil parametrli funksiyalar bo'lishi mumkin — bu overloading. Shu sababli o'chirishda parametr turi ko'rsatiladi.
RETURNS VOID da RETURN yozish:
-- ❌ — VOID funksiyada qiymat qaytarib bo'lmaydi
CREATE FUNCTION yangilash() RETURNS VOID AS $
BEGIN
UPDATE ...;
RETURN 1; -- xato
END;
$ LANGUAGE plpgsql;
-- ✅ — RETURN; yoki umuman yozmaslik
BEGIN
UPDATE ...;
RETURN; -- bo'sh, yoki umuman yozilmaydi
END;
Xulosa
Function — saqlanadigan, qayta ishlatiladigan kod bloki.
CREATE OR REPLACE FUNCTION nom(parametrlar)
RETURNS tur
LANGUAGE plpgsql / sql
AS $ ... $;
Qaytish turlari:
RETURNS tur— bitta qiymatRETURNS TABLE(...)+RETURN QUERY— ko'p qatorli natijaRETURNS VOID— hech narsa qaytarmaydi
Huquqlar:
SECURITY INVOKER(standart) — chaqiruvchi huquqiSECURITY DEFINER— yaratuvchi huquqi, ehtiyot bo'lish kerak
LANGUAGE sql — faqat SQL kerak bo'lsa, sodda va tezroq. LANGUAGE plpgsql — shartlar, sikllar, xatolar kerak bo'lsa.
Keyingi dars
33-dars: Stored Procedure — Function dan farqi, CALL