Commit 61c09742 authored by Karel Slaný's avatar Karel Slaný

Modify _dmFileSize column in files db to hold real file sizes.

The conversion is preformed once when database is accessed.
parent 0841f98e
......@@ -318,7 +318,7 @@ namespace FlsTbl {
{"dmFormat", DB_TEXT},
{"dmFileMetaType", DB_TEXT},
{"dmEncodedContent", DB_TEXT},
{"_dmFileSize", DB_TEXT},
{"_dmFileSize", DB_INTEGER},
{"_dmDownloadDate", DB_DATETIME},
{"_icon", DB_TEXT}
/*
......@@ -348,7 +348,7 @@ namespace FlsTbl {
{"dmFormat", {DB_TEXT, ""}},
{"dmFileMetaType", {DB_TEXT, ""}},
{"dmEncodedContent", {DB_TEXT, ""}},
{"_dmFileSize", {DB_TEXT, ""}},
{"_dmFileSize", {DB_INTEGER, ""}},
{"_dmDownloadDate", {DB_DATETIME, ""}},
{"_icon", {DB_TEXT, ""}}
};
......
......@@ -296,8 +296,7 @@ bool FileDb::insertUpdateFileIntoDb(qint64 dmId, const Isds::Document &document)
query.bindValue(":dmFileMetaType",
Isds::m_fileMetaType2Variant(document.fileMetaType()));
query.bindValue(":dmEncodedContent", document.base64Content());
query.bindValue(":_dmFileSize",
approximateDataSize(document.binaryContent().size()));
query.bindValue(":_dmFileSize", document.binaryContent().size());
query.bindValue(":_dmDownloadDate",
QDate::currentDate().toString(DATE_DB_FORMAT));
query.bindValue(":_icon",
......@@ -377,3 +376,198 @@ QList<class SQLiteTbl *> FileDb::listOfTables(void) const
tables.append(&flsTbl);
return tables;
}
/*!
* @brief Check whether file size is held in an integer-type column.
*
* @param[in] db Database object.
* @return 1 if file size is an INTEGER type
* @return 0 if file size is not an integer type (probably TEXT)
* @return -1 on any error
*/
static
int fileSizeColIsInt(QSqlDatabase &db)
{
QSqlQuery query(db);
QString queryStr("PRAGMA table_info(files)");
if (!query.prepare(queryStr)) {
logErrorNL("Cannot prepare SQL query: %s",
query.lastError().text().toUtf8().constData());
return -1;
}
if (query.exec() && query.isActive()) {
query.first();
while (query.isValid()) {
const int colNum = query.value(0).toInt();
if (colNum == 9) {
const QString colName(query.value(1).toString());
if (colName == QStringLiteral("_dmFileSize")) {
const QString colType(query.value(2).toString());
if (Q_UNLIKELY(colType.isEmpty())) {
return -1;
}
return (colType == QStringLiteral("INTEGER")) ? 1 : 0;
} else {
/* The column with the index 9 is not _dmFileSize. */
return -1;
}
}
query.next();
}
}
return -1;
}
/*!
* @brief Recompute the binary file sizes.
*
* @param[in] db Database object.
* @return True on success.
*/
static
bool fileSizeColRecompute(QSqlDatabase &db)
{
QSqlQuery query(db);
QString queryStr;
QList<int> ids;
queryStr = "SELECT id FROM files";
if (Q_UNLIKELY(!query.prepare(queryStr) || !query.exec() || !query.isActive())) {
logErrorNL("Cannot prepare or execute SQL query: %s",
query.lastError().text().toUtf8().constData());
return false;
}
query.first();
while (query.isValid()) {
ids.append(query.value(0).toInt());
query.next();
}
foreach (int id, ids) {
queryStr = "SELECT dmEncodedContent FROM files WHERE id = :id";
if (!query.prepare(queryStr)) {
logErrorNL("Cannot prepare SQL query: %s",
query.lastError().text().toUtf8().constData());
return false;
}
query.bindValue(":id", id);
if (Q_UNLIKELY(!query.exec() || !query.isActive())) {
logErrorNL("Cannot execute SQL query: %s",
query.lastError().text().toUtf8().constData());
return false;
}
query.first();
const qint64 fileSize =
QByteArray::fromBase64(query.value(0).toByteArray()).size();
queryStr = "UPDATE files SET _dmFileSize = :fileSize WHERE id = :id";
if (!query.prepare(queryStr)) {
logErrorNL("Cannot prepare SQL query: %s",
query.lastError().text().toUtf8().constData());
return false;
}
query.bindValue(":fileSize", fileSize);
query.bindValue(":id", id);
if (Q_UNLIKELY(!query.exec())) {
logErrorNL("Cannot execute SQL query: %s",
query.lastError().text().toUtf8().constData());
return false;
}
}
return true;
}
/*!
* @brief Change the type of _dmFileSize column to INTEGER and recompute the file size.
*
* @note ALTER TABLE does not support column modification. Instead the table
* must be renamed a new table must be created and data must be copied.
*
* @param[in,out] fDb File database.
* @param[in] db Internal database object of the file database.
*/
static
bool fileSizeColMakeInt(FileDb &fDb, QSqlDatabase &db)
{
QSqlQuery query(db);
QString queryStr;
fDb.beginTransaction();
queryStr = "ALTER TABLE files RENAME TO _files_old";
if (!query.prepare(queryStr) || !query.exec()) {
logErrorNL("Cannot prepare or execute SQL query: %s",
query.lastError().text().toUtf8().constData());
goto fail;
}
if (!flsTbl.createEmpty(db)) {
logErrorNL("%s", "Cannot create empty files table.");
goto fail;
}
queryStr = "INSERT INTO files "
"(id, dmID, dmFileDescr, dmUpFileGuid, dmFileGuid, dmMimeType, dmFormat, dmFileMetaType, dmEncodedContent, _dmFileSize, _dmDownloadDate, _icon) "
"SELECT id, dmID, dmFileDescr, dmUpFileGuid, dmFileGuid, dmMimeType, dmFormat, dmFileMetaType, dmEncodedContent, null, _dmDownloadDate, _icon "
"FROM _files_old";
if (!query.prepare(queryStr) || !query.exec()) {
logErrorNL("Cannot prepare or execute SQL query: %s",
query.lastError().text().toUtf8().constData());
goto fail;
}
if (!fileSizeColRecompute(db)) {
logErrorNL("%s", "Cannot recompute file sizes.");
goto fail;
}
queryStr = "DROP TABLE _files_old";
if (!query.prepare(queryStr) || !query.exec()) {
logErrorNL("Cannot prepare or execute SQL query: %s",
query.lastError().text().toUtf8().constData());
goto fail;
}
fDb.commitTransaction();
/* Cannot vacuum from within a transaction. */
fDb.vacuumFileDb();
return true;
fail:
fDb.rollbackTransaction();
return false;
}
bool FileDb::assureConsistency(void)
{
switch (fileSizeColIsInt(m_db)) {
case 1:
logInfoNL("Consistency check of database '%s' seems to be OK.",
fileName().toUtf8().constData());
return true;
break;
case 0:
/* Continue after switch. */
break;
case -1:
default:
logErrorNL("Consistency check of database '%s' failed.",
fileName().toUtf8().constData());
return false;
break;
}
if (!fileSizeColMakeInt(*this, m_db)) {
logErrorNL("%s", "Failed converting file size column type.");
return false;
}
return true;
}
......@@ -165,4 +165,13 @@ protected:
*/
virtual
QList<class SQLiteTbl *> listOfTables(void) const Q_DECL_OVERRIDE;
/*!
* @brief This function is used to make database content consistent
* (e.g. adding missing columns or entries).
*
* @return True on success.
*/
virtual
bool assureConsistency(void) Q_DECL_OVERRIDE;
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment