<commit_before>/*
 +----------------------------------------------------------------------+
 | Swoole                                                               |
 +----------------------------------------------------------------------+
 | Copyright (c) 2012-2018 The Swoole Group                             |
 +----------------------------------------------------------------------+
 | This source file is subject to version 2.0 of the Apache 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.apache.org/licenses/LICENSE-2.0.html                      |
 | If you did not receive a copy of the Apache2.0 license and are unable|
 | to obtain it through the world-wide-web, please send a note to       |
 | <EMAIL> so we can mail you a copy immediately.            |
 +----------------------------------------------------------------------+
 | Author: Twosee  <<EMAIL>>                                       |
 | Author: <NAME>  <<EMAIL>>                        |
 +----------------------------------------------------------------------+
 */

#include "php_swoole_cxx.h"

#include "swoole_mysql_proto.h"

// see mysqlnd 'L64' macro redefined
#undef L64

extern "C" {
#include "ext/hash/php_hash.h"
#include "ext/hash/php_hash_sha.h"
#include "ext/standard/php_math.h"
#ifdef SW_USE_MYSQLND
#include "ext/mysqlnd/mysqlnd.h"
#include "ext/mysqlnd/mysqlnd_charset.h"
#endif
}

#include <unordered_map>

using namespace swoole;
using swoole::coroutine::Socket;

/* keep same with pdo and mysqli */
#define MYSQLND_UNKNOWN_SQLSTATE        "HY000"
#define MYSQLND_SERVER_GONE             "MySQL server has gone away"
#define MYSQLND_CR_UNKNOWN_ERROR        2000
#define MYSQLND_CR_CONNECTION_ERROR     2002
#define MYSQLND_CR_SERVER_GONE_ERROR    2006
#define MYSQLND_CR_OUT_OF_MEMORY        2008
#define MYSQLND_CR_SERVER_LOST          2013
#define MYSQLND_CR_COMMANDS_OUT_OF_SYNC 2014
#define MYSQLND_CR_CANT_FIND_CHARSET    2019
#define MYSQLND_CR_MALFORMED_PACKET     2027
#define MYSQLND_CR_NOT_IMPLEMENTED      2054
#define MYSQLND_CR_NO_PREPARE_STMT      2030
#define MYSQLND_CR_PARAMS_NOT_BOUND     2031
#define MYSQLND_CR_INVALID_PARAMETER_NO 2034
#define MYSQLND_CR_INVALID_BUFFER_USE   2035

namespace swoole
{
class mysql_statement;
class mysql_client
{
public:
    /* session related {{{ */
    Socket *socket = nullptr;
    Socket::timeout_controller *tc = nullptr;

    enum sw_mysql_state state = SW_MYSQL_STATE_CLOSED;
    bool quit = false;
    mysql::result_info result;

    std::unordered_map<uint32_t, mysql_statement*> statements;
    mysql_statement* statement = nullptr;
    /* }}} */

    std::string host = SW_MYSQL_DEFAULT_HOST;
    uint16_t port = SW_MYSQL_DEFAULT_PORT;
    bool ssl = false;

    std::string user = "root";
    std::string password = "<PASSWORD>";
    std::string database = "test";
    char charset = SW_MYSQL_DEFAULT_CHARSET;

    double connect_timeout = Socket::default_connect_timeout;
    bool strict_type = false;

    inline int get_error_code()
    {
        return error_code;
    }

    inline const char* get_error_msg()
    {
        return error_msg.c_str();
    }

    inline void non_sql_error(int code, const char *msg)
    {
        error_code = code;
        error_msg = cpp_string::format("SQLSTATE[" MYSQLND_UNKNOWN_SQLSTATE "] [%d] %s", code, msg);
    }

    template<typename ...Args>
    inline void non_sql_error(int code, const char *format, Args ...args)
    {
        error_code = code;
        error_msg = cpp_string::format(
            "SQLSTATE[" MYSQLND_UNKNOWN_SQLSTATE "] [%d] %s",
            code, cpp_string::format(format, args...).c_str()
        );
    }

    void io_error()
    {
        if (state == SW_MYSQL_STATE_CLOSED)
        {
            non_sql_error(MYSQLND_CR_CONNECTION_ERROR, socket->errMsg);
        }
        else
        {
            non_sql_error(MYSQLND_CR_SERVER_GONE_ERROR, MYSQLND_SERVER_GONE " due to %s", socket->errMsg);
        }
        close();
    }

