EXEC to polecenie Transact-SQL wywołujące procedurę składowaną lub dynamicznie skonstruowane zapytanie.
EXEC w języku Transact-SQL
EXEC, zapisywane również jako EXECUTE, jest instrukcją języka Transact-SQL używaną w Microsoft SQL Server do uruchamiania procedur składowanych, funkcji skalarnych w określonych kontekstach oraz poleceń zapisanych jako tekst dynamiczny. Najczęstsze zastosowanie polega na wywołaniu procedury składowanej, która zawiera wcześniej zdefiniowany zestaw instrukcji SQL. Przykładowa forma ma postać EXEC dbo.PobierzKlienta @IdKlienta = 15;. Prefiks schematu, taki jak dbo, jednoznacznie wskazuje obiekt i ogranicza ryzyko odwołania do obiektu o tej samej nazwie znajdującego się w innym schemacie.
Procedura może przyjmować parametry wejściowe oraz parametry wyjściowe. Parametry nazwane zapisuje się po nazwie procedury, a parametr oznaczony słowem OUTPUT pozwala przekazać wartość z powrotem do kodu wywołującego. Przykład: DECLARE @Wynik int; EXEC dbo.PrzeliczKwote @Kwota = 250, @Rezultat = @Wynik OUTPUT;. Instrukcja może także zwrócić kod statusu przez słowo kluczowe RETURN umieszczone w procedurze. Taki kod nie jest tym samym co zestaw wierszy zwrócony przez zapytanie ani wartość parametru wyjściowego, dlatego aplikacja korzystająca z procedury powinna obsługiwać te trzy mechanizmy oddzielnie.
Wywoływanie procedur i obsługa parametrów
W SQL Server procedura składowana uruchomiona przez EXEC działa w bieżącej sesji i korzysta z jej kontekstu, między innymi z aktywnej bazy danych, ustawień sesji oraz dostępnych transakcji. Parametry można przekazywać pozycyjnie albo jawnie, po nazwie. W praktyce parametry nazwane są czytelniejsze i mniej podatne na błędy po zmianie kolejności definicji. Wartości tekstowe przekazuje się jako literały znakowe, a daty najlepiej przekazywać w jednoznacznym formacie lub jako parametry aplikacji. Przykład wywołania może wyglądać tak: EXEC dbo.ZnajdzZgloszenia @Numer = N'WK-1024', @OdDnia = '2026-01-01';.
Parametr wyjściowy musi być zmienną, a nie stałą lub wyrażeniem. Jeżeli procedura korzysta z parametrów opcjonalnych wyposażonych w wartości domyślne, wywołujący może pominąć takie argumenty. SQL Server nie pozwala jednak dowolnie mieszać pominiętych parametrów pozycyjnych z późniejszymi argumentami pozycyjnymi; przy bardziej rozbudowanych procedurach bezpieczniej stosować składnię nazwaną. Procedura może również zwrócić wiele zestawów wyników, komunikaty oraz kod statusu. Samo EXEC nie normalizuje tych rezultatów do jednego formatu, więc sterownik aplikacyjny musi poprawnie odczytać kolejność zestawów wynikowych i komunikatów.
Instrukcja może przechwycić wynik procedury do tabeli tymczasowej lub zmiennej tabelarycznej, ale tylko wtedy, gdy wynik ma zgodną strukturę i pochodzi z instrukcji możliwej do zapisania w takim kontekście. Na przykład INSERT INTO #Wyniki EXEC dbo.PobierzWyniki; zapisuje zwrócony zestaw wierszy w tabeli tymczasowej. Taka konstrukcja wymaga zgodności liczby kolumn, ich kolejności oraz typów danych. Nie należy traktować jej jako uniwersalnego sposobu odczytu dowolnych rezultatów procedury, zwłaszcza gdy procedura zwraca różne zestawy wyników zależnie od warunku wykonania.
EXEC a zapytania dynamiczne i bezpieczeństwo wykonania
Drugi ważny obszar zastosowania to uruchamianie dynamicznie budowanego tekstu SQL. Przykład EXEC(N'SELECT COUNT(*) FROM dbo.Zgloszenia;'); wykonuje stały tekst polecenia. Jeżeli tekst jest tworzony na podstawie danych wprowadzonych przez użytkownika, bezpośrednie sklejanie wartości z łańcuchem może doprowadzić do SQL injection, błędów składni oraz nieprzewidywalnych konwersji typów. Funkcja QUOTENAME służy do bezpieczniejszego opakowywania nazw obiektów, lecz nie zastępuje parametryzacji wartości.
Do dynamicznych zapytań zawierających wartości danych należy zwykle używać sys.sp_executesql, ponieważ pozwala ono oddzielić tekst zapytania od parametrów i określić ich typy. Przykład: DECLARE @sql nvarchar(max) = N'SELECT * FROM dbo.Urzadzenia WHERE Numer = @p;'; EXEC sys.sp_executesql @sql, N'@p nvarchar(50)', @p = N'LT-15';. W tym przypadku wartość parametru nie staje się częścią kodu SQL. Zwykłe EXEC również potrafi wykonać tekst dynamiczny, ale nie oferuje takiego samego mechanizmu deklarowania parametrów dla wartości zapytania.
Dynamiczny kod może działać w innym zakresie zmiennych niż kod zewnętrzny. Zmienna zadeklarowana wewnątrz uruchamianego tekstu nie jest automatycznie dostępna po jego zakończeniu, a zmienna zewnętrzna musi zostać przekazana przez parametry sp_executesql albo przez odpowiednią konstrukcję wywołania. Istotny jest także kontekst uprawnień. Uruchomienie procedury, użycie EXECUTE AS lub odwołanie do obiektu z innej bazy może zmienić sposób sprawdzania uprawnień. W przypadku dynamicznego SQL należy kontrolować zarówno źródło tekstu, jak i konto wykonujące kod, ponieważ poprawna składnia nie gwarantuje bezpiecznego zakresu dostępu.
Transakcje, błędy i diagnostyka działania EXEC
Jeżeli EXEC uruchamia procedurę w ramach aktywnej transakcji, instrukcje procedury mogą uczestniczyć w tej transakcji. Ostateczne zatwierdzenie lub wycofanie zmian zależy od kodu procedury oraz kodu wywołującego. W procedurach modyfikujących dane często stosuje się TRY...CATCH, kontrolę XACT_STATE() i odpowiednie ROLLBACK. Sam fakt wykonania instrukcji EXEC nie oznacza, że wszystkie zmiany zostały zatwierdzone na dysku logicznym bazy; mogą one nadal oczekiwać na zakończenie transakcji.
Błędy powstałe podczas wywołania mogą zostać przekazane do bloku CATCH, ale zachowanie zależy od rodzaju błędu i miejsca jego wystąpienia. Procedura może zgłosić błąd przez THROW lub starszą instrukcję RAISERROR. Kod zwrócony przez RETURN nie zastępuje wyjątków, dlatego aplikacja nie powinna uznawać każdego pomyślnego zakończenia technicznego EXEC za poprawny rezultat biznesowy. Należy sprawdzić kod statusu, komunikaty, liczbę zmodyfikowanych wierszy oraz ewentualny zestaw wyników.
Podczas diagnozowania problemu z EXEC warto ustalić dokładną nazwę procedury, bazę i schemat, wartości oraz typy przekazanych parametrów, aktywną transakcję i konto wykonujące polecenie. W przypadku SQL dynamicznego trzeba dodatkowo zarejestrować wygenerowany tekst bez ujawniania poufnych wartości parametrów. Pomocne są komunikaty SQL Server, informacje o czasie wykonania, blokadach i planie zapytania. Takie dane pozwalają rozróżnić błąd uprawnień, niezgodność typu, problem z procedurą, blokadę transakcyjną oraz błąd wynikający z niebezpiecznego składania tekstu SQL.