Database updates can be monitored by using INSERT,DELETE,UPDATE triggers on tables to be monitored, to add update details to a log table.
The SISfm user name can be included in logged update details by setting DbUpdateLogging to TRUE.
Here are examples of the triggers and stored procedures required to log updates in table sisfm_db_update_log:
The following procedure can be called by any INSERT,DELETE,UPDATE trigger as shown after it.
CREATE PROCEDURE sisfm_db_update_logger
@tableName VARCHAR(50),
@columnsUpdated VARBINARY(MAX)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @UserID VARCHAR(50) = UPPER(CONVERT(VARCHAR(50), SESSION_CONTEXT(N'UserID')));
IF @UserID IS NULL RETURN;
DECLARE @PK VARCHAR(8000) = '';
DECLARE curPK CURSOR LOCAL FOR
SELECT RTRIM(field_name) FROM sisfm_flds WHERE table_name=@tableName AND primary_key>0 ORDER BY primary_key;
OPEN curPK;
WHILE 1=1
BEGIN
DECLARE @fieldName VARCHAR(50);
FETCH NEXT FROM curPK INTO @fieldName; IF @@FETCH_STATUS <> 0 BREAK;
IF @PK <> '' SET @PK = @PK + '+''~''+';
SET @PK = @PK + 'RTRIM(CONVERT(VARCHAR(50), i.' + @fieldName + '))';
END
CLOSE curPK;
IF @PK = '' RETURN;
DECLARE @query NVARCHAR(4000);
IF EXISTS(SELECT * FROM #tempDeleted) AND EXISTS(SELECT * FROM #tempInserted)
BEGIN
DECLARE curColumnUpdated CURSOR LOCAL FOR
SELECT name
FROM syscolumns
WHERE id = OBJECT_ID(@tableName)
AND CONVERT(VARBINARY,REVERSE(@columnsUpdated)) & POWER(CONVERT(BIGINT, 2), colorder - 1) > 0;
OPEN curColumnUpdated;
WHILE 1=1
BEGIN
DECLARE @columnUpdated VARCHAR(50);
FETCH NEXT FROM curColumnUpdated INTO @columnUpdated; IF @@FETCH_STATUS <> 0 BREAK;
SET @query = 'SELECT GETDATE(),''' + @UserID + ''',''' + @tableName + ''',' + @PK + ',''UPDATE'','
+ '''' + @columnUpdated + ''','
+ 'd.' + @columnUpdated + ','
+ 'i.' + @columnUpdated
+ ' FROM #tempInserted i'
+ ' INNER JOIN #tempDeleted d ON ' + @PK + '=' + REPLACE(@PK,'i.','d.')
+ ' WHERE d.' + @columnUpdated + '!=i.'+@columnUpdated
+ ' OR d.' + @columnUpdated + ' IS NULL AND i.'+@columnUpdated + ' IS NOT NULL'
+ ' OR i.' + @columnUpdated + ' IS NULL AND d.'+@columnUpdated + ' IS NOT NULL';
INSERT INTO sisfm_db_update_log (date_time, user_name, table_name, primary_key, update_action , field_name, field_value_old, field_value_new)
EXEC sp_executesql @query;
END;
CLOSE curColumnUpdated;
END
ELSE
IF EXISTS(SELECT * FROM #tempDeleted)
BEGIN
SET @query = 'SELECT GETDATE(),''' + @UserID + ''',''' + @tableName + ''',' + @PK + ',''DELETE'' FROM #tempDeleted i';
INSERT INTO sisfm_db_update_log (date_time, user_name, table_name, primary_key, update_action )
EXEC sp_executesql @query;
END
ELSE
BEGIN
SET @query = 'SELECT GETDATE(),''' + @UserID + ''',''' + @tableName + ''',' + @PK + ',''INSERT'' FROM #tempInserted i';
INSERT INTO sisfm_db_update_log (date_time, user_name, table_name, primary_key, update_action )
EXEC sp_executesql @query;
END
The following creates a trigger for table rm which calls this stored procedure:
CREATE TRIGGER TR_rm ON rm AFTER INSERT,DELETE,UPDATE AS BEGIN SELECT * INTO #tempInserted FROM INSERTED; SELECT * INTO #tempDeleted FROM DELETED; DECLARE @tableName VARCHAR(50); SELECT @tableName = OBJECT_NAME(parent_obj) FROM SYSOBJECTS WHERE id=@@PROCID; DECLARE @columnsUpdated VARBINARY(MAX) = COLUMNS_UPDATED(); EXEC sisfm_db_update_logger @tableName, @columnsUpdated DROP TABLE #tempInserted; DROP TABLE #tempDeleted; END
If you need further assistance, please contact IFM Support <support@integratedfm.com.au>.