    void proto_error(const char *data, const enum sw_mysql_packet_types expected_type)
    {
        mysql::server_packet packet(data);
        non_sql_error(
            MYSQLND_CR_MALFORMED_PACKET, "Unexpected mysql packet length=%u, number=%u, type=%u, expected_type=%u",
            packet.header.length, packet.header.number, (uint8_t) data[SW_MYSQL_PACKET_HEADER_SIZE], expected_type
        );
        close();
    }

    void server_error(const char *data)
    {
        mysql::err_packet err_packet(data);
        error_code = err_packet.code;
        error_msg = cpp_string::format("SQLSTATE[%s] [%d] %s", err_packet.sql_state, err_packet.code, err_packet.msg.c_str());
        state = SW_MYSQL_STATE_IDLE;
    }

    inline bool get_fetch_mode()
    {
        return fetch_mode;
    }

    inline bool set_fetch_mode(bool v)
    {
        if (unlikely(socket && v))
        {
            non_sql_error(ENOTSUP, "Can not use fetch mode after the connection is established");
            return false;
        }
        fetch_mode = v;
        return true;
    }

    inline bool get_defer()
    {
        return defer;
    }

    inline bool set_defer(bool v)
    {
        if (unlikely(fetch_mode && v))
        {
            non_sql_error(ENOTSUP, "Can not use defer mode when fetch mode is on");
            return false;
        }
        defer = v;
        return true;
    }

