|
6 | 6 |
|
7 | 7 | #include <QCryptographicHash> |
8 | 8 | #include <QFile> |
| 9 | +#include <QJsonArray> |
| 10 | +#include <QJsonDocument> |
9 | 11 | #include <QLoggingCategory> |
10 | 12 | #include <QStringList> |
11 | 13 | #include <QElapsedTimer> |
|
33 | 35 | static constexpr auto MAJOR_VERSION_3 = 3; |
34 | 36 | static constexpr auto MINOR_VERSION_16 = 16; |
35 | 37 |
|
| 38 | +using namespace Qt::StringLiterals; |
| 39 | + |
36 | 40 | namespace OCC { |
37 | 41 |
|
38 | 42 | Q_LOGGING_CATEGORY(lcDb, "nextcloud.sync.database", QtInfoMsg) |
@@ -1769,6 +1773,58 @@ bool SyncJournalDb::updateLocalMetadata(const QString &filename, |
1769 | 1773 | return true; |
1770 | 1774 | } |
1771 | 1775 |
|
| 1776 | +bool SyncJournalDb::hasFileIds(const QList<qint64> &fileIds) |
| 1777 | +{ |
| 1778 | + if (fileIds.isEmpty()) { |
| 1779 | + // no need to check the db if no file id matches |
| 1780 | + return false; |
| 1781 | + } |
| 1782 | + |
| 1783 | + QMutexLocker locker(&_mutex); |
| 1784 | + |
| 1785 | + if (!checkConnect()) { |
| 1786 | + return false; |
| 1787 | + } |
| 1788 | + |
| 1789 | + // quick workaround for looking up pure numeric file IDs: cast it to integer |
| 1790 | + // |
| 1791 | + // using `IN` with a list of IDs does not allow for a prepared query: the execution plan |
| 1792 | + // would be different depending on the amount of elements as each element is added to a |
| 1793 | + // temporary table one-by-one. with `json_each()`, all that changes is one string |
| 1794 | + // parameter which is perfect for creating a prepared query :) |
| 1795 | + const auto query = _queryManager.get( |
| 1796 | + PreparedSqlQueryManager::HasFileIdQuery, |
| 1797 | + "SELECT 1 FROM metadata, json_each(?1) file_ids WHERE CAST(metadata.fileid AS INTEGER) = CAST(file_ids.value AS INTEGER) LIMIT 1;"_ba, |
| 1798 | + _db |
| 1799 | + ); |
| 1800 | + if (!query) { |
| 1801 | + qCWarning(lcDb) << "database error:" << query->error(); |
| 1802 | + return false; |
| 1803 | + } |
| 1804 | + |
| 1805 | + // we have a prepared query, so let's build up a JSON array of file IDs to check for. |
| 1806 | + // Strings are used here to avoid any surprises during serialisation: JSON only really |
| 1807 | + // has a double type, and who knows when the representation changes to the +e* variant. |
| 1808 | + QJsonArray fileIdStrings = {}; |
| 1809 | + for (const auto &fileId : fileIds) { |
| 1810 | + fileIdStrings.append(QString::number(fileId)); |
| 1811 | + } |
| 1812 | + const auto fileIdsParameter = QJsonDocument(fileIdStrings).toJson(QJsonDocument::Compact); |
| 1813 | + query->bindValue(1, fileIdsParameter); |
| 1814 | + |
| 1815 | + if (!query->exec()) { |
| 1816 | + qCWarning(lcDb) << "file id query failed:" << query->error(); |
| 1817 | + return false; |
| 1818 | + } |
| 1819 | + |
| 1820 | + if (query->next().hasData && query->intValue(0) == 1) { |
| 1821 | + // at least one file ID from the passed list is present |
| 1822 | + return true; |
| 1823 | + } |
| 1824 | + |
| 1825 | + return false; |
| 1826 | +} |
| 1827 | + |
1772 | 1828 | Optional<SyncJournalDb::HasHydratedDehydrated> SyncJournalDb::hasHydratedOrDehydratedFiles(const QByteArray &filename) |
1773 | 1829 | { |
1774 | 1830 | QMutexLocker locker(&_mutex); |
|
0 commit comments