mirror of
https://github.com/nextcloud/desktop.git
synced 2025-10-26 11:17:43 +00:00
Merge pull request #8561 from nextcloud/bugfix/dbquota
fix(quota): return unlimited free space for type changes.
This commit is contained in:
commit
decf1e7c3f
@ -712,9 +712,40 @@ bool SyncJournalDb::updateDatabaseStructure()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SyncJournalDb::hasDefaultValue(const QString &columnName)
|
||||
{
|
||||
SqlQuery query(_db);
|
||||
const auto selectDefault = QStringLiteral("SELECT dflt_value FROM pragma_table_info('metadata') WHERE name = '%1';").arg(columnName);
|
||||
query.prepare(selectDefault.toLatin1());
|
||||
if (!query.exec()) {
|
||||
sqlFail(QStringLiteral("check default value for: %1").arg(columnName), query);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (const auto result = query.next();!result.ok || !result.hasData) {
|
||||
qCWarning(lcDb) << "database error:" << query.error();
|
||||
return false;
|
||||
}
|
||||
|
||||
return !query.nullValue(0);
|
||||
}
|
||||
|
||||
bool SyncJournalDb::removeColumn(const QString &columnName)
|
||||
{
|
||||
SqlQuery query(_db);
|
||||
const auto request = QStringLiteral("ALTER TABLE metadata DROP COLUMN %1;").arg(columnName);
|
||||
query.prepare(request.toLatin1());
|
||||
if (!query.exec()) {
|
||||
sqlFail(QStringLiteral("update metadata structure: drop %1 column").arg(columnName), query);
|
||||
return false;
|
||||
}
|
||||
|
||||
commitInternal(QStringLiteral("update database structure: drop %1 column").arg(columnName));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SyncJournalDb::updateMetadataTableStructure()
|
||||
{
|
||||
|
||||
auto columns = tableColumns("metadata");
|
||||
bool re = true;
|
||||
|
||||
@ -723,11 +754,18 @@ bool SyncJournalDb::updateMetadataTableStructure()
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto addColumn = [this, &columns, &re] (const QString &columnName, const QString &dataType, const bool withIndex = false) {
|
||||
const auto latin1ColumnName = columnName.toLatin1();
|
||||
if (columns.indexOf(latin1ColumnName) == -1) {
|
||||
const auto columnExists = [&columns] (const QString &columnName) -> bool {
|
||||
return columns.indexOf(columnName.toLatin1()) > -1;
|
||||
};
|
||||
|
||||
const auto addColumn = [this, &re, &columnExists] (const QString &columnName, const QString &dataType, const bool withIndex = false, const QString defaultCommand = {}) {
|
||||
if (!columnExists(columnName)) {
|
||||
SqlQuery query(_db);
|
||||
const auto request = QStringLiteral("ALTER TABLE metadata ADD COLUMN %1 %2;").arg(columnName).arg(dataType);
|
||||
auto request = QStringLiteral("ALTER TABLE metadata ADD COLUMN %1 %2").arg(columnName).arg(dataType);
|
||||
if (!defaultCommand.isEmpty()) {
|
||||
request.append(QStringLiteral(" ") + defaultCommand);
|
||||
}
|
||||
request.append(QStringLiteral(";"));
|
||||
query.prepare(request.toLatin1());
|
||||
if (!query.exec()) {
|
||||
sqlFail(QStringLiteral("updateMetadataTableStructure: add %1 column").arg(columnName), query);
|
||||
@ -851,8 +889,29 @@ bool SyncJournalDb::updateMetadataTableStructure()
|
||||
|
||||
addColumn(QStringLiteral("isLivePhoto"), QStringLiteral("INTEGER"));
|
||||
addColumn(QStringLiteral("livePhotoFile"), QStringLiteral("TEXT"));
|
||||
addColumn(QStringLiteral("quotaBytesUsed"), QStringLiteral("BIGINT"));
|
||||
addColumn(QStringLiteral("quotaBytesAvailable"), QStringLiteral("BIGINT"));
|
||||
|
||||
{
|
||||
const auto quotaBytesUsed = QStringLiteral("quotaBytesUsed");
|
||||
const auto quotaBytesAvailable = QStringLiteral("quotaBytesAvailable");
|
||||
const auto defaultCommand = QStringLiteral("DEFAULT -1 NOT NULL");
|
||||
const auto bigInt = QStringLiteral("BIGINT");
|
||||
auto result = false;
|
||||
|
||||
if (columnExists(quotaBytesUsed) && !hasDefaultValue(quotaBytesUsed)) {
|
||||
result = removeColumn(quotaBytesUsed);
|
||||
}
|
||||
|
||||
if (columnExists(quotaBytesAvailable) && !hasDefaultValue(quotaBytesAvailable)) {
|
||||
result = removeColumn(quotaBytesAvailable);
|
||||
}
|
||||
|
||||
if (result) {
|
||||
columns = tableColumns("metadata");
|
||||
}
|
||||
|
||||
addColumn(quotaBytesUsed, bigInt, false, defaultCommand);
|
||||
addColumn(quotaBytesAvailable, bigInt, false, defaultCommand);
|
||||
}
|
||||
|
||||
return re;
|
||||
}
|
||||
|
||||
@ -21,6 +21,8 @@
|
||||
#include "common/result.h"
|
||||
#include "common/pinstate.h"
|
||||
|
||||
class TestSyncJournalDB;
|
||||
|
||||
namespace OCC {
|
||||
class SyncJournalFileRecord;
|
||||
|
||||
@ -399,6 +401,8 @@ private:
|
||||
[[nodiscard]] bool updateDatabaseStructure();
|
||||
[[nodiscard]] bool updateMetadataTableStructure();
|
||||
[[nodiscard]] bool updateErrorBlacklistTableStructure();
|
||||
[[nodiscard]] bool removeColumn(const QString &columnName);
|
||||
[[nodiscard]] bool hasDefaultValue(const QString &columnName);
|
||||
bool sqlFail(const QString &log, const SqlQuery &query);
|
||||
void commitInternal(const QString &context, bool startTrans = true);
|
||||
void startTransaction();
|
||||
@ -444,6 +448,8 @@ private:
|
||||
QByteArray _journalMode;
|
||||
|
||||
PreparedSqlQueryManager _queryManager;
|
||||
|
||||
friend class ::TestSyncJournalDB;
|
||||
};
|
||||
|
||||
bool OCSYNC_EXPORT
|
||||
|
||||
@ -1085,7 +1085,7 @@ void ProcessDirectoryJob::processFileAnalyzeRemoteInfo(const SyncFileItemPtr &it
|
||||
int64_t ProcessDirectoryJob::folderBytesAvailable(const SyncFileItemPtr &item, const FolderQuota::ServerEntry serverEntry) const
|
||||
{
|
||||
const auto unlimitedFreeSpace = -3;
|
||||
if (item->_size == 0 || item->_direction != SyncFileItem::Up || item->isDirectory()) {
|
||||
if (item->_size == 0 || item->_direction != SyncFileItem::Up || item->isDirectory() || item->_instruction == CSYNC_INSTRUCTION_TYPE_CHANGE) {
|
||||
return unlimitedFreeSpace;
|
||||
}
|
||||
|
||||
@ -1093,8 +1093,7 @@ int64_t ProcessDirectoryJob::folderBytesAvailable(const SyncFileItemPtr &item, c
|
||||
return unlimitedFreeSpace;
|
||||
}
|
||||
|
||||
if (item->_instruction != CSYNC_INSTRUCTION_TYPE_CHANGE
|
||||
&& (serverEntry == FolderQuota::ServerEntry::Valid || !_dirItem)) {
|
||||
if (serverEntry == FolderQuota::ServerEntry::Valid || !_dirItem) {
|
||||
return _folderQuota.bytesAvailable;
|
||||
}
|
||||
|
||||
|
||||
@ -98,6 +98,52 @@ private slots:
|
||||
QVERIFY(!record.isValid());
|
||||
}
|
||||
|
||||
void testFolderQuota()
|
||||
{
|
||||
const auto bigFolderRecord = QByteArray("bigfolder");
|
||||
SyncJournalFileRecord record;
|
||||
record._path = bigFolderRecord;
|
||||
record._inode = std::numeric_limits<quint32>::max() + 12ull;
|
||||
record._modtime = dropMsecs(QDateTime::currentDateTime());
|
||||
record._type = ItemTypeDirectory;
|
||||
record._etag = "123123";
|
||||
record._fileId = "abcd";
|
||||
record._fileSize = 213089999;
|
||||
QVERIFY(_db.setFileRecord(record));
|
||||
|
||||
SyncJournalFileRecord storedRecord;
|
||||
QVERIFY(_db.getFileRecord(bigFolderRecord, &storedRecord));
|
||||
QVERIFY(storedRecord == record);
|
||||
// default values
|
||||
QCOMPARE(storedRecord._folderQuota.bytesAvailable, -1);
|
||||
QCOMPARE(storedRecord._folderQuota.bytesUsed, -1);
|
||||
|
||||
record._folderQuota.bytesUsed = 100;
|
||||
record._folderQuota.bytesAvailable = 5000;
|
||||
QVERIFY(_db.setFileRecord(record));
|
||||
QVERIFY(_db.getFileRecord(bigFolderRecord, &storedRecord));
|
||||
QVERIFY(storedRecord == record);
|
||||
QCOMPARE(storedRecord._folderQuota.bytesAvailable, 5000);
|
||||
QCOMPARE(storedRecord._folderQuota.bytesUsed, 100);
|
||||
}
|
||||
|
||||
void testFolderMigration() {
|
||||
const auto quotaBytesUsed = QStringLiteral("quotaBytesUsed");
|
||||
const auto quotaBytesAvailable = QStringLiteral("quotaBytesAvailable");
|
||||
const auto metadata = QStringLiteral("metadata");
|
||||
const auto columnsBeforeRemoval = _db.tableColumns(metadata.toLatin1());
|
||||
QCOMPARE_GT(columnsBeforeRemoval.indexOf(quotaBytesUsed.toLatin1()), -1);
|
||||
QCOMPARE_GT(columnsBeforeRemoval.indexOf(quotaBytesAvailable.toLatin1()), -1);
|
||||
QVERIFY(_db.removeColumn(quotaBytesAvailable));
|
||||
QVERIFY(_db.removeColumn(quotaBytesUsed));
|
||||
QVERIFY(_db.updateMetadataTableStructure());
|
||||
const auto columnsAfterConnect = _db.tableColumns(metadata.toLatin1());
|
||||
QVERIFY(columnsAfterConnect.indexOf(quotaBytesUsed.toLatin1()) > -1);
|
||||
QVERIFY(columnsAfterConnect.indexOf(quotaBytesAvailable.toLatin1()) > -1);
|
||||
QVERIFY(_db.hasDefaultValue(quotaBytesUsed));
|
||||
QVERIFY(_db.hasDefaultValue(quotaBytesAvailable));
|
||||
}
|
||||
|
||||
void testFileRecordChecksum()
|
||||
{
|
||||
// Try with and without a checksum
|
||||
|
||||
Loading…
Reference in New Issue
Block a user