Contexte DB_ID de la pile d'appels la plus haute

11

Dans SQL Server, est-il possible d'extraire DB_IDle contexte du plus haut de la pile d'appels?

Mon objectif est de créer des fonctions utilitaires pratiques (et certes hacky) dans une base de données de bac à sable de développement qui permettent d'obtenir facilement et concis les noms complets des objets en fonction de leurs noms courts ou fragmentés, et en outre de supprimer des objets en utilisant le même nom court . Ces fonctions utilitaires se trouveraient dans une seule base de données utilitaires mais appelées à partir d'autres bases de données sur le même serveur.

D'après ce que je peux voir des tests:

  • ORIGINAL_DB_NAME()comme prévu renvoie tout ce qui était dans la chaîne de connexion, pas le contexte actuel (défini par USE [dbname]).
  • Lorsqu'elle est appelée dans une fonction, elle DB_NAME()renvoie le nom de la base de données où cette fonction est définie . Une autre façon de le dire est que le contexte à l'intérieur d'une fonction ou d'une procédure stockée est celui de la base de données dans laquelle il est défini

Je sais que le moteur garde une trace de chacun des contextes de base de données de haut en bas de la pile d'appels (voir ci-dessous pour la preuve). Existe-t-il un moyen d'accéder à ces informations?

Je veux pouvoir trouver et opérer sur des objets dans le contexte de la base de données de l'appelant, même si le code d'exécution n'est pas dans la même base de données. Par exemple:

use SomeDB
EXEC util.dbo.frobulate_table 'my_table'

Je sais que je peux juste faire

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

Mais je suis vraiment curieux de savoir s'il est possible d'interroger la pile d'appels de cette façon.

Mise à jour / note

J'ai lu et téléchargé le code sur le blog de Gabriel McAdams . Cela fournit un enregistrement de l'ID de la procédure d'appel de haut en bas de la pile, mais suppose toujours que tout se trouve dans la même base de données.

La preuve que SQL Server se souvient de la pile d'appels de haut en bas du contexte de base de données

Exemple: sur un serveur de développement avec les bases de données TestDB1 et 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 

Le proc ECHO_STACK imprime:

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
la source
Ce serait possible via des événements prolongés, mais uniquement en tant que nouveauté. Pas quelque chose pour une utilisation sérieuse en production. Même si vous connaissez le nom de la base de données, comment l'utiliseriez-vous de toute façon? Vous avez tout en sql dynamique avec un USE xyz;précédent?
Martin Smith
Honnêtement, je ne peux pas dire que j'ai des arguments solides pour expliquer pourquoi cela serait nécessaire . Je l'ai trouvé très intéressant et si je le découvre, je le mettrai dans deux petits procs pratiques que j'utilise dans ma base de données de développement sandbox: un qui obtient le nom complet d'un objet étant donné le fragment reconnaissable le plus court du nom (comme dans mon premier exemple dans la question), et un autre qui tue des objets en utilisant l'autre fonction pour obtenir le nom complet et utilise également le type de l'objet identifié pour générer une DROPdéclaration.
Joshua Honig
@SQLKiwi Question mise à jour en conséquence. Merci aussi pour l'autre réponse. J'ai déjà une variété de fonctions CLR pour la manipulation de chaînes, donc cela devrait être une prochaine étape naturelle pour moi.
Joshua Honig

Réponses:

4

Vous ne pouvez pas accomplir cela avec des fonctions dans une base de données utilitaire. Vous pouvez cependant créer des procédures utilitaires dans la base de données master, les marquer en tant qu'objets système et les appeler à partir du contexte de n'importe quelle base de données sur votre système. Un article avec un bon exemple peut être trouvé à cet endroit .

nabrond
la source
C'est nouveau mais un peu dangereux. Il est facile de perdre la trace de configurations de serveur personnalisées comme celle-ci lorsque vous migrez vers différents environnements (par exemple, un nouveau serveur ou une nouvelle version de SQL Server).
Riley Major