Dobra. Nie wiem czemu tak jest…
Spróbowałem stworzyć globalną procedurę tymczasową, chciałem pobrać jej nazwę w kodzie. Dostawałem wyniki bez sensu (zwracało mi nazwę jakiejś procedury z bazy, na której tworzyłem ##).
Zrobiłem zatem pętlę, która co sekundę tworzy ##DUPA od nowa i zwraca jego @@PROCID i pobraną nazwę z danej bazy. Oczywiście powinno być NULL (## istnieje tylko w tempdb). Ale takiego wyniku się nie spodziewałem…
USE SSISDB; GO DECLARE @SQL NVARCHAR(MAX) = ' CREATE PROC ##DUPA AS DECLARE @ProcName sysname = OBJECT_NAME(@@PROCID); RAISERROR(''Procedure id: %d, name: %s'',0,1,@@PROCID,@ProcName) WITH NOWAIT; '; WHILE ( 1 = 1 ) BEGIN EXEC (@SQL); EXEC ##DUPA; DROP PROC ##DUPA; WAITFOR DELAY '00:00:01'; END;
Czy ktoś ma pomysł czemu @@PROCID zwraca takie wyniki? 😀
#edit 2018.06.03
Jak słusznie zauważył Michał Krużel, @@PROCID zwraca id prawidłowe, pochodzi ono ze źródła w jakim znajduje się procedura, czyli bazy tempdb.
Problem nie leży zatem w samym @@PROCID, a w OBJECT_NAME(), które wykonuje się w kontekście obecnej bazy, nie na źródle.
…bo wykonujesz to w kontekście ssisdb a powinieneś w kontekście tempdb, to że procedura jest globalna nie znaczy że jej id znajdzie się w każdej bazie, ono (id) jest tylko w tempdb ( i całe szczęście że tylko tam ) , wyniki są przypadkowe , w pewnym momencie przestały by się nakładać i dostałbyś nulle
pozdrawiam
MK
no właśnie byłem święcie przekonany, że skoro ## jest tylko w tembdb, to kontekst działania @@procid i OBJECT_NAME powinien być względem bazy tymczasowej, czyli tej z której uruchamiam procedurę.
Widzisz, żeby zrozumieć mój ból 😉 trzeba pokazać jak to działa na przykładzie zwykłej procedury :]
Zobacz, jeśli utworzysz procedurę w przykładowej NORMALNEJ bazie o nazwie np. moja_baza:
USE moja_baza
GO
CREATE OR ALTER PROCEDURE testowa AS
SELECT @@PROCID
SELECT OBJECT_NAME(@@PROCID)
i uruchomisz ją z innej bazy. np. SSISDB dostaniesz PRAWIDŁOWY wynik podobny do tego:
USE SSISDB
GO
EXEC moja_baza.dbo.testowa
885578193
testowa
Jest zatem poprawnie wyniesiony ID procedury z bazy moja_baza, również sprawdzenie nazwy wykonało się względem niej, choć execute był na innej!
ALE, jeśli uruchomisz to w kontekście tempowej, OBJECT_NAME nie zadziała tak jak zadziałał na powyższej procedurze, tylko weźmie kontekst OBECNEJ bazy, choć @@PROCID zwróci ID z temdb:
USE SSISDB;
GO
DECLARE @SQL NVARCHAR(MAX) = ’
CREATE PROC ##testowa
AS
DECLARE @ProcName sysname = OBJECT_NAME(@@PROCID);
RAISERROR(”Procedure id: %d, name: %s”,0,1,@@PROCID,@ProcName) WITH NOWAIT;
’;
WHILE
(…)
wynik:
Procedure id: 821577965, name: FK_ObjectParameters_ProjectVersionLsn_ObjectVersions
Procedure id: 837578022, name: environments
Procedure id: 853578079, name: PK_Environments
Procedure id: 869578136, name: Unique_Folder_Environment
(…)
I faktycznie tytuł wpisu jest mylący! Bo tu nie chodzi o to, że zwraca ID z innej bazy (czyli tempdb), tylko miesza w OBJECT_NAME. Jak widać wtedy też do końca nie wiedziałem z czym walczę ;]
Sprawdziłem, czy przypadkiem dynamiczny sql jeszcze czegoś tu nie dodaje od siebie, ale nie ma to znaczenia 😉
Michał, dzięki za wykopanie tematu i nowe światło :>