Frequently Asked Questions

How do I log database updates?

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>.