Przechodząc do sedna, zatrzymajmy się na najczęstszych błędach i niedociągnięciach, na które możesz się natknąć. Bo błędy w SQL to ból każdego developera i zwykle pojawiają się w najmniej odpowiednim momencie.
1. Błędy składni: "zapomniałem zamknąć IF"
Błędy składni to najbardziej podstawowe problemy, ale pojawiają się częściej, niż myślisz. Na przykład, jeśli zapomnisz zamknąć blok warunkowy IF przez END IF;, kompilator od razu cię zgani.
Przykład błędu:
CREATE OR REPLACE FUNCTION check_number(num INTEGER)
RETURNS TEXT AS $$
BEGIN
IF num > 0 THEN
RETURN 'Pozytywna';
ELSE
RETURN 'Negatywna';
-- gdzieś zgubiło się END IF;
END;
$$ LANGUAGE plpgsql;
Przy próbie odpalenia tego kodu dostaniesz błąd: ERROR: syntax error at or near "END". Dlaczego? Bo blok IF został otwarty, ale nie zamknięty.
Jak unikać takich błędów?
Zawsze trzymaj się przejrzystej struktury kodu. Jak otwierasz blok (np. IF), od razu napisz jego zamknięcie. Oto poprawiony przykład:
CREATE OR REPLACE FUNCTION check_number(num INTEGER)
RETURNS TEXT AS $$
BEGIN
IF num > 0 THEN
RETURN 'Pozytywna';
ELSE
RETURN 'Negatywna';
END IF; -- nie zapomnij zamknąć bloku
END;
$$ LANGUAGE plpgsql;
2. Zapomniana obsługa wszystkich przypadków w CASE: "A co, jeśli nie trafię nigdzie?"
Kiedy używasz CASE, zawsze dodaj gałąź ELSE na nieoczekiwane przypadki. Brak tej gałęzi może sprawić, że dostaniesz niechciane NULL.
Przykład błędu:
CREATE OR REPLACE FUNCTION grade_result(grade CHAR)
RETURNS TEXT AS $$
BEGIN
RETURN CASE grade
WHEN 'A' THEN 'Świetnie'
WHEN 'B' THEN 'Dobrze'
WHEN 'C' THEN 'Średnio'
-- A co, jeśli grade = 'D' albo inna ocena?
END;
END;
$$ LANGUAGE plpgsql;
Jeśli przekażesz wartość D, funkcja zwróci NULL, co może namieszać w twoim kodzie.
Poprawiona wersja:
CREATE OR REPLACE FUNCTION grade_result(grade CHAR)
RETURNS TEXT AS $$
BEGIN
RETURN CASE grade
WHEN 'A' THEN 'Świetnie'
WHEN 'B' THEN 'Dobrze'
WHEN 'C' THEN 'Średnio'
ELSE 'Nieznana ocena' -- Łapiemy wszystkie inne przypadki
END;
END;
$$ LANGUAGE plpgsql;
3. Problemy z nieskończonymi pętlami: "Czemu serwer się zawiesił?"
Używając pętli LOOP, łatwo zapomnieć o warunku wyjścia. To może skończyć się nieskończonym wykonaniem:
Przykład błędu:
CREATE OR REPLACE FUNCTION infinite_loop_demo()
RETURNS VOID AS $$
DECLARE
i INTEGER := 1;
BEGIN
LOOP
i := i + 1;
-- Brak warunku wyjścia!
END LOOP;
END;
$$ LANGUAGE plpgsql;
Ten kod zawiesi serwer, bo pętla nigdy się nie skończy.
Jak naprawić:
Dodaj warunek wyjścia przez EXIT:
CREATE OR REPLACE FUNCTION finite_loop_demo()
RETURNS VOID AS $$
DECLARE
i INTEGER := 1;
BEGIN
LOOP
i := i + 1;
IF i > 10 THEN
EXIT; -- Warunek wyjścia
END IF;
END LOOP;
END;
$$ LANGUAGE plpgsql;
4. Pomijanie iteracji w pętlach: "A co z brakującymi danymi?"
Używając CONTINUE do pomijania iteracji, możesz popełnić błąd, jeśli nie ogarniesz wszystkich przypadków. Na przykład:
Przykład błędu:
CREATE OR REPLACE FUNCTION skip_even()
RETURNS VOID AS $$
DECLARE
i INTEGER := 0;
BEGIN
WHILE i < 10 LOOP
i := i + 1;
IF i % 2 = 0 THEN
CONTINUE; -- Po prostu pomijamy parzyste
END IF;
RAISE NOTICE 'Nieparzysta liczba: %', i;
END LOOP;
END;
$$ LANGUAGE plpgsql;
A co, jeśli wszystkie liczby będą parzyste? Serwer będzie działał, ale nic nie zobaczysz.
Jak naprawić:
Upewnij się, że dobrze obsługujesz wszystkie dane i dodaj logi dla kontroli:
CREATE OR REPLACE FUNCTION skip_even_logging()
RETURNS VOID AS $$
DECLARE
i INTEGER := 0;
BEGIN
WHILE i < 10 LOOP
i := i + 1;
IF i % 2 = 0 THEN
RAISE NOTICE 'Pomijam parzystą: %', i;
CONTINUE;
END IF;
RAISE NOTICE 'Nieparzysta liczba: %', i;
END LOOP;
END;
$$ LANGUAGE plpgsql;
Teraz widzisz, które liczby zostały pominięte.
5. Zła obsługa błędów: "Gdzie mój RAISE EXCEPTION?"
Obsługa błędów przez RAISE EXCEPTION to mocne narzędzie, ale łatwo je popsuć złym użyciem.
Przykład błędu:
CREATE OR REPLACE FUNCTION calculate_square(num INTEGER)
RETURNS INTEGER AS $$
BEGIN
IF num < 0 THEN
RAISE 'Liczba ujemna jest niedozwolona!';
END IF;
RETURN num * num;
END;
$$ LANGUAGE plpgsql;
Ten kod wywali błąd, bo składnia RAISE jest zła (brakuje poziomu komunikatu).
Poprawiona wersja:
CREATE OR REPLACE FUNCTION calculate_square(num INTEGER)
RETURNS INTEGER AS $$
BEGIN
IF num < 0 THEN
RAISE EXCEPTION 'Liczba ujemna jest niedozwolona!';
END IF;
RETURN num * num;
END;
$$ LANGUAGE plpgsql;
6. Błędy przy logowaniu: "Czemu moje błędy nie trafiają do error_log?"
Zła wstawka do tabeli error_log może się zdarzyć przez błędy w zapytaniach INSERT INTO.
Przykład błędu:
CREATE OR REPLACE FUNCTION log_error(err_msg TEXT)
RETURNS VOID AS $$
BEGIN
INSERT INTO error_log (error_message, error_time)
VALUES (err_msg, CURRENT_TIMESTAMP); -- A jeśli błąd w kolumnach?
END;
$$ LANGUAGE plpgsql;
Jeśli w tabeli error_log zmieniłeś nazwę kolumny (np. na error_msg), to wywali błąd.
Jak unikać:
Zawsze sprawdzaj strukturę tabeli albo używaj sztywnego schematu do zarządzania danymi.
7. Ogólna nieuwaga i "czynnik ludzki"
Błędy to nie tylko technika, ale też zwykła nieuwaga. Zapomniana diagnostyka, nieużywane zmienne czy brak formatowania mogą zamienić twoją funkcję w chaos.
Przykład:
DECLARE
i INTEGER; -- Po co, skoro zmienna nie jest używana?
Poprawka: wywalaj niepotrzebne kawałki kodu, żeby był czysty i czytelny.
Teraz jesteś gotowy, żeby unikać najczęstszych błędów w PL/pgSQL i pisać kod, który daje więcej frajdy niż bólu. Nie zapominaj testować, logować i na bieżąco łatać bugi — zaoszczędzisz sobie masę nerwów i telefonów od klientów!
GO TO FULL VERSION