aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs/sqlite/sqlitebasestatement.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/sqlite/sqlitebasestatement.cpp')
-rw-r--r--src/libs/sqlite/sqlitebasestatement.cpp313
1 files changed, 213 insertions, 100 deletions
diff --git a/src/libs/sqlite/sqlitebasestatement.cpp b/src/libs/sqlite/sqlitebasestatement.cpp
index 87aa3f68b3..dc4dd465e7 100644
--- a/src/libs/sqlite/sqlitebasestatement.cpp
+++ b/src/libs/sqlite/sqlitebasestatement.cpp
@@ -41,11 +41,10 @@
namespace Sqlite {
BaseStatement::BaseStatement(Utils::SmallStringView sqlStatement, Database &database)
- : m_compiledStatement(nullptr, deleteCompiledStatement),
- m_database(database),
- m_bindingParameterCount(0),
- m_columnCount(0),
- m_isReadyToFetchValues(false)
+ : m_compiledStatement(nullptr, deleteCompiledStatement)
+ , m_database(database)
+ , m_bindingParameterCount(0)
+ , m_columnCount(0)
{
prepare(sqlStatement);
setBindingParameterCount();
@@ -107,11 +106,8 @@ void BaseStatement::reset() const
{
int resultCode = sqlite3_reset(m_compiledStatement.get());
- if (resultCode != SQLITE_OK) {
+ if (resultCode != SQLITE_OK)
checkForResetError(resultCode);
-
- m_isReadyToFetchValues = false;
- }
}
bool BaseStatement::next() const
@@ -127,8 +123,6 @@ bool BaseStatement::next() const
} while (resultCode == SQLITE_LOCKED);
- setIfIsReadyToFetchValues(resultCode);
-
if (resultCode == SQLITE_ROW)
return true;
else if (resultCode == SQLITE_DONE)
@@ -147,15 +141,11 @@ int BaseStatement::columnCount() const
return m_columnCount;
}
-Utils::SmallStringVector BaseStatement::columnNames() const
+void BaseStatement::bind(int index, NullValue)
{
- Utils::SmallStringVector columnNames;
- int columnCount = BaseStatement::columnCount();
- columnNames.reserve(std::size_t(columnCount));
- for (int columnIndex = 0; columnIndex < columnCount; columnIndex++)
- columnNames.emplace_back(sqlite3_column_origin_name(m_compiledStatement.get(), columnIndex));
-
- return columnNames;
+ int resultCode = sqlite3_bind_null(m_compiledStatement.get(), index);
+ if (resultCode != SQLITE_OK)
+ checkForBindingError(resultCode);
}
void BaseStatement::bind(int index, int value)
@@ -179,6 +169,17 @@ void BaseStatement::bind(int index, double value)
checkForBindingError(resultCode);
}
+void BaseStatement::bind(int index, void *pointer)
+{
+ int resultCode = sqlite3_bind_pointer(m_compiledStatement.get(),
+ index,
+ pointer,
+ "carray",
+ nullptr);
+ if (resultCode != SQLITE_OK)
+ checkForBindingError(resultCode);
+}
+
void BaseStatement::bind(int index, Utils::SmallStringView text)
{
int resultCode = sqlite3_bind_text(m_compiledStatement.get(),
@@ -190,23 +191,33 @@ void BaseStatement::bind(int index, Utils::SmallStringView text)
checkForBindingError(resultCode);
}
-template <typename Type>
-void BaseStatement::bind(Utils::SmallStringView name, Type value)
+void BaseStatement::bind(int index, Utils::span<const byte> bytes)
{
- int index = bindingIndexForName(name);
- checkBindingName(index);
- bind(index, value);
+ int resultCode = sqlite3_bind_blob64(m_compiledStatement.get(),
+ index,
+ bytes.data(),
+ static_cast<long long>(bytes.size()),
+ SQLITE_STATIC);
+ if (resultCode != SQLITE_OK)
+ checkForBindingError(resultCode);
}
-template SQLITE_EXPORT void BaseStatement::bind(Utils::SmallStringView name, int value);
-template SQLITE_EXPORT void BaseStatement::bind(Utils::SmallStringView name, long value);
-template SQLITE_EXPORT void BaseStatement::bind(Utils::SmallStringView name, long long value);
-template SQLITE_EXPORT void BaseStatement::bind(Utils::SmallStringView name, double value);
-template SQLITE_EXPORT void BaseStatement::bind(Utils::SmallStringView name, Utils::SmallStringView text);
-
-int BaseStatement::bindingIndexForName(Utils::SmallStringView name) const
-{
- return sqlite3_bind_parameter_index(m_compiledStatement.get(), name.data());
+void BaseStatement::bind(int index, const Value &value)
+{
+ switch (value.type()) {
+ case ValueType::Integer:
+ bind(index, value.toInteger());
+ break;
+ case ValueType::Float:
+ bind(index, value.toFloat());
+ break;
+ case ValueType::String:
+ bind(index, value.toStringView());
+ break;
+ case ValueType::Null:
+ bind(index, NullValue{});
+ break;
+ }
}
void BaseStatement::prepare(Utils::SmallStringView sqlStatement)
@@ -237,18 +248,49 @@ sqlite3 *BaseStatement::sqliteDatabaseHandle() const
return m_database.backend().sqliteDatabaseHandle();
}
-TextEncoding BaseStatement::databaseTextEncoding()
-{
- return m_database.backend().textEncoding();
-}
-
void BaseStatement::checkForStepError(int resultCode) const
{
switch (resultCode) {
- 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!");
+ 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!");
+ case SQLITE_TOOBIG:
+ throwTooBig("SqliteStatement::stepStatement: Some is to bigger than SQLITE_MAX_LENGTH.");
+ case SQLITE_SCHEMA:
+ throwSchemaChangeError("SqliteStatement::stepStatement: Schema changed but the statement "
+ "cannot be recompiled.");
+ case SQLITE_READONLY:
+ throwCannotWriteToReadOnlyConnection(
+ "SqliteStatement::stepStatement: Cannot write to read only connection");
+ case SQLITE_PROTOCOL:
+ throwProtocolError(
+ "SqliteStatement::stepStatement: Something strang with the file locking happened.");
+ case SQLITE_NOMEM:
+ throw std::bad_alloc();
+ case SQLITE_NOLFS:
+ throwDatabaseExceedsMaximumFileSize(
+ "SqliteStatement::stepStatement: Database exceeds maximum file size.");
+ case SQLITE_MISMATCH:
+ throwDataTypeMismatch(
+ "SqliteStatement::stepStatement: Most probably you used not an integer for a rowid.");
+ case SQLITE_LOCKED:
+ throwConnectionIsLocked("SqliteStatement::stepStatement: Database connection is locked.");
+ case SQLITE_IOERR:
+ throwInputOutputError("SqliteStatement::stepStatement: An IO error happened.");
+ case SQLITE_INTERRUPT:
+ throwExecutionInterrupted("SqliteStatement::stepStatement: Execution was interrupted.");
+ case SQLITE_CORRUPT:
+ throwDatabaseIsCorrupt("SqliteStatement::stepStatement: Database is corrupt.");
+ case SQLITE_CANTOPEN:
+ throwCannotOpen("SqliteStatement::stepStatement: Cannot open database or temporary file.");
}
throwUnknowError("SqliteStatement::stepStatement: unknown error has happened");
@@ -257,10 +299,17 @@ void BaseStatement::checkForStepError(int resultCode) const
void BaseStatement::checkForResetError(int resultCode) const
{
switch (resultCode) {
- 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!");
+ 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!");
}
throwUnknowError("SqliteStatement::reset: unknown error has happened");
@@ -272,7 +321,8 @@ void BaseStatement::checkForPrepareError(int resultCode) const
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!");
- case SQLITE_IOERR: throwIoError("SqliteStatement::prepareStatement: IO error happened!");
+ case SQLITE_IOERR:
+ throwInputOutputError("SqliteStatement::prepareStatement: IO error happened!");
}
throwUnknowError("SqliteStatement::prepareStatement: unknown error has happened");
@@ -290,33 +340,10 @@ void BaseStatement::checkForBindingError(int resultCode) const
throwUnknowError("SqliteStatement::bind: unknown error has happened");
}
-void BaseStatement::setIfIsReadyToFetchValues(int resultCode) const
-{
- if (resultCode == SQLITE_ROW)
- m_isReadyToFetchValues = true;
- else
- m_isReadyToFetchValues = false;
-
-}
-
-void BaseStatement::checkIfIsReadyToFetchValues() const
-{
- if (!m_isReadyToFetchValues)
- throwNoValuesToFetch("SqliteStatement::value: there are no values to fetch!");
-}
-
-void BaseStatement::checkColumnsAreValid(const std::vector<int> &columns) const
-{
- for (int column : columns) {
- if (column < 0 || column >= m_columnCount)
- throwInvalidColumnFetched("SqliteStatement::values: column index out of bound!");
- }
-}
-
-void BaseStatement::checkColumnIsValid(int column) const
+void BaseStatement::checkColumnCount(int columnCount) const
{
- if (column < 0 || column >= m_columnCount)
- throwInvalidColumnFetched("SqliteStatement::values: column index out of bound!");
+ if (columnCount != m_columnCount)
+ throw ColumnCountDoesNotMatch("SqliteStatement::values: column count does not match!");
}
void BaseStatement::checkBindingName(int index) const
@@ -363,9 +390,9 @@ void BaseStatement::throwStatementIsMisused(const char *whatHasHappened) const
throw StatementIsMisused(whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle()));
}
-void BaseStatement::throwIoError(const char *whatHasHappened) const
+void BaseStatement::throwInputOutputError(const char *whatHasHappened) const
{
- throw IoError(whatHasHappened);
+ throw InputOutputError(whatHasHappened);
}
void BaseStatement::throwConstraintPreventsModification(const char *whatHasHappened) const
@@ -378,11 +405,6 @@ void BaseStatement::throwNoValuesToFetch(const char *whatHasHappened) const
throw NoValuesToFetch(whatHasHappened);
}
-void BaseStatement::throwInvalidColumnFetched(const char *whatHasHappened) const
-{
- throw InvalidColumnFetched(whatHasHappened);
-}
-
void BaseStatement::throwBindingIndexIsOutOfRange(const char *whatHasHappened) const
{
throw BindingIndexIsOutOfRange(whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle()));
@@ -406,6 +428,56 @@ void BaseStatement::throwBingingTooBig(const char *whatHasHappened) const
throw BindingTooBig(whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle()));
}
+void BaseStatement::throwTooBig(const char *whatHasHappened) const
+{
+ throw TooBig{whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle())};
+}
+
+void BaseStatement::throwSchemaChangeError(const char *whatHasHappened) const
+{
+ throw SchemeChangeError{whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle())};
+}
+
+void BaseStatement::throwCannotWriteToReadOnlyConnection(const char *whatHasHappened) const
+{
+ throw CannotWriteToReadOnlyConnection{whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle())};
+}
+
+void BaseStatement::throwProtocolError(const char *whatHasHappened) const
+{
+ throw ProtocolError{whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle())};
+}
+
+void BaseStatement::throwDatabaseExceedsMaximumFileSize(const char *whatHasHappened) const
+{
+ throw DatabaseExceedsMaximumFileSize{whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle())};
+}
+
+void BaseStatement::throwDataTypeMismatch(const char *whatHasHappened) const
+{
+ throw DataTypeMismatch{whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle())};
+}
+
+void BaseStatement::throwConnectionIsLocked(const char *whatHasHappened) const
+{
+ throw ConnectionIsLocked{whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle())};
+}
+
+void BaseStatement::throwExecutionInterrupted(const char *whatHasHappened) const
+{
+ throw ExecutionInterrupted{whatHasHappened};
+}
+
+void BaseStatement::throwDatabaseIsCorrupt(const char *whatHasHappened) const
+{
+ throw DatabaseIsCorrupt{whatHasHappened};
+}
+
+void BaseStatement::throwCannotOpen(const char *whatHasHappened) const
+{
+ throw CannotOpen{whatHasHappened};
+}
+
QString BaseStatement::columnName(int column) const
{
return QString::fromUtf8(sqlite3_column_name(m_compiledStatement.get(), column));
@@ -416,8 +488,9 @@ Database &BaseStatement::database() const
return m_database;
}
-template <typename StringType>
-static StringType textForColumn(sqlite3_stmt *sqlStatment, int column)
+namespace {
+template<typename StringType>
+StringType textForColumn(sqlite3_stmt *sqlStatment, int column)
{
const char *text = reinterpret_cast<const char*>(sqlite3_column_text(sqlStatment, column));
std::size_t size = std::size_t(sqlite3_column_bytes(sqlStatment, column));
@@ -425,25 +498,43 @@ static StringType textForColumn(sqlite3_stmt *sqlStatment, int column)
return StringType(text, size);
}
-template <typename StringType>
-static StringType convertToTextForColumn(sqlite3_stmt *sqlStatment, int column)
+Utils::span<const byte> blobForColumn(sqlite3_stmt *sqlStatment, int column)
+{
+ const byte *blob = reinterpret_cast<const byte *>(sqlite3_column_blob(sqlStatment, column));
+ std::size_t size = std::size_t(sqlite3_column_bytes(sqlStatment, column));
+
+ return {blob, size};
+}
+
+Utils::span<const byte> convertToBlobForColumn(sqlite3_stmt *sqlStatment, int column)
+{
+ int dataType = sqlite3_column_type(sqlStatment, column);
+ if (dataType == SQLITE_BLOB)
+ return blobForColumn(sqlStatment, column);
+
+ return {};
+}
+
+template<typename StringType>
+StringType convertToTextForColumn(sqlite3_stmt *sqlStatment, int column)
{
int dataType = sqlite3_column_type(sqlStatment, column);
switch (dataType) {
- case SQLITE_INTEGER:
- case SQLITE_FLOAT:
- case SQLITE3_TEXT: return textForColumn<StringType>(sqlStatment, column);
- case SQLITE_BLOB:
- case SQLITE_NULL: break;
+ case SQLITE_INTEGER:
+ case SQLITE_FLOAT:
+ case SQLITE3_TEXT:
+ return textForColumn<StringType>(sqlStatment, column);
+ case SQLITE_BLOB:
+ case SQLITE_NULL:
+ break;
}
return StringType{"", 0};
}
+} // namespace
int BaseStatement::fetchIntValue(int column) const
{
- checkIfIsReadyToFetchValues();
- checkColumnIsValid(column);
return sqlite3_column_int(m_compiledStatement.get(), column);
}
@@ -466,8 +557,6 @@ long BaseStatement::fetchValue<long>(int column) const
long long BaseStatement::fetchLongLongValue(int column) const
{
- checkIfIsReadyToFetchValues();
- checkColumnIsValid(column);
return sqlite3_column_int64(m_compiledStatement.get(), column);
}
@@ -479,11 +568,14 @@ long long BaseStatement::fetchValue<long long>(int column) const
double BaseStatement::fetchDoubleValue(int column) const
{
- checkIfIsReadyToFetchValues();
- checkColumnIsValid(column);
return sqlite3_column_double(m_compiledStatement.get(), column);
}
+Utils::span<const byte> BaseStatement::fetchBlobValue(int column) const
+{
+ return convertToBlobForColumn(m_compiledStatement.get(), column);
+}
+
template<>
double BaseStatement::fetchValue<double>(int column) const
{
@@ -493,17 +585,38 @@ double BaseStatement::fetchValue<double>(int column) const
template<typename StringType>
StringType BaseStatement::fetchValue(int column) const
{
- checkIfIsReadyToFetchValues();
- checkColumnIsValid(column);
return convertToTextForColumn<StringType>(m_compiledStatement.get(), column);
}
+template SQLITE_EXPORT Utils::SmallStringView BaseStatement::fetchValue<Utils::SmallStringView>(
+ int column) const;
+template SQLITE_EXPORT Utils::SmallString BaseStatement::fetchValue<Utils::SmallString>(
+ int column) const;
+template SQLITE_EXPORT Utils::PathString BaseStatement::fetchValue<Utils::PathString>(
+ int column) const;
+
Utils::SmallStringView BaseStatement::fetchSmallStringViewValue(int column) const
{
return fetchValue<Utils::SmallStringView>(column);
}
-template SQLITE_EXPORT Utils::SmallStringView BaseStatement::fetchValue<Utils::SmallStringView>(int column) const;
-template SQLITE_EXPORT Utils::SmallString BaseStatement::fetchValue<Utils::SmallString>(int column) const;
-template SQLITE_EXPORT Utils::PathString BaseStatement::fetchValue<Utils::PathString>(int column) const;
+ValueView BaseStatement::fetchValueView(int column) const
+{
+ int dataType = sqlite3_column_type(m_compiledStatement.get(), column);
+ switch (dataType) {
+ case SQLITE_NULL:
+ return ValueView::create(NullValue{});
+ case SQLITE_INTEGER:
+ return ValueView::create(fetchLongLongValue(column));
+ case SQLITE_FLOAT:
+ return ValueView::create(fetchDoubleValue(column));
+ case SQLITE3_TEXT:
+ return ValueView::create(fetchValue<Utils::SmallStringView>(column));
+ case SQLITE_BLOB:
+ break;
+ }
+
+ return ValueView::create(NullValue{});
+}
+
} // namespace Sqlite