384
386
set_fts_tokenizer.bindValue(":pointer", QByteArray(
385
387
reinterpret_cast<const char*>(&sFTSTokenizer), sizeof(&sFTSTokenizer)));
386
388
if (!set_fts_tokenizer.exec()) {
387
qWarning() << "Couldn't register FTS3 tokenizer";
389
qLog(Warning) << "Couldn't register FTS3 tokenizer";
390
392
// We want Unicode aware LIKE clauses and FTS if possible.
482
484
QSqlQuery q("DETACH DATABASE :alias", db);
483
485
q.bindValue(":alias", database_name);
485
qWarning() << "Failed to detach database" << database_name;
487
qLog(Warning) << "Failed to detach database" << database_name;
489
491
if (!QFile::remove(filename)) {
490
qWarning() << "Failed to remove file" << filename;
492
qLog(Warning) << "Failed to remove file" << filename;
505
507
filename = ":/schema/schema.sql";
507
509
filename = QString(":/schema/schema-%1.sql").arg(version);
509
511
ScopedTransaction t(&db);
510
ExecFromFile(filename, db);
514
// This version used to do a bad job of converting filenames in the songs
515
// table to file:// URLs. Now we do it properly here instead.
517
UrlEncodeFilenameColumn("songs", db);
518
UrlEncodeFilenameColumn("playlist_items", db);
520
foreach (const QString& table, db.tables()) {
521
if (table.startsWith("device_") && table.endsWith("_songs")) {
522
UrlEncodeFilenameColumn(table, db);
527
ExecFromFile(filename, db, version - 1);
514
void Database::ExecFromFile(const QString &filename, QSqlDatabase &db) {
531
void Database::UrlEncodeFilenameColumn(const QString& table, QSqlDatabase& db) {
532
QSqlQuery select(QString("SELECT ROWID, filename FROM %1").arg(table), db);
533
QSqlQuery update(QString("UPDATE %1 SET filename=:filename WHERE ROWID=:id").arg(table), db);
536
if (CheckErrors(select)) return;
537
while (select.next()) {
538
const int rowid = select.value(0).toInt();
539
const QString filename = select.value(1).toString();
541
if (filename.isEmpty() || filename.contains("://")) {
545
const QUrl url = QUrl::fromLocalFile(filename);
547
update.bindValue(":filename", url.toEncoded());
548
update.bindValue(":id", rowid);
554
void Database::ExecFromFile(const QString &filename, QSqlDatabase &db,
555
int schema_version) {
515
556
// Open and read the database schema
516
557
QFile schema_file(filename);
517
558
if (!schema_file.open(QIODevice::ReadOnly))
518
559
qFatal("Couldn't open schema file %s", filename.toUtf8().constData());
519
ExecCommands(QString::fromUtf8(schema_file.readAll()), db);
560
ExecCommands(QString::fromUtf8(schema_file.readAll()), db, schema_version);
522
void Database::ExecCommands(const QString &schema, QSqlDatabase &db) {
563
void Database::ExecCommands(const QString& schema, QSqlDatabase& db,
564
int schema_version) {
523
565
// Run each command
524
566
QStringList commands(schema.split(";\n\n"));
526
568
// We don't want this list to reflect possible DB schema changes
527
569
// so we initialize it before executing any statements.
528
QStringList tables = SongsTables(db);
570
QStringList tables = SongsTables(db, schema_version);
530
572
foreach (const QString& command, commands) {
531
573
// There are now lots of "songs" tables that need to have the same schema:
533
575
// in the schema files to update all songs tables at once.
534
576
if (command.contains(kMagicAllSongsTables)) {
535
577
foreach (const QString& table, tables) {
536
qDebug() << "Updating" << table << "for" << kMagicAllSongsTables;
578
qLog(Info) << "Updating" << table << "for" << kMagicAllSongsTables;
537
579
QString new_command(command);
538
580
new_command.replace(kMagicAllSongsTables, table);
539
581
QSqlQuery query(db.exec(new_command));
614
if (schema_version > 29) {
615
// The playlist_items table became a songs table in version 29.
616
ret << "playlist_items";
575
622
bool Database::CheckErrors(const QSqlQuery& query) {
576
623
QSqlError last_error = query.lastError();
577
624
if (last_error.isValid()) {
578
qDebug() << "db error: " << last_error;
579
qDebug() << "faulty query: " << query.lastQuery();
580
qDebug() << "bound values: " << query.boundValues();
625
qLog(Error) << "db error: " << last_error;
626
qLog(Error) << "faulty query: " << query.lastQuery();
627
qLog(Error) << "bound values: " << query.boundValues();
582
629
emit Error("LibraryBackend: " + last_error.text());