112 if (!nameSpace.startsWith(
"org.qt-project."_L1))
117 const QChar dot(u'.');
118 QString &tail = result.tail;
119 for (
int i = nameSpace.size(); i > 0; --i) {
120 const QChar c = nameSpace.at(i - 1);
121 if (c.isDigit() || c == dot)
128 if (!tail.startsWith(dot) && tail.count(dot) == 1) {
131 const int dotIndex = tail.indexOf(dot);
133 tail = tail.mid(dotIndex);
137 while (tail.startsWith(dot))
141 while (tail.endsWith(dot))
144 if (tail.size() >= 3 && tail.size() <= 5 && tail.count(dot) == 0) {
148 QStringView tail{result.tail};
149 result
.major = tail.left(1).toInt();
150 result
.minor = tail.size() == 3 ? tail.mid(1, 1).toInt() : tail.mid(1, 2).toInt();
151 result
.patch = tail.size() == 5 ? tail.right(2).toInt() : tail.right(1).toInt();
198 m_query->setForwardOnly(
true);
200 QMap<
int, QString> attributeIds;
201 m_query->exec(
"SELECT DISTINCT Id, Name FROM FilterAttributeTable ORDER BY Id"_L1);
202 while (m_query->next())
203 attributeIds.insert(m_query->value(0).toInt(), m_query->value(1).toString());
207 QList<
int> usedAttributeIds;
208 for (
auto it = attributeIds.cbegin(), end = attributeIds.cend(); it != end; ++it) {
209 const int attributeId = it.key();
210 if (isAttributeUsed(m_query.get(),
"IndexFilterTable"_L1, attributeId)
211 || isAttributeUsed(m_query.get(),
"ContentsFilterTable"_L1, attributeId)
212 || isAttributeUsed(m_query.get(),
"FileFilterTable"_L1, attributeId)) {
213 usedAttributeIds.append(attributeId);
218 m_query->exec(
"SELECT * FROM pragma_table_info('IndexTable') WHERE name='ContextName'"_L1);
222 const QString identifierColumnName = legacy ?
"ContextName"_L1 :
"Identifier"_L1;
223 const int usedAttributeCount = usedAttributeIds.size();
225 QMap<
int, IndexItem> idToIndexItem;
226 m_query->exec(QString::fromLatin1(
"SELECT Name, %1, FileId, Anchor, Id "
228 "ORDER BY Id").arg(identifierColumnName));
229 while (m_query->next()) {
231 indexItem.name = m_query->value(0).toString();
232 indexItem.identifier = m_query->value(1).toString();
233 indexItem.fileId = m_query->value(2).toInt();
234 indexItem.anchor = m_query->value(3).toString();
235 const int indexId = m_query->value(4).toInt();
237 idToIndexItem.insert(indexId, indexItem);
240 QMap<
int, FileItem> idToFileItem;
241 QMap<
int,
int> originalFileIdToNewFileId;
244 const bool filesRead = m_query->exec(
246 "FileNameTable.FileId, "
247 "FileNameTable.Name, "
248 "FileNameTable.Title "
249 "FROM FileNameTable, FolderTable "
250 "WHERE FileNameTable.FolderId = FolderTable.Id "
251 "ORDER BY FileId"_L1);
254 m_query->setForwardOnly(
false);
257 while (m_query->next()) {
258 const int fileId = m_query->value(0).toInt();
260 fileItem.name = m_query->value(1).toString();
261 fileItem.title = m_query->value(2).toString();
263 idToFileItem.insert(fileId, fileItem);
264 originalFileIdToNewFileId.insert(fileId, filesCount);
268 QMap<
int, ContentsItem> idToContentsItem;
270 m_query->exec(
"SELECT Data, Id FROM ContentsTable ORDER BY Id"_L1);
271 while (m_query->next()) {
273 contentsItem.data = m_query->value(0).toByteArray();
274 const int contentsId = m_query->value(1).toInt();
276 idToContentsItem.insert(contentsId, contentsItem);
279 bool optimized =
true;
281 if (usedAttributeCount) {
290 const bool mayOptimizeIndexTable = filterDataCount(m_query.get(),
"IndexFilterTable"_L1)
291 == idToIndexItem.size() * usedAttributeCount;
292 const bool mayOptimizeFileTable = filterDataCount(m_query.get(),
"FileFilterTable"_L1)
293 == idToFileItem.size() * usedAttributeCount;
294 const bool mayOptimizeContentsTable =
295 filterDataCount(m_query.get(),
"ContentsFilterTable"_L1)
296 == idToContentsItem.size() * usedAttributeCount;
297 optimized = mayOptimizeIndexTable && mayOptimizeFileTable && mayOptimizeContentsTable;
302 "IndexFilterTable.IndexId, "
303 "FilterAttributeTable.Name "
306 "FilterAttributeTable "
308 "IndexFilterTable.FilterAttributeId = FilterAttributeTable.Id"_L1);
309 while (m_query->next()) {
310 const int indexId = m_query->value(0).toInt();
311 auto it = idToIndexItem.find(indexId);
312 if (it != idToIndexItem.end())
313 it.value().filterAttributes.append(m_query->value(1).toString());
318 "FileFilterTable.FileId, "
319 "FilterAttributeTable.Name "
322 "FilterAttributeTable "
324 "FileFilterTable.FilterAttributeId = FilterAttributeTable.Id"_L1);
325 while (m_query->next()) {
326 const int fileId = m_query->value(0).toInt();
327 auto it = idToFileItem.find(fileId);
328 if (it != idToFileItem.end())
329 it.value().filterAttributes.append(m_query->value(1).toString());
334 "ContentsFilterTable.ContentsId, "
335 "FilterAttributeTable.Name "
337 "ContentsFilterTable, "
338 "FilterAttributeTable "
340 "ContentsFilterTable.FilterAttributeId = FilterAttributeTable.Id"_L1);
341 while (m_query->next()) {
342 const int contentsId = m_query->value(0).toInt();
343 auto it = idToContentsItem.find(contentsId);
344 if (it != idToContentsItem.end())
345 it.value().filterAttributes.append(m_query->value(1).toString());
353 QSet<
int> fileNotFoundIds;
354 m_query->exec(
"SELECT FileId FROM FileNameTable WHERE FolderId = 0 AND Name = ''"_L1);
355 while (m_query->next())
356 fileNotFoundIds.insert(m_query->value(0).toInt());
359 for (
auto it = idToIndexItem.cbegin(), end = idToIndexItem.cend(); it != end; ++it) {
360 IndexItem item = it.value();
361 if (fileNotFoundIds.contains(item.fileId))
364 item.fileId = originalFileIdToNewFileId.value(item.fileId, -1);
365 table.indexItems.append(item);
369 table.fileItems = idToFileItem.values();
370 table.contentsItems = idToContentsItem.values();
373 for (
int attributeId : std::as_const(usedAttributeIds))
374 table.usedFilterAttributes.append(attributeIds.value(attributeId));
377 m_query->setForwardOnly(
false);
477 const QStringList &extensionFilters,
478 const std::function<
bool(
const QString &fileName,
479 const QByteArray &data)> &handler)
const
486 if (!extensionFilters.isEmpty()) {
487 QStringList conditions;
488 for (
const QString &extensionFilter : extensionFilters)
489 conditions.append(
"FileNameTable.Name LIKE \'%.%1\'"_L1.arg(extensionFilter));
490 extension =
"AND (%1)"_L1.arg(conditions.join(
" OR "_L1));
493 if (filterAttributes.isEmpty()) {
496 "FileNameTable.Name, "
497 "FileDataTable.Data "
502 "WHERE FileDataTable.Id = FileNameTable.FileId "
503 "AND FileNameTable.FolderId = FolderTable.Id %1"_L1.arg(extension);
505 for (
int i = 0; i < filterAttributes.size(); ++i) {
507 query.append(
" INTERSECT "_L1);
510 "FileNameTable.Name, "
511 "FileDataTable.Data "
517 "FilterAttributeTable "
518 "WHERE FileDataTable.Id = FileNameTable.FileId "
519 "AND FileNameTable.FolderId = FolderTable.Id "
520 "AND FileNameTable.FileId = FileFilterTable.FileId "
521 "AND FileFilterTable.FilterAttributeId = FilterAttributeTable.Id "
522 "AND FilterAttributeTable.Name = \'%1\' %2"_L1
523 .arg(quote(filterAttributes.at(i)), extension));
528 m_query->setForwardOnly(
true);
529 m_query->exec(query);
530 while (m_query->next()) {
531 if (!handler(m_query->value(0).toString(),
532 qUncompress(m_query->value(1).toByteArray()))) {
537 m_query->setForwardOnly(
false);