xapi/mysqlx_cc_internal.h (376 lines of code) (raw):

/* * Copyright (c) 2016, 2024, Oracle and/or its affiliates. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, version 2.0, as * published by the Free Software Foundation. * * This program is designed to work with certain software (including * but not limited to OpenSSL) that is licensed under separate terms, as * designated in a particular file or component or in included license * documentation. The authors of MySQL hereby grant you an additional * permission to link the program and your derivative works with the * separately licensed software that they have either included with * the program or referenced in the documentation. * * Without limiting anything contained in the foregoing, this file, * which is part of Connector/C++, is also subject to the * Universal FOSS Exception, version 1.0, a copy of which can be found at * https://oss.oracle.com/licenses/universal-foss-exception. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License, version 2.0, for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __MYSQLX_CC_INTERNAL_H__ #define __MYSQLX_CC_INTERNAL_H__ #include <mysql/cdk.h> #include "../common/session.h" #include "../common/settings.h" #include "../common/db_object.h" #include <cstdarg> #include "def_internal.h" #include "error_internal.h" #include "crud_internal.h" using Db_obj_ref = ::mysqlx::impl::common::Object_ref; class Diag_info_list; struct mysqlx_session_options_struct : public Mysqlx_diag , Settings_impl { public: using Settings_impl::Session_option_impl; using Settings_impl::Client_option_impl; mysqlx_session_options_struct() = default; mysqlx_session_options_struct(const std::string host, unsigned short port, const std::string usr, const std::string *pwd, const std::string *db, unsigned int ssl_mode = #ifdef WITH_SSL SSL_MODE_REQUIRED #else SSL_MODE_DISABLED #endif ) { Setter set(*this); set.host(0, host, port); set.user(usr); if (pwd) set.password(*pwd); if (db) set.schema(*db); #ifdef WITH_SSL set.key_val(Session_option_impl::SSL_MODE)->scalar()->num(uint64_t(ssl_mode)); #endif set.commit(); } mysqlx_session_options_struct(const std::string &conn_str) { set_from_uri(conn_str); } using Settings_impl::get; bool has_option(mysqlx_opt_type_enum opt) { // Note: assumes the same enum values as used in Settings_impl::Option return Settings_impl::has_option(Client_option_impl(opt)); } void clear() { Mysqlx_diag::clear(); Settings_impl::clear(); } friend mysqlx_session_struct; friend int mysqlx_session_option_set(mysqlx_session_options_struct*, ...); }; template <class handle_t> class Db_obj_cache { using map_t = std::map<cdk::string, handle_t>; map_t m_storage; public: template <typename T> handle_t* get(T &parent, const char *name) { cdk::string obj_name(name); typename map_t::iterator it = m_storage.find(obj_name); if (it == m_storage.end()) it = m_storage.emplace(obj_name, handle_t(parent, obj_name)).first; return &it->second; } }; // TODO: Do not store entries for non-existing objects (if check was made) template <class handle_t> inline handle_t* check_existence(bool check, handle_t *obj) { assert(obj); if (check && !obj->exists()) throw Mysqlx_exception("Database object does not exist"); return obj; } struct mysqlx_session_struct : public Mysqlx_diag { using Stmt_cache = std::forward_list<mysqlx_stmt_struct>; std::string m_savepoint_name; public: std::shared_ptr<Session_impl> m_impl; Stmt_cache m_stmts; Db_obj_cache<mysqlx_schema_struct> m_schema_map; /* Create new statement. This session takes its ownership. */ template <mysqlx_op_t OP, typename... T> mysqlx_stmt_struct* new_stmt(const T&... args) { using Impl = typename stmt_traits<OP>::Impl; Impl *impl = new Impl(m_impl, args...); m_stmts.emplace_front(this, OP, impl); return &m_stmts.front(); } void rm_stmt(const mysqlx_stmt_struct *ptr) { m_stmts.remove_if( [ptr](const mysqlx_stmt_struct &stmt) { return &stmt == ptr; } ); } public: mysqlx_session_struct( mysqlx_client_t *cli); mysqlx_session_struct( const std::string &host, unsigned short port, const std::string &usr, const std::string *pwd, const std::string *db ); mysqlx_session_struct(const std::string &conn_str); mysqlx_session_struct(mysqlx_session_options_struct *opt); mysqlx_session_struct(mysqlx_session_options_struct &&opt) : mysqlx_session_struct(&opt) {} Session_impl& get_impl() { assert(m_impl); return *m_impl.get(); } bool is_valid() { return get_impl().m_sess->is_valid() == cdk::option_t::YES; } const cdk::Error* get_cdk_error(); cdk::Session &get_session() { return *(m_impl->m_sess); } /* Execute a plain SQL query (supports parameters and placeholders) PARAMETERS: query - SQL query length - length of the query RETURN: CRUD handler containing the results and/or error */ mysqlx_stmt_t *sql_query(const char *query, uint32_t length); void reset_diagnostic(); mysqlx_schema_struct* get_schema(const char *name, bool check) { assert(name && *name); return check_existence(check, m_schema_map.get(*this, name)); } mysqlx_result_struct* get_schemas(const char *pattern_utf8 = nullptr) { cdk::string pattern(pattern_utf8 ? pattern_utf8 : "%"); return new_stmt<OP_LIST_SCHEMAS>(pattern)->exec(); } void create_schema(const char *name) { assert(name && *name); Schema_ref schema(name); create_object<Object_type::SCHEMA>(m_impl, schema); } void drop_schema(const char *name) { assert(name && *name); Schema_ref schema(name); drop_object<Object_type::SCHEMA>(m_impl, schema); } void transaction_begin(); void transaction_commit(); void transaction_rollback(const char *sp); const char * savepoint_set(const char *); void savepoint_remove(const char *); mysqlx_error_t *get_last_error(); friend mysqlx_result_struct; friend mysqlx_stmt_struct; }; /* Client object implementation */ struct mysqlx_client_struct : public Mysqlx_diag { std::shared_ptr<Session_pool> m_impl; mysqlx_client_struct(const char *conn_str, const char *client_opt); mysqlx_client_struct(mysqlx_session_options_t *opt); std::shared_ptr<Session_pool>& get_impl() { return m_impl; } }; inline bool mysqlx_stmt_struct::session_valid() { return m_session.is_valid(); } struct mysqlx_schema_struct : public Mysqlx_diag , public Schema_ref { private: Db_obj_cache<mysqlx_collection_struct> m_collection_map; Db_obj_cache<mysqlx_table_struct> m_table_map; mysqlx_session_struct &m_session; public: mysqlx_schema_struct(mysqlx_session_struct &session, cdk::string name) : Schema_ref(name) , m_session(session) {} bool exists() { return check_schema_exists(m_session.m_impl, *this); } mysqlx_session_struct& get_session() { return m_session; } mysqlx_collection_struct* get_collection(const char *name, bool check) { assert(name && *name); return check_existence(check, m_collection_map.get(*this, name)); } mysqlx_table_struct* get_table(const char *name, bool check) { assert(name && *name); return check_existence(check, m_table_map.get(*this, name)); } mysqlx_result_struct* get_tables(const char *pattern_utf8, bool include_views) { cdk::string pattern(pattern_utf8 ? pattern_utf8 : "%"); return m_session.new_stmt<OP_LIST_TABLES>( *this, pattern, include_views )->exec(); } mysqlx_result_struct* get_collections(const char *pattern_utf8) { cdk::string pattern(pattern_utf8 ? pattern_utf8 : "%"); return m_session.new_stmt<OP_LIST_COLLECTIONS>(*this, pattern)->exec(); } void create_collection(const char *name, bool reuse) { assert(name && *name); Db_obj_ref coll(this->name(), name); create_object<Object_type::COLLECTION>( m_session.m_impl, coll, reuse, std::string() ); } void create_collection(const char *name, bool reuse, const std::string &level, const std::string &schema) { assert(name && *name); Db_obj_ref coll(this->name(), name); create_object<Object_type::COLLECTION>( m_session.m_impl, coll, reuse, level, schema ); } void create_collection(const char *name, bool reuse, const std::string &validation_json) { assert(name && *name); Db_obj_ref coll(this->name(), name); create_object<Object_type::COLLECTION>( m_session.m_impl, coll, reuse, validation_json ); } void create_collection(const char *name, const std::string &json) { assert(name && *name); Db_obj_ref coll(this->name(), name); create_object<Object_type::COLLECTION>( m_session.m_impl, coll, json ); } void modify_collection(const char *name, std::string level, std::string schema) { assert(name && *name); Db_obj_ref coll(this->name(), name); modify_object<Object_type::COLLECTION>( m_session.m_impl, coll, level, schema ); } void modify_collection(const char *name, std::string json, bool validation_json = false) { assert(name && *name); Db_obj_ref coll(this->name(), name); modify_object<Object_type::COLLECTION>( m_session.m_impl, coll, json, validation_json ); } template <Object_type T> void drop_object(const char *name) { assert(name && *name); Db_obj_ref obj(this->name(), name); ::mysqlx::impl::common::drop_object<T>(m_session.m_impl, obj); } void drop_collection(const char *name) { drop_object<Object_type::COLLECTION>(name); } }; struct mysqlx_collection_options_struct : public Mysqlx_diag { bool m_reuse = false; std::string m_validation; std::string m_validation_level; std::string m_validation_schema; enum Usage{ REUSE, VALIDATION, VALIDATION_LEVEL, VALIDATION_SCHEMA, LAST }; std::bitset<LAST> m_usage; }; struct mysqlx_collection_struct : public Mysqlx_diag , public Object_ref { private: mysqlx_session_struct &m_sess; public: mysqlx_collection_struct(mysqlx_schema_struct &schema, cdk::string name) : Object_ref(schema.name(), name) , m_sess(schema.get_session()) {} uint64_t count(); bool exists() { return check_object_exists<Object_type::COLLECTION>( m_sess.m_impl, *this ); } void create_index(const char* name_utf8, const char* idx_json) { mysqlx_result_struct *result = m_sess.new_stmt<OP_IDX_CREATE>( *this, cdk::string(name_utf8), cdk::string(idx_json) )->exec(); if (!result) throw_error("Failed to execute create index operation."); } void drop_index(const char* name_utf8) { mysqlx_result_struct *result = m_sess.new_stmt<OP_IDX_DROP>( *this, cdk::string(name_utf8) )->exec(); if (!result) throw_error("Failed to execute drop index operation."); } mysqlx_session_t &get_session() { return m_sess; } }; struct mysqlx_table_struct : public Mysqlx_diag , public Object_ref { private: mysqlx_session_struct &m_sess; public: mysqlx_table_struct(mysqlx_schema_struct &schema, cdk::string name) : Object_ref(schema.name(), name) , m_sess(schema.get_session()) {} uint64_t count(); bool exists() { return check_object_exists<Object_type::TABLE>( m_sess.m_impl, *this ); } mysqlx_session_struct &get_session() { return m_sess; } }; #endif /* __MYSQLX_CC_INTERNAL_H__ */