/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ #pragma once #include "sqliteglobal.h" #include "sqliteexception.h" #include #include #include #include #include #include using std::int64_t; struct sqlite3_stmt; struct sqlite3; namespace Sqlite { class Database; class DatabaseBackend; class SQLITE_EXPORT BaseStatement { public: explicit BaseStatement(Utils::SmallStringView sqlStatement, Database &database); static void deleteCompiledStatement(sqlite3_stmt *m_compiledStatement); bool next() const; void step() const; void execute() const; void reset() const; int fetchIntValue(int column) const; long fetchLongValue(int column) const; long long fetchLongLongValue(int column) const; double fetchDoubleValue(int column) const; Utils::SmallString fetchSmallStringValue(int column) const; Utils::PathString fetchPathStringValue(int column) const; template Type fetchValue(int column) const; int columnCount() const; Utils::SmallStringVector columnNames() const; void bind(int index, int fetchValue); void bind(int index, long long fetchValue); void bind(int index, double fetchValue); void bind(int index, Utils::SmallStringView fetchValue); void bind(int index, uint value) { bind(index, static_cast(value)); } void bind(int index, long value) { bind(index, static_cast(value)); } template void bind(Utils::SmallStringView name, Type fetchValue); int bindingIndexForName(Utils::SmallStringView name) const; void prepare(Utils::SmallStringView sqlStatement); void waitForUnlockNotify() const; sqlite3 *sqliteDatabaseHandle() const; TextEncoding databaseTextEncoding(); 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 &columns) const; void checkColumnIsValid(int column) const; void checkBindingName(int index) const; void setBindingParameterCount(); void setColumnCount(); bool isReadOnlyStatement() 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; QString columnName(int column) const; Database &database() const; private: std::unique_ptr m_compiledStatement; Database &m_database; int m_bindingParameterCount; int m_columnCount; mutable bool m_isReadyToFetchValues; }; extern template SQLITE_EXPORT void BaseStatement::bind(Utils::SmallStringView name, int value); extern template SQLITE_EXPORT void BaseStatement::bind(Utils::SmallStringView name, long value); extern template SQLITE_EXPORT void BaseStatement::bind(Utils::SmallStringView name, long long value); extern template SQLITE_EXPORT void BaseStatement::bind(Utils::SmallStringView name, double value); extern template SQLITE_EXPORT void BaseStatement::bind(Utils::SmallStringView name, Utils::SmallStringView text); template <> SQLITE_EXPORT int BaseStatement::fetchValue(int column) const; template <> SQLITE_EXPORT long BaseStatement::fetchValue(int column) const; template <> SQLITE_EXPORT long long BaseStatement::fetchValue(int column) const; template <> SQLITE_EXPORT double BaseStatement::fetchValue(int column) const; extern template SQLITE_EXPORT Utils::SmallString BaseStatement::fetchValue(int column) const; extern template SQLITE_EXPORT Utils::PathString BaseStatement::fetchValue(int column) const; template class SQLITE_EXPORT StatementImplementation : public BaseStatement { public: using BaseStatement::BaseStatement; void bindValues() { } template void bindValues(const ValueType&... values) { bindValuesByIndex(1, values...); } template void write(const ValueType&... values) { bindValuesByIndex(1, values...); BaseStatement::execute(); } template void bindNameValues(const ValueType&... values) { bindValuesByName(values...); } template void writeNamed(const ValueType&... values) { bindValuesByName(values...); BaseStatement::execute(); } template std::vector values(std::size_t reserveSize) { Resetter resetter{*this}; std::vector resultValues; resultValues.reserve(reserveSize); while (BaseStatement::next()) emplaceBackValues(resultValues); return resultValues; } template std::vector values(std::size_t reserveSize, const QueryTypes&... queryValues) { Resetter resetter{*this}; std::vector resultValues; resultValues.reserve(reserveSize); bindValues(queryValues...); while (BaseStatement::next()) emplaceBackValues(resultValues); return resultValues; } template std::vector values(std::size_t reserveSize, const std::vector &queryValues) { std::vector resultValues; resultValues.reserve(reserveSize); for (const QueryElementType &queryValue : queryValues) { Resetter resetter{*this}; bindValues(queryValue); while (BaseStatement::next()) emplaceBackValues(resultValues); } return resultValues; } template std::vector values(std::size_t reserveSize, const std::vector> &queryTuples) { using Container = std::vector; Container resultValues; resultValues.reserve(reserveSize); for (const auto &queryTuple : queryTuples) { Resetter resetter{*this}; bindTupleValues(queryTuple); while (BaseStatement::next()) emplaceBackValues(resultValues); } return resultValues; } template Utils::optional value(const QueryTypes&... queryValues) { Resetter resetter{*this}; Utils::optional resultValue; bindValues(queryValues...); if (BaseStatement::next()) resultValue = assignValue, ResultTypeCount>(); return resultValue; } template static Type toValue(Utils::SmallStringView sqlStatement, Database &database) { StatementImplementation statement(sqlStatement, database); statement.next(); return statement.template fetchValue(0); } private: struct Resetter { Resetter(StatementImplementation &statement) : statement(statement) {} ~Resetter() { statement.reset(); } StatementImplementation &statement; }; struct ValueGetter { ValueGetter(StatementImplementation &statement, int column) : statement(statement), column(column) {} operator int() { return statement.fetchIntValue(column); } operator long() { return statement.fetchLongValue(column); } operator long long() { return statement.fetchLongLongValue(column); } operator double() { return statement.fetchDoubleValue(column); } operator Utils::SmallString() { return statement.fetchSmallStringValue(column); } operator Utils::PathString() { return statement.fetchPathStringValue(column); } StatementImplementation &statement; int column; }; template void emplaceBackValues(ContainerType &container, std::integer_sequence) { container.emplace_back(ValueGetter(*this, ColumnIndices)...); } template void emplaceBackValues(ContainerType &container) { emplaceBackValues(container, std::make_integer_sequence{}); } template ResultOptionalType assignValue(std::integer_sequence) { return ResultOptionalType(Utils::in_place, ValueGetter(*this, ColumnIndices)...); } template ResultOptionalType assignValue() { return assignValue(std::make_integer_sequence{}); } template void bindValuesByIndex(int index, const ValueType &value) { BaseStatement::bind(index, value); } template void bindValuesByIndex(int index, const ValueType &value, const ValueTypes&... values) { BaseStatement::bind(index, value); bindValuesByIndex(index + 1, values...); } template void bindValuesByName(Utils::SmallStringView name, const ValueType &value) { BaseStatement::bind(BaseStatement::bindingIndexForName(name), value); } template void bindValuesByName(Utils::SmallStringView name, const ValueType &value, const ValueTypes&... values) { BaseStatement::bind(BaseStatement::bindingIndexForName(name), value); bindValuesByName(values...); } template void bindTupleValuesElement(const TupleType &tuple, std::index_sequence) { bindValues(std::get(tuple)...); } template ::value>> void bindTupleValues(const TupleType &element) { bindTupleValuesElement(element, ColumnIndices()); } }; } // namespace Sqlite