mirror of
https://github.com/abraunegg/onedrive
synced 2024-05-10 09:46:40 +02:00
* Implement better handling of database exit scenarios when there is zero disk space left on drive where the items database resides (Issue #77) * Implement better handling of incorrect database permissions * Implement better handling of different database versions to automatically re-create tables if version mis-match (RHBZ #1598934)
This commit is contained in:
parent
91d8b7ab93
commit
aa995eb3d3
72
src/itemdb.d
72
src/itemdb.d
|
@ -2,7 +2,9 @@ import std.datetime;
|
|||
import std.exception;
|
||||
import std.path;
|
||||
import std.string;
|
||||
import core.stdc.stdlib;
|
||||
import sqlite;
|
||||
static import log;
|
||||
|
||||
enum ItemType {
|
||||
file,
|
||||
|
@ -29,7 +31,7 @@ struct Item {
|
|||
final class ItemDatabase
|
||||
{
|
||||
// increment this for every change in the db schema
|
||||
immutable int itemDatabaseVersion = 6;
|
||||
immutable int itemDatabaseVersion = 7;
|
||||
|
||||
Database db;
|
||||
Statement insertItemStmt;
|
||||
|
@ -41,33 +43,21 @@ final class ItemDatabase
|
|||
this(const(char)[] filename)
|
||||
{
|
||||
db = Database(filename);
|
||||
if (db.getVersion() == 0) {
|
||||
db.exec("CREATE TABLE item (
|
||||
driveId TEXT NOT NULL,
|
||||
id TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
type TEXT NOT NULL,
|
||||
eTag TEXT,
|
||||
cTag TEXT,
|
||||
mtime TEXT NOT NULL,
|
||||
parentId TEXT,
|
||||
crc32Hash TEXT,
|
||||
sha1Hash TEXT,
|
||||
quickXorHash TEXT,
|
||||
remoteDriveId TEXT,
|
||||
remoteId TEXT,
|
||||
deltaLink TEXT,
|
||||
PRIMARY KEY (driveId, id),
|
||||
FOREIGN KEY (driveId, parentId)
|
||||
REFERENCES item (driveId, id)
|
||||
ON DELETE CASCADE
|
||||
ON UPDATE RESTRICT
|
||||
)");
|
||||
db.exec("CREATE INDEX name_idx ON item (name)");
|
||||
db.exec("CREATE INDEX remote_idx ON item (remoteDriveId, remoteId)");
|
||||
db.setVersion(itemDatabaseVersion);
|
||||
int dbVersion;
|
||||
try {
|
||||
dbVersion = db.getVersion();
|
||||
} catch (SqliteException e) {
|
||||
// An error was generated - what was the error?
|
||||
log.error("\nAn internal database error occurred: " ~ e.msg ~ "\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (dbVersion == 0) {
|
||||
createTable();
|
||||
} else if (db.getVersion() != itemDatabaseVersion) {
|
||||
throw new Exception("The item database is incompatible, please resync manually");
|
||||
log.log("The item database is incompatible, re-creating database table structures");
|
||||
db.exec("DROP TABLE item");
|
||||
createTable();
|
||||
}
|
||||
db.exec("PRAGMA foreign_keys = ON");
|
||||
db.exec("PRAGMA recursive_triggers = ON");
|
||||
|
@ -91,6 +81,34 @@ final class ItemDatabase
|
|||
deleteItemByIdStmt = db.prepare("DELETE FROM item WHERE driveId = ? AND id = ?");
|
||||
}
|
||||
|
||||
void createTable()
|
||||
{
|
||||
db.exec("CREATE TABLE item (
|
||||
driveId TEXT NOT NULL,
|
||||
id TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
type TEXT NOT NULL,
|
||||
eTag TEXT,
|
||||
cTag TEXT,
|
||||
mtime TEXT NOT NULL,
|
||||
parentId TEXT,
|
||||
crc32Hash TEXT,
|
||||
sha1Hash TEXT,
|
||||
quickXorHash TEXT,
|
||||
remoteDriveId TEXT,
|
||||
remoteId TEXT,
|
||||
deltaLink TEXT,
|
||||
PRIMARY KEY (driveId, id),
|
||||
FOREIGN KEY (driveId, parentId)
|
||||
REFERENCES item (driveId, id)
|
||||
ON DELETE CASCADE
|
||||
ON UPDATE RESTRICT
|
||||
)");
|
||||
db.exec("CREATE INDEX name_idx ON item (name)");
|
||||
db.exec("CREATE INDEX remote_idx ON item (remoteDriveId, remoteId)");
|
||||
db.setVersion(itemDatabaseVersion);
|
||||
}
|
||||
|
||||
void insert(const ref Item item)
|
||||
{
|
||||
bindItem(item, insertItemStmt);
|
||||
|
|
28
src/sqlite.d
28
src/sqlite.d
|
@ -2,6 +2,8 @@ module sqlite;
|
|||
import std.stdio;
|
||||
import etc.c.sqlite3;
|
||||
import std.string: fromStringz, toStringz;
|
||||
import core.stdc.stdlib;
|
||||
static import log;
|
||||
|
||||
extern (C) immutable(char)* sqlite3_errstr(int); // missing from the std library
|
||||
|
||||
|
@ -48,9 +50,16 @@ struct Database
|
|||
{
|
||||
// https://www.sqlite.org/c3ref/open.html
|
||||
int rc = sqlite3_open(toStringz(filename), &pDb);
|
||||
if (rc != SQLITE_OK) {
|
||||
if (rc == SQLITE_CANTOPEN) {
|
||||
// Database cannot be opened
|
||||
log.error("\nThe database cannot be opened. Please check the permissions of ~/.config/onedrive/items.sqlite3\n");
|
||||
close();
|
||||
throw new SqliteException(ifromStringz(sqlite3_errstr(rc)));
|
||||
exit(-1);
|
||||
}
|
||||
if (rc != SQLITE_OK) {
|
||||
log.error("\nA database access error occurred: " ~ getErrorMessage() ~ "\n");
|
||||
close();
|
||||
exit(-1);
|
||||
}
|
||||
sqlite3_extended_result_codes(pDb, 1); // always use extended result codes
|
||||
}
|
||||
|
@ -60,7 +69,9 @@ struct Database
|
|||
// https://www.sqlite.org/c3ref/exec.html
|
||||
int rc = sqlite3_exec(pDb, toStringz(sql), null, null, null);
|
||||
if (rc != SQLITE_OK) {
|
||||
throw new SqliteException(ifromStringz(sqlite3_errmsg(pDb)));
|
||||
log.error("\nA database execution error occurred: "~ getErrorMessage() ~ "\n");
|
||||
close();
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,6 +90,11 @@ struct Database
|
|||
return userVersion;
|
||||
}
|
||||
|
||||
string getErrorMessage()
|
||||
{
|
||||
return ifromStringz(sqlite3_errmsg(pDb));
|
||||
}
|
||||
|
||||
void setVersion(int userVersion)
|
||||
{
|
||||
import std.conv: to;
|
||||
|
@ -135,7 +151,7 @@ struct Statement
|
|||
int rc = sqlite3_step(pStmt);
|
||||
if (rc == SQLITE_BUSY) {
|
||||
// Database is locked by another onedrive process
|
||||
writeln("The database is currently locked by another process - cannot sync");
|
||||
log.error("The database is currently locked by another process - cannot sync");
|
||||
return;
|
||||
}
|
||||
if (rc == SQLITE_DONE) {
|
||||
|
@ -149,7 +165,9 @@ struct Statement
|
|||
column = fromStringz(sqlite3_column_text(pStmt, i));
|
||||
}
|
||||
} else {
|
||||
throw new SqliteException(ifromStringz(sqlite3_errmsg(sqlite3_db_handle(pStmt))));
|
||||
string errorMessage = ifromStringz(sqlite3_errmsg(sqlite3_db_handle(pStmt)));
|
||||
log.error("\nA database statement execution error occurred: "~ errorMessage ~ "\n");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue