78
78
return DatabaseAccess().db()->getUniqueHashVersion() >= uniqueHashVersion();
81
// --------------------------------------------------------------------------------------
83
class SchemaUpdater::Private
99
QVariant currentVersion;
100
QVariant currentRequiredVersion;
102
DatabaseBackend* backend;
104
DatabaseParameters parameters;
107
DatabaseAccess* access;
109
QString lastErrorMessage;
110
InitializationObserver* observer;
113
SchemaUpdater::SchemaUpdater(AlbumDB* const albumDB, DatabaseBackend* const backend, DatabaseParameters parameters)
116
d->backend = backend;
117
d->albumDB = albumDB;
118
d->parameters = parameters;
122
SchemaUpdater::~SchemaUpdater()
127
void SchemaUpdater::setDatabaseAccess(DatabaseAccess* const access)
81
132
const QString SchemaUpdater::getLastErrorMessage()
83
return m_LastErrorMessage;
86
void SchemaUpdater::setDatabaseAccess(DatabaseAccess* access)
91
SchemaUpdater::SchemaUpdater(AlbumDB* albumDB, DatabaseBackend* backend, DatabaseParameters parameters)
95
m_Parameters = parameters;
134
return d->lastErrorMessage;
100
137
bool SchemaUpdater::update()
129
166
void SchemaUpdater::setVersionSettings()
131
if (m_currentVersion.isValid())
168
if (d->currentVersion.isValid())
133
m_AlbumDB->setSetting("DBVersion", QString::number(m_currentVersion.toInt()));
170
d->albumDB->setSetting("DBVersion", QString::number(d->currentVersion.toInt()));
136
if (m_currentRequiredVersion.isValid())
173
if (d->currentRequiredVersion.isValid())
138
m_AlbumDB->setSetting("DBVersionRequired", QString::number(m_currentRequiredVersion.toInt()));
175
d->albumDB->setSetting("DBVersionRequired", QString::number(d->currentRequiredVersion.toInt()));
154
191
void SchemaUpdater::readVersionSettings()
156
m_currentVersion = safeToVariant(m_AlbumDB->getSetting("DBVersion"));
157
m_currentRequiredVersion = safeToVariant(m_AlbumDB->getSetting("DBVersionRequired"));
193
d->currentVersion = safeToVariant(d->albumDB->getSetting("DBVersion"));
194
d->currentRequiredVersion = safeToVariant(d->albumDB->getSetting("DBVersionRequired"));
160
void SchemaUpdater::setObserver(InitializationObserver* observer)
197
void SchemaUpdater::setObserver(InitializationObserver* const observer)
162
m_observer = observer;
199
d->observer = observer;
165
202
bool SchemaUpdater::startUpdates()
167
if (!m_Parameters.isSQLite())
204
if (!d->parameters.isSQLite())
169
206
// Do we have sufficient privileges
170
207
QStringList insufficientRights;
171
DatabasePrivilegesChecker checker(m_Parameters);
208
DatabasePrivilegesChecker checker(d->parameters);
173
210
if (!checker.checkPrivileges(insufficientRights))
180
217
insufficientRights.join(",\n")
183
m_LastErrorMessage=errorMsg;
220
d->lastErrorMessage=errorMsg;
187
m_observer->error(errorMsg);
188
m_observer->finishedSchemaUpdate(InitializationObserver::UpdateErrorMustAbort);
224
d->observer->error(errorMsg);
225
d->observer->finishedSchemaUpdate(InitializationObserver::UpdateErrorMustAbort);
195
232
// First step: do we have an empty database?
196
QStringList tables = m_Backend->tables();
233
QStringList tables = d->backend->tables();
198
235
if (tables.contains("Albums", Qt::CaseInsensitive))
200
237
// Find out schema version of db file
201
238
readVersionSettings();
202
kDebug() << "Have a database structure version " << m_currentVersion.toInt();
239
kDebug() << "Have a database structure version " << d->currentVersion.toInt();
204
241
// We absolutely require the DBVersion setting
205
if (!m_currentVersion.isValid())
242
if (!d->currentVersion.isValid())
207
244
// Something is damaged. Give up.
208
245
kError() << "DBVersion not available! Giving up schema upgrading.";
212
249
"The current database schema version cannot be verified. "
213
250
"Try to start with an empty database. "
215
m_LastErrorMessage=errorMsg;
252
d->lastErrorMessage=errorMsg;
219
m_observer->error(errorMsg);
220
m_observer->finishedSchemaUpdate(InitializationObserver::UpdateErrorMustAbort);
256
d->observer->error(errorMsg);
257
d->observer->finishedSchemaUpdate(InitializationObserver::UpdateErrorMustAbort);
226
263
// current version describes the current state of the schema in the db,
227
264
// schemaVersion is the version required by the program.
228
if (m_currentVersion.toInt() > schemaVersion())
265
if (d->currentVersion.toInt() > schemaVersion())
230
267
// trying to open a database with a more advanced than this SchemaUpdater supports
231
if (m_currentRequiredVersion.isValid() && m_currentRequiredVersion.toInt() <= schemaVersion())
268
if (d->currentRequiredVersion.isValid() && d->currentRequiredVersion.toInt() <= schemaVersion())
233
270
// version required may be less than current version
241
278
"(This means this digiKam version is too old, or the database format is too recent.) "
242
279
"Please use the more recent version of digiKam that you used before. "
244
m_LastErrorMessage=errorMsg;
281
d->lastErrorMessage=errorMsg;
248
m_observer->error(errorMsg);
249
m_observer->finishedSchemaUpdate(InitializationObserver::UpdateErrorMustAbort);
285
d->observer->error(errorMsg);
286
d->observer->finishedSchemaUpdate(InitializationObserver::UpdateErrorMustAbort);
274
311
// no schema changes.
275
312
// Version 4 writes "4", and from now on version x writes "x".
276
313
// Version 5 includes the schema changes from 0.9 to 0.10
314
// Version 6 brought new tables for history and ImageTagProperties, with version 2.0
315
// Version 7 brought the VideoMetadata table with 3.0
278
if (m_Parameters.isSQLite())
317
if (d->parameters.isSQLite())
280
QFileInfo currentDBFile(m_Parameters.databaseName);
319
QFileInfo currentDBFile(d->parameters.databaseName);
281
320
QFileInfo digikam3DB(currentDBFile.dir(), "digikam3.db");
282
321
QFileInfo digikamDB(currentDBFile.dir(), "digikam.db");
308
347
// No legacy handling: start with a fresh db
309
348
if (!createDatabase() || !createFilterSettings())
311
QString errorMsg = i18n("Failed to create tables in database.\n ")
312
+ m_Backend->lastError();
313
m_LastErrorMessage=errorMsg;
350
QString errorMsg = i18n("Failed to create tables in database.\n ") + d->backend->lastError();
351
d->lastErrorMessage = errorMsg;
317
m_observer->error(errorMsg);
318
m_observer->finishedSchemaUpdate(InitializationObserver::UpdateErrorMustAbort);
355
d->observer->error(errorMsg);
356
d->observer->finishedSchemaUpdate(InitializationObserver::UpdateErrorMustAbort);
328
366
bool SchemaUpdater::beginWrapSchemaUpdateStep()
330
if (!m_Backend->beginTransaction())
368
if (!d->backend->beginTransaction())
332
QFileInfo currentDBFile(m_Parameters.databaseName);
370
QFileInfo currentDBFile(d->parameters.databaseName);
333
371
QString errorMsg = i18n("Failed to open a database transaction on your database file \"%1\". "
334
372
"This is unusual. Please check that you can access the file and no "
335
373
"other process has currently locked the file. "
336
374
"If the problem persists you can get help from the digikam-devel@kde.org "
337
375
"mailing list. As well, please have a look at what digiKam prints on the console. ",
338
376
currentDBFile.filePath());
339
m_observer->error(errorMsg);
340
m_observer->finishedSchemaUpdate(InitializationObserver::UpdateErrorMustAbort);
377
d->observer->error(errorMsg);
378
d->observer->finishedSchemaUpdate(InitializationObserver::UpdateErrorMustAbort);
349
387
if (!stepOperationSuccess)
351
m_Backend->rollbackTransaction();
389
d->backend->rollbackTransaction();
355
393
// error or cancelled?
356
if (!m_observer->continueQuery())
394
if (!d->observer->continueQuery())
358
396
kDebug() << "Schema update cancelled by user";
360
else if (!m_setError)
398
else if (!d->setError)
362
m_observer->error(errorMsg);
363
m_observer->finishedSchemaUpdate(InitializationObserver::UpdateErrorMustAbort);
400
d->observer->error(errorMsg);
401
d->observer->finishedSchemaUpdate(InitializationObserver::UpdateErrorMustAbort);
370
408
kDebug() << "Success updating to v5";
371
m_Backend->commitTransaction();
409
d->backend->commitTransaction();
375
413
bool SchemaUpdater::makeUpdates()
377
kDebug() << "makeUpdates " << m_currentVersion.toInt() << " to " << schemaVersion();
415
kDebug() << "makeUpdates " << d->currentVersion.toInt() << " to " << schemaVersion();
379
if (m_currentVersion.toInt() < schemaVersion())
417
if (d->currentVersion.toInt() < schemaVersion())
381
if (m_currentVersion.toInt() < 5)
419
if (d->currentVersion.toInt() < 5)
383
421
if (!beginWrapSchemaUpdateStep())
407
445
setLegacySettingEntries();
410
if (m_currentVersion.toInt() < 6)
448
// Incremental updates, starting from version 5
449
for (int v = d->currentVersion.toInt(); v < schemaVersion(); v++)
451
int targetVersion = v + 1;
413
453
if (!beginWrapSchemaUpdateStep())
418
QString errorMsg = i18n("Failed to update the database schema from version 5 to version 6. "
458
QString errorMsg = i18n("Failed to update the database schema from version %1 to version %2. "
419
459
"Please read the error messages printed on the console and "
420
"report this error as a bug at bugs.kde.org. ");
460
"report this error as a bug at bugs.kde.org. ",
461
d->currentVersion.toInt(), targetVersion);
422
if (!endWrapSchemaUpdateStep(updateV5toV6(), errorMsg))
463
if (!endWrapSchemaUpdateStep(updateToVersion(targetVersion), errorMsg))
427
kDebug() << "Success updating to v6";
468
kDebug() << "Success updating to v" << d->currentVersion;
430
471
// add future updates here
436
void SchemaUpdater::defaultFilterSettings(QStringList& defaultImageFilter,
437
QStringList& defaultVideoFilter,
438
QStringList& defaultAudioFilter)
477
void SchemaUpdater::defaultFilterSettings(QStringList& defaultImageFilter, QStringList& defaultVideoFilter,
478
QStringList& defaultAudioFilter)
440
480
//NOTE for updating:
441
481
//When changing anything here, just increment filterSettingsVersion() so that the changes take effect
450
490
defaultImageFilter << KDcrawIface::KDcraw::rawFilesList();
452
defaultVideoFilter << "mpeg" << "mpg" << "mpo" << "mpe" // MPEG
453
<< "avi" << "mov" << "wmf" << "asf" << "mp4" << "3gp" << "wmv";
492
defaultVideoFilter << "mpeg" << "mpg" << "mpo" << "mpe" // MPEG
493
<< "avi" << "divx" // RIFF
494
<< "wmv" << "wmf" << "asf" // ASF
495
<< "mp4" << "3gp" << "mov" << "3g2" << "m4v" << "m2v" // QuickTime
496
<< "mkv" << "webm"; // Matroska
455
498
defaultAudioFilter << "ogg" << "mp3" << "wma" << "wav";
460
503
QStringList defaultImageFilter, defaultVideoFilter, defaultAudioFilter;
461
504
defaultFilterSettings(defaultImageFilter, defaultVideoFilter, defaultAudioFilter);
463
m_AlbumDB->setFilterSettings(defaultImageFilter, defaultVideoFilter, defaultAudioFilter);
464
m_AlbumDB->setSetting("FilterSettingsVersion", QString::number(filterSettingsVersion()));
465
m_AlbumDB->setSetting("DcrawFilterSettingsVersion", QString::number(KDcrawIface::KDcraw::rawFilesVersion()));
506
d->albumDB->setFilterSettings(defaultImageFilter, defaultVideoFilter, defaultAudioFilter);
507
d->albumDB->setSetting("FilterSettingsVersion", QString::number(filterSettingsVersion()));
508
d->albumDB->setSetting("DcrawFilterSettingsVersion", QString::number(KDcrawIface::KDcraw::rawFilesVersion()));
470
513
bool SchemaUpdater::updateFilterSettings()
472
QString filterVersion = m_AlbumDB->getSetting("FilterSettingsVersion");
473
QString dcrawFilterVersion = m_AlbumDB->getSetting("DcrawFilterSettingsVersion");
515
QString filterVersion = d->albumDB->getSetting("FilterSettingsVersion");
516
QString dcrawFilterVersion = d->albumDB->getSetting("DcrawFilterSettingsVersion");
476
519
filterVersion.toInt() < filterSettingsVersion() ||
492
535
setLegacySettingEntries();
494
m_currentVersion = schemaVersion();
537
d->currentVersion = schemaVersion();
496
539
// if we start with the V2 hash, version 6 is required
497
m_AlbumDB->setUniqueHashVersion(uniqueHashVersion());
498
m_currentRequiredVersion = schemaVersion();
540
d->albumDB->setUniqueHashVersion(uniqueHashVersion());
541
d->currentRequiredVersion = schemaVersion();
500
543
// Digikam for database version 5 can work with version 6, though not using the new features
501
m_currentRequiredVersion = 5;
544
d->currentRequiredVersion = 5;
511
554
bool SchemaUpdater::createTables()
513
return m_Backend->execDBAction(m_Backend->getDBAction("CreateDB"));
556
return d->backend->execDBAction(d->backend->getDBAction("CreateDB"));
516
559
bool SchemaUpdater::createIndices()
518
561
// TODO: see which more indices are needed
519
562
// create indices
520
return m_Backend->execDBAction(m_Backend->getDBAction("CreateIndices"));
563
return d->backend->execDBAction(d->backend->getDBAction("CreateIndices"));
523
566
bool SchemaUpdater::createTriggers()
525
return m_Backend->execDBAction(m_Backend->getDBAction(QString("CreateTriggers")));
568
return d->backend->execDBAction(d->backend->getDBAction(QString("CreateTriggers")));
528
571
bool SchemaUpdater::updateUniqueHash()
542
585
CollectionScanner scanner;
543
586
scanner.setNeedFileCount(true);
544
587
scanner.setUpdateHashHint();
547
m_observer->connectCollectionScanner(&scanner);
548
scanner.setObserver(m_observer);
590
d->observer->connectCollectionScanner(&scanner);
591
scanner.setObserver(d->observer);
550
593
scanner.completeScan();
552
595
// earlier digikam does not know about the hash
553
if (m_currentRequiredVersion.toInt() < 6)
596
if (d->currentRequiredVersion.toInt() < 6)
555
m_currentRequiredVersion = 6;
598
d->currentRequiredVersion = 6;
556
599
setVersionSettings();
562
bool SchemaUpdater::updateV5toV6()
605
bool SchemaUpdater::performUpdateToVersion(const QString& actionName, int newVersion, int newRequiredVersion)
566
if (!m_observer->continueQuery())
609
if (!d->observer->continueQuery())
571
m_observer->moreSchemaUpdateSteps(1);
614
d->observer->moreSchemaUpdateSteps(1);
574
DatabaseAction updateAction = m_Backend->getDBAction("UpdateSchemaFromV5ToV6");
617
DatabaseAction updateAction = d->backend->getDBAction(actionName);
575
618
if (updateAction.name.isNull())
577
620
QString errorMsg = i18n("The database update action cannot be found. Please ensure that "
579
622
"at the correct place. ");
582
if (!m_Backend->execDBAction(updateAction))
625
if (!d->backend->execDBAction(updateAction))
584
kError() << "Schema update to V6 failed!";
627
kError() << "Schema update to V" << newVersion << "failed!";
585
628
// resort to default error message, set above
591
if (!m_observer->continueQuery())
634
if (!d->observer->continueQuery())
596
m_observer->schemaUpdateProgress(i18n("Updated schema to version 6."));
639
d->observer->schemaUpdateProgress(i18n("Updated schema to version %1.", newVersion));
599
m_currentVersion = 6;
642
d->currentVersion = newVersion;
600
643
// Digikam for database version 5 can work with version 6, though not using the new features
601
644
// Note: We do not upgrade the uniqueHash
602
m_currentRequiredVersion = 5;
645
d->currentRequiredVersion = newRequiredVersion;
650
bool SchemaUpdater::updateToVersion(int targetVersion)
652
if (d->currentVersion != targetVersion-1)
654
kError() << "updateToVersion performs only incremental updates. Called to update from"
655
<< d->currentVersion << "to" << targetVersion << ", aborting.";
659
switch (targetVersion)
662
// Digikam for database version 5 can work with version 6, though not using the new features
663
// Note: We do not upgrade the uniqueHash
664
return performUpdateToVersion("UpdateSchemaFromV5ToV6", 6, 5);
666
// Digikam for database version 5 and 6 can work with version 7, though not using the support for video files.
667
return performUpdateToVersion("UpdateSchemaFromV6ToV7", 7, 5);
669
kError() << "Unsupported update to version" << targetVersion;
606
674
bool SchemaUpdater::copyV3toV4(const QString& digikam3DBPath, const QString& currentDBPath)
610
m_observer->moreSchemaUpdateSteps(2);
678
d->observer->moreSchemaUpdateSteps(2);
615
683
// We cannot use KIO here because KIO only works from the main thread
616
684
QFile oldFile(digikam3DBPath);
626
694
"Please make sure that the file can be copied, "
628
696
digikam3DBPath, currentDBPath, oldFile.errorString());
629
m_LastErrorMessage=errorMsg;
697
d->lastErrorMessage=errorMsg;
634
m_observer->error(errorMsg);
635
m_observer->finishedSchemaUpdate(InitializationObserver::UpdateErrorMustAbort);
702
d->observer->error(errorMsg);
703
d->observer->finishedSchemaUpdate(InitializationObserver::UpdateErrorMustAbort);
643
m_observer->schemaUpdateProgress(i18n("Copied database file"));
711
d->observer->schemaUpdateProgress(i18n("Copied database file"));
646
if (!m_Backend->open(m_Parameters))
714
if (!d->backend->open(d->parameters))
648
716
QString errorMsg = i18n("The old database file (\"%1\") has been copied "
649
717
"to the new location (\"%2\") but it cannot be opened. "
651
719
"starting with an empty database. ",
652
720
digikam3DBPath, currentDBPath);
654
m_LastErrorMessage=errorMsg;
722
d->lastErrorMessage=errorMsg;
659
m_observer->error(errorMsg);
660
m_observer->finishedSchemaUpdate(InitializationObserver::UpdateErrorMustAbort);
727
d->observer->error(errorMsg);
728
d->observer->finishedSchemaUpdate(InitializationObserver::UpdateErrorMustAbort);
668
m_observer->schemaUpdateProgress(i18n("Opened new database file"));
736
d->observer->schemaUpdateProgress(i18n("Opened new database file"));
671
m_currentVersion = 4;
739
d->currentVersion = 4;
675
743
bool SchemaUpdater::updateV2toV4(const QString& sqlite2DBPath)
679
m_observer->moreSchemaUpdateSteps(1);
747
d->observer->moreSchemaUpdateSteps(1);
682
if (upgradeDB_Sqlite2ToSqlite3(m_AlbumDB, m_Backend, sqlite2DBPath))
750
if (upgradeDB_Sqlite2ToSqlite3(d->albumDB, d->backend, sqlite2DBPath))
684
m_currentVersion = 4;
752
d->currentVersion = 4;
689
757
QString errorMsg = i18n("Could not update from the old SQLite2 file (\"%1\"). "
690
758
"Please delete this file and try again, "
691
759
"starting with an empty database. ", sqlite2DBPath);
692
m_LastErrorMessage=errorMsg;
760
d->lastErrorMessage=errorMsg;
696
m_observer->error(errorMsg);
697
m_observer->finishedSchemaUpdate(InitializationObserver::UpdateErrorMustAbort);
764
d->observer->error(errorMsg);
765
d->observer->finishedSchemaUpdate(InitializationObserver::UpdateErrorMustAbort);
703
771
// FIXME: We are not returning anything, if we land in this section of the code!
706
m_observer->schemaUpdateProgress(i18n("Updated from 0.7 database"));
774
d->observer->schemaUpdateProgress(i18n("Updated from 0.7 database"));
743
811
kDebug() << "updateV4toV6";
747
if (!m_observer->continueQuery())
815
if (!d->observer->continueQuery())
752
m_observer->moreSchemaUpdateSteps(11);
820
d->observer->moreSchemaUpdateSteps(11);
755
823
// This update was introduced from digikam version 0.9 to digikam 0.10
756
824
// We operator on an SQLite3 database under a transaction (which will be rolled back on error)
758
826
// --- Make space for new tables ---
759
if (!m_Backend->execSql(QString("ALTER TABLE Albums RENAME TO AlbumsV3;")))
764
if (!m_Backend->execSql(QString("ALTER TABLE Images RENAME TO ImagesV3;")))
769
if (!m_Backend->execSql(QString("ALTER TABLE Searches RENAME TO SearchesV3;")))
827
if (!d->backend->execSql(QString("ALTER TABLE Albums RENAME TO AlbumsV3;")))
832
if (!d->backend->execSql(QString("ALTER TABLE Images RENAME TO ImagesV3;")))
837
if (!d->backend->execSql(QString("ALTER TABLE Searches RENAME TO SearchesV3;")))
775
843
// --- Drop some triggers and indices ---
777
845
// Don't check for errors here. The "IF EXISTS" clauses seem not supported in SQLite
778
m_Backend->execSql(QString("DROP TRIGGER delete_album;"));
779
m_Backend->execSql(QString("DROP TRIGGER delete_image;"));
780
m_Backend->execSql(QString("DROP TRIGGER delete_tag;"));
781
m_Backend->execSql(QString("DROP TRIGGER insert_tagstree;"));
782
m_Backend->execSql(QString("DROP TRIGGER delete_tagstree;"));
783
m_Backend->execSql(QString("DROP TRIGGER move_tagstree;"));
784
m_Backend->execSql(QString("DROP INDEX dir_index;"));
785
m_Backend->execSql(QString("DROP INDEX tag_index;"));
846
d->backend->execSql(QString("DROP TRIGGER delete_album;"));
847
d->backend->execSql(QString("DROP TRIGGER delete_image;"));
848
d->backend->execSql(QString("DROP TRIGGER delete_tag;"));
849
d->backend->execSql(QString("DROP TRIGGER insert_tagstree;"));
850
d->backend->execSql(QString("DROP TRIGGER delete_tagstree;"));
851
d->backend->execSql(QString("DROP TRIGGER move_tagstree;"));
852
d->backend->execSql(QString("DROP INDEX dir_index;"));
853
d->backend->execSql(QString("DROP INDEX tag_index;"));
789
if (!m_observer->continueQuery())
857
if (!d->observer->continueQuery())
794
m_observer->schemaUpdateProgress(i18n("Prepared table creation"));
862
d->observer->schemaUpdateProgress(i18n("Prepared table creation"));
797
865
kDebug() << "Dropped triggers";
826
894
QString errorMsg = i18n("No album library path has been found in the configuration file. "
827
895
"Giving up the schema updating process. "
828
896
"Please try with an empty database, or repair your configuration.");
829
m_LastErrorMessage=errorMsg;
897
d->lastErrorMessage=errorMsg;
834
m_observer->error(errorMsg);
835
m_observer->finishedSchemaUpdate(InitializationObserver::UpdateErrorMustAbort);
902
d->observer->error(errorMsg);
903
d->observer->finishedSchemaUpdate(InitializationObserver::UpdateErrorMustAbort);
852
920
"The database updating process will now be aborted because we do not want "
853
921
"to create a new database based on false assumptions from a broken installation.",
854
922
albumLibraryPath);
855
m_LastErrorMessage=errorMsg;
923
d->lastErrorMessage=errorMsg;
860
m_observer->error(errorMsg);
861
m_observer->finishedSchemaUpdate(InitializationObserver::UpdateErrorMustAbort);
928
d->observer->error(errorMsg);
929
d->observer->finishedSchemaUpdate(InitializationObserver::UpdateErrorMustAbort);
869
if (!m_observer->continueQuery())
937
if (!d->observer->continueQuery())
874
m_observer->schemaUpdateProgress(i18n("Configured one album root"));
942
d->observer->schemaUpdateProgress(i18n("Configured one album root"));
877
945
kDebug() << "Inserted album root";
879
947
// --- With the album root, populate albums ---
881
if (!m_Backend->execSql(QString(
949
if (!d->backend->execSql(QString(
882
950
"REPLACE INTO Albums "
883
951
" (id, albumRoot, relativePath, date, caption, collection, icon) "
884
952
"SELECT id, ?, url, date, caption, collection, icon "
895
if (!m_observer->continueQuery())
963
if (!d->observer->continueQuery())
900
m_observer->schemaUpdateProgress(i18n("Imported albums"));
968
d->observer->schemaUpdateProgress(i18n("Imported albums"));
903
971
kDebug() << "Populated albums";
905
973
// --- Add images ---
907
if (!m_Backend->execSql(QString(
975
if (!d->backend->execSql(QString(
908
976
"REPLACE INTO Images "
909
977
" (id, album, name, status, category, modificationDate, fileSize, uniqueHash) "
910
978
"SELECT id, dirid, name, ?, ?, NULL, NULL, NULL"
926
994
// remove orphan images that would not be removed by CollectionScanner
927
m_Backend->execSql(QString("DELETE FROM Images WHERE album NOT IN (SELECT id FROM Albums);"));
995
d->backend->execSql(QString("DELETE FROM Images WHERE album NOT IN (SELECT id FROM Albums);"));
931
if (!m_observer->continueQuery())
999
if (!d->observer->continueQuery())
936
m_observer->schemaUpdateProgress(i18n("Imported images information"));
1004
d->observer->schemaUpdateProgress(i18n("Imported images information"));
939
1007
kDebug() << "Populated Images";
941
1009
// --- Port searches ---
943
if (!m_Backend->execSql(QString(
1011
if (!d->backend->execSql(QString(
944
1012
"REPLACE INTO Searches "
945
1013
" (id, type, name, query) "
946
1014
"SELECT id, ?, name, url"
970
1038
if (url.queryItem("type") == QString("datesearch"))
972
m_AlbumDB->updateSearch((*it).id, DatabaseSearch::TimeLineSearch, name, query);
1040
d->albumDB->updateSearch((*it).id, DatabaseSearch::TimeLineSearch, name, query);
974
1042
else if (url.queryItem("1.key") == "keyword")
976
m_AlbumDB->updateSearch((*it).id, DatabaseSearch::KeywordSearch, name, query);
1044
d->albumDB->updateSearch((*it).id, DatabaseSearch::KeywordSearch, name, query);
980
m_AlbumDB->updateSearch((*it).id, DatabaseSearch::AdvancedSearch, name, query);
1048
d->albumDB->updateSearch((*it).id, DatabaseSearch::AdvancedSearch, name, query);
1011
1079
configVideoFilter.subtract(defaultVideoFilter.toSet());
1012
1080
configAudioFilter.subtract(defaultAudioFilter.toSet());
1014
m_AlbumDB->setUserFilterSettings(configImageFilter.toList(), configVideoFilter.toList(), configAudioFilter.toList());
1082
d->albumDB->setUserFilterSettings(configImageFilter.toList(), configVideoFilter.toList(), configAudioFilter.toList());
1015
1083
kDebug() << "Set initial filter settings with user settings" << configImageFilter;
1019
if (!m_observer->continueQuery())
1087
if (!d->observer->continueQuery())
1024
m_observer->schemaUpdateProgress(i18n("Initialized and imported file suffix filter"));
1092
d->observer->schemaUpdateProgress(i18n("Initialized and imported file suffix filter"));
1027
1095
// --- do a full scan ---
1029
1097
CollectionScanner scanner;
1033
m_observer->connectCollectionScanner(&scanner);
1034
scanner.setObserver(m_observer);
1101
d->observer->connectCollectionScanner(&scanner);
1102
scanner.setObserver(d->observer);
1037
1105
scanner.completeScan();
1041
if (!m_observer->continueQuery())
1109
if (!d->observer->continueQuery())
1046
m_observer->schemaUpdateProgress(i18n("Did the initial full scan"));
1114
d->observer->schemaUpdateProgress(i18n("Did the initial full scan"));
1049
1117
// --- Port date, comment and rating (_after_ the scan) ---
1051
1119
// Port ImagesV3.date -> ImageInformation.creationDate
1052
if (!m_Backend->execSql(QString(
1120
if (!d->backend->execSql(QString(
1053
1121
"UPDATE ImageInformation SET "
1054
1122
" creationDate=(SELECT datetime FROM ImagesV3 WHERE ImagesV3.id=ImageInformation.imageid) "
1055
"WHERE imageid IN (SELECT id FROM ImagesV3);"
1123
"WHERE imageid IN (SELECT id FROM ImagesV3);")
1065
if (!m_observer->continueQuery())
1132
if (!d->observer->continueQuery())
1070
m_observer->schemaUpdateProgress(i18n("Imported creation dates"));
1137
d->observer->schemaUpdateProgress(i18n("Imported creation dates"));
1073
1140
// Port ImagesV3.comment to ImageComments
1075
1142
// An author of NULL will inhibt the UNIQUE restriction to take effect (but #189080). Work around.
1076
m_Backend->execSql(QString(
1143
d->backend->execSql(QString(
1077
1144
"DELETE FROM ImageComments WHERE "
1078
1145
"type=? AND language=? AND author IS NULL "
1079
1146
"AND imageid IN ( SELECT id FROM ImagesV3 ); "),
1080
1147
(int)DatabaseComment::Comment, QString("x-default"));
1082
if (!m_Backend->execSql(QString(
1149
if (!d->backend->execSql(QString(
1083
1150
"REPLACE INTO ImageComments "
1084
1151
" (imageid, type, language, comment) "
1085
1152
"SELECT id, ?, ?, caption FROM ImagesV3;"
1095
if (!m_observer->continueQuery())
1162
if (!d->observer->continueQuery())
1100
m_observer->schemaUpdateProgress(i18n("Imported comments"));
1167
d->observer->schemaUpdateProgress(i18n("Imported comments"));
1103
1170
// Port rating storage in ImageProperties to ImageInformation
1104
if (!m_Backend->execSql(QString(
1171
if (!d->backend->execSql(QString(
1105
1172
"UPDATE ImageInformation SET "
1106
1173
" rating=(SELECT value FROM ImageProperties "
1107
1174
" WHERE ImageInformation.imageid=ImageProperties.imageid AND ImageProperties.property=?) "
1116
m_Backend->execSql(QString("DELETE FROM ImageProperties WHERE property=?;"), QString("Rating"));
1117
m_Backend->execSql(QString("UPDATE ImageInformation SET rating=0 WHERE rating<0;"));
1183
d->backend->execSql(QString("DELETE FROM ImageProperties WHERE property=?;"), QString("Rating"));
1184
d->backend->execSql(QString("UPDATE ImageInformation SET rating=0 WHERE rating<0;"));
1121
if (!m_observer->continueQuery())
1188
if (!d->observer->continueQuery())
1126
m_observer->schemaUpdateProgress(i18n("Imported ratings"));
1193
d->observer->schemaUpdateProgress(i18n("Imported ratings"));
1129
1196
// --- Drop old tables ---
1131
m_Backend->execSql(QString("DROP TABLE ImagesV3;"));
1132
m_Backend->execSql(QString("DROP TABLE AlbumsV3;"));
1133
m_Backend->execSql(QString("DROP TABLE SearchesV3;"));
1198
d->backend->execSql(QString("DROP TABLE ImagesV3;"));
1199
d->backend->execSql(QString("DROP TABLE AlbumsV3;"));
1200
d->backend->execSql(QString("DROP TABLE SearchesV3;"));
1137
m_observer->schemaUpdateProgress(i18n("Dropped v3 tables"));
1204
d->observer->schemaUpdateProgress(i18n("Dropped v3 tables"));
1140
m_currentRequiredVersion = 5;
1141
m_currentVersion = 6;
1207
d->currentRequiredVersion = 5;
1208
d->currentVersion = 6;
1142
1209
kDebug() << "Returning true from updating to 5";
1146
1213
void SchemaUpdater::setLegacySettingEntries()
1148
m_AlbumDB->setSetting("preAlpha010Update1", "true");
1149
m_AlbumDB->setSetting("preAlpha010Update2", "true");
1150
m_AlbumDB->setSetting("preAlpha010Update3", "true");
1151
m_AlbumDB->setSetting("beta010Update1", "true");
1152
m_AlbumDB->setSetting("beta010Update2", "true");
1215
d->albumDB->setSetting("preAlpha010Update1", "true");
1216
d->albumDB->setSetting("preAlpha010Update2", "true");
1217
d->albumDB->setSetting("preAlpha010Update3", "true");
1218
d->albumDB->setSetting("beta010Update1", "true");
1219
d->albumDB->setSetting("beta010Update2", "true");
1155
1222
// ---------- Legacy code ------------
1158
1224
void SchemaUpdater::preAlpha010Update1()
1160
QString hasUpdate = m_AlbumDB->getSetting("preAlpha010Update1");
1226
QString hasUpdate = d->albumDB->getSetting("preAlpha010Update1");
1162
1228
if (!hasUpdate.isNull())
1167
if (!m_Backend->execSql(QString("ALTER TABLE Searches RENAME TO SearchesV3;")))
1233
if (!d->backend->execSql(QString("ALTER TABLE Searches RENAME TO SearchesV3;")))
1172
if ( !m_Backend->execSql(
1238
if ( !d->backend->execSql(
1173
1239
QString( "CREATE TABLE IF NOT EXISTS Searches \n"
1174
1240
" (id INTEGER PRIMARY KEY, \n"
1175
1241
" type INTEGER, \n"
1202
1268
if (url.queryItem("type") == QString("datesearch"))
1204
m_AlbumDB->updateSearch((*it).id, DatabaseSearch::TimeLineSearch, (*it).name, query);
1270
d->albumDB->updateSearch((*it).id, DatabaseSearch::TimeLineSearch, (*it).name, query);
1206
1272
else if (url.queryItem("1.key") == "keyword")
1208
m_AlbumDB->updateSearch((*it).id, DatabaseSearch::KeywordSearch, (*it).name, query);
1274
d->albumDB->updateSearch((*it).id, DatabaseSearch::KeywordSearch, (*it).name, query);
1212
m_AlbumDB->updateSearch((*it).id, DatabaseSearch::AdvancedSearch, (*it).name, query);
1278
d->albumDB->updateSearch((*it).id, DatabaseSearch::AdvancedSearch, (*it).name, query);
1216
m_Backend->execSql(QString("DROP TABLE SearchesV3;"));
1282
d->backend->execSql(QString("DROP TABLE SearchesV3;"));
1218
m_AlbumDB->setSetting("preAlpha010Update1", "true");
1284
d->albumDB->setSetting("preAlpha010Update1", "true");
1221
1287
void SchemaUpdater::preAlpha010Update2()
1223
QString hasUpdate = m_AlbumDB->getSetting("preAlpha010Update2");
1289
QString hasUpdate = d->albumDB->getSetting("preAlpha010Update2");
1225
1291
if (!hasUpdate.isNull())
1230
if (!m_Backend->execSql(QString("ALTER TABLE ImagePositions RENAME TO ImagePositionsTemp;")))
1235
if (!m_Backend->execSql(QString("ALTER TABLE ImageMetadata RENAME TO ImageMetadataTemp;")))
1296
if (!d->backend->execSql(QString("ALTER TABLE ImagePositions RENAME TO ImagePositionsTemp;")))
1301
if (!d->backend->execSql(QString("ALTER TABLE ImageMetadata RENAME TO ImageMetadataTemp;")))
1306
d->backend->execSql(
1241
1307
QString("CREATE TABLE ImagePositions\n"
1242
1308
" (imageid INTEGER PRIMARY KEY,\n"
1243
1309
" latitude TEXT,\n"
1251
1317
" accuracy REAL,\n"
1252
1318
" description TEXT);") );
1254
m_Backend->execSql(QString(
1320
d->backend->execSql(QString(
1255
1321
"REPLACE INTO ImagePositions "
1256
1322
" (imageid, latitude, latitudeNumber, longitude, longitudeNumber, "
1257
1323
" altitude, orientation, tilt, roll, accuracy, description) "
1279
1345
" subjectDistance REAL,\n"
1280
1346
" subjectDistanceCategory INTEGER);") );
1282
m_Backend->execSql( QString("INSERT INTO ImageMetadata "
1348
d->backend->execSql( QString("INSERT INTO ImageMetadata "
1283
1349
" (imageid, make, model, lens, aperture, focalLength, focalLength35, "
1284
1350
" exposureTime, exposureProgram, exposureMode, sensitivity, flash, whiteBalance, "
1285
1351
" whiteBalanceColorTemperature, meteringMode, subjectDistance, subjectDistanceCategory) "
1288
1354
" whiteBalanceColorTemperature, meteringMode, subjectDistance, subjectDistanceCategory "
1289
1355
"FROM ImageMetadataTemp;"));
1291
m_Backend->execSql(QString("DROP TABLE ImagePositionsTemp;"));
1292
m_Backend->execSql(QString("DROP TABLE ImageMetadataTemp;"));
1357
d->backend->execSql(QString("DROP TABLE ImagePositionsTemp;"));
1358
d->backend->execSql(QString("DROP TABLE ImageMetadataTemp;"));
1294
m_AlbumDB->setSetting("preAlpha010Update2", "true");
1360
d->albumDB->setSetting("preAlpha010Update2", "true");
1297
1363
void SchemaUpdater::preAlpha010Update3()
1299
QString hasUpdate = m_AlbumDB->getSetting("preAlpha010Update3");
1365
QString hasUpdate = d->albumDB->getSetting("preAlpha010Update3");
1301
1367
if (!hasUpdate.isNull())
1306
m_Backend->execSql(QString("DROP TABLE ImageCopyright;"));
1372
d->backend->execSql(QString("DROP TABLE ImageCopyright;"));
1373
d->backend->execSql(
1308
1374
QString("CREATE TABLE ImageCopyright\n"
1309
1375
" (imageid INTEGER,\n"
1310
1376
" property TEXT,\n"
1313
1379
" UNIQUE(imageid, property, value, extraValue));")
1316
m_AlbumDB->setSetting("preAlpha010Update3", "true");
1382
d->albumDB->setSetting("preAlpha010Update3", "true");
1319
1385
void SchemaUpdater::beta010Update1()
1321
QString hasUpdate = m_AlbumDB->getSetting("beta010Update1");
1387
QString hasUpdate = d->albumDB->getSetting("beta010Update1");
1323
1389
if (!hasUpdate.isNull())
1368
1434
// force rescan and creation of ImageInformation entry for videos and audio
1369
m_Backend->execSql("DELETE FROM Images WHERE category=2 OR category=3;");
1435
d->backend->execSql("DELETE FROM Images WHERE category=2 OR category=3;");
1371
m_AlbumDB->setSetting("beta010Update2", "true");
1437
d->albumDB->setSetting("beta010Update2", "true");
1374
1440
bool SchemaUpdater::createTablesV3()
1376
if (!m_Backend->execSql( QString("CREATE TABLE Albums\n"
1442
if (!d->backend->execSql( QString("CREATE TABLE Albums\n"
1377
1443
" (id INTEGER PRIMARY KEY,\n"
1378
1444
" url TEXT NOT NULL UNIQUE,\n"
1379
1445
" date DATE NOT NULL,\n"
1450
1516
// TODO: see which more indices are needed
1451
1517
// create indices
1452
m_Backend->execSql("CREATE INDEX dir_index ON Images (dirid);");
1453
m_Backend->execSql("CREATE INDEX tag_index ON ImageTags (tagid);");
1518
d->backend->execSql("CREATE INDEX dir_index ON Images (dirid);");
1519
d->backend->execSql("CREATE INDEX tag_index ON ImageTags (tagid);");
1455
1521
// create triggers
1457
1523
// trigger: delete from Images/ImageTags/ImageProperties
1458
1524
// if Album has been deleted
1459
m_Backend->execSql("CREATE TRIGGER delete_album DELETE ON Albums\n"
1525
d->backend->execSql("CREATE TRIGGER delete_album DELETE ON Albums\n"
1461
1527
" DELETE FROM ImageTags\n"
1462
1528
" WHERE imageid IN (SELECT id FROM Images WHERE dirid=OLD.id);\n"
1483
1549
// trigger: delete from ImageTags if Tag has been deleted
1484
m_Backend->execSql("CREATE TRIGGER delete_tag DELETE ON Tags\n"
1550
d->backend->execSql("CREATE TRIGGER delete_tag DELETE ON Tags\n"
1486
1552
" DELETE FROM ImageTags WHERE tagid=OLD.id;\n"
1489
1555
// trigger: insert into TagsTree if Tag has been added
1490
m_Backend->execSql("CREATE TRIGGER insert_tagstree AFTER INSERT ON Tags\n"
1556
d->backend->execSql("CREATE TRIGGER insert_tagstree AFTER INSERT ON Tags\n"
1492
1558
" INSERT INTO TagsTree\n"
1493
1559
" SELECT NEW.id, NEW.pid\n"