    void add_timeout_controller(double timeout, const enum swTimeout_type type)
    {
        if (unlikely(!socket))
        {
            return;
        }
        // Notice: `timeout > 0` is wrong, maybe -1
        if (timeout != 0)
        {
            SW_ASSERT(!tc);
            tc = new Socket::timeout_controller(socket, timeout, type);
        }<commit_msg>Remove MySQL Client mode limitation.<commit_after>/*
 +----------------------------------------------------------------------+
 | Swoole                                                               |
 +----------------------------------------------------------------------+
 | Copyright (c) 2012-2018 The Swoole Group                             |
 +----------------------------------------------------------------------+
 | This source file is subject to version 2.0 of the Apache 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.apache.org/licenses/LICENSE-2.0.html                      |
 | If you did not receive a copy of the Apache2.0 license and are unable|
 | to obtain it through the world-wide-web, please send a note to       |
 | <EMAIL> so we can mail you a copy immediately.            |
 +----------------------------------------------------------------------+
 | Author: Twosee  <<EMAIL>>                                       |
 | Author: <NAME>  <<EMAIL>>                        |
 +----------------------------------------------------------------------+
 */

#include "php_swoole_cxx.h"

#include "swoole_mysql_proto.h"

// see mysqlnd 'L64' macro redefined
#undef L64

extern "C" {
#include "ext/hash/php_hash.h"
#include "ext/hash/php_hash_sha.h"
#include "ext/standard/php_math.h"
#ifdef SW_USE_MYSQLND
#include "ext/mysqlnd/mysqlnd.h"
#include "ext/mysqlnd/mysqlnd_charset.h"
#endif
}

#include <unordered_map>

using namespace swoole;
using swoole::coroutine::Socket;

/* keep same with pdo and mysqli */
#define MYSQLND_UNKNOWN_SQLSTATE        "HY000"
#define MYSQLND_SERVER_GONE             "MySQL server has gone away"
#define MYSQLND_CR_UNKNOWN_ERROR        2000
#define MYSQLND_CR_CONNECTION_ERROR     2002
#define MYSQLND_CR_SERVER_GONE_ERROR    2006
#define MYSQLND_CR_OUT_OF_MEMORY        2008
#define MYSQLND_CR_SERVER_LOST          2013
#define MYSQLND_CR_COMMANDS_OUT_OF_SYNC 2014
#define MYSQLND_CR_CANT_FIND_CHARSET    2019
#define MYSQLND_CR_MALFORMED_PACKET     2027
#define MYSQLND_CR_NOT_IMPLEMENTED      2054
#define MYSQLND_CR_NO_PREPARE_STMT      2030
#define MYSQLND_CR_PARAMS_NOT_BOUND     2031
#define MYSQLND_CR_INVALID_PARAMETER_NO 2034
#define MYSQLND_CR_INVALID_BUFFER_USE   2035

namespace swoole
{
class mysql_statement;
class mysql_client
{
public:
    /* session related {{{ */
    Socket *socket = nullptr;
    Socket::timeout_controller *tc = nullptr;

    enum sw_mysql_state state = SW_MYSQL_STATE_CLOSED;
    bool quit = false;
    mysql::result_info result;

    std::unordered_map<uint32_t, mysql_statement*> statements;
    mysql_statement* statement = nullptr;
    /* }}} */

    std::string host = SW_MYSQL_DEFAULT_HOST;
    uint16_t port = SW_MYSQL_DEFAULT_PORT;
    bool ssl = false;

    std::string user = "root";
    std::string password = "<PASSWORD>";
    std::string database = "test";
    char charset = SW_MYSQL_DEFAULT_CHARSET;

    double connect_timeout = Socket::default_connect_timeout;
    bool strict_type = false;

    inline int get_error_code()
    {
        return error_code;
    }

    inline const char* get_error_msg()
    {
        return error_msg.c_str();
    }

    inline void non_sql_error(int code, const char *msg)
    {
        error_code = code;
        error_msg = cpp_string::format("SQLSTATE[" MYSQLND_UNKNOWN_SQLSTATE "] [%d] %s", code, msg);
    }

    template<typename ...Args>
    inline void non_sql_error(int code, const char *format, Args ...args)
    {
        error_code = code;
        error_msg = cpp_string::format(
            "SQLSTATE[" MYSQLND_UNKNOWN_SQLSTATE "] [%d] %s",
            code, cpp_string::format(format, args...).c_str()
        );
    }

    void io_error()
    {
        if (state == SW_MYSQL_STATE_CLOSED)
        {
            non_sql_error(MYSQLND_CR_CONNECTION_ERROR, socket->errMsg);
        }
        else
        {
            non_sql_error(MYSQLND_CR_SERVER_GONE_ERROR, MYSQLND_SERVER_GONE " due to %s", socket->errMsg);
        }
        close();
    }

    void proto_error(const char *data, const enum sw_mysql_packet_types expected_type)
    {
        mysql::server_packet packet(data);
        non_sql_error(
            MYSQLND_CR_MALFORMED_PACKET, "Unexpected mysql packet length=%u, number=%u, type=%u, expected_type=%u",
            packet.header.length, packet.header.number, (uint8_t) data[SW_MYSQL_PACKET_HEADER_SIZE], expected_type
        );
        close();
    }

    void server_error(const char *data)
    {
        mysql::err_packet err_packet(data);
        error_code = err_packet.code;
        error_msg = cpp_string::format("SQLSTATE[%s] [%d] %s", err_packet.sql_state, err_packet.code, err_packet.msg.c_str());
        state = SW_MYSQL_STATE_IDLE;
    }

    inline bool get_fetch_mode()
    {
        return fetch_mode;
    }

    inline bool set_fetch_mode(bool v)
    {
        // if (unlikely(socket && v))
        // {
        //     non_sql_error(ENOTSUP, "Can not use fetch mode after the connection is established");
        //     return false;
        // }
        fetch_mode = v;
        return true;
    }

    inline bool get_defer()
    {
        return defer;
    }

    inline bool set_defer(bool v)
    {
        // if (unlikely(fetch_mode && v))
        // {
        //      non_sql_error(ENOTSUP, "Can not use defer mode when fetch mode is on");
        //    return false;
        // }
        defer = v;
        return true;
    }

    void add_timeout_controller(double timeout, const enum swTimeout_type type)
    {
        if (unlikely(!socket))
        {
            return;
        }
        // Notice: `timeout > 0` is wrong, maybe -1
        if (timeout != 0)
        {
            SW_ASSERT(!tc);
            tc = new Socket::timeout_controller(socket, timeout, type);
        }
{'fraction_non_alphanumeric': 0.15116971501488727, 'fraction_numerical': 0.013781369629944704, 'mean_word_length': 1.9582284851534977, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3266249', 'n_tokens_mistral': 3698, 'n_tokens_neox': 3627, 'n_words': 836}