CodeGym /Kursy /SQL SELF /Omówka typowych błędów przy tworzeniu funkcji

Omówka typowych błędów przy tworzeniu funkcji

SQL SELF
Poziom 50, Lekcja 4
Dostępny

Dzisiaj przeanalizujemy typowe błędy przy pisaniu funkcji, ich przyczyny i jak sobie z nimi radzić. Bo tylko przez debugowanie prawdziwy ninja kodu ogarnia swój fach — kodowanie! Let's debug it!

Pisanie funkcji, zwłaszcza na początku przygody z PL/pgSQL, może wydawać się trudne. Nawet doświadczeni programiści w PostgreSQL potrafią się potknąć. Przejdźmy przez te pułapki po kolei.

1. Pominięcie słowa kluczowego RETURNS

PL/pgSQL jest bardzo wymagający jeśli chodzi o opis funkcji. Jedno z najczęstszych nieporozumień — zapomnieć podać typ danych, który funkcja ma zwracać. Zobacz przykład:

-- Błąd: brak słowa kluczowego RETURNS
CREATE FUNCTION incorrect_function() AS $$
BEGIN
    RETURN 1;
END;
$$ LANGUAGE plpgsql;

PostgreSQL nie ogarnie, co ta funkcja ma zwracać. RETURNS to obowiązkowy element składni, który określa typ zwracanych danych (np. RETURNS INT, RETURNS TEXT, albo nawet RETURNS VOID).

Poprawka: dodaj słowo kluczowe RETURNS z odpowiednim typem danych:

CREATE FUNCTION correct_function() RETURNS INT AS $$
BEGIN
    RETURN 1;
END;
$$ LANGUAGE plpgsql;

2. Zwracanie wyniku bez RETURN

Początkujący często zapominają, że w PL/pgSQL, żeby coś zwrócić, trzeba użyć operatora RETURN. Przykład:

-- Błąd: brak RETURN
CREATE FUNCTION missing_return() RETURNS TEXT AS $$
BEGIN
    'Hello, World!'; -- Tylko tekst, ale nie zwrócony
END;
$$ LANGUAGE plpgsql;

Tutaj tekst 'Hello, World!' po prostu jest, ale nie jest zwracany. PostgreSQL potraktuje to jako brak wyniku i rzuci błąd.

Poprawka: dodaj jawnie operator RETURN:

CREATE FUNCTION fixed_return() RETURNS TEXT AS $$
BEGIN
    RETURN 'Hello, World!';
END;
$$ LANGUAGE plpgsql;

3. Próba zapisania danych do niezadeklarowanej zmiennej

W PL/pgSQL przed użyciem zmiennej trzeba ją zadeklarować w bloku DECLARE. Przykład:

-- Błąd: zmienna my_var nie zadeklarowana
CREATE FUNCTION missing_variable() RETURNS VOID AS $$
BEGIN
    my_var := 'Hello, World!';
END;
$$ LANGUAGE plpgsql;

PostgreSQL nie wie o istnieniu zmiennej my_var, bo nie została zadeklarowana w bloku DECLARE.

Poprawka: zawsze deklaruj zmienne w DECLARE:

CREATE FUNCTION declared_variable() RETURNS VOID AS $$
DECLARE
    my_var TEXT;
BEGIN
    my_var := 'Hello, World!';
END;
$$ LANGUAGE plpgsql;

4. Nieprawidłowe użycie typu zwrotu VOID

Typ VOID oznacza, że funkcja nic nie zwraca. Czasem ktoś próbuje użyć RETURN w funkcji z typem VOID, co kończy się błędem:

-- Błąd: RETURN w funkcji z VOID
CREATE FUNCTION void_example() RETURNS VOID AS $$
BEGIN
    RETURN 1; -- Zwracanie wartości niedozwolone
END;
$$ LANGUAGE plpgsql;

Funkcje z typem VOID nie powinny zwracać wartości. Możesz użyć RETURN, ale bez żadnej wartości.

Poprawka: albo usuń RETURN, albo napisz go bez wartości:

CREATE FUNCTION correct_void() RETURNS VOID AS $$
BEGIN
    -- Po prostu wykonujemy akcje
    RAISE NOTICE 'Ta funkcja nic nie zwraca';
    RETURN; -- Zakończenie funkcji
END;
$$ LANGUAGE plpgsql;

5. Nieprawidłowe użycie RAISE do debugowania

Debugowanie w PL/pgSQL często robi się przez RAISE NOTICE. Ale złe formaty i zmienne mogą wywołać błąd.

Przykład:

-- Błąd: zły format
CREATE FUNCTION debug_example() RETURNS VOID AS $$
BEGIN
    RAISE NOTICE 'The value is %'; -- Brak zmiennej
