2016-10-11 54 views
6

Chciałbym utworzyć funkcję w PL/pgSQL z kilkoma zagnieżdżonymi (lub wewnętrznymi) funkcjami w niej. W ten sposób mogę zepsuć problem na mniejsze fragmenty, ale nie mam dostępnych mniejszych elementów poza tą funkcją.Jak utworzyć zagnieżdżoną funkcję w PL/pgSQL?

Czy można to zrobić w PL/pgSQL? Jeśli tak to jak?

+0

Dlaczego miałbyś to zrobić? Wydaje mi się niepraktyczne. Możesz rozwiązać problem na mniejsze kawałki bez wielu funkcji lub jeśli naprawdę tego potrzebujesz - dostosuj na nich uprawnienia. –

Odpowiedz

2

Funkcje zagnieżdżone nie są obsługiwane przez PLpgSQL. Emulacja nie ma żadnego sensu i jest nieproduktywna.

+1

Na pierwszy rzut oka emulacja opisana przez kiwi zadziałała. Testowałem go na mniejszych zestawach danych i wyglądało to dobrze. Podczas pracy z większymi zestawami dat zawsze jednak kończyło się niepowodzeniem z bardzo dziwnymi błędami blokowania. Myślę, że każdemu, kto to czyta, najlepiej służyć nie próbując wymusić działania funkcji zagnieżdżonych w PL/pgSQL. –

+0

@GregoryArenius: Zrobiłem trochę zabawy z tym przykładem, tworzy/zastępuje funkcję "wewnętrzną" (w tym samym zakresie co "zewnętrzna" funkcja) za każdym razem, gdy wywoływana jest funkcja "zewnętrzna", stąd dziwne błędy. Nie jest to wcale "funkcja wewnętrzna" i nie ma dostępu do wewnętrznego zakresu "zewnętrznego". –

7

Spróbuj:

CREATE OR REPLACE FUNCTION outer() RETURNS void AS $outer$ 
DECLARE s text; 
BEGIN 
    CREATE OR REPLACE FUNCTION inner() RETURNS text AS $inner$ 
    BEGIN 
    RETURN 'inner'; 
    END; 
    $inner$ language plpgsql; 

    SELECT inner() INTO s; 
    RAISE NOTICE '%', s; 

    DROP FUNCTION inner(); 
END; 
$outer$ language plpgsql; 

W PostgreSQL 9.5 SELECT outer(); wyjścia

psql:/vagrant/f.sql:14: NOTICE: inner 

EDIT: jeśli nie upuścić wewnętrzną funkcję na końcu funkcji zewnętrznej pozostanie widoczny dla reszta bazy danych.

+2

Kilka rzeczy do wskazania innym osobom, które próbują tego: Nie możesz po prostu użyć 'AS $$' dla funkcji wewnętrznej i zewnętrznej. Ponadto, jeśli twoja funkcja ma argumenty, musisz przekazać typy po upuszczeniu tej funkcji. I nie możesz wywoływać swoich funkcji w części zewnętrznej funkcji DECLARE, ponieważ nie zostały jeszcze utworzone. Po prostu utwórz zmienną i przypisz jej wartość po utworzeniu funkcji zagnieżdżonych. –

+2

@Gregory: Jeszcze jeden ważny punkt: jeśli dwie równoczesne transakcje spróbują wywołać tę funkcję, druga zablokuje się na wewnętrznym 'CREATE', dopóki pierwszy nie zostanie zatwierdzony, z powodu ograniczenia unikalności bazy danych dla nazw funkcji. Możesz obejść to, umieszczając funkcję wewnętrzną w schemacie temp sesji, czyli używając 'CREATE FUNCTION pg_temp.inner()'. Dodatkową korzyścią jest to, że wewnętrzne funkcje nigdy nie są widoczne z zewnątrz i są automatycznie czyszczone po sesji. –

+2

@Gregory: Przy okazji, bloki DECLARE ... BEGIN ... END mogą być zagnieżdżone, więc możesz wykonać deklaracje po utworzeniu funkcji wewnętrznej –