Please start any new threads on our new
site at https://forums.sqlteam.com. We've got lots of great SQL Server
experts to answer whatever question you can come up with.
| Author |
Topic |
|
t1g312
Posting Yak Master
148 Posts |
Posted - 2005-04-09 : 01:34:41
|
| All my users connect to the SQL server using the same SQL Server User ID (I have my own layer of authentication) and the only unique information I have about the user is the SPID which I store in the user table when he/she logs in. I use this SPID in my audit trail triggers to identify the user. I noticed that sometimes the SPID in the process info doesn't correspond to any of the SPIDs in the user table which means that it has changed. Is this possible? If yes, can someone suggest a better way to identify the user???Thanks in advance,Adi-------------------------/me sux @sql server |
|
|
Bustaz Kool
Master Smack Fu Yak Hacker
1834 Posts |
Posted - 2005-04-09 : 03:58:53
|
| Are you having the application leave the SQL connection open all of the time? If not, couldn't your spid change every time you re-connect?You seem to have a User table. Could you pass the primary key of this table to identify the user.There are some builtin functions, like USER, USER_NAME, and others that might be relevant to your problem. Look in BOL for details.HTH=================================================================In order to improve the mind, we ought less to learn than to contemplate.-Rene Descartes, philosopher and mathematician (1596-1650) |
 |
|
|
t1g312
Posting Yak Master
148 Posts |
Posted - 2005-04-09 : 04:54:50
|
I am leaving the connection open all the time but still it changes.quote: Originally posted by Bustaz Kool Are you having the application leave the SQL connection open all of the time? If not, couldn't your spid change every time you re-connect?You seem to have a User table. Could you pass the primary key of this table to identify the user.There are some builtin functions, like USER, USER_NAME, and others that might be relevant to your problem. Look in BOL for details.HTH=================================================================In order to improve the mind, we ought less to learn than to contemplate.-Rene Descartes, philosopher and mathematician (1596-1650)
Adi-------------------------/me sux @sql server |
 |
|
|
TG
Master Smack Fu Yak Hacker
6065 Posts |
Posted - 2005-04-09 : 08:49:33
|
| spid would not be a reliable candidate to associate with users since a spid is just a sql server process id. The application has no control over maintaining a consistent spid by user, especially for auditing over time when the connections will be broken and apps need to be restarted, connection pooling is implemented, etc. There are many ways to track usage with a custom authentication scheme. Typically, when a user "logs in" the userid (or authentication token of some sort) is captured and cached. The token is then sent along with the requests and can be used for column/row level entitlements, application object entitilements, auditing, etc. Also typically, each request would be only associated with a user or perhaps a user/session, but not by the internal server process id.Be One with the OptimizerTG |
 |
|
|
t1g312
Posting Yak Master
148 Posts |
Posted - 2005-04-10 : 00:39:17
|
quote: Originally posted by TG spid would not be a reliable candidate to associate with users since a spid is just a sql server process id. The application has no control over maintaining a consistent spid by user, especially for auditing over time when the connections will be broken and apps need to be restarted, connection pooling is implemented, etc. There are many ways to track usage with a custom authentication scheme. Typically, when a user "logs in" the userid (or authentication token of some sort) is captured and cached. The token is then sent along with the requests and can be used for column/row level entitlements, application object entitilements, auditing, etc. Also typically, each request would be only associated with a user or perhaps a user/session, but not by the internal server process id.Be One with the OptimizerTG
Thanks for the response TG. SPID seems to change only when more than one user is connected to the server. Could it have something to do with connection pooling?I can pass the username as a parameter to the stored procedure but can I access it from the trigger? AFAIK trigger can only use data from the table and cannot accept any parameters.Adi-------------------------/me sux @sql server |
 |