END;
$$ LANGUAGE plpgsql;

Operator RAISE oczekuje, że po % będzie zmienna lub wartość. Jeśli zostawisz % bez niczego, PostgreSQL nie ogarnie polecenia.

Poprawka: upewnij się, że zmienne lub wartości są podane poprawnie:

CREATE FUNCTION fixed_debug() RETURNS VOID AS $$
DECLARE
    my_var TEXT := 'PostgreSQL';
BEGIN
    RAISE NOTICE 'The value is %', my_var; -- Podana zmienna
END;
$$ LANGUAGE plpgsql;

6. Problemy z nazwami zmiennych i kolumn

Jeśli nazwa zmiennej jest taka sama jak kolumny, mogą wyjść dziwne rzeczy. Przykład:

-- Błąd: konflikt nazw zmiennej i kolumny
CREATE FUNCTION name_conflict() RETURNS TEXT AS $$
DECLARE
    name TEXT;
BEGIN
    SELECT name INTO name FROM students LIMIT 1; -- Które name jest używane?
    RETURN name;
END;
$$ LANGUAGE plpgsql;

PL/pgSQL wybiera zmienne zamiast kolumn, jeśli nazwy się pokrywają.

Poprawka: używaj aliasów tabel albo unikaj takich samych nazw.

CREATE FUNCTION fixed_conflict() RETURNS TEXT AS $$
DECLARE
    student_name TEXT;
BEGIN
    SELECT s.name INTO student_name FROM students s LIMIT 1;
    RETURN student_name;
END;
$$ LANGUAGE plpgsql;

7. Nieprawidłowe wykonywanie zapytań w pętli

Błędy często pojawiają się przy próbie wykonania zapytań SQL w pętlach. Przykład:

-- Błąd: złe zapytanie w pętli
CREATE FUNCTION cycle_error() RETURNS VOID AS $$
BEGIN
    FOR rec IN SELECT * FROM students LOOP
        EXECUTE 'UPDATE students SET active = TRUE WHERE id = ' || rec.id;
    END LOOP;
END;
$$ LANGUAGE plpgsql;

SQL-injection... Niebezpieczne! Sklejanie stringów w zapytaniach SQL to zły pomysł. Może prowadzić do podatności.

Poprawka: używaj parametrów:

CREATE FUNCTION safe_cycle() RETURNS VOID AS $$
BEGIN
    FOR rec IN SELECT * FROM students LOOP
        EXECUTE 'UPDATE students SET active = TRUE WHERE id = $1' USING rec.id;
    END LOOP;
END;
$$ LANGUAGE plpgsql;

8. Błędy typów danych

Przykład błędu:

-- Błąd: niezgodność typów danych
CREATE FUNCTION type_error() RETURNS INT AS $$
DECLARE
    my_var TEXT := 'not_a_number';
BEGIN
    RETURN my_var; -- Błąd przy zwrocie tekstu zamiast INT
END;
$$ LANGUAGE plpgsql;

PostgreSQL oczekuje INT, a dostaje TEXT. Typy danych są tu pilnowane bardzo dokładnie.

Jak naprawić? Upewnij się, że typy się zgadzają, albo zrób jawne rzutowanie:

CREATE FUNCTION type_correct() RETURNS INT AS $$
DECLARE
    my_var TEXT := '42';
BEGIN
    RETURN my_var::INT; -- Rzutowanie tekstu na liczbę
END;
$$ LANGUAGE plpgsql;

Najlepsze praktyki i tipy

  • Dziel skomplikowane funkcje na mniejsze. Łatwiej wtedy debugować i testować.
  • Używaj komentarzy w funkcjach, żeby opisać trudniejsze fragmenty.
  • Zawsze testuj funkcje na małych danych zanim odpalisz je na prawdziwych tabelach.
  • Debuguj przez RAISE NOTICE, żeby ogarnąć co się dzieje w środku.
  • Unikaj SQL-injection: używaj parametrów w zapytaniach.
-- Użycie RAISE do debugowania
DO $$
DECLARE
    total_students INT;
BEGIN
    SELECT COUNT(*) INTO total_students FROM students;
    RAISE NOTICE 'Total students: %', total_students; -- Komunikat debugowy
END;
$$;

Te tipy pozwolą Ci uniknąć masy bólu głowy i raz na zawsze rozwalić "pułapki" PL/pgSQL!

2
Zadanie
SQL SELF, poziom 50, lekcja 4
Niedostępne
Debugowanie z użyciem RAISE NOTICE
Debugowanie z użyciem RAISE NOTICE
1
Ankieta/quiz
Tworzenie prostych funkcji, poziom 50, lekcja 4
Niedostępny
Tworzenie prostych funkcji
Tworzenie prostych funkcji
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION