1 #include <QtSql>
2 #include <QString>
3 #include <QtDebug>
4 #include <QVariant>
5 #include <QThread>
6
7 #include "libraryhashdao.h"
8 #include "library/queryutil.h"
9
10 namespace {
11
12 // Store hash values as a signed 64-bit integer. Otherwise values greater
13 // than 2^63-1 would be converted into a floating point numbers while
14 // losing precision!!
dbHash(mixxx::cache_key_t hash)15 inline constexpr mixxx::cache_key_signed_t dbHash(mixxx::cache_key_t hash) {
16 return mixxx::signedCacheKey(hash);
17 }
18
19 } // anonymous namespace
20
getDirectoryHashes()21 QHash<QString, mixxx::cache_key_t> LibraryHashDAO::getDirectoryHashes() {
22 QSqlQuery query(m_database);
23 query.prepare("SELECT hash, directory_path FROM LibraryHashes");
24 QHash<QString, mixxx::cache_key_t> hashes;
25 if (!query.exec()) {
26 LOG_FAILED_QUERY(query);
27 }
28
29 int hashColumn = query.record().indexOf("hash");
30 int directoryPathColumn = query.record().indexOf("directory_path");
31 while (query.next()) {
32 hashes[query.value(directoryPathColumn).toString()] =
33 query.value(hashColumn).toULongLong();
34 }
35
36 return hashes;
37 }
38
getDirectoryHash(const QString & dirPath)39 mixxx::cache_key_t LibraryHashDAO::getDirectoryHash(const QString& dirPath) {
40 //qDebug() << "LibraryHashDAO::getDirectoryHash" << QThread::currentThread() << m_database.connectionName();
41 mixxx::cache_key_t hash = mixxx::invalidCacheKey();
42
43 QSqlQuery query(m_database);
44 query.prepare("SELECT hash FROM LibraryHashes "
45 "WHERE directory_path=:directory_path");
46 query.bindValue(":directory_path", dirPath);
47
48 if (!query.exec()) {
49 LOG_FAILED_QUERY(query) << "SELECT hash failed:";
50 }
51 //Grab a hash for this directory from the database, from the last time it was scanned.
52 if (query.next()) {
53 hash = query.value(query.record().indexOf("hash")).toULongLong();
54 //qDebug() << "prev hash exists" << hash << dirPath;
55 } else {
56 //qDebug() << "prev hash does not exist" << dirPath;
57 }
58
59 return hash;
60 }
61
saveDirectoryHash(const QString & dirPath,mixxx::cache_key_t hash)62 void LibraryHashDAO::saveDirectoryHash(const QString& dirPath, mixxx::cache_key_t hash) {
63 //qDebug() << "LibraryHashDAO::saveDirectoryHash" << QThread::currentThread() << m_database.connectionName();
64 QSqlQuery query(m_database);
65 query.prepare("INSERT INTO LibraryHashes (directory_path, hash, directory_deleted) "
66 "VALUES (:directory_path, :hash, :directory_deleted)");
67 query.bindValue(":directory_path", dirPath);
68 query.bindValue(":hash", dbHash(hash));
69 query.bindValue(":directory_deleted", 0);
70
71 if (!query.exec()) {
72 LOG_FAILED_QUERY(query) << "Creating new dirhash failed.";
73 }
74 //qDebug() << "created new hash" << hash;
75 }
76
updateDirectoryHash(const QString & dirPath,mixxx::cache_key_t newHash,int dir_deleted)77 void LibraryHashDAO::updateDirectoryHash(const QString& dirPath,
78 mixxx::cache_key_t newHash,
79 int dir_deleted) {
80 //qDebug() << "LibraryHashDAO::updateDirectoryHash" << QThread::currentThread() << m_database.connectionName();
81 QSqlQuery query(m_database);
82 // By definition if we have calculated a new hash for a directory then it
83 // exists and no longer needs verification.
84 query.prepare("UPDATE LibraryHashes "
85 "SET hash=:hash, directory_deleted=:directory_deleted, "
86 "needs_verification=0 "
87 "WHERE directory_path=:directory_path");
88 query.bindValue(":hash", dbHash(newHash));
89 query.bindValue(":directory_deleted", dir_deleted);
90 query.bindValue(":directory_path", dirPath);
91
92 if (!query.exec()) {
93 LOG_FAILED_QUERY(query) << "Updating existing dirhash failed.";
94 }
95 //qDebug() << "updated old existing hash" << newHash << dirPath << dir_deleted;
96
97 //DEBUG: Print out the directory hash we just saved to verify...
98 //qDebug() << getDirectoryHash(dirPath);
99 }
100
updateDirectoryStatuses(const QStringList & dirPaths,const bool deleted,const bool verified)101 void LibraryHashDAO::updateDirectoryStatuses(const QStringList& dirPaths,
102 const bool deleted,
103 const bool verified) {
104 //qDebug() << "LibraryHashDAO::updateDirectoryStatus" << QThread::currentThread() << m_database.connectionName();
105 FieldEscaper escaper(m_database);
106 QStringList escapedDirPaths = escaper.escapeStrings(dirPaths);
107
108 QSqlQuery query(m_database);
109 query.prepare(
110 QString("UPDATE LibraryHashes "
111 "SET directory_deleted=:directory_deleted, "
112 "needs_verification=:needs_verification "
113 "WHERE directory_path IN (%1)")
114 .arg(escapedDirPaths.join(",")));
115 query.bindValue(":directory_deleted", deleted ? 1 : 0);
116 query.bindValue(":needs_verification", !verified ? 1 : 0);
117 if (!query.exec()) {
118 LOG_FAILED_QUERY(query) << "Updating directory status failed.";
119 }
120 }
121
markAsExisting(const QString & dirPath)122 void LibraryHashDAO::markAsExisting(const QString& dirPath) {
123 //qDebug() << "LibraryHashDAO::markExisting" << QThread::currentThread() << m_database.connectionName();
124 QSqlQuery query(m_database);
125 query.prepare("UPDATE LibraryHashes "
126 "SET directory_deleted=:directory_deleted "
127 "WHERE directory_path=:directory_path");
128 query.bindValue(":directory_deleted", 0);
129 query.bindValue(":directory_path", dirPath);
130 if (!query.exec()) {
131 LOG_FAILED_QUERY(query) << "Updating dirhash to mark as existing failed.";
132 }
133 }
134
invalidateAllDirectories()135 void LibraryHashDAO::invalidateAllDirectories() {
136 //qDebug() << "LibraryHashDAO::invalidateAllDirectories"
137 //<< QThread::currentThread() << m_database.connectionName();
138 QSqlQuery query(m_database);
139 query.prepare("UPDATE LibraryHashes "
140 "SET needs_verification=1");
141 if (!query.exec()) {
142 LOG_FAILED_QUERY(query)
143 << "Couldn't mark directories previously hashed as needing verification.";
144 }
145 }
146
markUnverifiedDirectoriesAsDeleted()147 void LibraryHashDAO::markUnverifiedDirectoriesAsDeleted() {
148 //qDebug() << "LibraryHashDAO::markUnverifiedDirectoriesAsDeleted"
149 //<< QThread::currentThread() << m_database.connectionName();
150 QSqlQuery query(m_database);
151 query.prepare("UPDATE LibraryHashes "
152 "SET directory_deleted=:directory_deleted "
153 "WHERE needs_verification=1");
154 query.bindValue(":directory_deleted", 1);
155 if (!query.exec()) {
156 LOG_FAILED_QUERY(query);
157 }
158 }
159
removeDeletedDirectoryHashes()160 void LibraryHashDAO::removeDeletedDirectoryHashes() {
161 QSqlQuery query(m_database);
162 query.prepare("DELETE FROM LibraryHashes WHERE "
163 "directory_deleted=:directory_deleted");
164 query.bindValue(":directory_deleted", 1);
165 if (!query.exec()) {
166 LOG_FAILED_QUERY(query);
167 }
168 }
169
getDeletedDirectories()170 QStringList LibraryHashDAO::getDeletedDirectories() {
171 QStringList result;
172 QSqlQuery query(m_database);
173 query.prepare("SELECT directory_path FROM LibraryHashes "
174 "WHERE directory_deleted=1");
175 if (!query.exec()) {
176 LOG_FAILED_QUERY(query);
177 }
178 const int directoryPathColumn = query.record().indexOf("directory_path");
179 while (query.next()) {
180 QString directory = query.value(directoryPathColumn).toString();
181 result << directory;
182 }
183 return result;
184 }
185