| 4315 | if (dbver == "1224") |
| 4316 | { |
| 4317 | // Fix data corruption caused by a data conversion issue in the |
| 4318 | // original implementation of the 1215-1216 database upgrade |
| 4319 | MSqlQuery peopleQuery(MSqlQuery::InitCon()); |
| 4320 | peopleQuery.prepare("SELECT person FROM people " |
| 4321 | " WHERE LENGTH(name) = 128;"); |
| 4322 | if (peopleQuery.exec() && peopleQuery.isActive() && |
| 4323 | peopleQuery.size() > 0) |
| 4324 | { |
| 4325 | MSqlQuery duplicateQuery(MSqlQuery::InitCon()); |
| 4326 | duplicateQuery.prepare("SELECT person " |
| 4327 | " FROM people " |
| 4328 | " WHERE name = REPLACE( " |
| 4329 | " (SELECT name FROM people " |
| 4330 | " WHERE person = :ID), " |
| 4331 | " '\\0', '');"); |
| 4332 | // Rather than build an updateQuery with the table name inserted in |
| 4333 | // the QString used to build the SQL and reusing it for credits and |
| 4334 | // recordedcredits, use 2 prepared queries since we'll be executing |
| 4335 | // the updates thousands (or tens of thousands) of times each |
| 4336 | MSqlQuery updateCreditsQuery(MSqlQuery::InitCon()); |
| 4337 | updateCreditsQuery.prepare("UPDATE credits " |
| 4338 | " SET person = :ID " |
| 4339 | " WHERE person = :DUPLICATEID;"); |
| 4340 | MSqlQuery updateRecordedCreditsQuery(MSqlQuery::InitCon()); |
| 4341 | updateRecordedCreditsQuery.prepare("UPDATE recordedcredits " |
| 4342 | " SET person = :ID " |
| 4343 | " WHERE person = :DUPLICATEID;"); |
| 4344 | MSqlQuery deleteQuery(MSqlQuery::InitCon()); |
| 4345 | deleteQuery.prepare("DELETE FROM people " |
| 4346 | " WHERE person = :ID;"); |
| 4347 | MSqlQuery updatePeopleQuery(MSqlQuery::InitCon()); |
| 4348 | updatePeopleQuery.prepare("UPDATE people " |
| 4349 | " SET name = REPLACE(name, '\\0', '') " |
| 4350 | " WHERE person = :ID;"); |
| 4351 | VERBOSE(VB_IMPORTANT, "Fixing corrupt data in the people table. " |
| 4352 | "This may take a while. Please do not stop " |
| 4353 | "the program until it has finished."); |
| 4354 | while (peopleQuery.next()) |
| 4355 | { |
| 4356 | int person = peopleQuery.value(0).toInt(); |
| 4357 | duplicateQuery.bindValue(":ID", person); |
| 4358 | if (duplicateQuery.exec() && duplicateQuery.isActive() && |
| 4359 | duplicateQuery.size() > 0) |
| 4360 | { |
| 4361 | // Duplicate record, replace references and remove dup |
| 4362 | while (duplicateQuery.next()) |
| 4363 | { |
| 4364 | int duplicatePerson = duplicateQuery.value(0).toInt(); |
| 4365 | bool success = true; |
| 4366 | updateCreditsQuery.bindValue(":ID", person); |
| 4367 | updateCreditsQuery.bindValue(":DUPLICATEID", |
| 4368 | duplicatePerson); |
| 4369 | if (!updateCreditsQuery.exec()) |
| 4370 | { |
| 4371 | success = false; |
| 4372 | MythDB::DBError(QString("Updating references to " |
| 4373 | "duplicate person record " |
| 4374 | "in credits: %1 -> %2") |
| 4375 | .arg(duplicatePerson) |
| 4376 | .arg(person), |
| 4377 | updateCreditsQuery); |
| 4378 | } |
| 4379 | updateRecordedCreditsQuery.bindValue(":ID", person); |
| 4380 | updateRecordedCreditsQuery.bindValue(":DUPLICATEID", |
| 4381 | duplicatePerson); |
| 4382 | if (!updateRecordedCreditsQuery.exec()) |
| 4383 | { |
| 4384 | success = false; |
| 4385 | MythDB::DBError(QString("Updating references to " |
| 4386 | "duplicate person record " |
| 4387 | "in recordedcredits: " |
| 4388 | "%1 -> %2") |
| 4389 | .arg(duplicatePerson) |
| 4390 | .arg(person), |
| 4391 | updateRecordedCreditsQuery); |
| 4392 | } |
| 4393 | if (success) |
| 4394 | { |
| 4395 | // We need to keep the original person and fix the |
| 4396 | // corrupt name since we may have more than one |
| 4397 | // duplicate in the wild (with varying numbers |
| 4398 | // of null-pad characters) if users have edited |
| 4399 | // the database directly |
| 4400 | deleteQuery.bindValue(":ID", duplicatePerson); |
| 4401 | if (!deleteQuery.exec()) |
| 4402 | { |
| 4403 | MythDB::DBError( |
| 4404 | QString("Deleting duplicate person " |
| 4405 | "record: %1").arg(duplicatePerson), |
| 4406 | deleteQuery); |
| 4407 | } |
| 4408 | // This cannot be done outside the duplicate-check |
| 4409 | // conditional, even though it's done in the if and |
| 4410 | // the else because it's only safe to do if success |
| 4411 | updatePeopleQuery.bindValue(":ID", person); |
| 4412 | if (!updatePeopleQuery.exec()) |
| 4413 | { |
| 4414 | MythDB::DBError( |
| 4415 | QString("Fixing corrupt people.name " |
| 4416 | "for person: %1)").arg(person), |
| 4417 | updatePeopleQuery); |
| 4418 | } |
| 4419 | } |
| 4420 | } |
| 4421 | } |
| 4422 | else |
| 4423 | { |
| 4424 | // Not duplicated, corrupt record, fix name |
| 4425 | updatePeopleQuery.bindValue(":ID", person); |
| 4426 | if (!updatePeopleQuery.exec()) |
| 4427 | { |
| 4428 | MythDB::DBError(QString("Fixing corrupt people.name " |
| 4429 | "for person: %1)").arg(person), |
| 4430 | updatePeopleQuery); |
| 4431 | } |
| 4432 | } |
| 4433 | } |
| 4434 | VERBOSE(VB_IMPORTANT, "Finished fixing corrupt data in the people " |
| 4435 | "table."); |
| 4436 | } |
| 4437 | |
| 4438 | const char *updates[] = { |
| 4439 | "UPDATE programgenres SET genre = REPLACE(genre, '\\0', '');", |
| 4440 | "UPDATE programrating SET system = REPLACE(system, '\\0', ''), " |
| 4441 | " rating = REPLACE(rating, '\\0', '');", |
| 4442 | "UPDATE recordedrating SET system = REPLACE(system, '\\0', ''), " |
| 4443 | " rating = REPLACE(rating, '\\0', '');", |
| 4444 | NULL |
| 4445 | }; |
| 4446 | if (!performActualUpdate(updates, "1225", dbver)) |
| 4447 | return false; |
| 4448 | } |
| 4449 | |