namespace FrameworkDAL.Query.SessionStore { /// /// SQL constants for MSESSIONSTORE in the GB5 system database. /// /// Required indexes (already on MSESSIONSTORE): /// PK_MSESSIONSTORE_SESSIONID — SESSIONID (clustered) /// UK_MSESSIONSTORE_SERVERCONFIGID — LOGINEVENTLOGID, SERVERCONFIGID (unique) /// MSESSIONSTORE_SERVERCONFIGIDLOGINEVENTLOGID — SERVERCONFIGID, LOGINEVENTLOGID /// public static class SessionStoreQB { // ── INSERT / UPSERT ────────────────────────────────────────────────── /// /// SQL Server: MERGE-based upsert. /// Inserts a new session row or updates LASTLOGINUSEDTIME if the session /// already exists for the same (SERVERCONFIGID, LOGINEVENTLOGID) pair. /// Params: @ServerconfigId, @LoginEventLogId, @LoginTime, /// @LastLoginUsedTime, @MachineIp, @UserId, @UserCode, @UserName /// public const string UPSERT_SESSION_SQL = @" MERGE INTO MSESSIONSTORE WITH (HOLDLOCK) AS target USING (SELECT @ServerconfigId AS SERVERCONFIGID, @LoginEventLogId AS LOGINEVENTLOGID) AS source ON ( target.SERVERCONFIGID = source.SERVERCONFIGID AND target.LOGINEVENTLOGID = source.LOGINEVENTLOGID) WHEN NOT MATCHED THEN INSERT (SERVERCONFIGID, LOGINEVENTLOGID, LOGINTIME, LASTLOGINUSEDTIME, MACHINEIP, USERID, USERCODE, USERNAME, ISACTIVE) VALUES (@ServerconfigId, @LoginEventLogId, @LoginTime, @LastLoginUsedTime, @MachineIp, @UserId, @UserCode, @UserName, 0) WHEN MATCHED THEN UPDATE SET LASTLOGINUSEDTIME = @LastLoginUsedTime;"; /// /// PostgreSQL: INSERT … ON CONFLICT upsert. /// Params: same as UPSERT_SESSION_SQL. /// public const string UPSERT_SESSION_POSTGRESQL = @" INSERT INTO MSESSIONSTORE (SERVERCONFIGID, LOGINEVENTLOGID, LOGINTIME, LASTLOGINUSEDTIME, MACHINEIP, USERID, USERCODE, USERNAME, ISACTIVE) VALUES (@ServerconfigId, @LoginEventLogId, @LoginTime, @LastLoginUsedTime, @MachineIp, @UserId, @UserCode, @UserName, 0) ON CONFLICT (LOGINEVENTLOGID, SERVERCONFIGID) DO UPDATE SET LASTLOGINUSEDTIME = EXCLUDED.LASTLOGINUSEDTIME;"; // ── UPDATE ─────────────────────────────────────────────────────────── /// /// Update LASTLOGINUSEDTIME for an existing session (activity heartbeat). /// Params: @LastLoginUsedTime, @ServerconfigId, @LoginEventLogId /// public const string UPDATE_SESSION = @" UPDATE MSESSIONSTORE SET LASTLOGINUSEDTIME = @LastLoginUsedTime WHERE SERVERCONFIGID = @ServerconfigId AND LOGINEVENTLOGID = @LoginEventLogId;"; // ── DELETE ─────────────────────────────────────────────────────────── /// /// Delete a specific session on logout. /// Params: @ServerconfigId, @LoginEventLogId /// public const string DELETE_SESSION = @" DELETE FROM MSESSIONSTORE WHERE SERVERCONFIGID = @ServerconfigId AND LOGINEVENTLOGID = @LoginEventLogId;"; /// /// Delete stale sessions (SQL Server). /// Removes sessions whose LASTLOGINUSEDTIME is older than @TodayDate, /// and also cleans up GB5ADMIN sessions with a blank MachineIp. /// Params: @TodayDate (DateTime) /// public const string DELETE_OLD_SESSIONS_SQL = @" DELETE FROM MSESSIONSTORE WHERE LASTLOGINUSEDTIME < @TodayDate OR ( LASTLOGINUSEDTIME >= @TodayDate AND ISNULL(MACHINEIP, '') = '' AND USERCODE = 'GB5ADMIN');"; /// /// Delete stale sessions (PostgreSQL). /// Params: @TodayDate (DateTime) /// public const string DELETE_OLD_SESSIONS_POSTGRESQL = @" DELETE FROM MSESSIONSTORE WHERE LASTLOGINUSEDTIME < @TodayDate OR ( LASTLOGINUSEDTIME >= @TodayDate AND COALESCE(MACHINEIP, '') = '' AND USERCODE = 'GB5ADMIN');"; // ── SELECT ─────────────────────────────────────────────────────────── /// /// Count rows for a given session — used before UPDATE to guard against phantom writes. /// Params: @ServerconfigId, @LoginEventLogId /// public const string SELECT_SESSION_COUNT = @" SELECT COUNT(*) FROM MSESSIONSTORE WHERE SERVERCONFIGID = @ServerconfigId AND LOGINEVENTLOGID = @LoginEventLogId;"; /// /// Fetch idle sessions that have exceeded the expiry window (SQL Server). /// Used by the auto-logout background job. /// Params: @ExpiryTime (minutes, int), @ServerconfigId /// public const string GET_UNUSED_SESSIONS_SQL = @" SELECT LOGINEVENTLOGID AS LoginEventLogId, ISNULL(MACHINEIP,'NONE') AS MachineIp, USERID AS UserId, USERNAME AS UserName FROM MSESSIONSTORE WHERE DATEADD(MINUTE, @ExpiryTime, LASTLOGINUSEDTIME) <= GETUTCDATE() AND LOGINTIME >= CAST(GETUTCDATE() AS DATE) AND ISACTIVE = 0 AND SERVERCONFIGID = @ServerconfigId;"; /// /// Fetch idle sessions that have exceeded the expiry window (PostgreSQL). /// Params: @ExpiryTime (minutes, int), @ServerconfigId /// public const string GET_UNUSED_SESSIONS_POSTGRESQL = @" SELECT LOGINEVENTLOGID AS LoginEventLogId, COALESCE(MACHINEIP, 'NONE') AS MachineIp, USERID AS UserId, USERNAME AS UserName FROM MSESSIONSTORE WHERE LASTLOGINUSEDTIME + (@ExpiryTime * INTERVAL '1 minute') <= NOW() AT TIME ZONE 'UTC' AND LOGINTIME >= CURRENT_DATE AND ISACTIVE = 0 AND SERVERCONFIGID = @ServerconfigId;"; } }