forked from qt-creator/qt-creator
Sqlite: Improve exception handling
Introducing different exceptions for different error cases. Change-Id: I4371d1e64d9dca2a9f68dcbaa4a891c55879c1f5 Reviewed-by: Tim Jenssen <tim.jenssen@qt.io> Reviewed-by: Marco Bubke <marco.bubke@qt.io>
This commit is contained in:
@@ -31,6 +31,7 @@
|
||||
#include "sqlitestatement.h"
|
||||
#include "sqlitewritestatement.h"
|
||||
|
||||
#include <QFileInfo>
|
||||
#include <QThread>
|
||||
#include <QDebug>
|
||||
|
||||
@@ -230,24 +231,29 @@ void DatabaseBackend::cacheTextEncoding()
|
||||
void DatabaseBackend::checkForOpenDatabaseWhichCanBeClosed()
|
||||
{
|
||||
if (m_databaseHandle == nullptr)
|
||||
throwException("SqliteDatabaseBackend::close: database is not open so it can not be closed.");
|
||||
throw DatabaseIsAlreadyClosed("SqliteDatabaseBackend::close: database is not open so it can not be closed.");
|
||||
}
|
||||
|
||||
void DatabaseBackend::checkDatabaseClosing(int resultCode)
|
||||
{
|
||||
switch (resultCode) {
|
||||
case SQLITE_OK: return;
|
||||
default: throwException("SqliteDatabaseBackend::close: unknown error happens at closing!");
|
||||
case SQLITE_BUSY: throw DatabaseIsBusy("SqliteDatabaseBackend::close: database is busy because of e.g. unfinalized statements and will stay open!");
|
||||
default: throwUnknowError("SqliteDatabaseBackend::close: unknown error happens at closing!");
|
||||
}
|
||||
}
|
||||
|
||||
void DatabaseBackend::checkCanOpenDatabase(Utils::SmallStringView databaseFilePath)
|
||||
{
|
||||
if (databaseFilePath.isEmpty())
|
||||
throw Exception("SqliteDatabaseBackend::SqliteDatabaseBackend: database cannot be opened:", "database file path is empty!");
|
||||
throw DatabaseFilePathIsEmpty("SqliteDatabaseBackend::SqliteDatabaseBackend: database cannot be opened because the file path is empty!");
|
||||
|
||||
if (!QFileInfo::exists(QFileInfo(QString(databaseFilePath)).path()))
|
||||
throw WrongFilePath("SqliteDatabaseBackend::SqliteDatabaseBackend: database cannot be opened because of wrong file path!",
|
||||
Utils::SmallString(databaseFilePath));
|
||||
|
||||
if (databaseIsOpen())
|
||||
throw Exception("SqliteDatabaseBackend::SqliteDatabaseBackend: database cannot be opened:", "database is already open!");
|
||||
throw DatabaseIsAlreadyOpen("SqliteDatabaseBackend::SqliteDatabaseBackend: database cannot be opened because it is already open!");
|
||||
}
|
||||
|
||||
void DatabaseBackend::checkDatabaseCouldBeOpened(int resultCode)
|
||||
@@ -265,13 +271,13 @@ void DatabaseBackend::checkPragmaValue(Utils::SmallStringView databaseValue,
|
||||
Utils::SmallStringView expectedValue)
|
||||
{
|
||||
if (databaseValue != expectedValue)
|
||||
throwException("SqliteDatabaseBackend::setPragmaValue: pragma value is not set!");
|
||||
throw PragmaValueNotSet("SqliteDatabaseBackend::setPragmaValue: pragma value is not set!");
|
||||
}
|
||||
|
||||
void DatabaseBackend::checkDatabaseHandleIsNotNull()
|
||||
{
|
||||
if (m_databaseHandle == nullptr)
|
||||
throwException("SqliteDatabaseBackend: database is not open!");
|
||||
throwDatabaseIsNotOpen("SqliteDatabaseBackend: database is not open!");
|
||||
}
|
||||
|
||||
void DatabaseBackend::checkIfMultithreadingIsActivated(int resultCode)
|
||||
@@ -392,6 +398,16 @@ void DatabaseBackend::throwException(const char *whatHasHappens) const
|
||||
throw Exception(whatHasHappens);
|
||||
}
|
||||
|
||||
void DatabaseBackend::throwUnknowError(const char *whatHasHappens) const
|
||||
{
|
||||
throw UnknowError(whatHasHappens);
|
||||
}
|
||||
|
||||
void DatabaseBackend::throwDatabaseIsNotOpen(const char *whatHasHappens) const
|
||||
{
|
||||
throw DatabaseIsNotOpen(whatHasHappens);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
Type DatabaseBackend::toValue(Utils::SmallStringView sqlStatement)
|
||||
{
|
||||
|
||||
@@ -110,8 +110,9 @@ protected:
|
||||
|
||||
|
||||
Q_NORETURN static void throwExceptionStatic(const char *whatHasHappens);
|
||||
Q_NORETURN void throwException(const char *whatHasHappens) const;
|
||||
|
||||
[[noreturn]] void throwException(const char *whatHasHappens) const;
|
||||
[[noreturn]] void throwUnknowError(const char *whatHasHappens) const;
|
||||
[[noreturn]] void throwDatabaseIsNotOpen(const char *whatHasHappens) const;
|
||||
|
||||
private:
|
||||
Database &m_database;
|
||||
|
||||
@@ -48,4 +48,211 @@ private:
|
||||
Utils::SmallString m_sqliteErrorMessage;
|
||||
};
|
||||
|
||||
class StatementIsBusy : public Exception
|
||||
{
|
||||
public:
|
||||
StatementIsBusy(const char *whatErrorHasHappen,
|
||||
Utils::SmallString &&sqliteErrorMessage = Utils::SmallString())
|
||||
: Exception(whatErrorHasHappen, std::move(sqliteErrorMessage))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class DatabaseIsBusy : public Exception
|
||||
{
|
||||
public:
|
||||
DatabaseIsBusy(const char *whatErrorHasHappen)
|
||||
: Exception(whatErrorHasHappen)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class StatementHasError : public Exception
|
||||
{
|
||||
public:
|
||||
StatementHasError(const char *whatErrorHasHappen,
|
||||
Utils::SmallString &&sqliteErrorMessage = Utils::SmallString())
|
||||
: Exception(whatErrorHasHappen, std::move(sqliteErrorMessage))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class StatementIsMisused : public Exception
|
||||
{
|
||||
public:
|
||||
StatementIsMisused(const char *whatErrorHasHappen,
|
||||
Utils::SmallString &&sqliteErrorMessage = Utils::SmallString())
|
||||
: Exception(whatErrorHasHappen, std::move(sqliteErrorMessage))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class ContraintPreventsModification : public Exception
|
||||
{
|
||||
public:
|
||||
ContraintPreventsModification(const char *whatErrorHasHappen,
|
||||
Utils::SmallString &&sqliteErrorMessage = Utils::SmallString())
|
||||
: Exception(whatErrorHasHappen, std::move(sqliteErrorMessage))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class NoValuesToFetch : public Exception
|
||||
{
|
||||
public:
|
||||
NoValuesToFetch(const char *whatErrorHasHappen)
|
||||
: Exception(whatErrorHasHappen)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class InvalidColumnFetched : public Exception
|
||||
{
|
||||
public:
|
||||
InvalidColumnFetched(const char *whatErrorHasHappen)
|
||||
: Exception(whatErrorHasHappen)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class BindingIndexIsOutOfRange : public Exception
|
||||
{
|
||||
public:
|
||||
BindingIndexIsOutOfRange(const char *whatErrorHasHappen,
|
||||
Utils::SmallString &&sqliteErrorMessage = Utils::SmallString())
|
||||
: Exception(whatErrorHasHappen, std::move(sqliteErrorMessage))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class WrongBingingName : public Exception
|
||||
{
|
||||
public:
|
||||
WrongBingingName(const char *whatErrorHasHappen)
|
||||
: Exception(whatErrorHasHappen)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class DatabaseIsNotOpen : public Exception
|
||||
{
|
||||
public:
|
||||
DatabaseIsNotOpen(const char *whatErrorHasHappen)
|
||||
: Exception(whatErrorHasHappen)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class DatabaseCannotBeOpened : public Exception
|
||||
{
|
||||
public:
|
||||
DatabaseCannotBeOpened(const char *whatErrorHasHappen,
|
||||
Utils::SmallString &&errorMessage = Utils::SmallString())
|
||||
: Exception(whatErrorHasHappen, std::move(errorMessage))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class DatabaseFilePathIsEmpty : public DatabaseCannotBeOpened
|
||||
{
|
||||
public:
|
||||
DatabaseFilePathIsEmpty(const char *whatErrorHasHappen)
|
||||
: DatabaseCannotBeOpened(whatErrorHasHappen)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class DatabaseIsAlreadyOpen : public DatabaseCannotBeOpened
|
||||
{
|
||||
public:
|
||||
DatabaseIsAlreadyOpen(const char *whatErrorHasHappen)
|
||||
: DatabaseCannotBeOpened(whatErrorHasHappen)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class DatabaseCannotBeClosed : public Exception
|
||||
{
|
||||
public:
|
||||
DatabaseCannotBeClosed(const char *whatErrorHasHappen)
|
||||
: Exception(whatErrorHasHappen)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class DatabaseIsAlreadyClosed : public DatabaseCannotBeClosed
|
||||
{
|
||||
public:
|
||||
DatabaseIsAlreadyClosed(const char *whatErrorHasHappen)
|
||||
: DatabaseCannotBeClosed(whatErrorHasHappen)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class WrongFilePath : public DatabaseCannotBeOpened
|
||||
{
|
||||
public:
|
||||
WrongFilePath(const char *whatErrorHasHappen,
|
||||
Utils::SmallString &&errorMessage = Utils::SmallString())
|
||||
: DatabaseCannotBeOpened(whatErrorHasHappen, std::move(errorMessage))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class PragmaValueNotSet : public Exception
|
||||
{
|
||||
public:
|
||||
PragmaValueNotSet(const char *whatErrorHasHappen)
|
||||
: Exception(whatErrorHasHappen)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class NotReadOnlySqlStatement : public Exception
|
||||
{
|
||||
public:
|
||||
NotReadOnlySqlStatement(const char *whatErrorHasHappen)
|
||||
: Exception(whatErrorHasHappen)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class NotWriteSqlStatement : public Exception
|
||||
{
|
||||
public:
|
||||
NotWriteSqlStatement(const char *whatErrorHasHappen)
|
||||
: Exception(whatErrorHasHappen)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class DeadLock : public Exception
|
||||
{
|
||||
public:
|
||||
DeadLock(const char *whatErrorHasHappen)
|
||||
: Exception(whatErrorHasHappen)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class UnknowError : public Exception
|
||||
{
|
||||
public:
|
||||
UnknowError(const char *whatErrorHasHappen,
|
||||
Utils::SmallString &&errorMessage = Utils::SmallString())
|
||||
: Exception(whatErrorHasHappen, std::move(errorMessage))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class BindingTooBig : public Exception
|
||||
{
|
||||
public:
|
||||
BindingTooBig(const char *whatErrorHasHappen,
|
||||
Utils::SmallString &&errorMessage = Utils::SmallString())
|
||||
: Exception(whatErrorHasHappen, std::move(errorMessage))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Sqlite
|
||||
|
||||
@@ -39,7 +39,7 @@ ReadStatement::ReadStatement(Utils::SmallStringView sqlStatement,
|
||||
void ReadStatement::checkIsReadOnlyStatement()
|
||||
{
|
||||
if (!isReadOnlyStatement())
|
||||
throwException("SqliteStatement::SqliteReadStatement: is not read only statement!");
|
||||
throw NotReadOnlySqlStatement("SqliteStatement::SqliteReadStatement: is not read only statement!");
|
||||
}
|
||||
|
||||
} // namespace Sqlite
|
||||
|
||||
@@ -95,19 +95,26 @@ private:
|
||||
void Statement::waitForUnlockNotify() const
|
||||
{
|
||||
UnlockNotification unlockNotification;
|
||||
int resultCode = sqlite3_unlock_notify(sqliteDatabaseHandle(), UnlockNotification::unlockNotifyCallBack, &unlockNotification);
|
||||
int resultCode = sqlite3_unlock_notify(sqliteDatabaseHandle(),
|
||||
UnlockNotification::unlockNotifyCallBack,
|
||||
&unlockNotification);
|
||||
|
||||
if (resultCode == SQLITE_LOCKED)
|
||||
throw DeadLock("SqliteStatement::waitForUnlockNotify: database is in a dead lock!");
|
||||
|
||||
if (resultCode == SQLITE_OK)
|
||||
unlockNotification.wait();
|
||||
else
|
||||
throwException("SqliteStatement::waitForUnlockNotify: database is in a dead lock!");
|
||||
}
|
||||
|
||||
void Statement::reset() const
|
||||
{
|
||||
int resultCode = sqlite3_reset(m_compiledStatement.get());
|
||||
if (resultCode != SQLITE_OK)
|
||||
throwException("SqliteStatement::reset: can't reset statement!");
|
||||
switch (resultCode) {
|
||||
case SQLITE_OK: return;
|
||||
case SQLITE_BUSY: throwStatementIsBusy("SqliteStatement::stepStatement: database engine was unable to acquire the database locks!");
|
||||
case SQLITE_ERROR : throwStatementHasError("SqliteStatement::stepStatement: run-time error (such as a constraint violation) has occurred!");
|
||||
case SQLITE_MISUSE: throwStatementIsMisused("SqliteStatement::stepStatement: was called inappropriately!");
|
||||
case SQLITE_CONSTRAINT: throwConstraintPreventsModification("SqliteStatement::stepStatement: contraint prevent insert or update!");
|
||||
}
|
||||
|
||||
m_isReadyToFetchValues = false;
|
||||
}
|
||||
@@ -160,29 +167,29 @@ Utils::SmallStringVector Statement::columnNames() const
|
||||
void Statement::bind(int index, int value)
|
||||
{
|
||||
int resultCode = sqlite3_bind_int(m_compiledStatement.get(), index, value);
|
||||
if (resultCode != SQLITE_OK)
|
||||
throwException("SqliteStatement::bind: cant' bind 32 bit integer!");
|
||||
checkForBindingError(resultCode);
|
||||
}
|
||||
|
||||
void Statement::bind(int index, long long value)
|
||||
{
|
||||
int resultCode = sqlite3_bind_int64(m_compiledStatement.get(), index, value);
|
||||
if (resultCode != SQLITE_OK)
|
||||
throwException("SqliteStatement::bind: cant' bind 64 bit integer!");
|
||||
checkForBindingError(resultCode);
|
||||
}
|
||||
|
||||
void Statement::bind(int index, double value)
|
||||
{
|
||||
int resultCode = sqlite3_bind_double(m_compiledStatement.get(), index, value);
|
||||
if (resultCode != SQLITE_OK)
|
||||
throwException("SqliteStatement::bind: cant' bind double!");
|
||||
checkForBindingError(resultCode);
|
||||
}
|
||||
|
||||
void Statement::bind(int index, Utils::SmallStringView text)
|
||||
{
|
||||
int resultCode = sqlite3_bind_text(m_compiledStatement.get(), index, text.data(), int(text.size()), SQLITE_TRANSIENT);
|
||||
if (resultCode != SQLITE_OK)
|
||||
throwException("SqliteStatement::bind: cant' bind double!");
|
||||
int resultCode = sqlite3_bind_text(m_compiledStatement.get(),
|
||||
index,
|
||||
text.data(),
|
||||
int(text.size()),
|
||||
SQLITE_TRANSIENT);
|
||||
checkForBindingError(resultCode);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
@@ -250,13 +257,13 @@ bool Statement::checkForStepError(int resultCode) const
|
||||
switch (resultCode) {
|
||||
case SQLITE_ROW: return true;
|
||||
case SQLITE_DONE: return false;
|
||||
case SQLITE_BUSY: throwException("SqliteStatement::stepStatement: database engine was unable to acquire the database locks!");
|
||||
case SQLITE_ERROR : throwException("SqliteStatement::stepStatement: run-time error (such as a constraint violation) has occurred!");
|
||||
case SQLITE_MISUSE: throwException("SqliteStatement::stepStatement: was called inappropriately!");
|
||||
case SQLITE_CONSTRAINT: throwException("SqliteStatement::stepStatement: contraint prevent insert or update!");
|
||||
case SQLITE_BUSY: throwStatementIsBusy("SqliteStatement::stepStatement: database engine was unable to acquire the database locks!");
|
||||
case SQLITE_ERROR : throwStatementHasError("SqliteStatement::stepStatement: run-time error (such as a constraint violation) has occurred!");
|
||||
case SQLITE_MISUSE: throwStatementIsMisused("SqliteStatement::stepStatement: was called inappropriately!");
|
||||
case SQLITE_CONSTRAINT: throwConstraintPreventsModification("SqliteStatement::stepStatement: contraint prevent insert or update!");
|
||||
}
|
||||
|
||||
throwException("SqliteStatement::stepStatement: unknown error has happened");
|
||||
throwUnknowError("SqliteStatement::stepStatement: unknown error has happened");
|
||||
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
@@ -265,12 +272,24 @@ void Statement::checkForPrepareError(int resultCode) const
|
||||
{
|
||||
switch (resultCode) {
|
||||
case SQLITE_OK: return;
|
||||
case SQLITE_BUSY: throwException("SqliteStatement::prepareStatement: database engine was unable to acquire the database locks!");
|
||||
case SQLITE_ERROR : throwException("SqliteStatement::prepareStatement: run-time error (such as a constraint violation) has occurred!");
|
||||
case SQLITE_MISUSE: throwException("SqliteStatement::prepareStatement: was called inappropriately!");
|
||||
case SQLITE_BUSY: throwStatementIsBusy("SqliteStatement::prepareStatement: database engine was unable to acquire the database locks!");
|
||||
case SQLITE_ERROR : throwStatementHasError("SqliteStatement::prepareStatement: run-time error (such as a constraint violation) has occurred!");
|
||||
case SQLITE_MISUSE: throwStatementIsMisused("SqliteStatement::prepareStatement: was called inappropriately!");
|
||||
}
|
||||
|
||||
throwException("SqliteStatement::prepareStatement: unknown error has happened");
|
||||
throwUnknowError("SqliteStatement::prepareStatement: unknown error has happened");
|
||||
}
|
||||
|
||||
void Statement::checkForBindingError(int resultCode) const
|
||||
{
|
||||
switch (resultCode) {
|
||||
case SQLITE_OK: return;
|
||||
case SQLITE_TOOBIG: throwBingingTooBig("SqliteStatement::bind: string or blob are over size limits(SQLITE_LIMIT_LENGTH)!");
|
||||
case SQLITE_RANGE : throwBindingIndexIsOutOfRange("SqliteStatement::bind: binding index is out of range!");
|
||||
case SQLITE_NOMEM: throw std::bad_alloc();
|
||||
}
|
||||
|
||||
throwUnknowError("SqliteStatement::bind: unknown error has happened");
|
||||
}
|
||||
|
||||
void Statement::setIfIsReadyToFetchValues(int resultCode) const
|
||||
@@ -285,33 +304,27 @@ void Statement::setIfIsReadyToFetchValues(int resultCode) const
|
||||
void Statement::checkIfIsReadyToFetchValues() const
|
||||
{
|
||||
if (!m_isReadyToFetchValues)
|
||||
throwException("SqliteStatement::value: there are no values to fetch!");
|
||||
throwNoValuesToFetch("SqliteStatement::value: there are no values to fetch!");
|
||||
}
|
||||
|
||||
void Statement::checkColumnsAreValid(const std::vector<int> &columns) const
|
||||
{
|
||||
for (int column : columns) {
|
||||
if (column < 0 || column >= m_columnCount)
|
||||
throwException("SqliteStatement::values: column index out of bound!");
|
||||
throwInvalidColumnFetched("SqliteStatement::values: column index out of bound!");
|
||||
}
|
||||
}
|
||||
|
||||
void Statement::checkColumnIsValid(int column) const
|
||||
{
|
||||
if (column < 0 || column >= m_columnCount)
|
||||
throwException("SqliteStatement::values: column index out of bound!");
|
||||
}
|
||||
|
||||
void Statement::checkBindingIndex(int index) const
|
||||
{
|
||||
if (index <= 0 || index > m_bindingParameterCount)
|
||||
throwException("SqliteStatement::bind: binding index is out of bound!");
|
||||
throwInvalidColumnFetched("SqliteStatement::values: column index out of bound!");
|
||||
}
|
||||
|
||||
void Statement::checkBindingName(int index) const
|
||||
{
|
||||
if (index <= 0 || index > m_bindingParameterCount)
|
||||
throwException("SqliteStatement::bind: binding name are not exists in this statement!");
|
||||
throwWrongBingingName("SqliteStatement::bind: binding name are not exists in this statement!");
|
||||
}
|
||||
|
||||
void Statement::setBindingParameterCount()
|
||||
@@ -345,9 +358,57 @@ bool Statement::isReadOnlyStatement() const
|
||||
return sqlite3_stmt_readonly(m_compiledStatement.get());
|
||||
}
|
||||
|
||||
void Statement::throwException(const char *whatHasHappened) const
|
||||
void Statement::throwStatementIsBusy(const char *whatHasHappened) const
|
||||
{
|
||||
throw Exception(whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle()));
|
||||
throw StatementIsBusy(whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle()));
|
||||
}
|
||||
|
||||
void Statement::throwStatementHasError(const char *whatHasHappened) const
|
||||
{
|
||||
throw StatementHasError(whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle()));
|
||||
}
|
||||
|
||||
void Statement::throwStatementIsMisused(const char *whatHasHappened) const
|
||||
{
|
||||
throw StatementIsMisused(whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle()));
|
||||
}
|
||||
|
||||
void Statement::throwConstraintPreventsModification(const char *whatHasHappened) const
|
||||
{
|
||||
throw ContraintPreventsModification(whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle()));
|
||||
}
|
||||
|
||||
void Statement::throwNoValuesToFetch(const char *whatHasHappened) const
|
||||
{
|
||||
throw NoValuesToFetch(whatHasHappened);
|
||||
}
|
||||
|
||||
void Statement::throwInvalidColumnFetched(const char *whatHasHappened) const
|
||||
{
|
||||
throw InvalidColumnFetched(whatHasHappened);
|
||||
}
|
||||
|
||||
void Statement::throwBindingIndexIsOutOfRange(const char *whatHasHappened) const
|
||||
{
|
||||
throw BindingIndexIsOutOfRange(whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle()));
|
||||
}
|
||||
|
||||
void Statement::throwWrongBingingName(const char *whatHasHappened) const
|
||||
{
|
||||
throw WrongBingingName(whatHasHappened);
|
||||
}
|
||||
|
||||
void Statement::throwUnknowError(const char *whatHasHappened) const
|
||||
{
|
||||
if (sqliteDatabaseHandle())
|
||||
throw UnknowError(whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle()));
|
||||
else
|
||||
throw UnknowError(whatHasHappened);
|
||||
}
|
||||
|
||||
void Statement::throwBingingTooBig(const char *whatHasHappened) const
|
||||
{
|
||||
throw BindingTooBig(whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle()));
|
||||
}
|
||||
|
||||
QString Statement::columnName(int column) const
|
||||
|
||||
@@ -355,17 +355,26 @@ protected:
|
||||
|
||||
bool checkForStepError(int resultCode) const;
|
||||
void checkForPrepareError(int resultCode) const;
|
||||
void checkForBindingError(int resultCode) const;
|
||||
void setIfIsReadyToFetchValues(int resultCode) const;
|
||||
void checkIfIsReadyToFetchValues() const;
|
||||
void checkColumnsAreValid(const std::vector<int> &columns) const;
|
||||
void checkColumnIsValid(int column) const;
|
||||
void checkBindingIndex(int index) const;
|
||||
void checkBindingName(int index) const;
|
||||
void setBindingParameterCount();
|
||||
void setBindingColumnNamesFromStatement();
|
||||
void setColumnCount();
|
||||
bool isReadOnlyStatement() const;
|
||||
Q_NORETURN void throwException(const char *whatHasHappened) const;
|
||||
[[noreturn]] void throwStatementIsBusy(const char *whatHasHappened) const;
|
||||
[[noreturn]] void throwStatementHasError(const char *whatHasHappened) const;
|
||||
[[noreturn]] void throwStatementIsMisused(const char *whatHasHappened) const;
|
||||
[[noreturn]] void throwConstraintPreventsModification(const char *whatHasHappened) const;
|
||||
[[noreturn]] void throwNoValuesToFetch(const char *whatHasHappened) const;
|
||||
[[noreturn]] void throwInvalidColumnFetched(const char *whatHasHappened) const;
|
||||
[[noreturn]] void throwBindingIndexIsOutOfRange(const char *whatHasHappened) const;
|
||||
[[noreturn]] void throwWrongBingingName(const char *whatHasHappened) const;
|
||||
[[noreturn]] void throwUnknowError(const char *whatHasHappened) const;
|
||||
[[noreturn]] void throwBingingTooBig(const char *whatHasHappened) const;
|
||||
|
||||
template <typename ContainerType>
|
||||
ContainerType columnValues(const std::vector<int> &columnIndices) const;
|
||||
|
||||
@@ -37,7 +37,7 @@ WriteStatement::WriteStatement(Utils::SmallStringView sqlStatement,
|
||||
void WriteStatement::checkIsWritableStatement()
|
||||
{
|
||||
if (isReadOnlyStatement())
|
||||
throwException("SqliteStatement::SqliteWriteStatement: is not a writable statement!");
|
||||
throw NotWriteSqlStatement("SqliteStatement::SqliteWriteStatement: is not a writable statement!");
|
||||
}
|
||||
|
||||
} // namespace Sqlite
|
||||
|
||||
@@ -61,19 +61,21 @@ using SqliteDatabaseBackendSlowTest = SqliteDatabaseBackend;
|
||||
|
||||
TEST_F(SqliteDatabaseBackend, OpenAlreadyOpenDatabase)
|
||||
{
|
||||
ASSERT_THROW(databaseBackend.open(databaseFilePath, OpenMode::ReadWrite), Exception);
|
||||
ASSERT_THROW(databaseBackend.open(databaseFilePath, OpenMode::ReadWrite),
|
||||
Sqlite::DatabaseIsAlreadyOpen);
|
||||
}
|
||||
|
||||
TEST_F(SqliteDatabaseBackend, CloseAlreadyClosedDatabase)
|
||||
{
|
||||
databaseBackend.close();
|
||||
|
||||
ASSERT_THROW(databaseBackend.close(), Exception);
|
||||
ASSERT_THROW(databaseBackend.close(), Sqlite::DatabaseIsAlreadyClosed);
|
||||
}
|
||||
|
||||
TEST_F(SqliteDatabaseBackend, OpenWithWrongPath)
|
||||
{
|
||||
ASSERT_THROW(databaseBackend.open("/xxx/SqliteDatabaseBackendTest.db", OpenMode::ReadWrite), Exception);
|
||||
ASSERT_THROW(databaseBackend.open("/xxx/SqliteDatabaseBackendTest.db", OpenMode::ReadWrite),
|
||||
Sqlite::WrongFilePath);
|
||||
}
|
||||
|
||||
TEST_F(SqliteDatabaseBackend, DefaultJournalMode)
|
||||
@@ -148,7 +150,8 @@ TEST_F(SqliteDatabaseBackend, TextEncodingCannotBeChangedAfterTouchingDatabase)
|
||||
|
||||
databaseBackend.execute("CREATE TABLE text(name, number)");
|
||||
|
||||
ASSERT_THROW(databaseBackend.setTextEncoding(TextEncoding::Utf16), Exception);
|
||||
ASSERT_THROW(databaseBackend.setTextEncoding(TextEncoding::Utf16),
|
||||
Sqlite::PragmaValueNotSet);
|
||||
}
|
||||
|
||||
TEST_F(SqliteDatabaseBackend, OpenModeReadOnly)
|
||||
|
||||
@@ -87,12 +87,21 @@ struct Output
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(SqliteStatement, PrepareFailure)
|
||||
TEST_F(SqliteStatement, ThrowsStatementHasErrorForWrongSqlStatement)
|
||||
{
|
||||
ASSERT_THROW(ReadStatement("blah blah blah", database), Exception);
|
||||
ASSERT_THROW(WriteStatement("blah blah blah", database), Exception);
|
||||
ASSERT_THROW(ReadStatement("INSERT INTO test(name, number) VALUES (?, ?)", database), Exception);
|
||||
ASSERT_THROW(WriteStatement("SELECT name, number FROM test '", database), Exception);
|
||||
ASSERT_THROW(ReadStatement("blah blah blah", database), Sqlite::StatementHasError);
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, ThrowsNotReadOnlySqlStatementForWritableSqlStatementInReadStatement)
|
||||
{
|
||||
ASSERT_THROW(ReadStatement("INSERT INTO test(name, number) VALUES (?, ?)", database),
|
||||
Sqlite::NotReadOnlySqlStatement);
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, ThrowsNotReadonlySqlStatementForWritableSqlStatementInReadStatement)
|
||||
{
|
||||
ASSERT_THROW(WriteStatement("SELECT name, number FROM test", database),
|
||||
Sqlite::NotWriteSqlStatement);
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, CountRows)
|
||||
@@ -124,21 +133,35 @@ TEST_F(SqliteStatement, Value)
|
||||
ASSERT_THAT(statement.text(1), "23.3");
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, ValueFailure)
|
||||
TEST_F(SqliteStatement, ThrowNoValuesToFetchForNotSteppedStatement)
|
||||
{
|
||||
ReadStatement statement("SELECT name, number FROM test", database);
|
||||
ASSERT_THROW(statement.value<int>(0), Exception);
|
||||
|
||||
statement.reset();
|
||||
ASSERT_THROW(statement.value<int>(0), Sqlite::NoValuesToFetch);
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, ThrowNoValuesToFetchForDoneStatement)
|
||||
{
|
||||
ReadStatement statement("SELECT name, number FROM test", database);
|
||||
while (statement.next()) {}
|
||||
ASSERT_THROW(statement.value<int>(0), Exception);
|
||||
|
||||
statement.reset();
|
||||
ASSERT_THROW(statement.value<int>(0), Sqlite::NoValuesToFetch);
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, ThrowInvalidColumnFetchedForNegativeColumn)
|
||||
{
|
||||
ReadStatement statement("SELECT name, number FROM test", database);
|
||||
statement.next();
|
||||
ASSERT_THROW(statement.value<int>(-1), Exception);
|
||||
ASSERT_THROW(statement.value<int>(2), Exception);
|
||||
|
||||
ASSERT_THROW(statement.value<int>(-1), Sqlite::InvalidColumnFetched);
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, ThrowInvalidColumnFetchedForNotExistingColumn)
|
||||
{
|
||||
ReadStatement statement("SELECT name, number FROM test", database);
|
||||
statement.next();
|
||||
|
||||
ASSERT_THROW(statement.value<int>(2), Sqlite::InvalidColumnFetched);
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, ToIntergerValue)
|
||||
@@ -245,13 +268,25 @@ TEST_F(SqliteStatement, BindDoubleByIndex)
|
||||
ASSERT_THAT(statement.text(0), "foo");
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, BindFailure)
|
||||
TEST_F(SqliteStatement, BindIndexIsZeroIsThrowingBindingIndexIsOutOfBound)
|
||||
{
|
||||
ReadStatement statement("SELECT name, number FROM test WHERE number=@number", database);
|
||||
ReadStatement statement("SELECT name, number FROM test WHERE number=$1", database);
|
||||
|
||||
ASSERT_THROW(statement.bind(0, 40), Exception);
|
||||
ASSERT_THROW(statement.bind(2, 40), Exception);
|
||||
ASSERT_THROW(statement.bind("@name", 40), Exception);
|
||||
ASSERT_THROW(statement.bind(0, 40), Sqlite::BindingIndexIsOutOfRange);
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, BindIndexIsTpLargeIsThrowingBindingIndexIsOutOfBound)
|
||||
{
|
||||
ReadStatement statement("SELECT name, number FROM test WHERE number=$1", database);
|
||||
|
||||
ASSERT_THROW(statement.bind(2, 40), Sqlite::BindingIndexIsOutOfRange);
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, WrongBindingNameThrowingBindingIndexIsOutOfBound)
|
||||
{
|
||||
ReadStatement statement("SELECT name, number FROM test WHERE number=@name", database);
|
||||
|
||||
ASSERT_THROW(statement.bind("@name2", 40), Sqlite::WrongBingingName);
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, RequestBindingNamesFromStatement)
|
||||
@@ -299,13 +334,20 @@ TEST_F(SqliteStatement, WriteNamedValues)
|
||||
ASSERT_THAT(statement, HasValues("see", "7.23", 1));
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, ClosedDatabase)
|
||||
TEST_F(SqliteStatement, CannotWriteToClosedDatabase)
|
||||
{
|
||||
database.close();
|
||||
ASSERT_THROW(WriteStatement("INSERT INTO test(name, number) VALUES (?, ?)", database), Exception);
|
||||
ASSERT_THROW(ReadStatement("SELECT * FROM test", database), Exception);
|
||||
ASSERT_THROW(ReadWriteStatement("INSERT INTO test(name, number) VALUES (?, ?)", database), Exception);
|
||||
database.open(QDir::tempPath() + QStringLiteral("/SqliteStatementTest.db"));
|
||||
|
||||
ASSERT_THROW(WriteStatement("INSERT INTO test(name, number) VALUES (?, ?)", database),
|
||||
Sqlite::DatabaseIsNotOpen);
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, CannotReadFromClosedDatabase)
|
||||
{
|
||||
database.close();
|
||||
|
||||
ASSERT_THROW(ReadStatement("SELECT * FROM test", database),
|
||||
Sqlite::DatabaseIsNotOpen);
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, GetTupleValuesWithoutArguments)
|
||||
@@ -461,6 +503,7 @@ void SqliteStatement::SetUp()
|
||||
|
||||
void SqliteStatement::TearDown()
|
||||
{
|
||||
if (database.isOpen())
|
||||
database.close();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user