mirror of
https://github.com/php/pecl-database-mysql_xdevapi.git
synced 2026-03-23 23:02:08 +01:00
799 lines
23 KiB
C++
799 lines
23 KiB
C++
/*
|
|
+----------------------------------------------------------------------+
|
|
| PHP Version 7 |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) The PHP Group |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 3.01 of the PHP license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available through the world-wide-web at the following url: |
|
|
| http://www.php.net/license/3_01.txt |
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
| Authors: Andrey Hristov <andrey@php.net> |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
#include "php_api.h"
|
|
#include "mysqlnd_api.h"
|
|
extern "C" {
|
|
#include <ext/standard/url.h>
|
|
}
|
|
#include "xmysqlnd/xmysqlnd.h"
|
|
#include "xmysqlnd/xmysqlnd_session.h"
|
|
#include "xmysqlnd/xmysqlnd_schema.h"
|
|
#include "xmysqlnd/xmysqlnd_stmt.h"
|
|
#include "xmysqlnd/xmysqlnd_stmt_result.h"
|
|
#include "xmysqlnd/xmysqlnd_stmt_result_meta.h"
|
|
#include "xmysqlnd/xmysqlnd_utils.h"
|
|
#include "php_mysqlx.h"
|
|
#include "mysqlx_exception.h"
|
|
#include "mysqlx_class_properties.h"
|
|
#include "mysqlx_session.h"
|
|
#include "mysqlx_schema.h"
|
|
#include "mysqlx_sql_statement.h"
|
|
#include "util/object.h"
|
|
#include "util/string_utils.h"
|
|
#include "util/functions.h"
|
|
|
|
namespace mysqlx {
|
|
|
|
namespace devapi {
|
|
|
|
using namespace drv;
|
|
|
|
zend_class_entry *mysqlx_session_class_entry;
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqlx_session__construct, 0, ZEND_RETURN_VALUE, 0)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqlx_session__create_schema, 0, ZEND_RETURN_VALUE, 1)
|
|
ZEND_ARG_TYPE_INFO(no_pass_by_ref, schema_name, IS_STRING, dont_allow_null)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqlx_session__drop_schema, 0, ZEND_RETURN_VALUE, 1)
|
|
ZEND_ARG_TYPE_INFO(no_pass_by_ref, schema_name, IS_STRING, dont_allow_null)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqlx_session__get_server_version, 0, ZEND_RETURN_VALUE, 0)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqlx_session__generate_uuid, 0, ZEND_RETURN_VALUE, 0)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqlx_session__sql, 0, ZEND_RETURN_VALUE, 1)
|
|
ZEND_ARG_TYPE_INFO(no_pass_by_ref, query, IS_STRING, dont_allow_null)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqlx_session__quote_name, 0, ZEND_RETURN_VALUE, 1)
|
|
ZEND_ARG_TYPE_INFO(no_pass_by_ref, name, IS_STRING, dont_allow_null)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqlx_session__get_schemas, 0, ZEND_RETURN_VALUE, 0)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqlx_session__get_default_schema, 0, ZEND_RETURN_VALUE, 0)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqlx_session__get_schema, 0, ZEND_RETURN_VALUE, 1)
|
|
ZEND_ARG_TYPE_INFO(no_pass_by_ref, name, IS_STRING, dont_allow_null)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqlx_session__start_transaction, 0, ZEND_RETURN_VALUE, 0)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqlx_session__commit, 0, ZEND_RETURN_VALUE, 0)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqlx_session__rollback, 0, ZEND_RETURN_VALUE, 0)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqlx_session__set_savepoint, 0, ZEND_RETURN_VALUE, 0)
|
|
ZEND_ARG_INFO(no_pass_by_ref, savepoint_name)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqlx_session__rollback_to, 0, ZEND_RETURN_VALUE, 1)
|
|
ZEND_ARG_TYPE_INFO(no_pass_by_ref, savepoint_name, IS_STRING, dont_allow_null)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqlx_session__release_savepoint, 0, ZEND_RETURN_VALUE, 1)
|
|
ZEND_ARG_TYPE_INFO(no_pass_by_ref, savepoint_name, IS_STRING, dont_allow_null)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqlx_session__close, 0, ZEND_RETURN_VALUE, 0)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
bool Session_data::close_connection()
|
|
{
|
|
if (!session) return false;
|
|
|
|
if (session->is_pooled()) {
|
|
session->pool_callback->on_close(session);
|
|
} else {
|
|
session->close(Session_close_reason::Explicit);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
template<typename T>
|
|
Session_data& fetch_session_data(T* from, bool allow_closed = false)
|
|
{
|
|
auto& data_object{ util::fetch_data_object<Session_data>(from) };
|
|
if (!allow_closed && data_object.session->is_closed()) {
|
|
auto close_exception_code = data_object.session->get_data()->state.get_close_exception_code();
|
|
throw util::xdevapi_exception(close_exception_code);
|
|
}
|
|
return data_object;
|
|
}
|
|
|
|
static zend_bool
|
|
mysqlx_throw_exception_from_session_if_needed(const XMYSQLND_SESSION_DATA session)
|
|
{
|
|
const int error_num = session->get_error_no();
|
|
DBG_ENTER("mysqlx_throw_exception_from_session_if_needed");
|
|
if (error_num) {
|
|
const char* sqlstate = session->get_sqlstate();
|
|
const char* errmsg = session->get_error_str();
|
|
create_exception(error_num, sqlstate, errmsg);
|
|
DBG_RETURN(TRUE);
|
|
}
|
|
DBG_RETURN(FALSE);
|
|
}
|
|
|
|
MYSQL_XDEVAPI_PHP_METHOD(mysqlx_session, getServerVersion)
|
|
{
|
|
DBG_ENTER("mysqlx_session::getServerVersion");
|
|
|
|
util::raw_zval* object_zv{nullptr};
|
|
if (util::get_method_arguments(execute_data, getThis(), "O", &object_zv, mysqlx_session_class_entry) == FAILURE) {
|
|
DBG_VOID_RETURN;
|
|
}
|
|
|
|
auto& data_object{ fetch_session_data(object_zv) };
|
|
if (XMYSQLND_SESSION session = data_object.session) {
|
|
RETVAL_LONG(session->get_server_version());
|
|
mysqlx_throw_exception_from_session_if_needed(session->get_data());
|
|
} else {
|
|
RETVAL_FALSE;
|
|
}
|
|
|
|
DBG_VOID_RETURN;
|
|
}
|
|
|
|
MYSQL_XDEVAPI_PHP_METHOD(mysqlx_session, generateUUID)
|
|
{
|
|
DBG_ENTER("mysqlx_session::generateUUID");
|
|
|
|
util::raw_zval* object_zv{nullptr};
|
|
if (util::get_method_arguments(execute_data, getThis(), "O", &object_zv, mysqlx_session_class_entry) == FAILURE) {
|
|
DBG_VOID_RETURN;
|
|
}
|
|
RETVAL_FALSE;
|
|
|
|
auto& data_object{ fetch_session_data(object_zv) };
|
|
if (XMYSQLND_SESSION session = data_object.session) {
|
|
auto uuid = session->session_uuid->generate();
|
|
if (uuid.size() > 0) {
|
|
RETVAL_STRINGL(uuid.data(), uuid.size());
|
|
}
|
|
mysqlx_throw_exception_from_session_if_needed(session->data);
|
|
}
|
|
|
|
DBG_VOID_RETURN;
|
|
}
|
|
|
|
struct st_mysqlx_get_schemas_ctx
|
|
{
|
|
util::zvalue* list;
|
|
};
|
|
|
|
static const enum_hnd_func_status
|
|
get_schemas_handler_on_row(void * context,
|
|
XMYSQLND_SESSION const session,
|
|
xmysqlnd_stmt * const /*stmt*/,
|
|
const XMYSQLND_STMT_RESULT_META * const /*meta*/,
|
|
const zval * const row,
|
|
MYSQLND_STATS * const /*stats*/,
|
|
MYSQLND_ERROR_INFO * const /*error_info*/)
|
|
{
|
|
const st_mysqlx_get_schemas_ctx* ctx = reinterpret_cast<const st_mysqlx_get_schemas_ctx*>(context);
|
|
DBG_ENTER("get_schemas_handler_on_row");
|
|
if (ctx && ctx->list && row) {
|
|
assert(ctx->list->is_array());
|
|
const util::string_view schema_name{ Z_STRVAL(row[0]), Z_STRLEN(row[0]) };
|
|
xmysqlnd_schema * schema = session->create_schema_object(schema_name);
|
|
if (schema) {
|
|
util::zvalue schema_obj = create_schema(schema);
|
|
ctx->list->push_back(schema_obj);
|
|
}
|
|
}
|
|
DBG_RETURN(HND_AGAIN);
|
|
}
|
|
|
|
static const enum_hnd_func_status
|
|
mysqlx_session_command_handler_on_error(
|
|
void * /*context*/,
|
|
XMYSQLND_SESSION session,
|
|
xmysqlnd_stmt * const /*stmt*/,
|
|
const unsigned int code,
|
|
const util::string_view& sql_state,
|
|
const util::string_view& message)
|
|
{
|
|
DBG_ENTER("mysqlx_session_command_handler_on_error");
|
|
if (session) {
|
|
xmysqlnd_session_data_handler_on_error(session->data.get(), code, sql_state, message);
|
|
}
|
|
DBG_RETURN(HND_PASS_RETURN_FAIL);
|
|
}
|
|
|
|
MYSQL_XDEVAPI_PHP_METHOD(mysqlx_session, getSchemas)
|
|
{
|
|
DBG_ENTER("mysqlx_session::getSchemas");
|
|
|
|
util::raw_zval* object_zv{nullptr};
|
|
if (util::get_method_arguments(execute_data, getThis(), "O", &object_zv, mysqlx_session_class_entry) == FAILURE) {
|
|
DBG_VOID_RETURN;
|
|
}
|
|
|
|
auto& data_object{ fetch_session_data(object_zv) };
|
|
util::zvalue schemas = util::zvalue::create_array();
|
|
if (XMYSQLND_SESSION session = data_object.session) {
|
|
const st_xmysqlnd_session_query_bind_variable_bind var_binder{ nullptr, nullptr };
|
|
constexpr util::string_view list_query("SHOW DATABASES");
|
|
st_mysqlx_get_schemas_ctx ctx{ &schemas };
|
|
const st_xmysqlnd_session_on_result_start_bind on_result_start{ nullptr, nullptr };
|
|
const st_xmysqlnd_session_on_row_bind on_row{ get_schemas_handler_on_row, &ctx };
|
|
const st_xmysqlnd_session_on_warning_bind on_warning{ nullptr, nullptr };
|
|
const st_xmysqlnd_session_on_error_bind on_error{ mysqlx_session_command_handler_on_error, nullptr };
|
|
const st_xmysqlnd_session_on_result_end_bind on_result_end{ nullptr, nullptr };
|
|
const st_xmysqlnd_session_on_statement_ok_bind on_statement_ok{ nullptr, nullptr };
|
|
|
|
if (PASS != session->query_cb(namespace_sql, list_query, var_binder, on_result_start, on_row, on_warning, on_error, on_result_end, on_statement_ok)) {
|
|
schemas.clear();
|
|
mysqlx_throw_exception_from_session_if_needed(session->data);
|
|
}
|
|
}
|
|
schemas.move_to(return_value);
|
|
DBG_VOID_RETURN;
|
|
}
|
|
|
|
MYSQL_XDEVAPI_PHP_METHOD(mysqlx_session, getDefaultSchema)
|
|
{
|
|
DBG_ENTER("mysqlx_session::getDefaultSchema");
|
|
|
|
RETVAL_NULL();
|
|
|
|
util::raw_zval* object_zv{nullptr};
|
|
if (util::get_method_arguments(
|
|
execute_data,
|
|
getThis(),
|
|
"O", &object_zv,
|
|
mysqlx_session_class_entry) == FAILURE) {
|
|
DBG_VOID_RETURN;
|
|
}
|
|
|
|
auto& data_object{ fetch_session_data(object_zv) };
|
|
if (XMYSQLND_SESSION session = data_object.session) {
|
|
util::string_view schema_name{ session->get_data()->default_schema };
|
|
if (!schema_name.empty()) {
|
|
xmysqlnd_schema* schema = session->create_schema_object(schema_name);
|
|
if (schema) {
|
|
create_schema(schema).move_to(return_value);
|
|
} else {
|
|
mysqlx_throw_exception_from_session_if_needed(session->data);
|
|
}
|
|
}
|
|
}
|
|
|
|
DBG_VOID_RETURN;
|
|
}
|
|
|
|
MYSQL_XDEVAPI_PHP_METHOD(mysqlx_session, getSchema)
|
|
{
|
|
DBG_ENTER("mysqlx_session::getSchema");
|
|
|
|
util::raw_zval* object_zv{nullptr};
|
|
util::arg_string schema_name;
|
|
if (util::get_method_arguments(execute_data,
|
|
getThis(),
|
|
"Os", &object_zv,
|
|
mysqlx_session_class_entry,
|
|
&(schema_name.str), &(schema_name.len)) == FAILURE) {
|
|
DBG_VOID_RETURN;
|
|
}
|
|
|
|
auto& data_object{ fetch_session_data(object_zv) };
|
|
if (XMYSQLND_SESSION session = data_object.session) {
|
|
xmysqlnd_schema * schema = session->create_schema_object(schema_name.to_view());
|
|
if (schema) {
|
|
create_schema(schema).move_to(return_value);
|
|
} else {
|
|
mysqlx_throw_exception_from_session_if_needed(session->data);
|
|
}
|
|
} else {
|
|
RETVAL_FALSE;
|
|
}
|
|
|
|
DBG_VOID_RETURN;
|
|
}
|
|
|
|
static util::zvalue
|
|
mysqlx_execute_session_query(XMYSQLND_SESSION session,
|
|
const std::string_view& namespace_,
|
|
const util::string_view& query,
|
|
const zend_long flags,
|
|
const util::zvalues& args)
|
|
{
|
|
DBG_ENTER("mysqlx_execute_session_query");
|
|
xmysqlnd_stmt* stmt = session->create_statement_object(session);
|
|
util::zvalue stmt_obj = create_sql_stmt(stmt, namespace_, query);
|
|
|
|
bool found{ false };
|
|
for (const auto& arg : args) {
|
|
if (!mysqlx_sql_statement_bind_one_param(stmt_obj.ptr(), arg)) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
util::zvalue result;
|
|
if (!found) {
|
|
result = mysqlx_sql_statement_execute(Z_MYSQLX_P(stmt_obj.ptr()), flags);
|
|
}
|
|
|
|
DBG_RETURN(result);
|
|
}
|
|
|
|
MYSQL_XDEVAPI_PHP_METHOD(mysqlx_session, sql)
|
|
{
|
|
DBG_ENTER("mysqlx_session::sql");
|
|
|
|
util::raw_zval* object_zv{nullptr};
|
|
XMYSQLND_SESSION session;
|
|
util::arg_string query;
|
|
|
|
if (util::get_method_arguments(execute_data, getThis(), "Os", &object_zv, mysqlx_session_class_entry,
|
|
&query.str, &query.len) == FAILURE)
|
|
{
|
|
DBG_VOID_RETURN;
|
|
}
|
|
|
|
if (query.empty()) {
|
|
php_error_docref(nullptr, E_WARNING, "Empty query");
|
|
RETVAL_FALSE;
|
|
DBG_VOID_RETURN;
|
|
}
|
|
|
|
auto& data_object{ fetch_session_data(object_zv) };
|
|
if ((session = data_object.session)) {
|
|
xmysqlnd_stmt * const stmt = session->create_statement_object(session);
|
|
if (stmt) {
|
|
util::zvalue sql_stmt_obj = create_sql_stmt(stmt, namespace_sql, query.to_view());
|
|
if (sql_stmt_obj.is_null()) {
|
|
mysqlx_throw_exception_from_session_if_needed(session->data);
|
|
}
|
|
sql_stmt_obj.move_to(return_value);
|
|
}
|
|
}
|
|
|
|
DBG_VOID_RETURN;
|
|
}
|
|
|
|
MYSQL_XDEVAPI_PHP_METHOD(mysqlx_session, quoteName)
|
|
{
|
|
DBG_ENTER("mysqlx_session::quoteName");
|
|
|
|
util::raw_zval* object_zv{nullptr};
|
|
util::arg_string name;
|
|
if (util::get_method_arguments(execute_data, getThis(), "Os", &object_zv, mysqlx_session_class_entry,
|
|
&(name.str), &(name.len)) == FAILURE)
|
|
{
|
|
DBG_VOID_RETURN;
|
|
}
|
|
|
|
auto& data_object{ fetch_session_data(object_zv) };
|
|
if (XMYSQLND_SESSION session = data_object.session) {
|
|
util::string quoted_name = session->data->quote_name(name.to_view());
|
|
RETVAL_STRINGL(quoted_name.c_str(), quoted_name.length());
|
|
mysqlx_throw_exception_from_session_if_needed(session->data);
|
|
} else {
|
|
RETVAL_FALSE;
|
|
}
|
|
|
|
DBG_VOID_RETURN;
|
|
}
|
|
|
|
MYSQL_XDEVAPI_PHP_METHOD(mysqlx_session, createSchema)
|
|
{
|
|
DBG_ENTER("mysqlx_session::createSchema");
|
|
|
|
util::raw_zval* object_zv{nullptr};
|
|
util::arg_string schema_name;
|
|
if (util::get_method_arguments(execute_data, getThis(), "Os", &object_zv, mysqlx_session_class_entry,
|
|
&schema_name.str, &schema_name.len) == FAILURE) {
|
|
DBG_VOID_RETURN;
|
|
}
|
|
|
|
auto& data_object{ fetch_session_data(object_zv) };
|
|
if (XMYSQLND_SESSION session = data_object.session) {
|
|
xmysqlnd_schema* schema{nullptr};
|
|
const util::string_view& schema_name_view = schema_name.to_view();
|
|
if ((PASS == session->create_db(schema_name_view)) &&
|
|
((schema = session->create_schema_object(schema_name_view)) != nullptr))
|
|
{
|
|
DBG_INF_FMT("schema=%p", schema);
|
|
create_schema(schema).move_to(return_value);
|
|
} else {
|
|
mysqlx_throw_exception_from_session_if_needed(session->data);
|
|
}
|
|
} else {
|
|
RETVAL_FALSE;
|
|
}
|
|
|
|
DBG_VOID_RETURN;
|
|
}
|
|
|
|
MYSQL_XDEVAPI_PHP_METHOD(mysqlx_session, dropSchema)
|
|
{
|
|
DBG_ENTER("mysqlx_session::dropSchema");
|
|
|
|
util::raw_zval* object_zv{nullptr};
|
|
util::arg_string schema_name;
|
|
if (util::get_method_arguments(
|
|
execute_data, getThis(), "Os",
|
|
&object_zv, mysqlx_session_class_entry,
|
|
&(schema_name.str), &(schema_name.len)) == FAILURE) {
|
|
DBG_VOID_RETURN;
|
|
}
|
|
RETVAL_FALSE;
|
|
|
|
auto& data_object = fetch_session_data(object_zv);
|
|
try {
|
|
auto session = data_object.session;
|
|
if (PASS == session->drop_db(schema_name.to_view())) {
|
|
RETVAL_TRUE;
|
|
} else {
|
|
util::log_warning("cannot drop schema '" + schema_name.to_string() + "'");
|
|
}
|
|
} catch(std::exception& e) {
|
|
util::log_warning(e.what());
|
|
}
|
|
|
|
DBG_VOID_RETURN;
|
|
}
|
|
|
|
MYSQL_XDEVAPI_PHP_METHOD(mysqlx_session, startTransaction)
|
|
{
|
|
DBG_ENTER("mysqlx_session::startTransaction");
|
|
|
|
util::raw_zval* object_zv{nullptr};
|
|
constexpr util::string_view query{"START TRANSACTION"};
|
|
if (util::get_method_arguments(execute_data, getThis(), "O", &object_zv, mysqlx_session_class_entry) == FAILURE)
|
|
{
|
|
DBG_VOID_RETURN;
|
|
}
|
|
|
|
RETVAL_NULL();
|
|
|
|
auto& data_object{ fetch_session_data(object_zv) };
|
|
if (data_object.session) {
|
|
mysqlx_execute_session_query(
|
|
data_object.session,
|
|
namespace_sql, query,
|
|
MYSQLX_EXECUTE_FLAG_BUFFERED,
|
|
util::zvalues()
|
|
).move_to(return_value);
|
|
}
|
|
|
|
DBG_VOID_RETURN;
|
|
}
|
|
|
|
MYSQL_XDEVAPI_PHP_METHOD(mysqlx_session, commit)
|
|
{
|
|
DBG_ENTER("mysqlx_session::commit");
|
|
|
|
util::raw_zval* object_zv{nullptr};
|
|
constexpr util::string_view query{"COMMIT"};
|
|
if (util::get_method_arguments(execute_data, getThis(), "O", &object_zv, mysqlx_session_class_entry) == FAILURE)
|
|
{
|
|
DBG_VOID_RETURN;
|
|
}
|
|
|
|
RETVAL_NULL();
|
|
|
|
auto& data_object{ fetch_session_data(object_zv) };
|
|
if (data_object.session) {
|
|
mysqlx_execute_session_query(
|
|
data_object.session,
|
|
namespace_sql,
|
|
query,
|
|
MYSQLX_EXECUTE_FLAG_BUFFERED,
|
|
util::zvalues()
|
|
).move_to(return_value);
|
|
}
|
|
|
|
DBG_VOID_RETURN;
|
|
}
|
|
|
|
MYSQL_XDEVAPI_PHP_METHOD(mysqlx_session, rollback)
|
|
{
|
|
DBG_ENTER("mysqlx_session::rollback");
|
|
|
|
util::raw_zval* object_zv{nullptr};
|
|
constexpr util::string_view query{"ROLLBACK"};
|
|
if (util::get_method_arguments(execute_data, getThis(), "O", &object_zv, mysqlx_session_class_entry) == FAILURE)
|
|
{
|
|
DBG_VOID_RETURN;
|
|
}
|
|
|
|
RETVAL_NULL();
|
|
|
|
auto& data_object{ fetch_session_data(object_zv) };
|
|
if (data_object.session) {
|
|
mysqlx_execute_session_query(
|
|
data_object.session,
|
|
namespace_sql,
|
|
query,
|
|
MYSQLX_EXECUTE_FLAG_BUFFERED,
|
|
util::zvalues()
|
|
).move_to(return_value);
|
|
}
|
|
|
|
DBG_VOID_RETURN;
|
|
}
|
|
|
|
static util::string
|
|
generate_savepoint_name( const unsigned int name_seed )
|
|
{
|
|
static const std::string SAVEPOINT_NAME_PREFIX{ "SAVEPOINT" };
|
|
std::stringstream output;
|
|
output << SAVEPOINT_NAME_PREFIX << name_seed;
|
|
return output.str().c_str();
|
|
}
|
|
|
|
MYSQL_XDEVAPI_PHP_METHOD(mysqlx_session, setSavepoint)
|
|
{
|
|
DBG_ENTER("mysqlx_session::setSavepoint");
|
|
|
|
util::raw_zval* object_zv{nullptr};
|
|
util::arg_string savepoint_name;
|
|
if (util::get_method_arguments(
|
|
execute_data, getThis(), "O|s",
|
|
&object_zv, mysqlx_session_class_entry,
|
|
&(savepoint_name.str), &(savepoint_name.len)) == FAILURE) {
|
|
DBG_VOID_RETURN;
|
|
}
|
|
|
|
RETVAL_FALSE;
|
|
|
|
auto& data_object = fetch_session_data(object_zv);
|
|
util::string query{ "SAVEPOINT " };
|
|
util::zvalue name;
|
|
if( savepoint_name.empty() ) {
|
|
//Generate a valid savepoint name
|
|
name = generate_savepoint_name( data_object.session->data->savepoint_name_seed++ );
|
|
} else {
|
|
name = savepoint_name;
|
|
}
|
|
|
|
query += util::escape_identifier( name.to_string_view() );
|
|
|
|
if (data_object.session) {
|
|
mysqlx_execute_session_query(
|
|
data_object.session,
|
|
namespace_sql,
|
|
{query.c_str(), query.size()} ,
|
|
MYSQLX_EXECUTE_FLAG_BUFFERED,
|
|
util::zvalues());
|
|
}
|
|
name.move_to(return_value);
|
|
|
|
DBG_VOID_RETURN;
|
|
}
|
|
|
|
MYSQL_XDEVAPI_PHP_METHOD(mysqlx_session, rollbackTo)
|
|
{
|
|
DBG_ENTER("mysqlx_session::rollbackTo");
|
|
|
|
util::raw_zval* object_zv{ nullptr };
|
|
util::arg_string savepoint_name;
|
|
if (util::get_method_arguments(
|
|
execute_data, getThis(), "Os",
|
|
&object_zv, mysqlx_session_class_entry,
|
|
&(savepoint_name.str), &(savepoint_name.len)) == FAILURE) {
|
|
DBG_VOID_RETURN;
|
|
}
|
|
|
|
RETVAL_FALSE;
|
|
|
|
util::string name = util::escape_identifier( savepoint_name.to_view() );
|
|
auto& data_object{ fetch_session_data( object_zv) };
|
|
const util::string query{ "ROLLBACK TO " + name };
|
|
|
|
if (data_object.session) {
|
|
mysqlx_execute_session_query(
|
|
data_object.session,
|
|
namespace_sql,
|
|
{query.c_str(), query.size()} ,
|
|
MYSQLX_EXECUTE_FLAG_BUFFERED,
|
|
util::zvalues()
|
|
).move_to(return_value);
|
|
}
|
|
|
|
DBG_VOID_RETURN;
|
|
}
|
|
|
|
MYSQL_XDEVAPI_PHP_METHOD(mysqlx_session, releaseSavepoint)
|
|
{
|
|
DBG_ENTER("mysqlx_session::releaseSavepoint");
|
|
|
|
util::raw_zval* object_zv{ nullptr };
|
|
util::arg_string savepoint_name;
|
|
if (util::get_method_arguments(
|
|
execute_data, getThis(), "Os",
|
|
&object_zv, mysqlx_session_class_entry,
|
|
&(savepoint_name.str), &(savepoint_name.len)) == FAILURE) {
|
|
DBG_VOID_RETURN;
|
|
}
|
|
|
|
RETVAL_FALSE;
|
|
|
|
util::string name = util::escape_identifier( savepoint_name.to_view() );
|
|
auto& data_object{ fetch_session_data( object_zv) };
|
|
const util::string query{ "RELEASE SAVEPOINT " + name };
|
|
|
|
if (data_object.session) {
|
|
mysqlx_execute_session_query(
|
|
data_object.session,
|
|
namespace_sql,
|
|
{query.c_str(), query.size()} ,
|
|
MYSQLX_EXECUTE_FLAG_BUFFERED,
|
|
util::zvalues()
|
|
).move_to(return_value);
|
|
}
|
|
|
|
DBG_VOID_RETURN;
|
|
}
|
|
|
|
MYSQL_XDEVAPI_PHP_METHOD(mysqlx_session, close)
|
|
{
|
|
DBG_ENTER("mysqlx_session::close");
|
|
|
|
util::raw_zval* object_zv{nullptr};
|
|
if (util::get_method_arguments(execute_data, getThis(), "O", &object_zv, mysqlx_session_class_entry) == FAILURE) {
|
|
DBG_VOID_RETURN;
|
|
}
|
|
|
|
auto& data_object{ fetch_session_data(object_zv, true) };
|
|
if (data_object.close_connection()) {
|
|
RETVAL_TRUE;
|
|
} else {
|
|
RETVAL_FALSE;
|
|
}
|
|
|
|
DBG_VOID_RETURN;
|
|
}
|
|
|
|
MYSQL_XDEVAPI_PHP_METHOD(mysqlx_session, __construct)
|
|
{
|
|
UNUSED_INTERNAL_FUNCTION_PARAMETERS();
|
|
}
|
|
|
|
static const zend_function_entry mysqlx_session_methods[] = {
|
|
PHP_ME(mysqlx_session, __construct, arginfo_mysqlx_session__construct, ZEND_ACC_PRIVATE)
|
|
PHP_ME(mysqlx_session, sql, arginfo_mysqlx_session__sql, ZEND_ACC_PUBLIC)
|
|
PHP_ME(mysqlx_session, quoteName, arginfo_mysqlx_session__quote_name, ZEND_ACC_PUBLIC)
|
|
PHP_ME(mysqlx_session, getServerVersion, arginfo_mysqlx_session__get_server_version, ZEND_ACC_PUBLIC)
|
|
PHP_ME(mysqlx_session, generateUUID, arginfo_mysqlx_session__generate_uuid, ZEND_ACC_PUBLIC)
|
|
PHP_ME(mysqlx_session, createSchema, arginfo_mysqlx_session__create_schema, ZEND_ACC_PUBLIC)
|
|
PHP_ME(mysqlx_session, dropSchema, arginfo_mysqlx_session__drop_schema, ZEND_ACC_PUBLIC)
|
|
PHP_ME(mysqlx_session, getSchemas, arginfo_mysqlx_session__get_schemas, ZEND_ACC_PUBLIC)
|
|
PHP_ME(mysqlx_session, getDefaultSchema, arginfo_mysqlx_session__get_default_schema, ZEND_ACC_PUBLIC)
|
|
PHP_ME(mysqlx_session, getSchema, arginfo_mysqlx_session__get_schema, ZEND_ACC_PUBLIC)
|
|
PHP_ME(mysqlx_session, startTransaction, arginfo_mysqlx_session__start_transaction, ZEND_ACC_PUBLIC)
|
|
PHP_ME(mysqlx_session, commit, arginfo_mysqlx_session__commit, ZEND_ACC_PUBLIC)
|
|
PHP_ME(mysqlx_session, rollback, arginfo_mysqlx_session__rollback, ZEND_ACC_PUBLIC)
|
|
PHP_ME(mysqlx_session, setSavepoint, arginfo_mysqlx_session__set_savepoint, ZEND_ACC_PUBLIC)
|
|
PHP_ME(mysqlx_session, rollbackTo, arginfo_mysqlx_session__rollback_to, ZEND_ACC_PUBLIC)
|
|
PHP_ME(mysqlx_session, releaseSavepoint, arginfo_mysqlx_session__release_savepoint, ZEND_ACC_PUBLIC)
|
|
PHP_ME(mysqlx_session, close, arginfo_mysqlx_session__close, ZEND_ACC_PUBLIC)
|
|
{nullptr, nullptr, nullptr}
|
|
};
|
|
|
|
static zend_object_handlers mysqlx_object_session_handlers;
|
|
static HashTable mysqlx_session_properties;
|
|
|
|
const st_mysqlx_property_entry mysqlx_session_property_entries[] =
|
|
{
|
|
{std::string_view{}, nullptr, nullptr}
|
|
};
|
|
|
|
static void
|
|
mysqlx_session_free_storage(zend_object* object)
|
|
{
|
|
auto& data_object{ fetch_session_data(object, true) };
|
|
data_object.close_connection();
|
|
util::free_object<Session_data>(object);
|
|
}
|
|
|
|
static zend_object *
|
|
php_mysqlx_session_object_allocator(zend_class_entry* class_type)
|
|
{
|
|
DBG_ENTER("php_mysqlx_session_object_allocator");
|
|
st_mysqlx_object* mysqlx_object = util::alloc_object<Session_data>(
|
|
class_type,
|
|
&mysqlx_object_session_handlers,
|
|
&mysqlx_session_properties);
|
|
DBG_RETURN(&mysqlx_object->zo);
|
|
}
|
|
|
|
void
|
|
mysqlx_register_session_class(UNUSED_INIT_FUNC_ARGS, zend_object_handlers* mysqlx_std_object_handlers)
|
|
{
|
|
MYSQL_XDEVAPI_REGISTER_CLASS(
|
|
mysqlx_session_class_entry,
|
|
"Session",
|
|
mysqlx_std_object_handlers,
|
|
mysqlx_object_session_handlers,
|
|
php_mysqlx_session_object_allocator,
|
|
mysqlx_session_free_storage,
|
|
mysqlx_session_methods,
|
|
mysqlx_session_properties,
|
|
mysqlx_session_property_entries);
|
|
}
|
|
|
|
void
|
|
mysqlx_unregister_session_class(UNUSED_SHUTDOWN_FUNC_ARGS)
|
|
{
|
|
zend_hash_destroy(&mysqlx_session_properties);
|
|
}
|
|
|
|
util::zvalue
|
|
create_session()
|
|
{
|
|
DBG_ENTER("create_session");
|
|
DBG_RETURN(create_session(drv::create_session(false)));
|
|
}
|
|
|
|
util::zvalue
|
|
create_session(drv::XMYSQLND_SESSION session)
|
|
{
|
|
DBG_ENTER("create_session");
|
|
|
|
util::zvalue session_obj;
|
|
Session_data& data_object{
|
|
util::init_object<Session_data>(mysqlx_session_class_entry, session_obj) };
|
|
data_object.session = session;
|
|
|
|
DBG_RETURN(session_obj);
|
|
}
|
|
|
|
MYSQL_XDEVAPI_PHP_FUNCTION(mysql_xdevapi_getSession)
|
|
{
|
|
util::arg_string uri_string;
|
|
|
|
RETVAL_NULL();
|
|
|
|
DBG_ENTER("mysql_xdevapi_getSession");
|
|
if (FAILURE == util::get_function_arguments(execute_data, "s",
|
|
&(uri_string.str), &(uri_string.len)))
|
|
{
|
|
DBG_VOID_RETURN;
|
|
}
|
|
|
|
if (uri_string.empty()) {
|
|
php_error_docref(nullptr, E_WARNING, "Empty URI string");
|
|
DBG_VOID_RETURN;
|
|
}
|
|
|
|
drv::xmysqlnd_new_session_connect(uri_string.str,return_value);
|
|
|
|
DBG_VOID_RETURN;
|
|
}
|
|
|
|
} // namespace devapi
|
|
|
|
} // namespace mysqlx
|