@@ -78,18 +78,37 @@ public static function setArchiveAttribute(array & $chatsId)
7878
7979 foreach ($ archivedChats as $ archiveChatId ) {
8080
81- if (empty ($ archivesRanges ) || ($ archiveId = self ::isInRange ($ archiveChatId , $ archivesRanges )) === null ) {
82- $ stmt = $ db ->prepare ('SELECT id,first_id,last_id FROM lh_chat_archive_range WHERE :chat_id_1 <= last_id && :chat_id_2 >= first_id LIMIT 1 ' );
83- $ stmt ->bindValue (':chat_id_1 ' , $ archiveChatId );
84- $ stmt ->bindValue (':chat_id_2 ' , $ archiveChatId );
81+ $ archiveId = null ;
82+
83+ // Collect all matching ranges from cache first
84+ $ matchingRanges = self ::getMatchingRanges ($ archiveChatId , $ archivesRanges );
85+
86+ // If no cached ranges match, query the database
87+ if (empty ($ matchingRanges )) {
88+ $ stmt = $ db ->prepare ('SELECT id, first_id, last_id FROM lh_chat_archive_range WHERE :chat_id <= last_id AND :chat_id >= first_id ' );
89+ $ stmt ->bindValue (':chat_id ' , $ archiveChatId );
8590 $ stmt ->execute ();
86- $ dataArchive = $ stmt ->fetch (PDO ::FETCH_ASSOC );
91+ $ matchingRanges = $ stmt ->fetchAll (PDO ::FETCH_ASSOC );
92+ }
8793
88- if (is_array ($ dataArchive )) {
94+ // If multiple ranges match (overlap), verify by checking the archive table
95+ if (count ($ matchingRanges ) > 1 ) {
96+ foreach ($ matchingRanges as $ dataArchive ) {
97+ if (self ::chatExistsInArchive ($ db , $ dataArchive ['id ' ], $ archiveChatId )) {
98+ $ archiveId = $ dataArchive ['id ' ];
99+
100+ if (! self ::isRangeCached ($ dataArchive ['id ' ], $ archivesRanges )) {
101+ $ archivesRanges [] = $ dataArchive ;
102+ }
103+ break ;
104+ }
105+ }
106+ } elseif (count ($ matchingRanges ) === 1 ) {
107+ $ dataArchive = reset ($ matchingRanges );
108+ $ archiveId = $ dataArchive ['id ' ];
109+
110+ if (! self ::isRangeCached ($ dataArchive ['id ' ], $ archivesRanges )) {
89111 $ archivesRanges [] = $ dataArchive ;
90- $ archiveId = $ dataArchive ['id ' ];
91- } else {
92- $ archiveId = null ;
93112 }
94113 }
95114
@@ -113,4 +132,42 @@ public static function isInRange($chatId, $ranges)
113132
114133 return null ;
115134 }
135+
136+ /**
137+ * Returns all cached ranges that could contain the given chat ID.
138+ * When ranges overlap, multiple ranges may match.
139+ */
140+ private static function getMatchingRanges ($ chatId , $ ranges )
141+ {
142+ $ matched = array ();
143+ foreach ($ ranges as $ range ) {
144+ if ($ chatId >= $ range ['first_id ' ] && $ chatId <= $ range ['last_id ' ]) {
145+ $ matched [] = $ range ;
146+ }
147+ }
148+ return $ matched ;
149+ }
150+
151+ private static function isRangeCached ($ rangeId , $ ranges )
152+ {
153+ foreach ($ ranges as $ r ) {
154+ if ($ r ['id ' ] == $ rangeId ) {
155+ return true ;
156+ }
157+ }
158+ return false ;
159+ }
160+
161+ /**
162+ * Verifies whether a chat actually exists in a specific archive table.
163+ * This resolves ambiguity when archive ranges overlap.
164+ */
165+ private static function chatExistsInArchive ($ db , $ archiveRangeId , $ chatId )
166+ {
167+ $ tableName = 'lh_chat_archive_ ' . (int )$ archiveRangeId ;
168+ $ stmt = $ db ->prepare ("SELECT 1 FROM ` {$ tableName }` WHERE id = :chat_id LIMIT 1 " );
169+ $ stmt ->bindValue (':chat_id ' , $ chatId , PDO ::PARAM_INT );
170+ $ stmt ->execute ();
171+ return (bool )$ stmt ->fetchColumn ();
172+ }
116173}
0 commit comments