sqlschool.gr logo

articles

Articles of SQLschool.gr Team

Using CONTEXT_INFO function–Another useful usage scenario

Antonios Chatzipavlis
Thursday 14 June 2012

Πρόλογος

Αυτό που με εξιτάρει περισσότερο στην δουλειά μου και στην ενασχόληση μου με τον SQL Server είναι να βρίσκω λύση σε προβλήματα, αλλά και σε ποιον δεν αρέσει αυτό;

Το Πρόβλημα

Σήμερα ένας συνάδελφος στην εταιρία που εργάζομαι έρχεται με το εξής ερώτημα-πρόβλημα

«Έχω ένα πίνακα και έχω φτιάξει μια stored procedure η οποία περιέχει ένα business logic αρκετά σημαντικό και περίπλοκο με το οποίο κάνω insert στον συγκεκριμένο πίνακα. Θέλω να κάνω insert στο συγκεκριμένο πίνακα μόνο από την συγκεκριμένη stored procedure και μόνο πως μπορεί να γίνει αυτό;»

Στην αρχή ξαφνιάστηκα καθώς ο συνάδελφος είναι εμπειρότατος και η ερώτηση του μου φάνηκε κάπως. Του απάντησα ότι αυτό είναι στο χέρι του καθώς αυτός γράφει τον κώδικα. Φυσικά η απάντηση μου δεν τον ικανοποίησε. Έτσι μετά από μια σύντομη συζήτηση κατάλαβα τι ακριβώς ήθελε να κάνει το οποίο τελικά ήταν:

«Έχω ένα πίνακα και έχω φτιάξει μια stored procedure η οποία περιέχει ένα business logic αρκετά σημαντικό και περίπλοκο με το οποίο κάνω insert στον συγκεκριμένο πίνακα. Θέλω να κάνω insert στο συγκεκριμένο πίνακα μόνο από την συγκεκριμένη stored procedure και μόνο είτε από την εφαρμογή είτε από τον SSMS είτε από οπουδήποτε. Θέλω δηλαδή εκτός από να προστατέψω την ποιότητα των δεδομένων που θα μπαίνουν στον συγκεκριμένο πίνακα θέλω να προστατέψω και εμένα και τους άλλους developers καθώς στην καθημερινότητα μας φτιάχνουμε πολλές stored procedures και υπάρχει πάντα το ενδεχόμενο σε μια νέα που φτιάχνουμε να κάνουμε insert στον συγκεκριμένο πίνακα χωρίς να καλέσουμε την εν λόγο stored procedure με αποτέλεσμα να έχω λάθος στα δεδομένα στον πίνακα. Επίσης αυτό θέλω να μπορεί να γίνει ακόμα και για αυτούς που έχουν δικαιώματα sysadmin στον SQL Server. Πως μπορεί να γίνει αυτό;»

Η Λύση

Μετά από τα παραπάνω το πρόβλημα ήταν σαφές. Ομολογώ ότι κάτι τέτοιο δεν είχα αντιμετωπίσει στο παρελθόν και μου πήρε μερικά λεπτά να συνειδητοποιήσω τι ακριβώς ήθελε να κάνει. Αφού τελικά κατάλαβα ότι στην ουσία ήθελε μόνο μέσα από ένα συγκεκριμένο context να κάνει insert στον πίνακα του τα πράγματα έγιναν αρκετά εύκολα καθώς αμέσως πήγε το μυαλό μου στην CONTEXT_INFO function που έχει ο SQL Server και με την οποία μπορώ να περάσω πληροφορίες στο session που θα δημιουργηθεί ή υπάρχει στον SQL Server και τις οποίες μπορώ να διαβάζω μέσα από την DMV sys.dm_exec_sessions.

Στο κώδικα που ακολουθεί υπάρχει ένα παράδειγμα το οποίο εξομοιώνει την λύση, αλλά πριν από αυτό καλό θα είναι να σας εξηγήσω μερικά πράγματα ώστε να γίνει ευκολότερη η ανάγνωση του κώδικα που ακολουθεί.

Εφόσον όλη η δουλειά θέλουμε να γίνει μέσα από την συγκεκριμένη stored procedure τότε μέσα σε αυτή θα ορίζουμε κάτι μέσα στο session context με την χρήση της context_info το οποίο να δηλώνει ότι γίνεται χρήση της stored procedure. Στο πίνακα που γίνεται το insert θα πρέπει να φτιάξουμε ένα trigger for insert που θα ελέγχει αυτό το κάτι και αν το βρει τότε θα κάνει insert καθώς θα έρχεται από την χρήση της stored procedure ενώ σε άλλες περιπτώσεις θα κάνει rollback. Τόσα απλά είναι τα πράγματα. Το μόνο που θα πρέπει να φροντίσω είναι να κρατάω το context όπως ήταν πριν ορίσω το δικό μου χαρακτηριστικό (ή προσθέσω σε αυτό ) και με το τέλος της stored procedure αν το επαναφέρω το οποίο δεν είναι κάτι δύσκολο.

