xapi/crud_internal.h (237 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 XAPI_INTERNAL_CRUD
#define XAPI_INTERNAL_CRUD
#include "../common/op_impl.h"
/*
CRUD implementation
Copy constructor must be disabled for this class
*/
using namespace ::mysqlx::impl::common;
using namespace ::mysqlx;
uint32_t get_type(const Format_info&);
struct mysqlx_row_struct
: public Mysqlx_diag
, public Row_impl<>
{
using Row_impl<>::Row_impl;
};
struct mysqlx_result_struct
: public Mysqlx_diag
, Result_impl
{
using Impl = Result_impl;
mysqlx_stmt_struct *m_stmt;
cdk::Diagnostic_iterator m_warn_it;
public:
std::list<mysqlx_row_struct> m_row_set;
cdk::scoped_ptr<mysqlx_error_struct> m_current_warning;
std::vector<std::string> m_doc_id_list;
size_t m_current_id_index = 0;
public:
mysqlx_result_struct(mysqlx_stmt_struct *sess, Result_init &init)
: Impl(init), m_stmt(sess)
{
next_result();
check_errors();
}
void check_errors()
{
// TODO: this iterator will iterate also over errors - is that ok?
if (!m_reply)
return;
m_warn_it = m_reply->get_entries(cdk::api::Severity::WARNING);
if ( 0 < m_reply->entry_count())
set_diagnostic(mysqlx_error_struct(m_reply->get_error()));
}
mysqlx_error_struct *get_next_warning();
/*
Read the next row from the result set and advance the cursor position
*/
mysqlx_row_struct *read_row()
{
const Row_data *data = get_row();
check_errors();
if (!data)
return nullptr;
m_row_set.emplace_back(*data, m_result_mdata.front());
return &m_row_set.back();
}
const char * read_json(size_t *json_byte_size);
const char *get_next_generated_id();
};
struct mysqlx_stmt_struct : public Mysqlx_diag
{
private:
using Impl = Executable_if;
using Result_impl = mysqlx_result_struct::Impl;
mysqlx_session_struct &m_session;
cdk::scoped_ptr<mysqlx_result_struct> m_result;
public:
cdk::scoped_ptr<Impl> m_impl;
mysqlx_op_enum m_op_type;
mysqlx_stmt_struct(mysqlx_session_struct *session, mysqlx_op_t op, Impl *impl)
: m_session(*session), m_impl(impl), m_op_type(op)
{}
mysqlx_result_struct* new_result(Result_init &init)
{
m_result.reset(new mysqlx_result_struct(this, init));
return m_result.get();
}
void rm_result(mysqlx_result_struct *res)
{
if (res != m_result.get())
return;
// TODO: notify the current result so that it can cache data etc?
m_result.reset(NULL);
}
mysqlx_result_struct* get_result() { return m_result.get(); }
/*
Execute a CRUD statement.
RETURN: pointer to mysqlx_result_t, which is being allocated each time
when this function is called. The old result is freed automatically.
On error the function returns NULL
NOTE: no need to free the result in the end cdk::scoped_ptr will
take care of it
*/
mysqlx_result_struct *exec()
{
Mysqlx_diag::clear();
return new_result(m_impl->execute());
}
int sql_bind(va_list &args);
int sql_bind(cdk::string s);
int param_bind(va_list &args);
/*
Return the operation type OP_SELECT, OP_INSERT, OP_UPDATE, OP_DELETE,
OP_FIND, OP_ADD, OP_MODIFY, OP_REMOVE, OP_SQL
*/
mysqlx_op_t op_type() { return m_op_type; }
mysqlx_session_t &get_session() { return m_session; }
int set_where(const char *where_expr);
int set_limit(cdk::row_count_t row_count, cdk::row_count_t offset);
int set_having(const char *having_expr);
int add_order_by(va_list &args);
int add_row(bool get_columns, va_list &args);
int add_columns(va_list &args);
int add_document(const char *json_doc);
int add_multiple_documents(va_list &args);
int add_projections(va_list &args);
int add_table_update_values(va_list &args);
int add_coll_modify_values(va_list &args, mysqlx_modify_op op);
int add_group_by(va_list &args);
// Return the session validity state
bool session_valid();
void set_row_locking(mysqlx_row_locking_t row_locking,
mysqlx_lock_contention_t lock_contention);
friend class Group_by_list;
};
typedef mysqlx_stmt_struct mysqlx_stmt_t;
/*
The stmt_traits<> template defines implementation class for different
CRUD operations identified by mysqlx_op_enum constants.
*/
template <mysqlx_op_enum OP>
struct stmt_traits;
template<>
struct stmt_traits<OP_SQL>
{
using Impl = Op_sql;
};
template<>
struct stmt_traits<OP_TRX_BEGIN>
{
using Impl = Op_trx<Trx_op::BEGIN>;
};
template<>
struct stmt_traits<OP_TRX_COMMIT>
{
using Impl = Op_trx<Trx_op::COMMIT>;
};
template<>
struct stmt_traits<OP_TRX_ROLLBACK>
{
using Impl = Op_trx<Trx_op::ROLLBACK>;
};
template<>
struct stmt_traits<OP_TRX_SAVEPOINT_SET>
{
using Impl = Op_trx<Trx_op::SAVEPOINT_SET>;
};
template<>
struct stmt_traits<OP_TRX_SAVEPOINT_RM>
{
using Impl = Op_trx<Trx_op::SAVEPOINT_REMOVE>;
};
template<>
struct stmt_traits<OP_SELECT>
{
using Impl = Op_table_select;
};
template<>
struct stmt_traits<OP_INSERT>
{
using Impl = Op_table_insert<>;
};
template<>
struct stmt_traits<OP_UPDATE>
{
using Impl = Op_table_update;
};
template<>
struct stmt_traits<OP_DELETE>
{
using Impl = Op_table_remove;
};
template<>
struct stmt_traits<OP_ADD>
{
using Impl = Op_collection_add;
};
template<>
struct stmt_traits<OP_REMOVE>
{
using Impl = Op_collection_remove;
};
template<>
struct stmt_traits<OP_FIND>
{
using Impl = Op_collection_find;
};
template<>
struct stmt_traits<OP_MODIFY>
{
using Impl = Op_collection_modify;
};
template<>
struct stmt_traits<OP_SCHEMA_CREATE>
{
using Impl = Op_create<Object_type::SCHEMA>;
};
template<>
struct stmt_traits<OP_SCHEMA_DROP>
{
using Impl = Op_drop<Object_type::SCHEMA>;
};
template<>
struct stmt_traits<OP_COLLECTION_DROP>
{
using Impl = Op_drop<Object_type::COLLECTION>;
};
template<>
struct stmt_traits<OP_LIST_SCHEMAS>
{
using Impl = Op_list<Object_type::SCHEMA>;
};
template<>
struct stmt_traits<OP_LIST_COLLECTIONS>
{
using Impl = Op_list<Object_type::COLLECTION>;
};
template<>
struct stmt_traits<OP_LIST_TABLES>
{
using Impl = Op_list<Object_type::TABLE>;
};
template<>
struct stmt_traits<OP_IDX_CREATE>
{
using Impl = Op_idx_create;
};
template<>
struct stmt_traits<OP_IDX_DROP>
{
using Impl = Op_idx_drop;
};
/*
Return pointer to internal statement implementation after casting it to
the appropriate implementation class for operation OP (as defined
by stmt_traits<> template).
*/
template <typename Impl>
inline
auto get_impl(mysqlx_stmt_struct *stmt)
-> Impl*
{
assert(stmt && stmt->m_impl);
// TODO: dynamic_cast<> did not work - rtti not enabled?
Impl *impl = (Impl*)(stmt->m_impl.get());
assert(impl);
return impl;
}
template <mysqlx_op_t OP>
inline
auto get_impl(mysqlx_stmt_struct *stmt)
-> typename stmt_traits<OP>::Impl*
{
if (OP != stmt->m_op_type)
throw Mysqlx_exception("Invalid operation type");
return get_impl<typename stmt_traits<OP>::Impl>(stmt);
}
#endif