diff --git a/demo/work.cpp b/demo/work.cpp index 948120e..72cc814 100644 --- a/demo/work.cpp +++ b/demo/work.cpp @@ -79,10 +79,11 @@ int main() { object::repository repo("Administration"); auto result = repo.attach("collection_centers"); - repo.create(pool); - repo.drop(pool); + // repo.create(pool); + // repo.drop(pool); - orm::session ses(pool); + utils::message_bus bus; + orm::session ses({bus, pool}); result = ses.attach("collection_centers") .and_then([&ses] { return ses.attach("user_directories"); }) diff --git a/include/matador/query/intermediates/fetchable_query.hpp b/include/matador/query/intermediates/fetchable_query.hpp index 345be36..958e3df 100644 --- a/include/matador/query/intermediates/fetchable_query.hpp +++ b/include/matador/query/intermediates/fetchable_query.hpp @@ -77,7 +77,7 @@ public: [[nodiscard]] utils::result prepare(sql::executor &exec) const; [[nodiscard]] std::string str(const sql::executor &exec) const; - [[nodiscard]] sql::query_context compile(const sql::dialect &d, query_mode mode) const; + [[nodiscard]] sql::query_context compile(const sql::dialect &d) const; private: [[nodiscard]] utils::result, utils::error> fetch(const sql::executor &exec) const; diff --git a/include/matador/query/intermediates/query_create_intermediate.hpp b/include/matador/query/intermediates/query_create_intermediate.hpp index 7acfcab..79400fe 100644 --- a/include/matador/query/intermediates/query_create_intermediate.hpp +++ b/include/matador/query/intermediates/query_create_intermediate.hpp @@ -9,8 +9,7 @@ namespace matador::query { -class query_create_intermediate : public query_intermediate -{ +class query_create_intermediate : public query_intermediate { public: query_create_intermediate(); @@ -20,6 +19,7 @@ public: executable_query table(const sql::table &table, const object::repository &schema) { return this->table(table, object::attribute_definition_generator::generate(schema)); } + executable_query schema(const std::string &schema_name); }; } diff --git a/include/matador/query/intermediates/query_drop_intermediate.hpp b/include/matador/query/intermediates/query_drop_intermediate.hpp index 2940f8e..26dd33a 100644 --- a/include/matador/query/intermediates/query_drop_intermediate.hpp +++ b/include/matador/query/intermediates/query_drop_intermediate.hpp @@ -5,12 +5,12 @@ namespace matador::query { -class query_drop_intermediate : query_intermediate -{ +class query_drop_intermediate : query_intermediate { public: query_drop_intermediate(); executable_query table(const sql::table &table); + executable_query schema(const std::string &schema_name); }; } diff --git a/include/matador/query/internal/key_value_pair.hpp b/include/matador/query/internal/key_value_pair.hpp index bdea78d..19bc41d 100644 --- a/include/matador/query/internal/key_value_pair.hpp +++ b/include/matador/query/internal/key_value_pair.hpp @@ -3,6 +3,7 @@ #include "matador/sql/column.hpp" +#include "matador/utils/placeholder.hpp" #include "matador/utils/types.hpp" namespace matador::query::internal { @@ -12,13 +13,14 @@ public: key_value_pair(const sql::column &col, utils::database_type value); key_value_pair(std::string name, utils::database_type value); key_value_pair(const char *name, utils::database_type value); + key_value_pair(const char *name, utils::placeholder p); [[nodiscard]] const std::string& name() const; - [[nodiscard]] const utils::database_type& value() const; + [[nodiscard]] const std::variant& value() const; private: std::string name_; - utils::database_type value_; + std::variant value_; }; } diff --git a/include/matador/query/internal/query_parts.hpp b/include/matador/query/internal/query_parts.hpp index 15f0e52..0eb68c8 100644 --- a/include/matador/query/internal/query_parts.hpp +++ b/include/matador/query/internal/query_parts.hpp @@ -91,7 +91,7 @@ private: class query_drop_foreign_key_constraint_part final : public query_part { public: - explicit query_drop_foreign_key_constraint_part( const std::vector& columns); + query_drop_foreign_key_constraint_part(); void accept(query_part_visitor &visitor) override; }; @@ -377,6 +377,19 @@ private: std::vector columns_; }; +class query_create_schema_part final : public query_part { +public: + explicit query_create_schema_part(std::string schema); + + [[nodiscard]] const std::string& schema() const; + +private: + void accept(query_part_visitor &visitor) override; + +private: + std::string schema_; +}; + class query_drop_part final : public query_part { public: @@ -400,5 +413,18 @@ private: sql::table table_; }; +class query_drop_schema_part final : public query_part { +public: + explicit query_drop_schema_part(std::string schema_); + + [[nodiscard]] const std::string& schema() const; + +private: + void accept(query_part_visitor &visitor) override; + +private: + std::string schema_; +}; + } #endif //QUERY_QUERY_PARTS_HPP diff --git a/include/matador/query/query.hpp b/include/matador/query/query.hpp index c5df24a..ae669fd 100644 --- a/include/matador/query/query.hpp +++ b/include/matador/query/query.hpp @@ -20,6 +20,7 @@ class query public: [[nodiscard]] static query_create_intermediate create(); [[nodiscard]] static query_drop_intermediate drop(); + [[nodiscard]] static query_select_intermediate select(); [[nodiscard]] static query_select_intermediate select(std::initializer_list columns); [[nodiscard]] static query_select_intermediate select(const std::vector& columns); [[nodiscard]] static query_select_intermediate select(const std::vector &column_names); diff --git a/include/matador/query/query_compiler.hpp b/include/matador/query/query_compiler.hpp index 0fc0642..7363756 100644 --- a/include/matador/query/query_compiler.hpp +++ b/include/matador/query/query_compiler.hpp @@ -22,8 +22,7 @@ struct basic_type_to_string_visitor; struct query_data; struct value_visitor; -class query_compiler final : public query_part_visitor -{ +class query_compiler final : public query_part_visitor { public: sql::query_context compile(const query_data &data, const sql::dialect &d, @@ -33,42 +32,45 @@ protected: void visit(internal::query_alter_part& part) override; void visit(internal::query_alter_table_part& part) override; void visit(internal::query_add_key_constraint_part& part) override; - void visit( internal::query_add_foreign_key_constraint_part& part ) override; - void visit( internal::query_add_primary_key_constraint_part& part ) override; - void visit( internal::query_add_foreign_key_reference_part& part ) override; + void visit(internal::query_add_foreign_key_constraint_part& part) override; + void visit(internal::query_add_primary_key_constraint_part& part) override; + void visit(internal::query_add_foreign_key_reference_part& part) override; void visit(internal::query_drop_key_constraint_part& part) override; + void visit(internal::query_drop_foreign_key_constraint_part& part) override; - void visit(internal::query_select_part &select_part) override; - void visit(internal::query_from_part &from_part) override; - void visit(internal::query_join_part &join_part) override; - void visit(internal::query_on_part &on_part) override; - void visit(internal::query_where_part &where_part) override; - void visit(internal::query_group_by_part &group_by_part) override; - void visit(internal::query_order_by_part &order_by_part) override; - void visit(internal::query_order_by_asc_part &order_by_asc_part) override; - void visit(internal::query_order_by_desc_part &order_by_desc_part) override; - void visit(internal::query_offset_part &offset_part) override; - void visit(internal::query_limit_part &limit_part) override; - void visit(internal::query_insert_part &insert_part) override; - void visit(internal::query_into_part &into_part) override; - void visit(internal::query_values_part &values_part) override; +protected: + void visit(internal::query_select_part &part) override; + void visit(internal::query_from_part &part) override; + void visit(internal::query_join_part &part) override; + void visit(internal::query_on_part &part) override; + void visit(internal::query_where_part &part) override; + void visit(internal::query_group_by_part &part) override; + void visit(internal::query_order_by_part &part) override; + void visit(internal::query_order_by_asc_part &part) override; + void visit(internal::query_order_by_desc_part &part) override; + void visit(internal::query_offset_part &part) override; + void visit(internal::query_limit_part &part) override; + void visit(internal::query_insert_part &part) override; + void visit(internal::query_into_part &part) override; + void visit(internal::query_values_part &part) override; - void visit(internal::query_update_part &update_part) override; - void visit(internal::query_set_part &set_part) override; + void visit(internal::query_update_part &part) override; + void visit(internal::query_set_part &part) override; - void visit(internal::query_delete_part &delete_part) override; - void visit(internal::query_delete_from_part &delete_from_part) override; + void visit(internal::query_delete_part &part) override; + void visit(internal::query_delete_from_part &part) override; - void visit(internal::query_create_part &create_part) override; - void visit(internal::query_create_table_part &create_table_part) override; + void visit(internal::query_create_part &part) override; + void visit(internal::query_create_table_part &part) override; + void visit(internal::query_create_schema_part& part) override; - void visit(internal::query_drop_part &drop_part) override; - void visit(internal::query_drop_table_part &drop_table_part) override; + void visit(internal::query_drop_part &part) override; + void visit(internal::query_drop_table_part &part) override; + void visit(internal::query_drop_schema_part& part) override; static std::string build_table_name(sql::dialect_token token, const sql::dialect &d, const sql::table& t); - std::string determine_value(value_visitor &visitor, const std::variant &val); - std::string determine_set_value(internal::basic_type_to_string_visitor &visitor, const utils::database_type &val); + static std::string determine_value(value_visitor &visitor, const std::variant &val); protected: const query_data *data_{}; diff --git a/include/matador/query/query_data.hpp b/include/matador/query/query_data.hpp index f2409c3..bd0ff7f 100644 --- a/include/matador/query/query_data.hpp +++ b/include/matador/query/query_data.hpp @@ -12,16 +12,10 @@ namespace matador::query { -enum struct query_mode { - Direct = 0, - Prepared = 1 -}; - struct query_data { - std::vector> parts{}; - std::vector columns{}; - std::unordered_map tables{}; - query_mode mode = query_mode::Direct; + std::vector> parts{}; + std::vector columns{}; + std::unordered_map tables{}; }; } diff --git a/include/matador/query/query_part_visitor.hpp b/include/matador/query/query_part_visitor.hpp index ce9b530..e246669 100644 --- a/include/matador/query/query_part_visitor.hpp +++ b/include/matador/query/query_part_visitor.hpp @@ -8,6 +8,7 @@ class query_alter_part; class query_alter_table_part; class query_add_key_constraint_part; class query_drop_key_constraint_part; +class query_drop_foreign_key_constraint_part; class query_add_foreign_key_constraint_part; class query_add_foreign_key_reference_part; class query_add_primary_key_constraint_part; @@ -31,8 +32,10 @@ class query_delete_part; class query_delete_from_part; class query_create_part; class query_create_table_part; +class query_create_schema_part; class query_drop_part; class query_drop_table_part; +class query_drop_schema_part; } class query_part_visitor { @@ -46,34 +49,37 @@ public: virtual void visit(internal::query_add_primary_key_constraint_part &part) = 0; virtual void visit(internal::query_add_foreign_key_reference_part &part) = 0; virtual void visit(internal::query_drop_key_constraint_part &part) = 0; + virtual void visit(internal::query_drop_foreign_key_constraint_part &part) = 0; - virtual void visit(internal::query_select_part &select_part) = 0; - virtual void visit(internal::query_from_part &from_part) = 0; - virtual void visit(internal::query_join_part &join_part) = 0; - virtual void visit(internal::query_on_part &on_part) = 0; - virtual void visit(internal::query_where_part &where_part) = 0; - virtual void visit(internal::query_group_by_part &group_by_part) = 0; - virtual void visit(internal::query_order_by_part &order_by_part) = 0; - virtual void visit(internal::query_order_by_asc_part &order_by_asc_part) = 0; - virtual void visit(internal::query_order_by_desc_part &order_by_desc_part) = 0; - virtual void visit(internal::query_offset_part &offset_part) = 0; - virtual void visit(internal::query_limit_part &limit_part) = 0; + virtual void visit(internal::query_select_part &part) = 0; + virtual void visit(internal::query_from_part &part) = 0; + virtual void visit(internal::query_join_part &part) = 0; + virtual void visit(internal::query_on_part &part) = 0; + virtual void visit(internal::query_where_part &part) = 0; + virtual void visit(internal::query_group_by_part &part) = 0; + virtual void visit(internal::query_order_by_part &part) = 0; + virtual void visit(internal::query_order_by_asc_part &part) = 0; + virtual void visit(internal::query_order_by_desc_part &part) = 0; + virtual void visit(internal::query_offset_part &part) = 0; + virtual void visit(internal::query_limit_part &part) = 0; - virtual void visit(internal::query_insert_part &insert_part) = 0; - virtual void visit(internal::query_into_part &into_part) = 0; - virtual void visit(internal::query_values_part &values_part) = 0; + virtual void visit(internal::query_insert_part &part) = 0; + virtual void visit(internal::query_into_part &part) = 0; + virtual void visit(internal::query_values_part &part) = 0; - virtual void visit(internal::query_update_part &update_part) = 0; - virtual void visit(internal::query_set_part &set_part) = 0; + virtual void visit(internal::query_update_part &part) = 0; + virtual void visit(internal::query_set_part &part) = 0; - virtual void visit(internal::query_delete_part &delete_part) = 0; - virtual void visit(internal::query_delete_from_part &delete_from_part) = 0; + virtual void visit(internal::query_delete_part &part) = 0; + virtual void visit(internal::query_delete_from_part &part) = 0; - virtual void visit(internal::query_create_part &create_part) = 0; - virtual void visit(internal::query_create_table_part &create_table_part) = 0; + virtual void visit(internal::query_create_part &part) = 0; + virtual void visit(internal::query_create_table_part &part) = 0; + virtual void visit(internal::query_create_schema_part &part) = 0; - virtual void visit(internal::query_drop_part &drop_part) = 0; - virtual void visit(internal::query_drop_table_part &drop_table_part) = 0; + virtual void visit(internal::query_drop_part &part) = 0; + virtual void visit(internal::query_drop_table_part &part) = 0; + virtual void visit(internal::query_drop_schema_part &part) = 0; }; } diff --git a/include/matador/sql/dialect.hpp b/include/matador/sql/dialect.hpp index 9dab6a4..22efd2b 100644 --- a/include/matador/sql/dialect.hpp +++ b/include/matador/sql/dialect.hpp @@ -136,58 +136,57 @@ private: escape_identifier_t identifier_escape_type_ = escape_identifier_t::ESCAPE_BOTH_SAME; std::string default_schema_name_; - // std::unique_ptr compiler_; token_to_string_map tokens_ { - {dialect_token::Create, "CREATE"}, - {dialect_token::Drop, "DROP"}, - {dialect_token::Remove, "DELETE"}, - {dialect_token::Insert, "INSERT"}, - {dialect_token::Alter, "ALTER"}, - {dialect_token::Table, "TABLE"}, - {dialect_token::Into, "INTO"}, - {dialect_token::Values, "VALUES"}, - {dialect_token::Update, "UPDATE"}, - {dialect_token::Select, "SELECT"}, - {dialect_token::Columns, "COLUMNS"}, - {dialect_token::Column, "COLUMN"}, - {dialect_token::From, "FROM"}, - {dialect_token::Join, "LEFT JOIN"}, - {dialect_token::On, "ON"}, - {dialect_token::Where, "WHERE"}, - {dialect_token::And, "AND"}, - {dialect_token::Or, "OR"}, - {dialect_token::Not, "NOT"}, - {dialect_token::Like, "LIKE"}, - {dialect_token::Between, "BETWEEN"}, - {dialect_token::In, "IN"}, - {dialect_token::OrderBy, "ORDER BY"}, - {dialect_token::GroupBy, "GROUP BY"}, - {dialect_token::Asc, "ASC"}, - {dialect_token::Desc, "DESC"}, - {dialect_token::Offset, "OFFSET"}, - {dialect_token::Limit, "LIMIT"}, - {dialect_token::As, "AS"}, - {dialect_token::Offset, "OFFSET"}, - {dialect_token::Distinct, "DISTINCT"}, - {dialect_token::Set, "SET"}, - {dialect_token::NotNull, "NOT NULL"}, - {dialect_token::PrimaryKey, "PRIMARY KEY"}, - {dialect_token::ForeignKey, "FOREIGN KEY"}, - {dialect_token::References, "REFERENCES"}, {dialect_token::AddConstraint, "ADD CONSTRAINT"}, - {dialect_token::DropConstraint, "DROP CONSTRAINT"}, + {dialect_token::Alter, "ALTER"}, + {dialect_token::And, "AND"}, + {dialect_token::As, "AS"}, + {dialect_token::Asc, "ASC"}, + {dialect_token::Asterisk, "*"}, {dialect_token::Begin, "BEGIN TRANSACTION"}, - {dialect_token::Commit, "COMMIT TRANSACTION"}, - {dialect_token::Rollback, "ROLLBACK TRANSACTION"}, - {dialect_token::StartQuote, "\""}, - {dialect_token::EndQuote, "\""}, - {dialect_token::StringQuote, "'"}, {dialect_token::BeginBinaryData, "X'"}, - {dialect_token::EndBinaryData, "'"}, {dialect_token::BeginStringData, "'"}, + {dialect_token::Between, "BETWEEN"}, + {dialect_token::Column, "COLUMN"}, + {dialect_token::Columns, "COLUMNS"}, + {dialect_token::Commit, "COMMIT TRANSACTION"}, + {dialect_token::Create, "CREATE"}, + {dialect_token::Desc, "DESC"}, + {dialect_token::Distinct, "DISTINCT"}, + {dialect_token::Drop, "DROP"}, + {dialect_token::DropConstraint, "DROP CONSTRAINT"}, + {dialect_token::EndBinaryData, "'"}, + {dialect_token::EndQuote, "\""}, {dialect_token::EndStringData, "'"}, - {dialect_token::None, ""} + {dialect_token::ForeignKey, "FOREIGN KEY"}, + {dialect_token::From, "FROM"}, + {dialect_token::GroupBy, "GROUP BY"}, + {dialect_token::In, "IN"}, + {dialect_token::Insert, "INSERT"}, + {dialect_token::Into, "INTO"}, + {dialect_token::Join, "LEFT JOIN"}, + {dialect_token::Like, "LIKE"}, + {dialect_token::Limit, "LIMIT"}, + {dialect_token::None, ""}, + {dialect_token::Not, "NOT"}, + {dialect_token::NotNull, "NOT NULL"}, + {dialect_token::Offset, "OFFSET"}, + {dialect_token::On, "ON"}, + {dialect_token::Or, "OR"}, + {dialect_token::OrderBy, "ORDER BY"}, + {dialect_token::PrimaryKey, "PRIMARY KEY"}, + {dialect_token::References, "REFERENCES"}, + {dialect_token::Remove, "DELETE"}, + {dialect_token::Rollback, "ROLLBACK TRANSACTION"}, + {dialect_token::Select, "SELECT"}, + {dialect_token::Set, "SET"}, + {dialect_token::StartQuote, "\""}, + {dialect_token::StringQuote, "'"}, + {dialect_token::Table, "TABLE"}, + {dialect_token::Update, "UPDATE"}, + {dialect_token::Values, "VALUES"}, + {dialect_token::Where, "WHERE"} }; data_type_to_string_map data_types_ { diff --git a/include/matador/sql/dialect_token.hpp b/include/matador/sql/dialect_token.hpp index 3703789..eb663c5 100644 --- a/include/matador/sql/dialect_token.hpp +++ b/include/matador/sql/dialect_token.hpp @@ -6,59 +6,57 @@ namespace matador::sql { enum class dialect_token : uint8_t { - Create = 0, - Drop, - Remove, - Insert, - Update, - Select, + AddConstraint = 0, Alter, - ForeignKey, - PrimaryKey, - AddConstraint, - DropConstraint, - References, - Schema, - Database, - Table, - Values, - InsertValues, - Columns, - Column, - From, - Join, - On, - Into, - Where, - WhereClause, And, - Or, - Not, - Like, - Between, - In, - OrderBy, - GroupBy, - Asc, - Desc, - Limit, As, - Offset, - Distinct, - Set, - UpdateValues, - NotNull, + Asc, + Asterisk, Begin, - Commit, - Rollback, - StartQuote, - EndQuote, - StringQuote, BeginBinaryData, - EndBinaryData, BeginStringData, + Between, + Column, + Columns, + Commit, + Create, + Database, + Desc, + Distinct, + Drop, + DropConstraint, + EndBinaryData, + EndQuote, EndStringData, - None + ForeignKey, + From, + GroupBy, + In, + Insert, + Into, + Join, + Like, + Limit, + None, + Not, + NotNull, + Offset, + On, + Or, + OrderBy, + PrimaryKey, + References, + Remove, + Rollback, + Schema, + Select, + Set, + StartQuote, + StringQuote, + Table, + Update, + Values, + Where }; } diff --git a/include/matador/sql/query_context.hpp b/include/matador/sql/query_context.hpp index 614bfcd..856ee3c 100644 --- a/include/matador/sql/query_context.hpp +++ b/include/matador/sql/query_context.hpp @@ -10,6 +10,7 @@ namespace matador::sql { enum class sql_command { SQL_UNKNOWN, + SQL_CREATE, SQL_CREATE_TABLE, SQL_CREATE_SCHEMA, SQL_CREATE_DATABASE, @@ -17,6 +18,7 @@ enum class sql_command { SQL_INSERT, SQL_DELETE, SQL_SELECT, + SQL_DROP, SQL_DROP_TABLE, SQL_DROP_SCHEMA, SQL_DROP_DATABASE, diff --git a/include/matador/sql/record.hpp b/include/matador/sql/record.hpp index 70775b5..1cf17c9 100644 --- a/include/matador/sql/record.hpp +++ b/include/matador/sql/record.hpp @@ -10,8 +10,7 @@ namespace matador::sql { struct column; -class record -{ +class record final { private: using field_ref = std::reference_wrapper; using field_by_index = std::vector; @@ -45,13 +44,11 @@ public: [[nodiscard]] const field& at(const column &col) const; [[nodiscard]] const field& at(size_t index) const; template - std::optional at(const column &col) const - { + std::optional at(const column &col) const { return at(col).as(); } template - std::optional at(size_t index) const - { + std::optional at(const size_t index) const { return at(index).as(); } @@ -70,8 +67,6 @@ public: [[nodiscard]] bool empty() const; void clear(); -// [[nodiscard]] bool unknown() const; - private: void init(); void add_to_map(field &col, size_t index); @@ -79,8 +74,6 @@ private: private: field_by_index fields_; field_by_name_map fields_by_name_; - -// int pk_index_{-1}; }; } diff --git a/include/matador/sql/statement_cache.hpp b/include/matador/sql/statement_cache.hpp index a79cc88..ef567b0 100644 --- a/include/matador/sql/statement_cache.hpp +++ b/include/matador/sql/statement_cache.hpp @@ -68,7 +68,7 @@ public: return bus_.subscribe(handler); } - connection_pool& pool() const; + [[nodiscard]] connection_pool& pool() const; private: size_t max_size_{}; diff --git a/source/orm/CMakeLists.txt b/source/orm/CMakeLists.txt index f0326d5..222449b 100644 --- a/source/orm/CMakeLists.txt +++ b/source/orm/CMakeLists.txt @@ -19,6 +19,7 @@ add_library(matador-orm STATIC ../../include/matador/query/intermediates/executable_query.hpp ../../include/matador/query/intermediates/fetchable_query.hpp ../../include/matador/query/intermediates/query_alter_intermediate.hpp + ../../include/matador/query/intermediates/query_alter_table_intermediate.hpp ../../include/matador/query/intermediates/query_create_intermediate.hpp ../../include/matador/query/intermediates/query_delete_from_intermediate.hpp ../../include/matador/query/intermediates/query_delete_intermediate.hpp @@ -97,6 +98,7 @@ add_library(matador-orm STATIC query/intermediates/executable_query.cpp query/intermediates/fetchable_query.cpp query/intermediates/query_alter_intermediate.cpp + query/intermediates/query_alter_table_intermediate.cpp query/intermediates/query_create_intermediate.cpp query/intermediates/query_delete_from_intermediate.cpp query/intermediates/query_delete_intermediate.cpp @@ -118,6 +120,7 @@ add_library(matador-orm STATIC query/intermediates/query_order_direction_intermediate.cpp query/intermediates/query_select_intermediate.cpp query/intermediates/query_set_intermediate.cpp + query/intermediates/query_update_intermediate.cpp query/intermediates/query_where_intermediate.cpp query/internal/basic_type_to_string_visitor.cpp query/internal/key_value_pair.cpp @@ -127,7 +130,6 @@ add_library(matador-orm STATIC query/query.cpp query/query_compiler.cpp query/query_part.cpp - query/query_update_intermediate.cpp query/value_extractor.cpp sql/backend_provider.cpp sql/column.cpp @@ -152,8 +154,6 @@ add_library(matador-orm STATIC sql/statement.cpp sql/statement_cache.cpp sql/table.cpp - ../../include/matador/query/intermediates/query_alter_table_intermediate.hpp - query/intermediates/query_alter_table_intermediate.cpp ) target_include_directories(matador-orm diff --git a/source/orm/query/intermediates/executable_query.cpp b/source/orm/query/intermediates/executable_query.cpp index 30329fb..98b4175 100644 --- a/source/orm/query/intermediates/executable_query.cpp +++ b/source/orm/query/intermediates/executable_query.cpp @@ -8,25 +8,21 @@ namespace matador::query { utils::result executable_query::execute(const sql::executor &exec) const { query_compiler compiler; - context_->mode = query_mode::Direct; return exec.execute(compiler.compile(*context_, exec.dialect(), std::nullopt)); } utils::result executable_query::prepare(sql::executor &exec) const { query_compiler compiler; - context_->mode = query_mode::Prepared; return exec.prepare(compiler.compile(*context_, exec.dialect(), std::nullopt)); } sql::query_context executable_query::compile( const sql::executor& exec ) const { query_compiler compiler; - context_->mode = query_mode::Prepared; return compiler.compile(*context_, exec.dialect(), std::nullopt); } std::string executable_query::str(const sql::executor &exec) const { query_compiler compiler; - context_->mode = query_mode::Direct; return exec.str(compiler.compile(*context_, exec.dialect(), std::nullopt)); } diff --git a/source/orm/query/intermediates/fetchable_query.cpp b/source/orm/query/intermediates/fetchable_query.cpp index bc8a3ee..90b2c6e 100644 --- a/source/orm/query/intermediates/fetchable_query.cpp +++ b/source/orm/query/intermediates/fetchable_query.cpp @@ -34,7 +34,6 @@ sql::record *create_prototype(const std::vector &p } utils::result, utils::error> fetchable_query::fetch_all(const sql::executor &exec) const { query_compiler compiler; - context_->mode = query_mode::Direct; const auto ctx = compiler.compile(*context_, exec.dialect(), std::nullopt); return exec.fetch(ctx) .and_then([](auto &&res) { @@ -47,7 +46,6 @@ utils::result, utils::error> fetchable_query::fet utils::result, utils::error> fetchable_query::fetch_one(const sql::executor &exec) const { query_compiler compiler; - context_->mode = query_mode::Direct; auto result = exec.fetch(compiler.compile(*context_, exec.dialect(), std::nullopt)); if (!result.is_ok()) { return utils::failure(result.err()); @@ -66,21 +64,20 @@ utils::result, utils::error> fetchable_query::fetch_o } std::string fetchable_query::str(const sql::executor &exec) const { - return exec.str(compile(exec.dialect(), query_mode::Direct)); + return exec.str(compile(exec.dialect())); } -sql::query_context fetchable_query::compile(const sql::dialect &d, const query_mode mode) const { +sql::query_context fetchable_query::compile(const sql::dialect &d) const { query_compiler compiler; - context_->mode = mode; return compiler.compile(*context_, d, std::nullopt); } utils::result, utils::error> fetchable_query::fetch(const sql::executor &exec) const { - return exec.fetch(compile(exec.dialect(), query_mode::Direct)); + return exec.fetch(compile(exec.dialect())); } utils::result fetchable_query::prepare(sql::executor &exec) const { - return exec.prepare(compile(exec.dialect(), query_mode::Prepared)); + return exec.prepare(compile(exec.dialect())); } } \ No newline at end of file diff --git a/source/orm/query/intermediates/query_create_intermediate.cpp b/source/orm/query/intermediates/query_create_intermediate.cpp index 40436db..0895ba7 100644 --- a/source/orm/query/intermediates/query_create_intermediate.cpp +++ b/source/orm/query/intermediates/query_create_intermediate.cpp @@ -4,20 +4,21 @@ namespace matador::query { -query_create_intermediate::query_create_intermediate() -{ +query_create_intermediate::query_create_intermediate() { context_->parts.push_back(std::make_unique()); } -executable_query query_create_intermediate::table(const sql::table &table, const std::initializer_list columns) -{ +executable_query query_create_intermediate::table(const sql::table &table, const std::initializer_list columns) { return this->table(table, std::vector{columns}); } -executable_query query_create_intermediate::table(const sql::table &table, const std::vector &columns) -{ +executable_query query_create_intermediate::table(const sql::table &table, const std::vector &columns) { context_->parts.push_back(std::make_unique(table, columns)); return {context_}; } +executable_query query_create_intermediate::schema( const std::string& schema_name ) { + context_->parts.push_back(std::make_unique(schema_name)); + return {context_}; +} } diff --git a/source/orm/query/intermediates/query_drop_intermediate.cpp b/source/orm/query/intermediates/query_drop_intermediate.cpp index 617fc0a..ae9814e 100644 --- a/source/orm/query/intermediates/query_drop_intermediate.cpp +++ b/source/orm/query/intermediates/query_drop_intermediate.cpp @@ -4,13 +4,11 @@ namespace matador::query { -query_drop_intermediate::query_drop_intermediate() -{ +query_drop_intermediate::query_drop_intermediate() { context_->parts.push_back(std::make_unique()); } -executable_query query_drop_intermediate::table(const sql::table &table) -{ +executable_query query_drop_intermediate::table(const sql::table &table) { context_->parts.push_back(std::make_unique(table)); return {context_}; } diff --git a/source/orm/query/query_update_intermediate.cpp b/source/orm/query/intermediates/query_update_intermediate.cpp similarity index 100% rename from source/orm/query/query_update_intermediate.cpp rename to source/orm/query/intermediates/query_update_intermediate.cpp diff --git a/source/orm/query/internal/key_value_pair.cpp b/source/orm/query/internal/key_value_pair.cpp index 4a24007..97ef1df 100644 --- a/source/orm/query/internal/key_value_pair.cpp +++ b/source/orm/query/internal/key_value_pair.cpp @@ -15,15 +15,19 @@ key_value_pair::key_value_pair(const sql::column &col, utils::database_type valu } key_value_pair::key_value_pair(const char *name, utils::database_type value) - : name_(name) - , value_(std::move(value)) { +: name_(name) +, value_(std::move(value)) { } +key_value_pair::key_value_pair( const char* name, utils::placeholder p ) +: name_(name) +, value_(p) {} + const std::string &key_value_pair::name() const { return name_; } -const utils::database_type& key_value_pair::value() const { +const std::variant& key_value_pair::value() const { return value_; } } \ No newline at end of file diff --git a/source/orm/query/internal/query_parts.cpp b/source/orm/query/internal/query_parts.cpp index 1e2151d..9466cbf 100644 --- a/source/orm/query/internal/query_parts.cpp +++ b/source/orm/query/internal/query_parts.cpp @@ -46,6 +46,13 @@ const std::string& query_drop_key_constraint_part::name() const { return name_; } +query_drop_foreign_key_constraint_part::query_drop_foreign_key_constraint_part() +: query_part( sql::dialect_token::DropConstraint ) {} + +void query_drop_foreign_key_constraint_part::accept( query_part_visitor& visitor ) { + visitor.visit(*this); +} + query_add_foreign_key_constraint_part::query_add_foreign_key_constraint_part(const std::vector& columns) : query_part(sql::dialect_token::ForeignKey) , columns_(columns) {} @@ -357,6 +364,18 @@ void query_create_table_part::accept(query_part_visitor &visitor) visitor.visit(*this); } +query_create_schema_part::query_create_schema_part(std::string schema) +: query_part( sql::dialect_token::Schema ) +, schema_( std::move( schema ) ){} + +const std::string& query_create_schema_part::schema() const { + return schema_; +} + +void query_create_schema_part::accept( query_part_visitor& visitor ) { + visitor.visit(*this); +} + query_drop_part::query_drop_part() : query_part(sql::dialect_token::Drop) {} @@ -379,4 +398,15 @@ void query_drop_table_part::accept(query_part_visitor &visitor) visitor.visit(*this); } +query_drop_schema_part::query_drop_schema_part(std::string schema_) +: query_part( sql::dialect_token::Schema ) +, schema_( std::move( schema_ ) ) {} + +const std::string& query_drop_schema_part::schema() const { + return schema_; +} + +void query_drop_schema_part::accept( query_part_visitor& visitor ) { + visitor.visit(*this); +} } \ No newline at end of file diff --git a/source/orm/query/query.cpp b/source/orm/query/query.cpp index c575f4e..6249e2a 100644 --- a/source/orm/query/query.cpp +++ b/source/orm/query/query.cpp @@ -32,6 +32,10 @@ query_drop_intermediate query::drop() { return {}; } +query_select_intermediate query::select() { + return query_select_intermediate{{}}; +} + query_select_intermediate query::select( const std::initializer_list columns) { return select(std::vector{columns}); } diff --git a/source/orm/query/query_compiler.cpp b/source/orm/query/query_compiler.cpp index 9cb8216..d7711ef 100644 --- a/source/orm/query/query_compiler.cpp +++ b/source/orm/query/query_compiler.cpp @@ -65,7 +65,7 @@ void query_compiler::visit(internal::query_add_key_constraint_part& part) { query_.sql += " " + dialect_->token_at(sql::dialect_token::AddConstraint) + " " + part.name(); } -void query_compiler::visit( internal::query_add_foreign_key_constraint_part& part ) { +void query_compiler::visit(internal::query_add_foreign_key_constraint_part& part) { query_.sql += " " + dialect_->token_at(part.token()) + " ("; if (part.columns().size() < 2) { @@ -82,9 +82,9 @@ void query_compiler::visit( internal::query_add_foreign_key_constraint_part& par query_.sql += ")"; } -void query_compiler::visit( internal::query_add_primary_key_constraint_part& part ) {} +void query_compiler::visit(internal::query_add_primary_key_constraint_part& part) {} -void query_compiler::visit( internal::query_add_foreign_key_reference_part& part ) { +void query_compiler::visit(internal::query_add_foreign_key_reference_part& part) { query_.sql += " " + dialect_->token_at(part.token()) + " " + part.table().name + " ("; @@ -106,7 +106,10 @@ void query_compiler::visit(internal::query_drop_key_constraint_part& part) { query_.sql += " " + dialect_->token_at(part.token()) + " " + part.name(); } -void query_compiler::visit(internal::query_select_part &select_part) +void query_compiler::visit(internal::query_drop_foreign_key_constraint_part& part) { +} + +void query_compiler::visit(internal::query_select_part &part) { query_.command = sql::sql_command::SQL_SELECT; query_.sql = dialect_->token_at(sql::dialect_token::Select) + " "; @@ -114,7 +117,9 @@ void query_compiler::visit(internal::query_select_part &select_part) query_.prototype.clear(); std::string result; - if (const auto &columns = select_part.columns(); columns.size() < 2) { + if (part.columns().empty()) { + result = dialect_->token_at(sql::dialect_token::Asterisk); + } else if (const auto &columns = part.columns(); columns.size() < 2) { for (const auto &col: columns) { result.append(handle_column(query_, dialect_, *data_, col )); } @@ -130,38 +135,38 @@ void query_compiler::visit(internal::query_select_part &select_part) query_.sql += result; } -void query_compiler::visit(internal::query_from_part &from_part) +void query_compiler::visit(internal::query_from_part &part) { - query_.table = from_part.table(); - query_.sql += " " + build_table_name(from_part.token(), *dialect_, query_.table); + query_.table = part.table(); + query_.sql += " " + build_table_name(part.token(), *dialect_, query_.table); query_.table_aliases.insert({query_.table.name, query_.table.alias}); } -void query_compiler::visit(internal::query_join_part &join_part) +void query_compiler::visit(internal::query_join_part &part) { - query_.sql += " " + query_compiler::build_table_name(join_part.token(), *dialect_, join_part.table()); + query_.sql += " " + query_compiler::build_table_name(part.token(), *dialect_, part.table()); } -void query_compiler::visit(internal::query_on_part &on_part) { +void query_compiler::visit(internal::query_on_part &part) { criteria_evaluator evaluator(*dialect_, query_); query_.sql += " " + dialect_->token_at(sql::dialect_token::On) + - " " + evaluator.evaluate(on_part.condition()); + " " + evaluator.evaluate(part.condition()); } -void query_compiler::visit(internal::query_where_part &where_part) { +void query_compiler::visit(internal::query_where_part &part) { criteria_evaluator evaluator(*dialect_, query_); query_.sql += " " + dialect_->token_at(sql::dialect_token::Where) + - " " + evaluator.evaluate(where_part.condition()); + " " + evaluator.evaluate(part.condition()); } -void query_compiler::visit(internal::query_group_by_part &group_by_part) { - query_.sql += " " + dialect_->token_at(sql::dialect_token::GroupBy) + " " + dialect_->prepare_identifier(group_by_part.column()); +void query_compiler::visit(internal::query_group_by_part &part) { + query_.sql += " " + dialect_->token_at(sql::dialect_token::GroupBy) + " " + dialect_->prepare_identifier(part.column()); } -void query_compiler::visit(internal::query_order_by_part &order_by_part) +void query_compiler::visit(internal::query_order_by_part &part) { query_.sql += " " + dialect_->token_at(sql::dialect_token::OrderBy) + - " " + dialect_->prepare_condition(order_by_part.column()); + " " + dialect_->prepare_condition(part.column()); } void query_compiler::visit(internal::query_order_by_asc_part &/*order_by_asc_part*/) @@ -174,14 +179,14 @@ void query_compiler::visit(internal::query_order_by_desc_part &/*order_by_desc_p query_.sql += " " + dialect_->token_at(sql::dialect_token::Desc); } -void query_compiler::visit(internal::query_offset_part &offset_part) +void query_compiler::visit(internal::query_offset_part &part) { - query_.sql += " " + dialect_->token_at(sql::dialect_token::Offset) + " " + std::to_string(offset_part.offset()); + query_.sql += " " + dialect_->token_at(sql::dialect_token::Offset) + " " + std::to_string(part.offset()); } -void query_compiler::visit(internal::query_limit_part &limit_part) +void query_compiler::visit(internal::query_limit_part &part) { - query_.sql += " " + dialect_->token_at(sql::dialect_token::Limit) + " " + std::to_string(limit_part.limit()); + query_.sql += " " + dialect_->token_at(sql::dialect_token::Limit) + " " + std::to_string(part.limit()); } void query_compiler::visit(internal::query_insert_part &/*insert_part*/) @@ -190,21 +195,21 @@ void query_compiler::visit(internal::query_insert_part &/*insert_part*/) query_.sql = dialect_->token_at(sql::dialect_token::Insert); } -void query_compiler::visit(internal::query_into_part &into_part) +void query_compiler::visit(internal::query_into_part &part) { - query_.table = into_part.table(); + query_.table = part.table(); query_.sql += " " + dialect_->token_at(sql::dialect_token::Into) + - " " + dialect_->prepare_identifier_string(into_part.table().name); + " " + dialect_->prepare_identifier_string(part.table().name); std::string result{"("}; - if (into_part.columns().size() < 2) { - for (const auto &col: into_part.columns()) { + if (part.columns().size() < 2) { + for (const auto &col: part.columns()) { result.append(dialect_->prepare_identifier_string(col.name)); } } else { - auto it = into_part.columns().begin(); + auto it = part.columns().begin(); result.append(dialect_->prepare_identifier_string((it++)->name)); - for (; it != into_part.columns().end(); ++it) { + for (; it != part.columns().end(); ++it) { result.append(", "); result.append(dialect_->prepare_identifier_string(it->name)); } @@ -222,7 +227,7 @@ struct value_visitor { } void operator()(const utils::placeholder &/*val*/) { - value_to_string_visitor.query.bind_vars.emplace_back("unknown"); + value_to_string_visitor.query.bind_vars.emplace_back(std::string("value_") + std::to_string(value_to_string_visitor.query.bind_vars.size() + 1)); value_to_string_visitor.result = value_to_string_visitor.writer->dialect().next_placeholder(value_to_string_visitor.query.bind_vars); } @@ -230,31 +235,26 @@ struct value_visitor { }; std::string query_compiler::determine_value(value_visitor &visitor, const std::variant &val) { - if (data_->mode == query_mode::Direct) { - std::visit(visitor, val); - return visitor.value_to_string_visitor.result; - } - - query_.bind_vars.emplace_back(std::string("value_") + std::to_string(query_.bind_vars.size() + 1)); - return dialect_->next_placeholder(query_.bind_vars); + std::visit(visitor, val); + return visitor.value_to_string_visitor.result; } -void query_compiler::visit(internal::query_values_part &values_part) { +void query_compiler::visit(internal::query_values_part &part) { query_.sql += " " + dialect_->token_at(sql::dialect_token::Values); attribute_string_writer writer(*dialect_, connection_); value_visitor visitor(writer, query_); std::string result{"("}; - if (values_part.values().size() < 2) { - for (const auto& val: values_part.values()) { + if (part.values().size() < 2) { + for (const auto& val: part.values()) { result.append(determine_value(visitor, val)); } } else { - auto it = values_part.values().begin(); + auto it = part.values().begin(); auto val = *it++; result.append(determine_value(visitor, val)); - for (; it != values_part.values().end(); ++it) { + for (; it != part.values().end(); ++it) { result.append(", "); val = *it; result.append(determine_value(visitor, val)); @@ -265,11 +265,11 @@ void query_compiler::visit(internal::query_values_part &values_part) { query_.sql += " " + result; } -void query_compiler::visit(internal::query_update_part &update_part) +void query_compiler::visit(internal::query_update_part &part) { query_.command = sql::sql_command::SQL_UPDATE; - query_.table = update_part.table(); - query_.sql += query_compiler::build_table_name(update_part.token(), *dialect_, query_.table); + query_.table = part.table(); + query_.sql += query_compiler::build_table_name(part.token(), *dialect_, query_.table); } void query_compiler::visit(internal::query_delete_part &/*delete_part*/) @@ -278,10 +278,10 @@ void query_compiler::visit(internal::query_delete_part &/*delete_part*/) query_.sql = dialect_->token_at(sql::dialect_token::Remove); } -void query_compiler::visit(internal::query_delete_from_part &delete_from_part) +void query_compiler::visit(internal::query_delete_from_part &part) { - query_.table = delete_from_part.table(); - query_.sql += " " + build_table_name(delete_from_part.token(), *dialect_, query_.table); + query_.table = part.table(); + query_.sql += " " + build_table_name(part.token(), *dialect_, query_.table); } void query_compiler::visit(internal::query_create_part &/*create_part*/) @@ -303,30 +303,30 @@ struct column_context std::string build_create_column(const object::attribute_definition &col, const sql::dialect &d, column_context &context); -void query_compiler::visit(internal::query_create_table_part &create_table_part) +void query_compiler::visit(internal::query_create_table_part &part) { - query_.sql += " " + dialect_->token_at(sql::dialect_token::Table) + " " + dialect_->prepare_identifier_string(create_table_part.table().name) + " "; - query_.table = create_table_part.table(); + query_.sql += " " + dialect_->token_at(sql::dialect_token::Table) + " " + dialect_->prepare_identifier_string(part.table().name) + " "; + query_.table = part.table(); std::string result = "("; column_context context; - if (create_table_part.columns().size() < 2) { - for (const auto &col: create_table_part.columns()) { + if (part.columns().size() < 2) { + for (const auto &col: part.columns()) { result.append(build_create_column(col, *dialect_, context)); } } else { - auto it = create_table_part.columns().begin(); + auto it = part.columns().begin(); result.append(build_create_column(*it++, *dialect_, context)); - for (; it != create_table_part.columns().end(); ++it) { + for (; it != part.columns().end(); ++it) { result.append(", "); result.append(build_create_column(*it, *dialect_, context)); } } if (!context.primary_keys.empty()) { - result.append(", CONSTRAINT PK_" + create_table_part.table().name + " PRIMARY KEY (" + utils::join(context.primary_keys, ", ") + ")"); + result.append(", CONSTRAINT PK_" + part.table().name + " PRIMARY KEY (" + utils::join(context.primary_keys, ", ") + ")"); } for (const auto &[column, reference_column]: context.foreign_contexts) { // ALTER TABLE Orders ADD CONSTRAINT FK_PersonOrder FOREIGN KEY (PersonID) REFERENCES Persons(PersonID); @@ -342,52 +342,50 @@ void query_compiler::visit(internal::query_create_table_part &create_table_part) query_.sql += result; } -void query_compiler::visit(internal::query_drop_part &/*drop_part*/) -{ +void query_compiler::visit( internal::query_create_schema_part& part ) { + query_.sql += " " + dialect_->token_at(sql::dialect_token::Create) + " " + + dialect_->token_at(sql::dialect_token::Schema) + " " + dialect_->prepare_identifier_string(part.schema()); +} + +void query_compiler::visit(internal::query_drop_part &part) { query_.command = sql::sql_command::SQL_DROP_TABLE; - query_.sql = dialect_->token_at(sql::dialect_token::Drop); + query_.sql = dialect_->token_at(part.token()); } -std::string query_compiler::determine_set_value(internal::basic_type_to_string_visitor &visitor, const utils::database_type &val) { - if (data_->mode == query_mode::Direct) { - std::visit(visitor, val); - return visitor.result; - } - - query_.bind_vars.emplace_back(std::string("value_") + std::to_string(query_.bind_vars.size() + 1)); - return dialect_->next_placeholder(query_.bind_vars); +void query_compiler::visit( internal::query_drop_schema_part& part ) { + query_.sql += " " + dialect_->token_at(sql::dialect_token::Drop) + " " + + dialect_->token_at(sql::dialect_token::Schema) + " " + dialect_->prepare_identifier_string(part.schema()); } -void query_compiler::visit(internal::query_set_part &set_part) -{ +void query_compiler::visit(internal::query_set_part &part) { query_.sql += " " + dialect_->token_at(sql::dialect_token::Set) + " "; attribute_string_writer writer(*dialect_, connection_); - internal::basic_type_to_string_visitor visitor(writer, query_); std::string result; - if (set_part.key_values().size() < 2) { - for (const auto &col: set_part.key_values()) { + + value_visitor visitor(writer, query_); if (part.key_values().size() < 2) { + for (const auto &col: part.key_values()) { result.append(dialect_->prepare_identifier_string(col.name()) + "="); - result.append(determine_set_value(visitor, col.value())); + result.append(determine_value(visitor, col.value())); } } else { - auto it = set_part.key_values().begin(); + auto it = part.key_values().begin(); result.append(dialect_->prepare_identifier_string(it->name()) + "="); - result.append(determine_set_value(visitor, (it++)->value())); - for (; it != set_part.key_values().end(); ++it) { + result.append(determine_value(visitor, (it++)->value())); + for (; it != part.key_values().end(); ++it) { result.append(", "); result.append(dialect_->prepare_identifier_string(it->name()) + "="); - result.append(determine_set_value(visitor, it->value())); + result.append(determine_value(visitor, it->value())); } } query_.sql += result; } -void query_compiler::visit(internal::query_drop_table_part &drop_table_part) +void query_compiler::visit(internal::query_drop_table_part &part) { - query_.table = drop_table_part.table(); - query_.sql += " " + query_compiler::build_table_name(drop_table_part.token(), *dialect_, query_.table); + query_.table = part.table(); + query_.sql += " " + query_compiler::build_table_name(part.token(), *dialect_, query_.table); } std::string build_create_column(const object::attribute_definition &col, const sql::dialect &d, column_context &context) diff --git a/test/orm/query/QueryBuilderTest.cpp b/test/orm/query/QueryBuilderTest.cpp index 0427e38..0ab44f0 100644 --- a/test/orm/query/QueryBuilderTest.cpp +++ b/test/orm/query/QueryBuilderTest.cpp @@ -66,6 +66,14 @@ TEST_CASE_METHOD(QueryFixture, "Test drop table sql statement string", "[query]" REQUIRE(result == R"(DROP TABLE "person")"); } +TEST_CASE_METHOD(QueryFixture, "Test select all columns with asterisk", "[query][select][asterisk]") { + const auto result = query::select() + .from("person") + .str(*db); + + REQUIRE(result == R"(SELECT * FROM "person")"); +} + TEST_CASE_METHOD(QueryFixture, "Test select sql statement string", "[query]") { const auto result = query::select({"id", "name", "age"}) .from("person") diff --git a/test/orm/sql/StatementCacheTest.cpp b/test/orm/sql/StatementCacheTest.cpp index d2cf60e..901f8e0 100644 --- a/test/orm/sql/StatementCacheTest.cpp +++ b/test/orm/sql/StatementCacheTest.cpp @@ -172,11 +172,11 @@ TEST_CASE("Test LRU cache evicts oldest entries", "[statement][cache][evict]") { result = cache.acquire({"SELECT title FROM book"}); REQUIRE(result); auto stmt2 = result.value(); - result = cache.acquire({"SELECT name FROM author"}); // Should evict first statement + result = cache.acquire({"SELECT name FROM author"}); // Should evict the first statement REQUIRE(result); auto stmt3 = result.value(); - // Trigger re-prepare of evicted statement + // Trigger re-prepares of an evicted statement result = cache.acquire({"SELECT 1"}); REQUIRE(result); auto stmt4 = result.value(); @@ -317,6 +317,7 @@ TEST_CASE("Race condition simulation with mixed access", "[statement_cache][race }; std::vector jobs; + jobs.reserve(threads); for (int i = 0; i < threads; ++i) { jobs.emplace_back(task, i); }