diff options
Diffstat (limited to 'src/libs/sqlite/sqlitebasestatement.cpp')
-rw-r--r-- | src/libs/sqlite/sqlitebasestatement.cpp | 313 |
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 |