/// <summary>
        /// Is called before the base class detaches the filter from the collection.
        /// </summary>
        protected override void OnDetachFromCollection()
        {
            // release prepared statements
            mAccessor.ReleasePreparedCommand(ref mSelectContinuousMessagesCommand_Forward);
            mAccessor.ReleasePreparedCommand(ref mSelectContinuousMessagesCommand_Backwards);
            mAccessor.ReleasePreparedCommand(ref mAddProcessIdToFilterCommand);
            mAccessor.ReleasePreparedCommand(ref mAddProcessNameToFilterCommand);
            mAccessor.ReleasePreparedCommand(ref mAddApplicationNameToFilterCommand);
            mAccessor.ReleasePreparedCommand(ref mAddLogWriterToFilterCommand);
            mAccessor.ReleasePreparedCommand(ref mAddLogLevelToFilterCommand);
            mAccessor.ReleasePreparedCommand(ref mAddTagToFilterCommand);

            // drop temporary tables (drops indexes as well)
            // (should not be necessary for an in-memory database, but it is cleaner so)
            mAccessor.ExecuteNonQueryCommands($"DROP TABLE IF EXISTS {mFilterDatabaseName}.{mProcessIdFilterTableName};");
            mAccessor.ExecuteNonQueryCommands($"DROP TABLE IF EXISTS {mFilterDatabaseName}.{mProcessNameFilterTableName};");
            mAccessor.ExecuteNonQueryCommands($"DROP TABLE IF EXISTS {mFilterDatabaseName}.{mApplicationNameFilterTableName};");
            mAccessor.ExecuteNonQueryCommands($"DROP TABLE IF EXISTS {mFilterDatabaseName}.{mLogWriterFilterTableName};");
            mAccessor.ExecuteNonQueryCommands($"DROP TABLE IF EXISTS {mFilterDatabaseName}.{mLogLevelFilterTableName};");
            mAccessor.ExecuteNonQueryCommands($"DROP TABLE IF EXISTS {mFilterDatabaseName}.{mTagFilterTableName};");

            // detach from in-memory database
            mAccessor.ExecuteNonQueryCommands($"DETACH DATABASE {mFilterDatabaseName};");

            mAccessor = null;
        }
        /// <summary>
        /// Is called after the base class has attached the filter to the collection.
        /// </summary>
        protected override void OnAttachToCollection()
        {
            mAccessor = Collection.LogFile.Accessor;

            // create an in-memory database for filter settings
            mAccessor.ExecuteNonQueryCommands($"ATTACH DATABASE 'file::{mFilterDatabaseName}?mode=memory' AS {mFilterDatabaseName};");

            // create temporary tables that will store the selected log writers, levels, tags, application names and process names/ids
            mAccessor.ExecuteNonQueryCommands($"CREATE TABLE {mFilterDatabaseName}.{mProcessIdFilterTableName} (id INTEGER);");
            mAccessor.ExecuteNonQueryCommands($"CREATE TABLE {mFilterDatabaseName}.{mProcessNameFilterTableName} (id INTEGER);");
            mAccessor.ExecuteNonQueryCommands($"CREATE TABLE {mFilterDatabaseName}.{mApplicationNameFilterTableName} (id INTEGER);");
            mAccessor.ExecuteNonQueryCommands($"CREATE TABLE {mFilterDatabaseName}.{mLogWriterFilterTableName} (id INTEGER);");
            mAccessor.ExecuteNonQueryCommands($"CREATE TABLE {mFilterDatabaseName}.{mLogLevelFilterTableName} (id INTEGER);");
            mAccessor.ExecuteNonQueryCommands($"CREATE TABLE {mFilterDatabaseName}.{mTagFilterTableName} (id INTEGER);");

            // create indices on the filter tables to accelerate lookups
            mAccessor.ExecuteNonQueryCommands($"CREATE UNIQUE INDEX {mFilterDatabaseName}.{mProcessIdFilterTableName}_index ON {mProcessIdFilterTableName} (id);");
            mAccessor.ExecuteNonQueryCommands($"CREATE UNIQUE INDEX {mFilterDatabaseName}.{mProcessNameFilterTableName}_index ON {mProcessNameFilterTableName} (id);");
            mAccessor.ExecuteNonQueryCommands($"CREATE UNIQUE INDEX {mFilterDatabaseName}.{mApplicationNameFilterTableName}_index ON {mApplicationNameFilterTableName} (id);");
            mAccessor.ExecuteNonQueryCommands($"CREATE UNIQUE INDEX {mFilterDatabaseName}.{mLogWriterFilterTableName}_index ON {mApplicationNameFilterTableName} (id);");
            mAccessor.ExecuteNonQueryCommands($"CREATE UNIQUE INDEX {mFilterDatabaseName}.{mLogLevelFilterTableName}_index ON {mLogLevelFilterTableName} (id);");
            mAccessor.ExecuteNonQueryCommands($"CREATE UNIQUE INDEX {mFilterDatabaseName}.{mTagFilterTableName}_index ON {mTagFilterTableName} (id);");

            // prepare query to retrieve log messages
            SetupMessageQuery();

            // prepare queries to add enabled filter items
            mAddProcessIdToFilterCommand = mAccessor.PrepareCommand($"INSERT OR IGNORE INTO {mFilterDatabaseName}.{mProcessIdFilterTableName} VALUES (@id);");
            mAddProcessIdToFilterCommand.Parameters.Add(mAddProcessIdToFilterCommand_IdParameter = new SQLiteParameter("@id", DbType.Int32));
            mAddProcessNameToFilterCommand = mAccessor.PrepareCommand($"INSERT OR IGNORE INTO {mFilterDatabaseName}.{mProcessNameFilterTableName} SELECT id FROM processes WHERE name = @name;");
            mAddProcessNameToFilterCommand.Parameters.Add(mAddProcessNameToFilterCommand_NameParameter = new SQLiteParameter("@name", DbType.String));
            mAddApplicationNameToFilterCommand = mAccessor.PrepareCommand($"INSERT OR IGNORE INTO {mFilterDatabaseName}.{mApplicationNameFilterTableName} SELECT id FROM applications WHERE name = @name;");
            mAddApplicationNameToFilterCommand.Parameters.Add(mAddApplicationNameToFilterCommand_NameParameter = new SQLiteParameter("@name", DbType.String));
            mAddLogWriterToFilterCommand = mAccessor.PrepareCommand($"INSERT OR IGNORE INTO {mFilterDatabaseName}.{mLogWriterFilterTableName} SELECT id FROM writers WHERE name = @name;");
            mAddLogWriterToFilterCommand.Parameters.Add(mAddLogWriterToFilterCommand_NameParameter = new SQLiteParameter("@name", DbType.String));
            mAddLogLevelToFilterCommand = mAccessor.PrepareCommand($"INSERT OR IGNORE INTO {mFilterDatabaseName}.{mLogLevelFilterTableName} SELECT id FROM levels WHERE name = @name;");
            mAddLogLevelToFilterCommand.Parameters.Add(mAddLogLevelToFilterCommand_NameParameter = new SQLiteParameter("@name", DbType.String));
            mAddTagToFilterCommand = mAccessor.PrepareCommand($"INSERT OR IGNORE INTO {mFilterDatabaseName}.{mTagFilterTableName} SELECT id FROM tags WHERE name = @name;");
            mAddTagToFilterCommand.Parameters.Add(mAddTagToFilterCommand_NameParameter = new SQLiteParameter("@name", DbType.String));

            // set up filter tables
            RebuildFilterTables();
        }