|
|
TG
Master Smack Fu Yak Hacker
6065 Posts |
Posted - 2005-04-10 : 10:09:17
|
>>Could it have something to do with connection pooling?Certainly could. depends on your architecture (sql Provider, web app, windows app, client server/multi-tier) The point is it's not worth figuring out because it will change without the app knowing about it.>>AFAIK trigger can only use data from the table and cannot accept any parameters.true. We've done it a couple ways. Tables we audited had 4 columns (CreatedBy CreatedDate, LastUpdatedBy, UpdateDAte) Those columns were used by the triggers for insert/update. The other way we've done it is to only change tables via their Insert, Update, and Delete SPs. The SPs controlled auditing as well as other business rules.I also remember a topic on this forum where someone was using Context_Info column of sysProcesses table to relate current spid with spid's user. I'll look for it and post the topic_ID if I find it.EDIT: found it: http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=47048using context_info is possible however, it still depends on the context_info being set by the current session prior to performing the insert/update/delete. In other words, adhoc changes to the table won't necessarily capture who made the changes. Also, this stategy requires the additional steps of setting and getting the context_info (from sysprocesses).My preference is keeping the extra columns in the tables you want to audit. That way adhoc changes are audited correctly and you report that info to the user as part of the main data without having to make special trip to audit table.Here is my tesing of context_info (in case you're interested)set nocount oncreate table MyTable (MyTableID int identity(1,1), col1 int)create table MyTableAudit (MyTableAuditID int identity(1,1), MyTableID int, Action char(1), oldCol1 int, newCol1 int, ChangedByUserID int, ChangedDate dateTime)GOcreate trigger tr_insMyTable ON MyTable for insert, updateas--Get UserID from Context_Info column of sysProcesses --(context_info must be set by insert or update SP)declare @userid intselect @userid = convert(int,convert(binary(4), context_info)) from sysProcesses where spid = @@spidinsert myTableAudit (MyTableID, Action, oldcol1, newcol1, ChangedByUserID, ChangedDate)Select i.MyTableID ,case when d.MyTableID is NULL then 'I' else 'U' End ,d.col1 ,i.col1 ,@userid ,getDate()From inserted ileft JOIN deleted d ON i.MyTableID = d.MyTableIDGOcreate proc insMyTable@userid int,@col1 intas --set context_info to useriddeclare @user_CI varbinary(128)set @user_CI = convert(varbinary(128),@UserID)set Context_Info @user_CIinsert myTable (col1)values (@col1)GOcreate proc updMyTable@myTableID int,@userID int,@col1 intas--set context_info to useriddeclare @user_CI varbinary(128)set @user_CI = convert(varbinary(128),@UserID)set Context_Info @user_CIupdate MyTable set col1 = @col1 where myTableID = @myTableIDGOexec insMyTable @userid = 15, @col1 = 12345exec insMyTable @userid = 15, @col1 = 100exec updMyTable @myTableID = 1, @userID = 25, @col1 = 7890Select * from MyTableSelect * from MyTableAuditGOdrop proc insMyTabledrop proc updMyTabledrop table myTableAuditdrop table myTable Be One with the OptimizerTG |
 |
|
|
t1g312
Posting Yak Master
148 Posts |
Posted - 2005-04-16 : 02:37:40
|
quote: Originally posted by TG >>Could it have something to do with connection pooling?Certainly could. depends on your architecture (sql Provider, web app, windows app, client server/multi-tier) The point is it's not worth figuring out because it will change without the app knowing about it.>>AFAIK trigger can only use data from the table and cannot accept any parameters.true. We've done it a couple ways. Tables we audited had 4 columns (CreatedBy CreatedDate, LastUpdatedBy, UpdateDAte) Those columns were used by the triggers for insert/update. The other way we've done it is to only change tables via their Insert, Update, and Delete SPs. The SPs controlled auditing as well as other business rules.I also remember a topic on this forum where someone was using Context_Info column of sysProcesses table to relate current spid with spid's user. I'll look for it and post the topic_ID if I find it.EDIT: found it: http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=47048using context_info is possible however, it still depends on the context_info being set by the current session prior to performing the insert/update/delete. In other words, adhoc changes to the table won't necessarily capture who made the changes. Also, this stategy requires the additional steps of setting and getting the context_info (from sysprocesses).My preference is keeping the extra columns in the tables you want to audit. That way adhoc changes are audited correctly and you report that info to the user as part of the main data without having to make special trip to audit table.Here is my tesing of context_info (in case you're interested)set nocount oncreate table MyTable (MyTableID int identity(1,1), col1 int)create table MyTableAudit (MyTableAuditID int identity(1,1), MyTableID int, Action char(1), oldCol1 int, newCol1 int, ChangedByUserID int, ChangedDate dateTime)GOcreate trigger tr_insMyTable ON MyTable for insert, updateas--Get UserID from Context_Info column of sysProcesses --(context_info must be set by insert or update SP)declare @userid intselect @userid = convert(int,convert(binary(4), context_info)) from sysProcesses where spid = @@spidinsert myTableAudit (MyTableID, Action, oldcol1, newcol1, ChangedByUserID, ChangedDate)Select i.MyTableID ,case when d.MyTableID is NULL then 'I' else 'U' End ,d.col1 ,i.col1 ,@userid ,getDate()From inserted ileft JOIN deleted d ON i.MyTableID = d.MyTableIDGOcreate proc insMyTable@userid int,@col1 intas --set context_info to useriddeclare @user_CI varbinary(128)set @user_CI = convert(varbinary(128),@UserID)set Context_Info @user_CIinsert myTable (col1)values (@col1)GOcreate proc updMyTable@myTableID int,@userID int,@col1 intas--set context_info to useriddeclare @user_CI varbinary(128)set @user_CI = convert(varbinary(128),@UserID)set Context_Info @user_CIupdate MyTable set col1 = @col1 where myTableID = @myTableIDGOexec insMyTable @userid = 15, @col1 = 12345exec insMyTable @userid = 15, @col1 = 100exec updMyTable @myTableID = 1, @userID = 25, @col1 = 7890Select * from MyTableSelect * from MyTableAuditGOdrop proc insMyTabledrop proc updMyTabledrop table myTableAuditdrop table myTable Be One with the OptimizerTG
Thanks for the detailed reply. The context_info method needs spid too which seems to keep changing. The reason why I don't want to add username and timestamp in all my transaction tables is that it will increase the size of the database drastically since I have several transaction tables.What about using host_name? Wouldn't that be a good idea?Thanks in advance.Adi-------------------------/me sux @sql server |
 |
|
|
TG
Master Smack Fu Yak Hacker
6065 Posts |
Posted - 2005-04-16 : 08:52:36
|
| >The context_info method needs spid too which seems to keep changing. I'm not pushing this idea, but for the solution I provided, the spid doesn't change between the call to the sp and the firing of the trigger. It can't change because it happens in the same process. It uses the spid but only as a means to communicate the context (specific instance of the sp firing) to the trigger. The UserID is what is stored in the context_info column and posted to the audit table. This solution satisfies your requirements.The only problem I have with it is that I've never heard of anyone doing it before. I'm not sure what would happen under heavy contention.>>What about using host_name? Wouldn't that be a good idea?Well, that would make more sense than spid. Host_Name is just a machine identifier. When user's get a new machine, you will loose audit continuity. Also if a user logs into another machine, the host_name will not follow the user around. The readers of the audit tables will inacurately believe the normal operator of that machine made the modifications.>>will increase the size of the database drastically since I have several transaction tables.Disc space is pretty cheap these days :)Be One with the OptimizerTG |
 |
|
|
t1g312
Posting Yak Master
148 Posts |
Posted - 2005-04-16 : 15:44:04
|
quote: Originally posted by TG >The context_info method needs spid too which seems to keep changing. I'm not pushing this idea, but for the solution I provided, the spid doesn't change between the call to the sp and the firing of the trigger. It can't change because it happens in the same process. It uses the spid but only as a means to communicate the context (specific instance of the sp firing) to the trigger. The UserID is what is stored in the context_info column and posted to the audit table. This solution satisfies your requirements.The only problem I have with it is that I've never heard of anyone doing it before. I'm not sure what would happen under heavy contention.>>What about using host_name? Wouldn't that be a good idea?Well, that would make more sense than spid. Host_Name is just a machine identifier. When user's get a new machine, you will loose audit continuity. Also if a user logs into another machine, the host_name will not follow the user around. The readers of the audit tables will inacurately believe the normal operator of that machine made the modifications.>>will increase the size of the database drastically since I have several transaction tables.Disc space is pretty cheap these days :)Be One with the OptimizerTG
You're right about the host name and disk space. Besides, my company has deep pockets.Thanks man!Adi-------------------------/me sux @sql server |
 |
|
|
|
|
|
|
|