Η Υλοποίηση

Μετά από τις απαραίτητες εξηγήσεις ο κώδικας που υλοποίει τα παραπάνω είναι

USE tempdb;
GO

CREATE TABLE K (id INT IDENTITY, f1 INT);
GO

CREATE PROC spInsertOnK @p INT
AS
    -- variable to keep old context
    DECLARE @CurrentContextInfo varbinary(128) = CONTEXT_INFO();
    -- variable to build new context
    -- for simplicity send the sp name only
    DECLARE @NewContextInfo varbinary(128);
    SET @NewContextInfo = CAST('spInsertOnK' AS VARBINARY(20) );
    -- set the new context    
    SET CONTEXT_INFO @NewContextInfo;
    -- insert on table K
    INSERT INTO K(f1) VALUES (@p);
    -- restore old context
    SET CONTEXT_INFO @CurrentContextInfo;
    return 1;
GO

CREATE TRIGGER InsertOnKviaspInsertOnK ON K FOR INSERT
AS
    DECLARE @CurrentContextInfoString varchar(20);
    -- get the current info
    SELECT  
            @CurrentContextInfoString = 
            convert(varchar(20), substring(context_info, 1, 20))
    FROM    sys.dm_exec_sessions
    WHERE   session_id = @@spid;
    -- check if this insert comes from sp 
    IF @CurrentContextInfoString <> 'spInsertOnK'
        BEGIN
            ROLLBACK;
            RAISERROR ('Inserts on table K allowed only by using the spInsertOnK 
                        stored procedure.',17,1);
        END;
GO 

Η Εφαρμογή

Μετά από τα παραπάνω ας έρθουμε να δοκιμάσουμε την λύσης μας.

Ανοίγω δυο νέα query window και στο πρώτο εκτελώ την stored procedure

EXEC spInsertOnK 1;
GO
SELECT * FROM K;
GO

Παρατηρώ ότι όλα πάνε μια χαρά και παώ στο δεύτερο query window στο όποιο προσπαθώ να κάνω κατευθείαν insert στον πίνακα

INSERT INTO K(f1) VALUES (10);

Όπως θα δείτε θα πάρω ένα ωραιότατο μύνημα λάθους το οποίο θα με ενημερώνει και δεν θα με αφήνει να κάνω insert στο πίνακα

Msg 3609, Level 16, State 1, Line 1
The transaction ended in the trigger. The batch has been aborted.
Msg 50000, Level 17, State 1, Procedure InsertOnKviaspInsertOnK, Line 13
Inserts on table K allowed only by using the spInsertOnK stored procedure.

Επίλογος

Όπως είδαμε με απλές κινήσεις η απαίτηση του συναδέλφου λύθηκε. Πέρα όμως από αυτή υπάρχουν ακόμα πολλά ωραία πράγματα τα οποία μπορώ να κάνω όπως για παράδειγμα να περνάω μέσα σε αυτή από την εφαρμογή μου πληροφορίες όπως computer name, user name ειδικά σε εφαρμογές που χρησιμοποιούν ένα συγκεκριμένο sql user για να μπαίνουν όλοι χρήστες της στον SQL Server ;-)

/*antonch*/

Antonios Chatzipavlis

Antonios Chatzipavlis

Antonios is a Data Solutions Consultant and Trainer. He has been working in IT since 1988. In his career, he has worked as senior developer, IT Manager, Solutions Architect and IT Consultant. Since 1995 he has been devoted on new technologies and software development tools, mainly by Microsoft, either by training company staff and colleagues or assisting them in design, development and implementation as a consultant or chief developer. He has focused in Databases and Data Science since 1995. He specialized in Microsoft SQL Server since version 6.0 in areas like SQL Server Internals, Database Design and Development, Business Intelligence and in 2010 he has started working with Azure Data Platform, NoSQL databases, Big Data Technologies and Machine Learning. He is an active member of many IT communities in Greece, answering colleagues' questions and writing articles in his web site. He is the owner of SQLschool.gr which is a community portal with a lot of information about Microsoft SQL Server. He has been a Microsoft Certified Trainer (MCT) since 2000. Microsoft honored him as MVP on Data Platform due to his activities in SQL Server since 2010. He holds a large number of Microsoft Certifications and Microsoft SQL Server Certifications since version 6.5.

Episode

First look: SQL Database in Microsoft Fabric

image

More Episodes...

Tip

What's New in SQL Server 2022 - Episodes

More Tips...

Become a member

If you want to receive updates from us become a member to our community.

Connect

Explore

Learn


sqlschool.gr © 2010-2024 All rights reserved

This site uses cookies for operational and analytics purposes only. By continuing to browse this site, you agree to their use.