/**************************************************************************** ** ** 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 using std::int64_t; struct sqlite3_stmt; struct sqlite3; namespace Sqlite { class SqliteDatabase; class SqliteDatabaseBackend; class SQLITE_EXPORT SqliteStatement { protected: explicit SqliteStatement(Utils::SmallStringView sqlStatement, SqliteDatabase &database); static void deleteCompiledStatement(sqlite3_stmt *m_compiledStatement); bool next() const; void step() const; void execute() const; void reset() const; template Type value(int column) const; Utils::SmallString text(int column) const; int columnCount() const; Utils::SmallStringVector columnNames() const; void bind(int index, int value); void bind(int index, long long value); void bind(int index, double value); void bind(int index, Utils::SmallStringView value); void bind(int index, uint value) { bind(index, static_cast(value)); } void bind(int index, long value) { bind(index, static_cast(value)); } void bindValues() { } template void bindValues(Values... values) { bindValuesByIndex(1, values...); } template void write(Values... values) { bindValuesByIndex(1, values...); execute(); } template void bindNameValues(Values... values) { bindValuesByName(values...); } template void writeNamed(Values... values) { bindValuesByName(values...); execute(); } template void bind(Utils::SmallStringView name, Type value); int bindingIndexForName(Utils::SmallStringView name) const; void setBindingColumnNames(const Utils::SmallStringVector &bindingColumnNames); const Utils::SmallStringVector &bindingColumnNames() const; template std::vector> tupleValues(std::size_t reserveSize) { using Container = std::vector>; Container resultValues; resultValues.reserve(reserveSize); while (next()) emplaceTupleValues(resultValues); reset(); return resultValues; } template std::vector> tupleValues(std::size_t reserveSize, const QueryType&... queryValues) { using Container = std::vector>; Container resultValues; resultValues.reserve(reserveSize); bindValues(queryValues...); while (next()) emplaceTupleValues(resultValues); reset(); return resultValues; } template std::vector> tupleValues(std::size_t reserveSize, const std::vector> &queryTuples) { using Container = std::vector>; Container resultValues; resultValues.reserve(reserveSize); for (const auto &queryTuple : queryTuples) { bindTupleValues(queryTuple); while (next()) emplaceTupleValues(resultValues); reset(); } return resultValues; } template std::vector> tupleValues(std::size_t reserveSize, const std::vector &queryValues) { using Container = std::vector>; Container resultValues; resultValues.reserve(reserveSize); for (const QueryElementType &queryValue : queryValues) { bindValues(queryValue); while (next()) emplaceTupleValues(resultValues); reset(); } return resultValues; } template std::vector structValues(std::size_t reserveSize) { using Container = std::vector; Container resultValues; resultValues.reserve(reserveSize); while (next()) pushBackStructValues(resultValues); reset(); return resultValues; } template std::vector structValues(std::size_t reserveSize, const QueryType&... queryValues) { using Container = std::vector; Container resultValues; resultValues.reserve(reserveSize); bindValues(queryValues...); while (next()) pushBackStructValues(resultValues); reset(); return resultValues; } template std::vector structValues(std::size_t reserveSize, const std::vector &queryValues) { using Container = std::vector; Container resultValues; resultValues.reserve(reserveSize); for (const QueryElementType &queryValue : queryValues) { bindValues(queryValue); while (next()) pushBackStructValues(resultValues); reset(); } return resultValues; } template std::vector structValues(std::size_t reserveSize, const std::vector> &queryTuples) { using Container = std::vector; Container resultValues; resultValues.reserve(reserveSize); for (const auto &queryTuple : queryTuples) { bindTupleValues(queryTuple); while (next()) pushBackStructValues(resultValues); reset(); } return resultValues; } template std::vector values(std::size_t reserveSize) { std::vector resultValues; resultValues.reserve(reserveSize); while (next()) resultValues.push_back(value(0)); reset(); return resultValues; } template std::vector values(std::size_t reserveSize, const std::vector> &queryTuples) { std::vector resultValues; resultValues.reserve(reserveSize); for (const auto &queryTuple : queryTuples) { bindTupleValues(queryTuple); while (next()) resultValues.push_back(value(0)); reset(); } return resultValues; } template std::vector values(std::size_t reserveSize, const std::vector &queryValues) { std::vector resultValues; resultValues.reserve(reserveSize); for (const ElementType &queryValue : queryValues) { bindValues(queryValue); while (next()) resultValues.push_back(value(0)); reset(); } return resultValues; } template std::vector values(std::size_t reserveSize, const QueryType&... queryValues) { std::vector resultValues; resultValues.reserve(reserveSize); bindValues(queryValues...); while (next()) resultValues.push_back(value(0)); reset(); return resultValues; } template static Type toValue(Utils::SmallStringView sqlStatement, SqliteDatabase &database); void prepare(Utils::SmallStringView sqlStatement); void waitForUnlockNotify() const; sqlite3 *sqliteDatabaseHandle() const; TextEncoding databaseTextEncoding(); bool checkForStepError(int resultCode) const; void checkForPrepareError(int resultCode) const; void setIfIsReadyToFetchValues(int resultCode) const; void checkIfIsReadyToFetchValues() const; void checkColumnsAreValid(const std::vector &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; template ContainerType columnValues(const std::vector &columnIndices) const; QString columnName(int column) const; SqliteDatabase &database() const; protected: explicit SqliteStatement(Utils::SmallStringView sqlStatement, SqliteDatabaseBackend &databaseBackend); private: template void emplaceTupleValues(Container &container, std::integer_sequence) { container.emplace_back(value(Index)...); } template void emplaceTupleValues(Container &container) { emplaceTupleValues(container, std::make_integer_sequence{}); } template void pushBackStructValues(Container &container, std::integer_sequence) { using ResultType = typename Container::value_type; container.push_back(ResultType{value(Index)...}); } template void pushBackStructValues(Container &container) { pushBackStructValues(container, std::make_integer_sequence{}); } template void bindValuesByIndex(int index, Type value) { bind(index, value); } template void bindValuesByIndex(int index, Type value, Value... values) { bind(index, value); bindValuesByIndex(index + 1, values...); } template void bindValuesByName(Utils::SmallStringView name, Type value) { bind(bindingIndexForName(name), value); } template void bindValuesByName(Utils::SmallStringView name, Type value, Values... values) { bind(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, Indices()); } private: std::unique_ptr m_compiledStatement; Utils::SmallStringVector m_bindingColumnNames; SqliteDatabase &m_database; int m_bindingParameterCount; int m_columnCount; mutable bool m_isReadyToFetchValues; }; extern template SQLITE_EXPORT void SqliteStatement::bind(Utils::SmallStringView name, int value); extern template SQLITE_EXPORT void SqliteStatement::bind(Utils::SmallStringView name, long value); extern template SQLITE_EXPORT void SqliteStatement::bind(Utils::SmallStringView name, long long value); extern template SQLITE_EXPORT void SqliteStatement::bind(Utils::SmallStringView name, double value); extern template SQLITE_EXPORT void SqliteStatement::bind(Utils::SmallStringView name, Utils::SmallStringView text); extern template SQLITE_EXPORT int SqliteStatement::toValue(Utils::SmallStringView sqlStatement, SqliteDatabase &database); extern template SQLITE_EXPORT long long SqliteStatement::toValue(Utils::SmallStringView sqlStatement, SqliteDatabase &database); extern template SQLITE_EXPORT double SqliteStatement::toValue(Utils::SmallStringView sqlStatement, SqliteDatabase &database); extern template SQLITE_EXPORT Utils::SmallString SqliteStatement::toValue(Utils::SmallStringView sqlStatement, SqliteDatabase &database); template <> SQLITE_EXPORT int SqliteStatement::value(int column) const; template <> SQLITE_EXPORT long SqliteStatement::value(int column) const; template <> SQLITE_EXPORT long long SqliteStatement::value(int column) const; template <> SQLITE_EXPORT double SqliteStatement::value(int column) const; extern template SQLITE_EXPORT Utils::SmallString SqliteStatement::value(int column) const; extern template SQLITE_EXPORT Utils::PathString SqliteStatement::value(int column) const; } // namespace Sqlite