| |
|
|
| |
|
|
| |
| |
|
|
BA 372 - Triggers and Stored Procdure Lab
The purpose of this lab is to expose you to the use of database
stored procedures and database triggers.
Imagine that a company tracks its clients and stores a credit limit for
each client as a business control. Credit limit changes can be made by
only a few individuals and any changes to the credit limit should be
tracked. The company implements integrated authentication where the end
user’s Windows login credentials are used within the
application program for authorization.
To prepare for this exercise, we created a database for you on server Cobmisclass01. Your database name is StDB_ABC123 but replace ABC123 with your COB account name.
Open up SQL Server Management Studio, which can be found under the Start => Programs => Microsoft SQL Server 2005 => SQL Server Management Studio. For the server name type in cobmisclass01 and select Connect. Now open a new query window by selecting the New Query button below the File menu. Make sure that the database selected is your student database. Under the New Query button is a drop down menu with databases.
We start by setting up the database. It contains only three tables:
Notice how in the above inserts, SYSTEM_USER is a built-in variable that evaluates to your login; hence, it is not contained in quotes, even though creditlimit_changedby contains a string.
You can re-run this script at any time to reset the database if you want to try again or when you get stuck.Notice that in the above code we have abstracted the various catch blocks used to handle database interaction errors in a sub called HandleError; saves a lot of lines of code.
Also notice that the action log record we create and return is an XML snippet. We do this because XML is easily parsed and so we make it easy to exchange these comments later.
Compile and Run. The output should look something like this:Many programs will likely perform the same type of check. If each of them has the code to access the security tables, then a change in the authorization scheme would affect a lot of applications. If the authorization logic is encapsulated in a separate stored procedure it becomes somewhat equivalent to a subroutine stored in a separate code library which is linked to many individual application programs. When we modularize by creating a separate stored procedure the same code can be executed either by programs directly or by other stored procedures. However, please note that because the code lives in the database, changes go into effect without recompiling, relinking, or redistributing copies of the executable. This can save time and reduce the complexity of deployment. It also means that an errant procedure could immediately and negatively impact a whole bunch of applications. Thus, the use of a separate authorization procedure has significant architectural implications.
Create this procedure:Note that AuthCheck records denied attempts. The code to decide which denied attempts must be logged is thereby captured in a single location. Keeping it consistent and verifying its implementation does not require going to multiple programs or multiple procedures. This illustrates how good modular design can be implemented in a stored procedure environment. Please also note that tried and true return code processing and error handling are supported by the stored procedure environment.
Next, lets think about comprehensive logging.Recall from class that a database trigger is a stored procedure that can be set to execute whenever specific database changes occur. Hence, we can define a trigger which executes and enters information into the log when credit limits are changed.
Do you see that it logs the change even though the change was made through the SQL query window rather than by a business process-specific application? These sorts of utilities are widely available and can be used to alter sensitive data while avoiding controls that might be built into a business application.
Now try:As you can see in this trigger’s code, a trigger can access other
tables and respond to the details of any changes. For example, if we
wanted we could adjust the trigger so that it only logs changes to
existing records where the credit limit is changed rather than logging
all changes.
How to do that? Well, you could make the trigger FOR
UPDATE instead of FOR
INSERT, DELETE, UPDATE
and then you
could take out the first two insert commands and add WHERE
inserted.creditlimit <> deleted.creditlimit.
At this point you should have a good idea on how, when writing code
that interacts with a database, we have a choice as to where to write
and store certain sections of functionality. In the app? In the
database? or use a mix? With any of these choices come advantages and
disadvantages. Although it’ll take some experience to really appreciate
these differences, you should be aware of their existence and have at
least some ideas on how these different methods work.
For those of you interested in just a bit more depth, you should
realize that all of the above codes can be refined quite a bit using
much more sophisticated methods and procedures. For instance, we can
much improve our error handling, debug messages and logging messages.
For example, for denials let’s log who tried to change which client to
what amount. This might be important if the updates should have been
allowed or if we are looking for fraudulent activity.
Note how in the above code, system errors, denials, and attempts to
change a nonexistent client are tracked separately and reported to the
calling program.
Also note that a detailed message is prepared and passed to AuthCheck
to produce a more detailed log of security-related events. AuthCheck
was not changed, we just used more of the features. But again, we did
this without altering the VB code. Thus, without changing any of the
application programs which use the stored procedure, we can adjust the
functionality associated with this action in the database.