DB_ID-Kontext vom weiter oben liegenden Aufrufstapel

11

Ist es in SQL Server möglich, das DB_IDaus dem Kontext weiter oben im Aufrufstapel abzurufen?

Mein Ziel ist es, einige praktische (und zugegebenermaßen hackige) Dienstprogrammfunktionen in einer Entwickler-Sandbox-Datenbank zu erstellen, die es einfach und übersichtlich machen, die vollständig qualifizierten Namen von Objekten anhand ihrer kurzen oder fragmentierten Namen abzurufen und zusätzlich Objekte mit demselben Kurznamen zu löschen . Diese Dienstprogrammfunktionen befinden sich in einer einzelnen Dienstprogrammdatenbank, werden jedoch von anderen Datenbanken auf demselben Server aufgerufen.

Nach dem, was ich beim Testen sehen kann:

  • ORIGINAL_DB_NAME()Wie beabsichtigt wird zurückgegeben, was auch immer in der Verbindungszeichenfolge enthalten war, nicht der aktuelle Kontext (festgelegt von USE [dbname]).
  • Beim Aufruf einer Funktion wird DB_NAME()der Name der Datenbank zurückgegeben, in der diese Funktion definiert ist . Eine andere Möglichkeit, dies zu sagen, besteht darin, dass der Kontext innerhalb einer Funktion oder gespeicherten Prozedur der der Datenbank ist, in der sie definiert ist

Ich weiß, dass die Engine jeden Datenbankkontext auf und ab des Aufrufstapels verfolgt (Beweis siehe unten). Gibt es also eine Möglichkeit, auf diese Informationen zuzugreifen?

Ich möchte in der Lage sein, Objekte im Kontext der Datenbank des Aufrufers zu finden und zu bearbeiten, obwohl sich der ausführende Code nicht in derselben Datenbank befindet. Beispielsweise:

use SomeDB
EXEC util.dbo.frobulate_table 'my_table'

Ich weiß, ich kann es einfach tun

EXEC util.dbo.frobulate_table 'SomeDB.dbo.my_table'

Aber ich bin nur sehr gespannt, ob es möglich ist, den Aufrufstapel auf diese Weise abzufragen.

Update / Hinweis

Ich habe den Code aus Gabriel McAdams 'Blog gelesen und heruntergeladen . Dies liefert eine Aufzeichnung der aufrufenden Prozedur-ID im Stapel, setzt jedoch voraus, dass sich alles in derselben Datenbank befindet.

Beweis Der SQL Server merkt sich den Auf- und Ab-Aufrufstapel des DB-Kontexts

Beispiel: Auf einem Entwicklungsserver mit den Datenbanken TestDB1 und TestDB2

use TestDB1
GO
CREATE FUNCTION dbo.ECHO_DB_NAME() RETURNS nvarchar(128) BEGIN RETURN DB_NAME() END
GO

use TestDB2
GO
CREATE PROCEDURE dbo.ECHO_STACK AS 
BEGIN
    DECLARE @name nvarchar(128)
    SET @name = DB_NAME()
    PRINT 'Before, DB_NAME inside dbo.ECHO_STACK : ' + @name
    SET @name = TestDB1.dbo.ECHO_DB_NAME()        
    PRINT 'TestDB1.dbo.ECHO_DB_NAME returned     : ' + @name
    SET @name = DB_NAME()
    PRINT 'After, DB_NAME inside dbo.ECHO_STACK  : ' + @name
END
GO

use master
SELECT DB_NAME()  -- Returns 'master'
EXEC TestDB2.dbo.ECHO_STACK 

Der ECHO_STACK-Prozess druckt:

Before, DB_NAME inside dbo.ECHO_STACK : TestDB2
TestDB1.dbo.ECHO_DB_NAME returned     : TestDB1
After, DB_NAME inside dbo.ECHO_STACK  : TestDB2
Joshua Honig
quelle
Es wäre über erweiterte Veranstaltungen möglich, aber eigentlich nur als Neuheit. Nichts für ernsthafte Produktionszwecke. Selbst wenn Sie den Datenbanknamen kennen, wie würden Sie ihn trotzdem verwenden? Haben Sie alles in dynamischem SQL mit einem USE xyz;vorangestellten?
Martin Smith
Ehrlich gesagt kann ich nicht sagen, dass ich ein solides Argument dafür habe, warum dies notwendig wäre . Ich fand es sehr interessant , und wenn ich tun es herauszufinden , werde ich es in zwei handliche kleine Procs habe ich in meiner Sandbox - dev - Datenbank verwenden: Eines , das den vollständigen Namen eines der kürzesten erkennbar Fragment des Namens gegeben Objekt wird (wie in mein erstes Beispiel in der Frage) und ein anderes, das Objekte tötet, indem es die andere Funktion verwendet, um den vollständigen Namen zu erhalten, und auch den Typ des identifizierten Objekts verwendet, um eine DROPAnweisung zu generieren .
Joshua Honig
@ SQLKiwi Frage entsprechend aktualisiert. Danke auch für die andere Antwort. Ich habe bereits eine Vielzahl von CLR-Funktionen für die String-Manipulation, daher sollte dies für mich ein natürlicher nächster Schritt sein.
Joshua Honig

Antworten:

4

Sie können dies nicht mit Funktionen in einer Dienstprogrammdatenbank erreichen. Sie können jedoch Dienstprogrammprozeduren in der Masterdatenbank erstellen, sie als Systemobjekte markieren und sie aus dem Kontext einer beliebigen Datenbank auf Ihrem System aufrufen. Ein Artikel mit einem guten Beispiel finden Sie an dieser Stelle .

Nabrond
quelle
Das ist neuartig, aber ein bisschen gefährlich. Es ist leicht, benutzerdefinierte Serverkonfigurationen wie diese aus den Augen zu verlieren, wenn Sie in verschiedene Umgebungen migrieren (z. B. neuer Server oder neue Version von SQL Server).
Riley Major