From 70cb38cf7cd1cc92775ae9536339a744d50fd371 Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Thu, 6 Jun 2019 00:59:37 -0700 Subject: Inital commit of Clustrix backend plugin. --- storage/clustrixdb/CMakeLists.txt | 24 + storage/clustrixdb/clustrix_connection.cc | 589 +++++++++++++++++ storage/clustrixdb/clustrix_connection.h | 100 +++ storage/clustrixdb/ha_clustrixdb.cc | 1011 +++++++++++++++++++++++++++++ storage/clustrixdb/ha_clustrixdb.h | 124 ++++ 5 files changed, 1848 insertions(+) create mode 100644 storage/clustrixdb/CMakeLists.txt create mode 100644 storage/clustrixdb/clustrix_connection.cc create mode 100644 storage/clustrixdb/clustrix_connection.h create mode 100644 storage/clustrixdb/ha_clustrixdb.cc create mode 100644 storage/clustrixdb/ha_clustrixdb.h diff --git a/storage/clustrixdb/CMakeLists.txt b/storage/clustrixdb/CMakeLists.txt new file mode 100644 index 00000000000..6cf4410c516 --- /dev/null +++ b/storage/clustrixdb/CMakeLists.txt @@ -0,0 +1,24 @@ +#***************************************************************************** +# Copyright (c) 2019, MariaDB Corporation. +#****************************************************************************/ + +IF(MSVC) + # Temporarily disable "conversion from size_t .." + IF(CMAKE_SIZEOF_VOID_P EQUAL 8) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4267") + ENDIF() +ENDIF() + +SET(CLUSTRIXDB_PLUGIN_STATIC "clustrixdb") +SET(CLUSTRIXDB_PLUGIN_DYNAMIC "ha_clustrixdb") +SET(CLUSTRIXDB_SOURCES ha_clustrixdb.cc clustrix_connection.cc) +MYSQL_ADD_PLUGIN(clustrixdb ${CLUSTRIXDB_SOURCES} STORAGE_ENGINE) + +IF(MSVC) + IF (CMAKE_BUILD_TYPE STREQUAL "Debug") + ADD_CUSTOM_COMMAND(TARGET clustrixdb + POST_BUILD + COMMAND if not exist ..\\..\\sql\\lib mkdir ..\\..\\sql\\lib\\plugin + COMMAND copy Debug\\ha_clustrixdb.dll ..\\..\\sql\\lib\\plugin\\ha_clustrixdb.dll) + ENDIF() +ENDIF() diff --git a/storage/clustrixdb/clustrix_connection.cc b/storage/clustrixdb/clustrix_connection.cc new file mode 100644 index 00000000000..456907d50a7 --- /dev/null +++ b/storage/clustrixdb/clustrix_connection.cc @@ -0,0 +1,589 @@ +/***************************************************************************** +Copyright (c) 2019, MariaDB Corporation. +*****************************************************************************/ + +/** @file clustrix_connection.cc */ + +#include "clustrix_connection.h" +#include +#include "errmsg.h" +#include "handler.h" +#include "table.h" + +extern int clustrix_connect_timeout; +extern int clustrix_read_timeout; +extern int clustrix_write_timeout; +extern char *clustrix_host; +extern char *clustrix_username; +extern char *clustrix_password; +extern uint clustrix_port; +extern char *clustrix_socket; + +static const char charset_name[] = "latin1"; + +enum clustrix_commands { + CLUSTRIX_WRITE_ROW = 1, + CLUSTRIX_SCAN_INIT, + CLUSTRIX_SCAN_NEXT, + CLUSTRIX_SCAN_STOP, + CLUSTRIX_KEY_READ, + CLUSTRIX_KEY_DELETE, +}; + +/**************************************************************************** +** Class clustrix_connection +****************************************************************************/ + +void clustrix_connection::disconnect(bool is_destructor) +{ + if (is_destructor) + { + /* + Connection object destruction occurs after the destruction of + the thread used by the network has begun, so usage of that + thread object now is not reliable + */ + clustrix_net.net.thd = NULL; + } + mysql_close(&clustrix_net); +} + +int clustrix_connection::connect() +{ + int error_code = 0; + my_bool my_true = 1; + DBUG_ENTER("connect"); + + /* Validate the connection parameters */ + if (!strcmp(clustrix_socket, "")) + if (!strcmp(clustrix_host, "127.0.0.1")) + if (clustrix_port == MYSQL_PORT_DEFAULT) + DBUG_RETURN(ER_CONNECT_TO_FOREIGN_DATA_SOURCE); + + //clustrix_net.methods = &connection_methods; + + if (!mysql_init(&clustrix_net)) + DBUG_RETURN(HA_ERR_OUT_OF_MEM); + + mysql_options(&clustrix_net, MYSQL_OPT_READ_TIMEOUT, + &clustrix_read_timeout); + mysql_options(&clustrix_net, MYSQL_OPT_WRITE_TIMEOUT, + &clustrix_write_timeout); + mysql_options(&clustrix_net, MYSQL_OPT_CONNECT_TIMEOUT, + &clustrix_connect_timeout); + mysql_options(&clustrix_net, MYSQL_OPT_USE_REMOTE_CONNECTION, + NULL); + mysql_options(&clustrix_net, MYSQL_SET_CHARSET_NAME, charset_name); + mysql_options(&clustrix_net, MYSQL_OPT_USE_THREAD_SPECIFIC_MEMORY, + (char *) &my_true); + mysql_options(&clustrix_net, MYSQL_INIT_COMMAND,"SET autocommit=0"); + +#ifdef CLUSTRIX_CONNECTION_SSL + if (opt_ssl_ca_length | conn->tgt_ssl_capath_length | + conn->tgt_ssl_cert_length | conn->tgt_ssl_key_length) + { + mysql_ssl_set(&clustrix_net, conn->tgt_ssl_key, conn->tgt_ssl_cert, + conn->tgt_ssl_ca, conn->tgt_ssl_capath, conn->tgt_ssl_cipher); + if (conn->tgt_ssl_vsc) + { + my_bool verify_flg = TRUE; + mysql_options(&clustrix_net, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, + &verify_flg); + } + } +#endif + + if (!mysql_real_connect(&clustrix_net, clustrix_host, + clustrix_username, clustrix_password, + NULL, clustrix_port, clustrix_socket, + CLIENT_MULTI_STATEMENTS)) + { + error_code = mysql_errno(&clustrix_net); + disconnect(); + + if (error_code != CR_CONN_HOST_ERROR && + error_code != CR_CONNECTION_ERROR) + { + if (error_code == ER_CON_COUNT_ERROR) + { + my_error(ER_CON_COUNT_ERROR, MYF(0)); + DBUG_RETURN(ER_CON_COUNT_ERROR); + } + my_error(ER_CONNECT_TO_FOREIGN_DATA_SOURCE, MYF(0), clustrix_host); + DBUG_RETURN(ER_CONNECT_TO_FOREIGN_DATA_SOURCE); + } + } + + clustrix_net.reconnect = 1; + + DBUG_RETURN(0); +} + +int clustrix_connection::send_command() +{ + my_bool com_error; + com_error = simple_command(&clustrix_net, + (enum_server_command)CLUSTRIX_SERVER_REQUEST, + command_buffer, command_length, TRUE); + + if (com_error) + { + my_printf_error(mysql_errno(&clustrix_net), + "Clustrix error: %s", MYF(0), + mysql_error(&clustrix_net)); + return ER_QUERY_ON_FOREIGN_DATA_SOURCE; + } + + return 0; +} + +int clustrix_connection::read_query_response() +{ + my_bool comerr = clustrix_net.methods->read_query_result(&clustrix_net); + if (comerr) + { + my_printf_error(mysql_errno(&clustrix_net), + "Clustrix error: %s", MYF(0), + mysql_error(&clustrix_net)); + return ER_QUERY_ON_FOREIGN_DATA_SOURCE; + } + + return 0; +} + +int clustrix_connection::begin_trans() +{ + const char *stmt = "BEGIN TRANSACTION"; + int error_code = mysql_real_query(&clustrix_net, stmt, strlen(stmt)); + if (error_code) + return mysql_errno(&clustrix_net); + return error_code; +} + +int clustrix_connection::commit_trans() +{ + const char *stmt = "COMMIT TRANSACTION"; + int error_code = mysql_real_query(&clustrix_net, stmt, strlen(stmt)); + if (error_code) + return mysql_errno(&clustrix_net); + return error_code; +} + +int clustrix_connection::rollback_trans() +{ + const char *stmt = "ROLLBACK TRANSACTION"; + int error_code = mysql_real_query(&clustrix_net, stmt, strlen(stmt)); + if (error_code) + return mysql_errno(&clustrix_net); + return error_code; +} + +int clustrix_connection::create_table(char *stmt) +{ + int error_code = mysql_real_query(&clustrix_net, stmt, strlen(stmt)); + if (error_code) + return mysql_errno(&clustrix_net); + + return error_code; +} + +int clustrix_connection::delete_table(char *stmt) +{ + int error_code = mysql_real_query(&clustrix_net, stmt, strlen(stmt)); + if (error_code) + return mysql_errno(&clustrix_net); + return error_code; +} + +int clustrix_connection::write_row(ulonglong clustrix_table_oid, + uchar *packed_row, size_t packed_size) +{ + int error_code; + command_length = 0; + + if ((error_code = add_command_operand_uchar(CLUSTRIX_WRITE_ROW))) + return error_code; + + if ((error_code = add_command_operand_ulonglong(clustrix_table_oid))) + return error_code; + + if ((error_code = add_command_operand_str(packed_row, packed_size))) + return error_code; + + if ((error_code = send_command())) + return error_code; + + if ((error_code = read_query_response())) + return error_code; + + last_insert_id = clustrix_net.insert_id; + return error_code; +} + +int clustrix_connection::key_delete(ulonglong clustrix_table_oid, + uchar *packed_key, size_t packed_key_length) +{ + int error_code; + command_length = 0; + + if ((error_code = add_command_operand_uchar(CLUSTRIX_KEY_DELETE))) + return error_code; + + if ((error_code = add_command_operand_ulonglong(clustrix_table_oid))) + return error_code; + + if ((error_code = add_command_operand_str(packed_key, packed_key_length))) + return error_code; + + if ((error_code = send_command())) + return error_code; + + if ((error_code = read_query_response())) + return mysql_errno(&clustrix_net); + + return error_code; +} + +int clustrix_connection::key_read(ulonglong clustrix_table_oid, uint index, + MY_BITMAP *read_set, uchar *packed_key, + ulong packed_key_length, uchar **rowdata, + ulong *rowdata_length) +{ + int error_code; + command_length = 0; + + if ((error_code = add_command_operand_uchar(CLUSTRIX_KEY_READ))) + return error_code; + + if ((error_code = add_command_operand_ulonglong(clustrix_table_oid))) + return error_code; + + if ((error_code = add_command_operand_uint(index))) + return error_code; + + if ((error_code = add_command_operand_bitmap(read_set))) + return error_code; + + if ((error_code = add_command_operand_str(packed_key, packed_key_length))) + return error_code; + + if ((error_code = send_command())) + return error_code; + + ulong packet_length = cli_safe_read(&clustrix_net); + if (packet_length == packet_error) + return mysql_errno(&clustrix_net); + + *rowdata = clustrix_net.net.read_pos; + *rowdata_length = safe_net_field_length_ll(rowdata, packet_length); + + return 0; +} + +int clustrix_connection::scan_init(ulonglong clustrix_table_oid, uint index, + enum sort_order sort, MY_BITMAP *read_set, + ulonglong *scan_refid) +{ + int error_code; + command_length = 0; + + if ((error_code = add_command_operand_uchar(CLUSTRIX_SCAN_INIT))) + return error_code; + + if ((error_code = add_command_operand_ulonglong(clustrix_table_oid))) + return error_code; + + if ((error_code = add_command_operand_uint(index))) + return error_code; + + if ((error_code = add_command_operand_uchar(sort))) + return error_code; + + if ((error_code = add_command_operand_bitmap(read_set))) + return error_code; + + if ((error_code = send_command())) + return error_code; + + ulong packet_length = cli_safe_read(&clustrix_net); + if (packet_length == packet_error) + return mysql_errno(&clustrix_net); + + unsigned char *pos = clustrix_net.net.read_pos; + *scan_refid = safe_net_field_length_ll(&pos, packet_length); + return error_code; +} + +int clustrix_connection::scan_next(ulonglong scan_refid, uchar **rowdata, + ulong *rowdata_length) +{ + int error_code; + command_length = 0; + + if ((error_code = add_command_operand_uchar(CLUSTRIX_SCAN_NEXT))) + return error_code; + + if ((error_code = add_command_operand_lcb(scan_refid))) + return error_code; + + if ((error_code = send_command())) + return error_code; + + ulong packet_length = cli_safe_read(&clustrix_net); + if (packet_length == packet_error) + return mysql_errno(&clustrix_net); + + *rowdata = clustrix_net.net.read_pos; + *rowdata_length = safe_net_field_length_ll(rowdata, packet_length); + + return 0; +} + +int clustrix_connection::scan_end(ulonglong scan_refid) +{ + int error_code; + command_length = 0; + + if ((error_code = add_command_operand_uchar(CLUSTRIX_SCAN_STOP))) + return error_code; + + if ((error_code = add_command_operand_lcb(scan_refid))) + return error_code; + + if ((error_code = send_command())) + return error_code; + + ulong packet_length = cli_safe_read(&clustrix_net); + if (packet_length == packet_error) + return mysql_errno(&clustrix_net); + + return 0; +} + +int clustrix_connection::populate_table_list(LEX_CSTRING *db, + handlerton::discovered_list *result) +{ + int error_code = 0; + String stmt; + stmt.append("SHOW FULL TABLES FROM "); + stmt.append(db); + stmt.append(" WHERE table_type = 'BASE TABLE'"); + + if (mysql_real_query(&clustrix_net, stmt.c_ptr(), stmt.length())) { + int error_code = mysql_errno(&clustrix_net); + if (error_code == ER_BAD_DB_ERROR) + return 0; + else + return error_code; + } + + MYSQL_RES *results = mysql_store_result(&clustrix_net); + if (mysql_num_fields(results) != 2) { + error_code = HA_ERR_CORRUPT_EVENT; + goto error; + } + + MYSQL_ROW row; + while((row = mysql_fetch_row(results))) + result->add_table(row[0], strlen(row[0])); + +error: + mysql_free_result(results); + return error_code; +} + +int clustrix_connection::discover_table_details(LEX_CSTRING *db, + LEX_CSTRING *name, THD *thd, + TABLE_SHARE *share) +{ + DBUG_ENTER("clustrix_connection::discover_table_details"); + int error_code = 0; + MYSQL_RES *results = NULL; + MYSQL_ROW row; + String get_oid, show; + + /* get oid */ + get_oid.append("select r.table " + "from system.databases d " + " inner join ""system.relations r on d.db = r.db " + "where d.name = '"); + get_oid.append(db); + get_oid.append("' and r.name = '"); + get_oid.append(name); + get_oid.append("'"); + if (mysql_real_query(&clustrix_net, get_oid.c_ptr(), get_oid.length())) { + if ((error_code = mysql_errno(&clustrix_net))) + return error_code; + } + + results = mysql_store_result(&clustrix_net); + DBUG_PRINT("oid results", + ("rows: %llu, fields: %u", mysql_num_rows(results), + mysql_num_fields(results))); + + if (mysql_num_rows(results) != 1) { + error_code = HA_ERR_NO_SUCH_TABLE; + goto error; + } + + while((row = mysql_fetch_row(results))) { + DBUG_PRINT("row", ("%s", row[0])); + uchar *to = (uchar*)alloc_root(&share->mem_root, strlen(row[0]) + 1); + if (!to) { + error_code = HA_ERR_OUT_OF_MEM; + goto error; + } + + strcpy((char *)to, (char *)row[0]); + share->tabledef_version.str = to; + share->tabledef_version.length = strlen(row[0]); + } + + mysql_free_result(results); + + /* get show create statement */ + show.append("show create table "); + show.append(db); + show.append("."); + show.append(name); + if (mysql_real_query(&clustrix_net, show.c_ptr(), show.length())) { + if ((error_code = mysql_errno(&clustrix_net))) + return error_code; + } + + results = mysql_store_result(&clustrix_net); + DBUG_PRINT("show table results", + ("rows: %llu, fields: %u", mysql_num_rows(results), + mysql_num_fields(results))); + + if (mysql_num_rows(results) != 1) { + error_code = HA_ERR_NO_SUCH_TABLE; + goto error; + } + + if (mysql_num_fields(results) != 2) { + error_code = HA_ERR_CORRUPT_EVENT; + goto error; + } + + while((row = mysql_fetch_row(results))) { + DBUG_PRINT("row", ("%s - %s", row[0], row[1])); + error_code = share->init_from_sql_statement_string(thd, false, row[1], + strlen(row[1])); + } + +error: + if (results) + mysql_free_result(results); + DBUG_RETURN(error_code); +} + +int clustrix_connection::expand_command_buffer(size_t add_length) +{ + size_t expanded_length; + + if (command_buffer_length >= command_length + add_length) + return 0; + + expanded_length = command_buffer_length + + ((add_length >> COMMAND_BUFFER_SIZE_INCREMENT_BITS) + << COMMAND_BUFFER_SIZE_INCREMENT_BITS) + + COMMAND_BUFFER_SIZE_INCREMENT; + + if (!command_buffer_length) + command_buffer = (uchar *) my_malloc(expanded_length, MYF(MY_WME)); + else + command_buffer = (uchar *) my_realloc(command_buffer, expanded_length, + MYF(MY_WME)); + if (!command_buffer) + return HA_ERR_OUT_OF_MEM; + + command_buffer_length = expanded_length; + + return 0; +} + +int clustrix_connection::add_command_operand_uchar(uchar value) +{ + int error_code = expand_command_buffer(sizeof(value)); + if (error_code) + return error_code; + + memcpy(command_buffer + command_length, &value, sizeof(value)); + command_length += sizeof(value); + + return 0; +} + +int clustrix_connection::add_command_operand_uint(uint value) +{ + uint be_value = htobe32(value); + int error_code = expand_command_buffer(sizeof(be_value)); + if (error_code) + return error_code; + + memcpy(command_buffer + command_length, &be_value, sizeof(be_value)); + command_length += sizeof(be_value); + return 0; +} + +int clustrix_connection::add_command_operand_ulonglong(ulonglong value) +{ + ulonglong be_value = htobe64(value); + int error_code = expand_command_buffer(sizeof(be_value)); + if (error_code) + return error_code; + + memcpy(command_buffer + command_length, &be_value, sizeof(be_value)); + command_length += sizeof(be_value); + return 0; +} + +int clustrix_connection::add_command_operand_lcb(ulonglong value) +{ + int len = net_length_size(value); + int error_code = expand_command_buffer(len); + if (error_code) + return error_code; + + net_store_length(command_buffer + command_length, value); + command_length += len; + return 0; +} + +int clustrix_connection::add_command_operand_str(const uchar *str, + size_t str_length) +{ + int error_code = add_command_operand_lcb(str_length); + if (error_code) + return error_code; + + error_code = expand_command_buffer(str_length); + if (error_code) + return error_code; + + memcpy(command_buffer + command_length, str, str_length); + command_length += str_length; + return 0; +} + +int clustrix_connection::add_command_operand_lex_string(LEX_CSTRING str) +{ + return add_command_operand_str((const uchar *)str.str, str.length); +} + +int clustrix_connection::add_command_operand_bitmap(MY_BITMAP *bitmap) +{ + int error_code = add_command_operand_lcb(bitmap->n_bits); + if (error_code) + return error_code; + + int no_bytes = no_bytes_in_map(bitmap); + error_code = expand_command_buffer(no_bytes); + if (error_code) + return error_code; + + memcpy(command_buffer + command_length, bitmap->bitmap, no_bytes); + command_length += no_bytes; + return 0; +} diff --git a/storage/clustrixdb/clustrix_connection.h b/storage/clustrixdb/clustrix_connection.h new file mode 100644 index 00000000000..d460f33d9cc --- /dev/null +++ b/storage/clustrixdb/clustrix_connection.h @@ -0,0 +1,100 @@ +/***************************************************************************** +Copyright (c) 2019, MariaDB Corporation. +*****************************************************************************/ + +#ifndef _clustrix_connection_h +#define _clustrix_connection_h + +#ifdef USE_PRAGMA_INTERFACE +#pragma interface /* gcc class implementation */ +#endif + +#define MYSQL_SERVER 1 +#include "my_global.h" +#include "m_string.h" +#include "mysql.h" +#include "sql_common.h" +#include "my_base.h" +#include "mysqld_error.h" +#include "my_bitmap.h" +#include "handler.h" + +#define CLUSTRIX_SERVER_REQUEST 30 + +class clustrix_connection +{ +private: +# define COMMAND_BUFFER_SIZE_INCREMENT 1024 +# define COMMAND_BUFFER_SIZE_INCREMENT_BITS 10 + + MYSQL clustrix_net; + uchar *command_buffer; + size_t command_buffer_length; + size_t command_length; + + uchar *reply_buffer; + size_t reply_length; + +public: + ulonglong last_insert_id; + clustrix_connection() + : command_buffer(NULL), command_buffer_length(0), command_length(0) + { + memset(&clustrix_net, 0, sizeof(MYSQL)); + } + + ~clustrix_connection() + { + if (is_connected()) + disconnect(TRUE); + + if (command_buffer) + my_free(command_buffer); + } + + inline bool is_connected() + { + return clustrix_net.net.vio; + } + + int connect(); + + void disconnect(bool is_destructor = FALSE); + int begin_trans(); + int commit_trans(); + int rollback_trans(); + + int create_table(char *stmt); + int delete_table(char *stmt); + + int write_row(ulonglong clustrix_table_oid, + uchar *packed_row, size_t packed_size); + int key_delete(ulonglong clustrix_table_oid, + uchar *packed_key, size_t packed_key_length); + int key_read(ulonglong clustrix_table_oid, uint index, MY_BITMAP *read_set, + uchar *packed_key, ulong packed_key_length, + uchar **rowdata, ulong *rowdata_length); + + enum sort_order {SORT_NONE = 0, SORT_ASC = 1, SORT_DESC = 2}; + int scan_init(ulonglong clustrix_table_oid, uint index, + enum sort_order sort, MY_BITMAP *read_set, + ulonglong *scan_refid); + int scan_next(ulonglong scan_refid, uchar **rowdata, ulong *rowdata_length); + int scan_end(ulonglong scan_refid); + + int populate_table_list(LEX_CSTRING *db, handlerton::discovered_list *result); + int discover_table_details(LEX_CSTRING *db, LEX_CSTRING *name, THD *thd, + TABLE_SHARE *share); +private: + int expand_command_buffer(size_t add_length); + int add_command_operand_uchar(uchar value); + int add_command_operand_uint(uint value); + int add_command_operand_ulonglong(ulonglong value); + int add_command_operand_lcb(ulonglong value); + int add_command_operand_str(const uchar *str, size_t length); + int add_command_operand_lex_string(LEX_CSTRING str); + int add_command_operand_bitmap(MY_BITMAP *bitmap); + int send_command(); + int read_query_response(); +}; +#endif // _clustrix_connection_h diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc new file mode 100644 index 00000000000..83e7c2a2581 --- /dev/null +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -0,0 +1,1011 @@ +/***************************************************************************** +Copyright (c) 2019, MariaDB Corporation. +*****************************************************************************/ + +/** @file ha_clustrixdb.cc */ + +#include "ha_clustrixdb.h" +#include "key.h" + +handlerton *clustrixdb_hton = NULL; + +int clustrix_connect_timeout; +static MYSQL_SYSVAR_INT +( + connect_timeout, + clustrix_connect_timeout, + PLUGIN_VAR_OPCMDARG, + "Timeout for connecting to Clustrix", + NULL, NULL, -1, -1, 2147483647, 0 +); + +int clustrix_read_timeout; +static MYSQL_SYSVAR_INT +( + read_timeout, + clustrix_read_timeout, + PLUGIN_VAR_OPCMDARG, + "Timeout for receiving data from Clustrix", + NULL, NULL, -1, -1, 2147483647, 0 +); + +int clustrix_write_timeout; +static MYSQL_SYSVAR_INT +( + write_timeout, + clustrix_write_timeout, + PLUGIN_VAR_OPCMDARG, + "Timeout for sending data to Clustrix", + NULL, NULL, -1, -1, 2147483647, 0 +); + +char *clustrix_host; +static MYSQL_SYSVAR_STR +( + host, + clustrix_host, + PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_MEMALLOC, + "Clustrix host", + NULL, NULL, "127.0.0.1" +); + +char *clustrix_username; +static MYSQL_SYSVAR_STR +( + username, + clustrix_username, + PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_MEMALLOC, + "Clustrix user name", + NULL, NULL, "root" +); + +char *clustrix_password; +static MYSQL_SYSVAR_STR +( + password, + clustrix_password, + PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_MEMALLOC, + "Clustrix password", + NULL, NULL, "" +); + +uint clustrix_port; +static MYSQL_SYSVAR_UINT +( + port, + clustrix_port, + PLUGIN_VAR_RQCMDARG, + "Clustrix port", + NULL, NULL, MYSQL_PORT_DEFAULT, MYSQL_PORT_DEFAULT, 65535, 0 +); + +char *clustrix_socket; +static MYSQL_SYSVAR_STR +( + socket, + clustrix_socket, + PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_MEMALLOC, + "Clustrix socket", + NULL, NULL, "" +); + +/**************************************************************************** +** Class ha_clustrixdb_trx +****************************************************************************/ + +st_clustrixdb_trx::st_clustrixdb_trx(THD *trx_thd) +{ + thd = trx_thd; + clustrix_net = NULL; + //query_id = 0; + //mem_root = NULL; + has_transaction = FALSE; +} + +st_clustrixdb_trx::~st_clustrixdb_trx() +{ + if (clustrix_net) + delete clustrix_net; +} + + +int st_clustrixdb_trx::net_init() +{ + if (!this->clustrix_net) + { + this->clustrix_net = new clustrix_connection(); + int error_code = this->clustrix_net->connect(); + if (error_code) + return error_code; + } + + return 0; +} + +int st_clustrixdb_trx::begin_trans() +{ + // XXX: What were these for? + //if (thd->transaction.stmt.trans_did_ddl() || + // thd->transaction.stmt.modified_non_trans_table) + + if (!has_transaction) { + int error_code = this->clustrix_net->begin_trans(); + if (error_code) + return error_code; + + /* Register for commit/rollback on the transaction */ + if (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) + trans_register_ha(thd, FALSE, clustrixdb_hton); + else + trans_register_ha(thd, TRUE, clustrixdb_hton); + + has_transaction = TRUE; + } + + return 0; +} + +/**************************************************************************** +** Class ha_clustrixdb +****************************************************************************/ + +ha_clustrixdb::ha_clustrixdb(handlerton *hton, TABLE_SHARE *table_arg) + : handler(hton, table_arg) +{ + DBUG_ENTER("ha_clustrixdb::ha_clustrixdb"); + rli = NULL; + rgi = NULL; + scan_refid = 0; + clustrix_table_oid = 0; + DBUG_VOID_RETURN; +} + +ha_clustrixdb::~ha_clustrixdb() +{ + if (rli) + ha_clustrixdb::remove_current_table_from_rpl_table_list(); +} + +int ha_clustrixdb::create(const char *name, TABLE *form, HA_CREATE_INFO *info) +{ + int error_code; + THD *thd = ha_thd(); + st_clustrixdb_trx *trx = get_trx(thd, &error_code); + if (!trx) + return error_code; + + enum tmp_table_type saved_tmp_table_type = form->s->tmp_table; + Table_specification_st *create_info = &thd->lex->create_info; + const bool is_tmp_table = info->options & HA_LEX_CREATE_TMP_TABLE; + char create_table_stmt_buffer[2048]; + String create_table_stmt(create_table_stmt_buffer, + sizeof(create_table_stmt_buffer), + system_charset_info); + create_table_stmt.length(0); + + /* Create a copy of the CREATE TABLE statement */ + if (!is_tmp_table) + form->s->tmp_table = NO_TMP_TABLE; + const char *old_dbstr = thd->db.str; + thd->db.str = NULL; + ulong old = create_info->used_fields; + create_info->used_fields &= ~HA_CREATE_USED_ENGINE; + + TABLE_LIST table_list; + memset(&table_list, 0, sizeof(table_list)); + table_list.table = form; + error_code = show_create_table(thd, &table_list, &create_table_stmt, + create_info, WITH_DB_NAME); + + if (!is_tmp_table) + form->s->tmp_table = saved_tmp_table_type; + create_info->used_fields = old; + thd->db.str = old_dbstr; + if (error_code) + return error_code; + + error_code = trx->clustrix_net->create_table(create_table_stmt_buffer); + return error_code; +} + +int ha_clustrixdb::delete_table(const char *name) +{ + int error_code; + THD *thd = ha_thd(); + st_clustrixdb_trx *trx = get_trx(thd, &error_code); + if (!trx) + return error_code; + + /* XXX: I know this is unsafe. */ + char db_name[1000]; + const char *ptr = name + 2; + int i = 0; + while (*ptr != '/') + db_name[i++] = *ptr++; + db_name[i] = '\0'; + char tbl_name[1000]; + ptr++; + strcpy(tbl_name, ptr); + + char delete_cmd[2000]; + /* XXX: I know this is unsafe. */ + sprintf(delete_cmd, "drop table `%s`.`%s`", db_name, tbl_name); + return trx->clustrix_net->delete_table(delete_cmd); +} + +int ha_clustrixdb::open(const char *name, int mode, uint test_if_locked) +{ + DBUG_ENTER("ha_clustrixdb::open"); + DBUG_PRINT("oid", + ("%s", table->s->tabledef_version.str)); + + if (!table->s->tabledef_version.str) + return HA_ERR_TABLE_DEF_CHANGED; + if (!clustrix_table_oid) + clustrix_table_oid = atoll((const char *)table->s->tabledef_version.str); + + has_hidden_key = table->s->primary_key == MAX_KEY; + if (has_hidden_key) { + ref_length = 8; + } else { + KEY* key_info = table->key_info + table->s->primary_key; + ref_length = key_info->key_length; + } + + DBUG_PRINT("open finished", + ("oid: %llu, ref_length: %u", clustrix_table_oid, ref_length)); + DBUG_RETURN(0); +} + +int ha_clustrixdb::close(void) +{ + return 0; +} + +int ha_clustrixdb::reset() +{ + return 0; +} + +int ha_clustrixdb::write_row(uchar *buf) +{ + int error_code = 0; + THD *thd = ha_thd(); + st_clustrixdb_trx *trx = get_trx(thd, &error_code); + if (!trx) + return error_code; + + assert(trx->has_transaction); + + /* Convert the row format to binlog (packed) format */ + /* XXX: We cannot use a fixed length buffer for this. */ + uchar packed_new_row[CLUSTRIXDB_ROW_LIMIT]; + size_t packed_size = pack_row(table, table->write_set, packed_new_row, buf); + + /* XXX: Clustrix may needs to return HA_ERR_AUTOINC_ERANGE if we hit that + error. */ + if ((error_code = trx->clustrix_net->write_row(clustrix_table_oid, + packed_new_row, packed_size))) + return error_code; + + Field *auto_inc_field = table->next_number_field; + if (auto_inc_field) + insert_id_for_cur_row = trx->clustrix_net->last_insert_id; + + return error_code; +} + +int ha_clustrixdb::update_row(const uchar *old_data, const uchar *new_data) +{ + int error_code; + THD *thd = ha_thd(); + st_clustrixdb_trx *trx = get_trx(thd, &error_code); + if (!trx) + return error_code; + + assert(trx->has_transaction); + + /* XXX: We cannot use a fixed length buffer for this. */ + uchar packed_new_row[CLUSTRIXDB_ROW_LIMIT]; + /*size_t packed_new_size =*/ pack_row(table, table->write_set, packed_new_row, new_data); + /* XXX: We cannot use a fixed length buffer for this. */ + uchar packed_old_row[CLUSTRIXDB_ROW_LIMIT]; + /*size_t packed_old_size =*/ pack_row(table, table->write_set, packed_old_row, old_data); + + /* Send the packed rows to Clustrix */ + + return error_code; +} + +int ha_clustrixdb::delete_row(const uchar *buf) +{ + int error_code; + THD *thd = ha_thd(); + st_clustrixdb_trx *trx = get_trx(thd, &error_code); + if (!trx) + return error_code; + + assert(trx->has_transaction); + + /* XXX: We cannot use a fixed length buffer for this. */ + uchar packed_key[CLUSTRIXDB_ROW_LIMIT]; + size_t packed_key_len; + build_key_packed_row(table->s->primary_key, packed_key, &packed_key_len); + + if ((error_code = trx->clustrix_net->key_delete(clustrix_table_oid, + packed_key, packed_key_len))) + return error_code; + + return error_code; +} + +ha_clustrixdb::Table_flags ha_clustrixdb::table_flags(void) const +{ + Table_flags flags = HA_PARTIAL_COLUMN_READ | + HA_REC_NOT_IN_SEQ | + HA_FAST_KEY_READ | + HA_NULL_IN_KEY | + HA_CAN_INDEX_BLOBS | + HA_AUTO_PART_KEY | + HA_CAN_SQL_HANDLER | + HA_BINLOG_ROW_CAPABLE | + HA_BINLOG_STMT_CAPABLE | + HA_CAN_TABLE_CONDITION_PUSHDOWN; + + return flags; +} + +ulong ha_clustrixdb::index_flags(uint idx, uint part, bool all_parts) const +{ + ulong flags = HA_READ_NEXT | + HA_READ_PREV | + HA_READ_ORDER; + + return flags; +} + +ha_rows ha_clustrixdb::records() +{ + return 10000; +} + +ha_rows ha_clustrixdb::records_in_range(uint inx, key_range *min_key, + key_range *max_key) +{ + return 2; +} + +int ha_clustrixdb::info(uint flag) +{ + //THD *thd = ha_thd(); + if (flag & HA_STATUS_TIME) + { + /* Retrieve the time of the most recent update to the table */ + // stats.update_time = + } + + if (flag & HA_STATUS_AUTO) + { + /* Retrieve the latest auto_increment value */ + stats.auto_increment_value = next_insert_id; + } + + if (flag & HA_STATUS_VARIABLE) + { + /* Retrieve variable info, such as row counts and file lengths */ + stats.records = records(); + stats.deleted = 0; + // stats.data_file_length = + // stats.index_file_length = + // stats.delete_length = + stats.check_time = 0; + // stats.mrr_length_per_rec = + + if (stats.records == 0) + stats.mean_rec_length = 0; + else + stats.mean_rec_length = (ulong) + (stats.data_file_length / stats.records); + } + + if (flag & HA_STATUS_CONST) + { + /* + Retrieve constant info, such as file names, max file lengths, + create time, block size + */ + // stats.max_data_file_length = + // stats.create_time = + // stats.block_size = + } + + return 0; +} + +int ha_clustrixdb::index_init(uint idx, bool sorted) +{ + int error_code = 0; + THD *thd = ha_thd(); + st_clustrixdb_trx *trx = get_trx(thd, &error_code); + if (!trx) + return error_code; + + active_index = idx; + add_current_table_to_rpl_table_list(); + scan_refid = 0; + + return 0; + +} + +int ha_clustrixdb::index_read(uchar * buf, const uchar * key, uint key_len, + enum ha_rkey_function find_flag) +{ + DBUG_ENTER("ha_clustrixdb::index_read"); + int error_code = 0; + THD *thd = ha_thd(); + st_clustrixdb_trx *trx = get_trx(thd, &error_code); + if (!trx) + DBUG_RETURN(error_code); + + is_scan = false; + key_restore(table->record[0], key, &table->key_info[active_index], key_len); + /* XXX: We cannot use a fixed length buffer for this. */ + uchar packed_key[CLUSTRIXDB_ROW_LIMIT]; + size_t packed_key_len; + build_key_packed_row(active_index, packed_key, &packed_key_len); + + uchar *rowdata; + ulong rowdata_length; + if ((error_code = trx->clustrix_net->key_read(clustrix_table_oid, + active_index, table->read_set, + packed_key, packed_key_len, + &rowdata, &rowdata_length))) + DBUG_RETURN(error_code); + + uchar const *current_row_end; + ulong master_reclength; + if ((error_code = unpack_row(rgi, table, table->s->fields, rowdata, + table->read_set, ¤t_row_end, + &master_reclength, rowdata + rowdata_length))) + DBUG_RETURN(error_code); + + DBUG_RETURN(0); + +} + +int ha_clustrixdb::index_first(uchar *buf) +{ + int error_code = 0; + THD *thd = ha_thd(); + st_clustrixdb_trx *trx = get_trx(thd, &error_code); + if (!trx) + return error_code; + + is_scan = true; + + if (my_bitmap_init(&scan_fields, NULL, table->read_set->n_bits, false)) + return ER_OUTOFMEMORY; +#if 0 + if (table->s->keys) + table->mark_columns_used_by_index(table->s->primary_key, &scan_fields); + else + bitmap_clear_all(&scan_fields); + + bitmap_union(&scan_fields, table->read_set); +#else + /* Why is read_set not setup correctly? */ + bitmap_set_all(&scan_fields); +#endif + + if ((error_code = trx->clustrix_net->scan_init(clustrix_table_oid, + active_index, + clustrix_connection::SORT_NONE, + &scan_fields, + &scan_refid))) + return error_code; + + + return rnd_next(buf); +} + +int ha_clustrixdb::index_last(uchar *buf) +{ + int error_code = 0; + THD *thd = ha_thd(); + st_clustrixdb_trx *trx = get_trx(thd, &error_code); + if (!trx) + return error_code; + + is_scan = true; + + if (my_bitmap_init(&scan_fields, NULL, table->read_set->n_bits, false)) + return ER_OUTOFMEMORY; +#if 0 + if (table->s->keys) + table->mark_columns_used_by_index(table->s->primary_key, &scan_fields); + else + bitmap_clear_all(&scan_fields); + + bitmap_union(&scan_fields, table->read_set); +#else + /* Why is read_set not setup correctly? */ + bitmap_set_all(&scan_fields); +#endif + + if ((error_code = trx->clustrix_net->scan_init(clustrix_table_oid, + active_index, + clustrix_connection::SORT_NONE, + &scan_fields, + &scan_refid))) + return error_code; + + + return rnd_next(buf); + +} + +int ha_clustrixdb::index_next(uchar *buf) +{ + DBUG_ENTER("index_next"); + DBUG_RETURN(rnd_next(buf)); +} + +#if 0 +int ha_clustrixdb::index_next_same(uchar *buf, const uchar *key, uint keylen) +{ + DBUG_ENTER("index_next_same"); + DBUG_RETURN(rnd_next(buf)); +} +#endif + +int ha_clustrixdb::index_prev(uchar *buf) +{ + DBUG_ENTER("index_prev"); + DBUG_RETURN(rnd_next(buf)); +} + +int ha_clustrixdb::index_end() +{ + DBUG_ENTER("index_prev"); + if (scan_refid) + DBUG_RETURN(rnd_end()); + else + DBUG_RETURN(0); + +} + +int ha_clustrixdb::rnd_init(bool scan) +{ + int error_code = 0; + THD *thd = ha_thd(); + st_clustrixdb_trx *trx = get_trx(thd, &error_code); + if (!trx) + return error_code; + + add_current_table_to_rpl_table_list(); + is_scan = scan; + scan_refid = 0; + + if (my_bitmap_init(&scan_fields, NULL, table->read_set->n_bits, false)) + return ER_OUTOFMEMORY; + +#if 0 + if (table->s->keys) + table->mark_columns_used_by_index(table->s->primary_key, &scan_fields); + else + bitmap_clear_all(&scan_fields); + + bitmap_union(&scan_fields, table->read_set); +#else + /* Why is read_set not setup correctly? */ + bitmap_set_all(&scan_fields); +#endif + + if ((error_code = trx->clustrix_net->scan_init(clustrix_table_oid, + 0, + clustrix_connection::SORT_NONE, + &scan_fields, + &scan_refid))) + return error_code; + + return 0; +} + +int ha_clustrixdb::rnd_next(uchar *buf) +{ + int error_code = 0; + THD *thd = ha_thd(); + st_clustrixdb_trx *trx = get_trx(thd, &error_code); + if (!trx) + return error_code; + + assert(is_scan); + assert(scan_refid); + + uchar *rowdata; + ulong rowdata_length; + if ((error_code = trx->clustrix_net->scan_next(scan_refid, &rowdata, + &rowdata_length))) + return error_code; + + if (has_hidden_key) { + last_hidden_key = *(ulonglong *)rowdata; + rowdata += 8; + rowdata_length -= 8; + } + + uchar const *current_row_end; + ulong master_reclength; + + error_code = unpack_row(rgi, table, table->s->fields, rowdata, + &scan_fields, ¤t_row_end, + &master_reclength, rowdata + rowdata_length); + + if (error_code) + return error_code; + + return 0; +} + +int ha_clustrixdb::rnd_pos(uchar * buf, uchar *pos) +{ + DBUG_ENTER("clx_rnd_pos"); + DBUG_DUMP("pos", pos, ref_length); + + int error_code = 0; + THD *thd = ha_thd(); + st_clustrixdb_trx *trx = get_trx(thd, &error_code); + if (!trx) + DBUG_RETURN(error_code); + + /* WDD: We need a way to convert key buffers directy to rbr buffers. */ + + if (has_hidden_key) { + memcpy(&last_hidden_key, pos, sizeof(ulonglong)); + } else { + uint keyno = table->s->primary_key; + uint len = calculate_key_len(table, keyno, pos, table->const_key_parts[keyno]); + key_restore(table->record[0], pos, &table->key_info[keyno], len); + } + + /* XXX: We cannot use a fixed length buffer for this. */ + uchar packed_key[CLUSTRIXDB_ROW_LIMIT]; + size_t packed_key_len; + build_key_packed_row(table->s->primary_key, packed_key, &packed_key_len); + + uchar *rowdata; + ulong rowdata_length; + if ((error_code = trx->clustrix_net->key_read(clustrix_table_oid, 0, + table->read_set, + packed_key, packed_key_len, + &rowdata, &rowdata_length))) + DBUG_RETURN(error_code); + + uchar const *current_row_end; + ulong master_reclength; + if ((error_code = unpack_row(rgi, table, table->s->fields, rowdata, + table->read_set, ¤t_row_end, + &master_reclength, rowdata + rowdata_length))) + DBUG_RETURN(error_code); + + DBUG_RETURN(0); +} + +int ha_clustrixdb::rnd_end() +{ + int error_code = 0; + THD *thd = ha_thd(); + st_clustrixdb_trx *trx = get_trx(thd, &error_code); + if (!trx) + return error_code; + + my_bitmap_free(&scan_fields); + if (scan_refid && (error_code = trx->clustrix_net->scan_end(scan_refid))) + return error_code; + scan_refid = 0; + + return 0; +} + +void ha_clustrixdb::position(const uchar *record) +{ + DBUG_ENTER("clx_position"); + if (has_hidden_key) { + memcpy(ref, &last_hidden_key, sizeof(ulonglong)); + } else { + KEY* key_info = table->key_info + table->s->primary_key; + key_copy(ref, record, key_info, key_info->key_length); + } + DBUG_DUMP("key", ref, ref_length); + DBUG_VOID_RETURN; +} + +uint ha_clustrixdb::lock_count(void) const +{ + /* Hopefully, we don't need to use thread locks */ + return 0; +} + +THR_LOCK_DATA **ha_clustrixdb::store_lock(THD *thd, + THR_LOCK_DATA **to, + enum thr_lock_type lock_type) +{ + /* Hopefully, we don't need to use thread locks */ + return to; +} + +int ha_clustrixdb::external_lock(THD *thd, int lock_type) +{ + int error_code; + st_clustrixdb_trx *trx = get_trx(thd, &error_code); + if (lock_type != F_UNLCK) + trx->begin_trans(); + + //if (lock_type != F_UNLCK) + //DBUG_ASSERT(trx && trx == get_trx(thd, &error_code)); + + return 0; +} + +/**************************************************************************** + Engine Condition Pushdown +****************************************************************************/ + +const COND *ha_clustrixdb::cond_push(const COND *cond) +{ + return cond; +} + +void ha_clustrixdb::cond_pop() +{ +} + +int ha_clustrixdb::info_push(uint info_type, void *info) +{ + return 0; +} + +void ha_clustrixdb::add_current_table_to_rpl_table_list() +{ + if (rli) + return; + + THD *thd = ha_thd(); + rli = new Relay_log_info(FALSE); + rli->sql_driver_thd = thd; + + rgi = new rpl_group_info(rli); + rgi->thd = thd; + rgi->tables_to_lock_count = 0; + rgi->tables_to_lock = NULL; + if (rgi->tables_to_lock_count) + return; + + rgi->tables_to_lock = (RPL_TABLE_LIST *)my_malloc(sizeof(RPL_TABLE_LIST), + MYF(MY_WME)); + rgi->tables_to_lock->init_one_table(&table->s->db, &table->s->table_name, 0, + TL_READ); + rgi->tables_to_lock->table = table; + rgi->tables_to_lock->table_id = table->tablenr; + rgi->tables_to_lock->m_conv_table = NULL; + rgi->tables_to_lock->master_had_triggers = FALSE; + rgi->tables_to_lock->m_tabledef_valid = TRUE; + /* XXX: We cannot use a fixed length buffer for this. */ + uchar col_type[CLUSTRIXDB_ROW_LIMIT]; + for (uint i = 0 ; i < table->s->fields ; ++i) + col_type[i] = table->field[i]->binlog_type(); + + table_def *tabledef = &rgi->tables_to_lock->m_tabledef; + new (tabledef) table_def(col_type, table->s->fields, NULL, 0, NULL, 0); + rgi->tables_to_lock_count++; +} + +void ha_clustrixdb::remove_current_table_from_rpl_table_list() +{ + if (!rgi->tables_to_lock) + return; + + rgi->tables_to_lock->m_tabledef.table_def::~table_def(); + rgi->tables_to_lock->m_tabledef_valid = FALSE; + my_free(rgi->tables_to_lock); + rgi->tables_to_lock_count--; + rgi->tables_to_lock = NULL; + delete rli; + delete rgi; +} + +st_clustrixdb_trx *ha_clustrixdb::get_trx(THD *thd, int *error_code) +{ + *error_code = 0; + st_clustrixdb_trx *trx; + if (!(trx = (st_clustrixdb_trx *)thd_get_ha_data(thd, clustrixdb_hton))) + { + if (!(trx = new st_clustrixdb_trx(thd))) { + *error_code = HA_ERR_OUT_OF_MEM; + return NULL; + } + + if ((*error_code = trx->net_init())) { + delete trx; + return NULL; + } + + thd_set_ha_data(thd, clustrixdb_hton, trx); + } + + return trx; +} + +void ha_clustrixdb::build_key_packed_row(uint index, uchar *packed_key, + size_t *packed_key_len) +{ + if (index == table->s->primary_key && has_hidden_key) { + memcpy(packed_key, &last_hidden_key, sizeof(ulonglong)); + *packed_key_len = sizeof(ulonglong); + } else { + // make a row from the table + table->mark_columns_used_by_index(index, &table->tmp_set); + *packed_key_len = pack_row(table, &table->tmp_set, packed_key, + table->record[0]); + } +} + +/**************************************************************************** +** Plugin Functions +****************************************************************************/ + +static int clustrixdb_commit(handlerton *hton, THD *thd, bool all) +{ + int error_code = 0; + st_clustrixdb_trx* trx = (st_clustrixdb_trx *) thd_get_ha_data(thd, hton); + assert(trx); + + if (trx->has_transaction) + { + if (all || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) + { + error_code = trx->clustrix_net->commit_trans(); + trx->has_transaction = FALSE; + } + } + + return error_code; +} + +static int clustrixdb_rollback(handlerton *hton, THD *thd, bool all) +{ + int error_code = 0; + st_clustrixdb_trx* trx = (st_clustrixdb_trx *) thd_get_ha_data(thd, hton); + assert(trx); + + if (trx->has_transaction) + { + if (all || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) + { + error_code = trx->clustrix_net->rollback_trans(); + trx->has_transaction = FALSE; + } + } + + return error_code; +} + +static handler* clustrixdb_create_handler(handlerton *hton, TABLE_SHARE *table, + MEM_ROOT *mem_root) +{ + return new (mem_root) ha_clustrixdb(hton, table); +} + +static int clustrixdb_close_connection(handlerton* hton, THD* thd) +{ + st_clustrixdb_trx* trx = (st_clustrixdb_trx *) thd_get_ha_data(thd, hton); + if (!trx) + return 0; /* Transaction is not started */ + + if (trx->has_transaction) + clustrixdb_rollback(clustrixdb_hton, thd, TRUE); + + thd_set_ha_data(thd, clustrixdb_hton, NULL); + delete trx; + + return 0; +} + +static int clustrixdb_panic(handlerton *hton, ha_panic_function type) +{ + return 0; +} + + +static bool clustrixdb_show_status(handlerton *hton, THD *thd, + stat_print_fn *stat_print, + enum ha_stat_type stat_type) +{ + return FALSE; +} + +static int clustrixdb_discover_table_names(handlerton *hton, LEX_CSTRING *db, + MY_DIR *dir, + handlerton::discovered_list *result) +{ + clustrix_connection *clustrix_net = new clustrix_connection(); + int error_code = clustrix_net->connect(); + if (error_code) + return error_code; + + error_code = clustrix_net->populate_table_list(db, result); + delete clustrix_net; + return 0; // error_code; +} + +int clustrixdb_discover_table(handlerton *hton, THD *thd, TABLE_SHARE *share) +{ + clustrix_connection *clustrix_net = new clustrix_connection(); + int error_code = clustrix_net->connect(); + if (error_code) + return error_code; + + error_code = clustrix_net->discover_table_details(&share->db, + &share->table_name, + thd, share); + + delete clustrix_net; + return error_code; +} + +static int clustrixdb_init(void *p) +{ + clustrixdb_hton = (handlerton *) p; + clustrixdb_hton->state = SHOW_OPTION_YES; + clustrixdb_hton->flags = HTON_NO_FLAGS; + clustrixdb_hton->panic = clustrixdb_panic; + clustrixdb_hton->close_connection = clustrixdb_close_connection; + clustrixdb_hton->commit = clustrixdb_commit; + clustrixdb_hton->rollback = clustrixdb_rollback; + clustrixdb_hton->create = clustrixdb_create_handler; + clustrixdb_hton->show_status = clustrixdb_show_status; + clustrixdb_hton->discover_table_names = clustrixdb_discover_table_names; + clustrixdb_hton->discover_table = clustrixdb_discover_table; + + return 0; +} + +struct st_mysql_show_var clustrixdb_status_vars[] = +{ + {NullS, NullS, SHOW_LONG} +}; + +static struct st_mysql_sys_var* clustrixdb_system_variables[] = +{ + MYSQL_SYSVAR(connect_timeout), + MYSQL_SYSVAR(read_timeout), + MYSQL_SYSVAR(write_timeout), + MYSQL_SYSVAR(host), + MYSQL_SYSVAR(username), + MYSQL_SYSVAR(password), + MYSQL_SYSVAR(port), + MYSQL_SYSVAR(socket), + NULL +}; + +static struct st_mysql_storage_engine clustrixdb_storage_engine = + {MYSQL_HANDLERTON_INTERFACE_VERSION}; + +maria_declare_plugin(clustrixdb) +{ + MYSQL_STORAGE_ENGINE_PLUGIN, /* Plugin Type */ + &clustrixdb_storage_engine, /* Plugin Descriptor */ + "CLUSTRIXDB", /* Plugin Name */ + "MariaDB", /* Plugin Author */ + "ClustrixDB storage engine", /* Plugin Description */ + PLUGIN_LICENSE_GPL, /* Plugin Licence */ + clustrixdb_init, /* Plugin Entry Point */ + NULL, /* Plugin Deinitializer */ + 0x0001, /* Hex Version Number (0.1) */ + NULL /* clustrixdb_status_vars */, /* Status Variables */ + clustrixdb_system_variables, /* System Variables */ + "0.1", /* String Version */ + MariaDB_PLUGIN_MATURITY_EXPERIMENTAL /* Maturity Level */ +} +maria_declare_plugin_end; diff --git a/storage/clustrixdb/ha_clustrixdb.h b/storage/clustrixdb/ha_clustrixdb.h new file mode 100644 index 00000000000..1b25428b313 --- /dev/null +++ b/storage/clustrixdb/ha_clustrixdb.h @@ -0,0 +1,124 @@ +/***************************************************************************** +Copyright (c) 2019, MariaDB Corporation. +*****************************************************************************/ + +#ifndef _ha_clustrixdb_h +#define _ha_clustrixdb_h + +#ifdef USE_PRAGMA_INTERFACE +#pragma interface /* gcc class implementation */ +#endif + +#define MYSQL_SERVER 1 +#include "clustrix_connection.h" +#include "my_bitmap.h" +#include "table.h" +#include "rpl_rli.h" +#include "handler.h" +#include "sql_class.h" +#include "sql_show.h" +#include "mysql.h" +#include "../../sql/rpl_record.h" + +class ha_clustrixdb; + +class st_clustrixdb_trx +{ +public: + THD *thd; + clustrix_connection *clustrix_net; + //query_id_t query_id; + //MEM_ROOT mem_root; /* Memory allocated for the executing transaction */ + bool has_transaction; + + st_clustrixdb_trx(THD* trx_thd); + ~st_clustrixdb_trx(); + int net_init(); + int begin_trans(); +}; + +class ha_clustrixdb : public handler +{ +private: +# define CLUSTRIXDB_ROW_LIMIT 1024 + + ulonglong clustrix_table_oid; + rpl_group_info *rgi; + Relay_log_info *rli; + RPL_TABLE_LIST *rpl_table_list; + + Field *auto_inc_field; + ulonglong auto_inc_value; + + bool has_hidden_key; + ulonglong last_hidden_key; + ulonglong scan_refid; + bool is_scan; + MY_BITMAP scan_fields; + +public: + ha_clustrixdb(handlerton *hton, TABLE_SHARE *table_arg); + ~ha_clustrixdb(); + int create(const char *name, TABLE *form, HA_CREATE_INFO *info); + int delete_table(const char *name); + int open(const char *name, int mode, uint test_if_locked); + int close(void); + int reset(); + int write_row(uchar *buf); + // start_bulk_update exec_bulk_update + int update_row(const uchar *old_data, const uchar *new_data); + // start_bulk_delete exec_bulk_delete + int delete_row(const uchar *buf); + + Table_flags table_flags(void) const; + ulong index_flags(uint idx, uint part, bool all_parts) const; + uint max_supported_keys() const { return MAX_KEY; } + + ha_rows records(); + ha_rows records_in_range(uint inx, key_range *min_key, + key_range *max_key); + + int info(uint flag); // see my_base.h for full description + + // multi_read_range + // read_range + int index_init(uint idx, bool sorted); + int index_read(uchar * buf, const uchar * key, uint key_len, + enum ha_rkey_function find_flag); + int index_first(uchar *buf); + int index_prev(uchar *buf); + int index_last(uchar *buf); + int index_next(uchar *buf); + //int index_next_same(uchar *buf, const uchar *key, uint keylen); + int index_end(); + + int rnd_init(bool scan); + int rnd_next(uchar *buf); + int rnd_pos(uchar * buf, uchar *pos); + int rnd_end(); + + void position(const uchar *record); + uint lock_count(void) const; + THR_LOCK_DATA **store_lock(THD *thd, + THR_LOCK_DATA **to, + enum thr_lock_type lock_type); + int external_lock(THD *thd, int lock_type); + + uint8 table_cache_type() + { + return(HA_CACHE_TBL_NOCACHE); + } + + const COND *cond_push(const COND *cond); + void cond_pop(); + int info_push(uint info_type, void *info); + +private: + st_clustrixdb_trx *get_trx(THD *thd, int *error_code); + void add_current_table_to_rpl_table_list(); + void remove_current_table_from_rpl_table_list(); + void build_key_packed_row(uint index, uchar *packed_key, + size_t *packed_key_len); +}; + +#endif // _ha_clustrixdb_h -- cgit v1.2.1 From f53c65351263bc42cacee528f4abb80487bc3288 Mon Sep 17 00:00:00 2001 From: Roman Nozdrin Date: Wed, 12 Jun 2019 22:57:55 +0000 Subject: Replaced fixed size char arrays with strings when working with SQL query texts. Replaced fixed size uchar arrays for buffers with memory allocations. Fixed MDB crash in discover_table_details with CX unavailable. --- storage/clustrixdb/clustrix_connection.cc | 21 +++-- storage/clustrixdb/clustrix_connection.h | 4 +- storage/clustrixdb/ha_clustrixdb.cc | 134 ++++++++++++++++++++---------- storage/clustrixdb/ha_clustrixdb.h | 2 + 4 files changed, 107 insertions(+), 54 deletions(-) diff --git a/storage/clustrixdb/clustrix_connection.cc b/storage/clustrixdb/clustrix_connection.cc index 456907d50a7..e2538abce40 100644 --- a/storage/clustrixdb/clustrix_connection.cc +++ b/storage/clustrixdb/clustrix_connection.cc @@ -178,18 +178,18 @@ int clustrix_connection::rollback_trans() return error_code; } -int clustrix_connection::create_table(char *stmt) +int clustrix_connection::create_table(String &stmt) { - int error_code = mysql_real_query(&clustrix_net, stmt, strlen(stmt)); + int error_code = mysql_real_query(&clustrix_net, stmt.ptr(), stmt.length()); if (error_code) return mysql_errno(&clustrix_net); return error_code; } -int clustrix_connection::delete_table(char *stmt) +int clustrix_connection::delete_table(String &stmt) { - int error_code = mysql_real_query(&clustrix_net, stmt, strlen(stmt)); + int error_code = mysql_real_query(&clustrix_net, stmt.ptr(), stmt.length()); if (error_code) return mysql_errno(&clustrix_net); return error_code; @@ -412,8 +412,10 @@ int clustrix_connection::discover_table_details(LEX_CSTRING *db, get_oid.append(name); get_oid.append("'"); if (mysql_real_query(&clustrix_net, get_oid.c_ptr(), get_oid.length())) { - if ((error_code = mysql_errno(&clustrix_net))) - return error_code; + if ((error_code = mysql_errno(&clustrix_net))) { + error_code = HA_ERR_NO_SUCH_TABLE; + goto error; + } } results = mysql_store_result(&clustrix_net); @@ -447,8 +449,11 @@ int clustrix_connection::discover_table_details(LEX_CSTRING *db, show.append("."); show.append(name); if (mysql_real_query(&clustrix_net, show.c_ptr(), show.length())) { - if ((error_code = mysql_errno(&clustrix_net))) - return error_code; + if ((error_code = mysql_errno(&clustrix_net))) { + DBUG_PRINT("mysql_real_query returns ",("%d", error_code)); + error_code = HA_ERR_NO_SUCH_TABLE; + goto error; + } } results = mysql_store_result(&clustrix_net); diff --git a/storage/clustrixdb/clustrix_connection.h b/storage/clustrixdb/clustrix_connection.h index d460f33d9cc..fd39abb6e21 100644 --- a/storage/clustrixdb/clustrix_connection.h +++ b/storage/clustrixdb/clustrix_connection.h @@ -64,8 +64,8 @@ public: int commit_trans(); int rollback_trans(); - int create_table(char *stmt); - int delete_table(char *stmt); + int create_table(String &stmt); + int delete_table(String &stmt); int write_row(ulonglong clustrix_table_oid, uchar *packed_row, size_t packed_size); diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index 83e7c2a2581..ab14f36f2a7 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -145,6 +145,22 @@ int st_clustrixdb_trx::begin_trans() return 0; } +/**************************************************************************** +** Utility functions +****************************************************************************/ +// This is a wastefull aproach but better then fixed sized buffer.RALLEL +size_t estimate_row_size(TABLE *table) +{ + size_t row_size = 0; + size_t null_byte_count = (bitmap_bits_set(table->write_set) + 7) / 8; + row_size += null_byte_count; + Field **p_field= table->field, *field; + for ( ; (field= *p_field) ; p_field++) { + row_size += field->max_data_length(); + } + return row_size; +} + /**************************************************************************** ** Class ha_clustrixdb ****************************************************************************/ @@ -177,11 +193,7 @@ int ha_clustrixdb::create(const char *name, TABLE *form, HA_CREATE_INFO *info) enum tmp_table_type saved_tmp_table_type = form->s->tmp_table; Table_specification_st *create_info = &thd->lex->create_info; const bool is_tmp_table = info->options & HA_LEX_CREATE_TMP_TABLE; - char create_table_stmt_buffer[2048]; - String create_table_stmt(create_table_stmt_buffer, - sizeof(create_table_stmt_buffer), - system_charset_info); - create_table_stmt.length(0); + String create_table_stmt; /* Create a copy of the CREATE TABLE statement */ if (!is_tmp_table) @@ -204,7 +216,7 @@ int ha_clustrixdb::create(const char *name, TABLE *form, HA_CREATE_INFO *info) if (error_code) return error_code; - error_code = trx->clustrix_net->create_table(create_table_stmt_buffer); + error_code = trx->clustrix_net->create_table(create_table_stmt); return error_code; } @@ -216,20 +228,28 @@ int ha_clustrixdb::delete_table(const char *name) if (!trx) return error_code; - /* XXX: I know this is unsafe. */ - char db_name[1000]; - const char *ptr = name + 2; - int i = 0; + // This block isn't UTF aware yet. + // The format contains './' in the beginning of a path. + char *ptr = (char*) name + 2; while (*ptr != '/') - db_name[i++] = *ptr++; - db_name[i] = '\0'; - char tbl_name[1000]; + { + ptr++; + } + *ptr = '\0'; + String db_name; + db_name.append(name + 2); + *ptr = '/'; ptr++; - strcpy(tbl_name, ptr); + String tbl_name; + tbl_name.append(ptr); + + String delete_cmd; + delete_cmd.append("DROP TABLE `"); + delete_cmd.append(db_name); + delete_cmd.append("`.`"); + delete_cmd.append(tbl_name); + delete_cmd.append("`"); - char delete_cmd[2000]; - /* XXX: I know this is unsafe. */ - sprintf(delete_cmd, "drop table `%s`.`%s`", db_name, tbl_name); return trx->clustrix_net->delete_table(delete_cmd); } @@ -278,21 +298,26 @@ int ha_clustrixdb::write_row(uchar *buf) assert(trx->has_transaction); /* Convert the row format to binlog (packed) format */ - /* XXX: We cannot use a fixed length buffer for this. */ - uchar packed_new_row[CLUSTRIXDB_ROW_LIMIT]; + uchar *packed_new_row = (uchar*) my_alloca(estimate_row_size(table)); size_t packed_size = pack_row(table, table->write_set, packed_new_row, buf); /* XXX: Clustrix may needs to return HA_ERR_AUTOINC_ERANGE if we hit that error. */ if ((error_code = trx->clustrix_net->write_row(clustrix_table_oid, packed_new_row, packed_size))) - return error_code; + goto err; - Field *auto_inc_field = table->next_number_field; - if (auto_inc_field) - insert_id_for_cur_row = trx->clustrix_net->last_insert_id; + { + Field *auto_inc_field = table->next_number_field; + if (auto_inc_field) + insert_id_for_cur_row = trx->clustrix_net->last_insert_id; + } - return error_code; +err: + if (packed_size) + my_afree(packed_new_row); + + return error_code; } int ha_clustrixdb::update_row(const uchar *old_data, const uchar *new_data) @@ -305,15 +330,21 @@ int ha_clustrixdb::update_row(const uchar *old_data, const uchar *new_data) assert(trx->has_transaction); - /* XXX: We cannot use a fixed length buffer for this. */ - uchar packed_new_row[CLUSTRIXDB_ROW_LIMIT]; + size_t row_size = estimate_row_size(table); + uchar *packed_new_row = (uchar*) my_alloca(row_size); + // Add checks for actual size of the packed data /*size_t packed_new_size =*/ pack_row(table, table->write_set, packed_new_row, new_data); - /* XXX: We cannot use a fixed length buffer for this. */ - uchar packed_old_row[CLUSTRIXDB_ROW_LIMIT]; + uchar *packed_old_row = (uchar*) my_alloca(row_size); /*size_t packed_old_size =*/ pack_row(table, table->write_set, packed_old_row, old_data); /* Send the packed rows to Clustrix */ + if(packed_new_row) + my_afree(packed_new_row); + + if(packed_old_row) + my_afree(packed_old_row); + return error_code; } @@ -327,14 +358,18 @@ int ha_clustrixdb::delete_row(const uchar *buf) assert(trx->has_transaction); - /* XXX: We cannot use a fixed length buffer for this. */ - uchar packed_key[CLUSTRIXDB_ROW_LIMIT]; + // The estimate should consider only key fields widths. size_t packed_key_len; + uchar *packed_key = (uchar*) my_alloca(estimate_row_size(table)); build_key_packed_row(table->s->primary_key, packed_key, &packed_key_len); if ((error_code = trx->clustrix_net->key_delete(clustrix_table_oid, packed_key, packed_key_len))) - return error_code; + goto err; + +err: + if (packed_key) + my_afree(packed_key); return error_code; } @@ -450,9 +485,9 @@ int ha_clustrixdb::index_read(uchar * buf, const uchar * key, uint key_len, is_scan = false; key_restore(table->record[0], key, &table->key_info[active_index], key_len); - /* XXX: We cannot use a fixed length buffer for this. */ - uchar packed_key[CLUSTRIXDB_ROW_LIMIT]; + // The estimate should consider only key fields widths. size_t packed_key_len; + uchar *packed_key = (uchar*) my_alloca(estimate_row_size(table)); build_key_packed_row(active_index, packed_key, &packed_key_len); uchar *rowdata; @@ -461,17 +496,21 @@ int ha_clustrixdb::index_read(uchar * buf, const uchar * key, uint key_len, active_index, table->read_set, packed_key, packed_key_len, &rowdata, &rowdata_length))) - DBUG_RETURN(error_code); + goto err; uchar const *current_row_end; ulong master_reclength; if ((error_code = unpack_row(rgi, table, table->s->fields, rowdata, table->read_set, ¤t_row_end, &master_reclength, rowdata + rowdata_length))) - DBUG_RETURN(error_code); + goto err; - DBUG_RETURN(0); + error_code = 0; +err: + if (packed_key) + my_afree(packed_key); + DBUG_RETURN(error_code); } int ha_clustrixdb::index_first(uchar *buf) @@ -669,8 +708,8 @@ int ha_clustrixdb::rnd_pos(uchar * buf, uchar *pos) key_restore(table->record[0], pos, &table->key_info[keyno], len); } - /* XXX: We cannot use a fixed length buffer for this. */ - uchar packed_key[CLUSTRIXDB_ROW_LIMIT]; + // The estimate should consider only key fields widths. + uchar *packed_key = (uchar*) my_alloca(estimate_row_size(table)); size_t packed_key_len; build_key_packed_row(table->s->primary_key, packed_key, &packed_key_len); @@ -680,16 +719,22 @@ int ha_clustrixdb::rnd_pos(uchar * buf, uchar *pos) table->read_set, packed_key, packed_key_len, &rowdata, &rowdata_length))) - DBUG_RETURN(error_code); + goto err; uchar const *current_row_end; ulong master_reclength; if ((error_code = unpack_row(rgi, table, table->s->fields, rowdata, table->read_set, ¤t_row_end, &master_reclength, rowdata + rowdata_length))) - DBUG_RETURN(error_code); + goto err; - DBUG_RETURN(0); + error_code = 0; +err: + + if (packed_key) + my_afree(packed_key); + + DBUG_RETURN(error_code); } int ha_clustrixdb::rnd_end() @@ -791,14 +836,16 @@ void ha_clustrixdb::add_current_table_to_rpl_table_list() rgi->tables_to_lock->m_conv_table = NULL; rgi->tables_to_lock->master_had_triggers = FALSE; rgi->tables_to_lock->m_tabledef_valid = TRUE; - /* XXX: We cannot use a fixed length buffer for this. */ - uchar col_type[CLUSTRIXDB_ROW_LIMIT]; + // We need one byte per column to save a column's binlog type. + uchar *col_type = (uchar*) my_alloca(table->s->fields); for (uint i = 0 ; i < table->s->fields ; ++i) col_type[i] = table->field[i]->binlog_type(); table_def *tabledef = &rgi->tables_to_lock->m_tabledef; new (tabledef) table_def(col_type, table->s->fields, NULL, 0, NULL, 0); rgi->tables_to_lock_count++; + if (col_type) + my_afree(col_type); } void ha_clustrixdb::remove_current_table_from_rpl_table_list() @@ -906,7 +953,6 @@ static int clustrixdb_close_connection(handlerton* hton, THD* thd) if (trx->has_transaction) clustrixdb_rollback(clustrixdb_hton, thd, TRUE); - thd_set_ha_data(thd, clustrixdb_hton, NULL); delete trx; return 0; diff --git a/storage/clustrixdb/ha_clustrixdb.h b/storage/clustrixdb/ha_clustrixdb.h index 1b25428b313..d9417b79743 100644 --- a/storage/clustrixdb/ha_clustrixdb.h +++ b/storage/clustrixdb/ha_clustrixdb.h @@ -20,6 +20,8 @@ Copyright (c) 2019, MariaDB Corporation. #include "mysql.h" #include "../../sql/rpl_record.h" +size_t estimate_row_size(TABLE *table); + class ha_clustrixdb; class st_clustrixdb_trx -- cgit v1.2.1 From c45ae5f01b7b96f7d18636ca539c27907ba5bdd8 Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Thu, 13 Jun 2019 13:00:48 -0700 Subject: Simplify delete_table and fix a few little things. --- storage/clustrixdb/clustrix_connection.cc | 7 ++++--- storage/clustrixdb/ha_clustrixdb.cc | 29 ++++++++--------------------- 2 files changed, 12 insertions(+), 24 deletions(-) diff --git a/storage/clustrixdb/clustrix_connection.cc b/storage/clustrixdb/clustrix_connection.cc index e2538abce40..506cbb61ad1 100644 --- a/storage/clustrixdb/clustrix_connection.cc +++ b/storage/clustrixdb/clustrix_connection.cc @@ -413,8 +413,9 @@ int clustrix_connection::discover_table_details(LEX_CSTRING *db, get_oid.append("'"); if (mysql_real_query(&clustrix_net, get_oid.c_ptr(), get_oid.length())) { if ((error_code = mysql_errno(&clustrix_net))) { - error_code = HA_ERR_NO_SUCH_TABLE; - goto error; + DBUG_PRINT("mysql_real_query returns ", ("%d", error_code)); + error_code = HA_ERR_NO_SUCH_TABLE; + goto error; } } @@ -450,7 +451,7 @@ int clustrix_connection::discover_table_details(LEX_CSTRING *db, show.append(name); if (mysql_real_query(&clustrix_net, show.c_ptr(), show.length())) { if ((error_code = mysql_errno(&clustrix_net))) { - DBUG_PRINT("mysql_real_query returns ",("%d", error_code)); + DBUG_PRINT("mysql_real_query returns ", ("%d", error_code)); error_code = HA_ERR_NO_SUCH_TABLE; goto error; } diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index ab14f36f2a7..785f8264803 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -230,24 +230,15 @@ int ha_clustrixdb::delete_table(const char *name) // This block isn't UTF aware yet. // The format contains './' in the beginning of a path. - char *ptr = (char*) name + 2; - while (*ptr != '/') - { - ptr++; - } - *ptr = '\0'; - String db_name; - db_name.append(name + 2); - *ptr = '/'; - ptr++; - String tbl_name; - tbl_name.append(ptr); + char *dbname_end = (char*) name + 2; + while (*dbname_end != '/') + dbname_end++; String delete_cmd; delete_cmd.append("DROP TABLE `"); - delete_cmd.append(db_name); + delete_cmd.append(name + 2, dbname_end - name - 2); delete_cmd.append("`.`"); - delete_cmd.append(tbl_name); + delete_cmd.append(dbname_end + 1); delete_cmd.append("`"); return trx->clustrix_net->delete_table(delete_cmd); @@ -307,11 +298,9 @@ int ha_clustrixdb::write_row(uchar *buf) packed_new_row, packed_size))) goto err; - { - Field *auto_inc_field = table->next_number_field; - if (auto_inc_field) - insert_id_for_cur_row = trx->clustrix_net->last_insert_id; - } + Field *auto_inc_field = table->next_number_field; + if (auto_inc_field) + insert_id_for_cur_row = trx->clustrix_net->last_insert_id; err: if (packed_size) @@ -505,7 +494,6 @@ int ha_clustrixdb::index_read(uchar * buf, const uchar * key, uint key_len, &master_reclength, rowdata + rowdata_length))) goto err; - error_code = 0; err: if (packed_key) my_afree(packed_key); @@ -728,7 +716,6 @@ int ha_clustrixdb::rnd_pos(uchar * buf, uchar *pos) &master_reclength, rowdata + rowdata_length))) goto err; - error_code = 0; err: if (packed_key) -- cgit v1.2.1 From 20629a5226d019472e6931ca4a41ea98d9e0bef8 Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Thu, 13 Jun 2019 13:22:06 -0700 Subject: Remove 'Field *auto_inc_field'. --- storage/clustrixdb/ha_clustrixdb.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index 785f8264803..5cc603f84a9 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -298,8 +298,7 @@ int ha_clustrixdb::write_row(uchar *buf) packed_new_row, packed_size))) goto err; - Field *auto_inc_field = table->next_number_field; - if (auto_inc_field) + if (table->next_number_field) insert_id_for_cur_row = trx->clustrix_net->last_insert_id; err: -- cgit v1.2.1 From ab09e22aef9e2da31c8d43e069cb64d7ce28b59c Mon Sep 17 00:00:00 2001 From: Roman Nozdrin Date: Wed, 19 Jun 2019 21:07:57 +0000 Subject: CLX-3 Add support for UTF-8 encoded object names in SQL statements. Add support for RENAME TABLE. Fixed a double free bug in discover_table_details. --- storage/clustrixdb/clustrix_connection.cc | 45 ++++++++++++-------- storage/clustrixdb/clustrix_connection.h | 1 + storage/clustrixdb/ha_clustrixdb.cc | 69 ++++++++++++++++++++++++++++--- storage/clustrixdb/ha_clustrixdb.h | 1 + 4 files changed, 93 insertions(+), 23 deletions(-) diff --git a/storage/clustrixdb/clustrix_connection.cc b/storage/clustrixdb/clustrix_connection.cc index 506cbb61ad1..1c6c10a913f 100644 --- a/storage/clustrixdb/clustrix_connection.cc +++ b/storage/clustrixdb/clustrix_connection.cc @@ -19,7 +19,7 @@ extern char *clustrix_password; extern uint clustrix_port; extern char *clustrix_socket; -static const char charset_name[] = "latin1"; +static const char charset_name[] = "utf8"; enum clustrix_commands { CLUSTRIX_WRITE_ROW = 1, @@ -195,6 +195,14 @@ int clustrix_connection::delete_table(String &stmt) return error_code; } +int clustrix_connection::rename_table(String &stmt) +{ + int error_code = mysql_real_query(&clustrix_net, stmt.ptr(), stmt.length()); + if (error_code) + return mysql_errno(&clustrix_net); + return error_code; +} + int clustrix_connection::write_row(ulonglong clustrix_table_oid, uchar *packed_row, size_t packed_size) { @@ -398,7 +406,8 @@ int clustrix_connection::discover_table_details(LEX_CSTRING *db, { DBUG_ENTER("clustrix_connection::discover_table_details"); int error_code = 0; - MYSQL_RES *results = NULL; + MYSQL_RES *results_oid = NULL; + MYSQL_RES *results_create = NULL; MYSQL_ROW row; String get_oid, show; @@ -411,6 +420,7 @@ int clustrix_connection::discover_table_details(LEX_CSTRING *db, get_oid.append("' and r.name = '"); get_oid.append(name); get_oid.append("'"); + if (mysql_real_query(&clustrix_net, get_oid.c_ptr(), get_oid.length())) { if ((error_code = mysql_errno(&clustrix_net))) { DBUG_PRINT("mysql_real_query returns ", ("%d", error_code)); @@ -419,17 +429,17 @@ int clustrix_connection::discover_table_details(LEX_CSTRING *db, } } - results = mysql_store_result(&clustrix_net); + results_oid = mysql_store_result(&clustrix_net); DBUG_PRINT("oid results", - ("rows: %llu, fields: %u", mysql_num_rows(results), - mysql_num_fields(results))); + ("rows: %llu, fields: %u", mysql_num_rows(results_oid), + mysql_num_fields(results_oid))); - if (mysql_num_rows(results) != 1) { + if (mysql_num_rows(results_oid) != 1) { error_code = HA_ERR_NO_SUCH_TABLE; goto error; } - while((row = mysql_fetch_row(results))) { + while((row = mysql_fetch_row(results_oid))) { DBUG_PRINT("row", ("%s", row[0])); uchar *to = (uchar*)alloc_root(&share->mem_root, strlen(row[0]) + 1); if (!to) { @@ -442,8 +452,6 @@ int clustrix_connection::discover_table_details(LEX_CSTRING *db, share->tabledef_version.length = strlen(row[0]); } - mysql_free_result(results); - /* get show create statement */ show.append("show create table "); show.append(db); @@ -457,30 +465,33 @@ int clustrix_connection::discover_table_details(LEX_CSTRING *db, } } - results = mysql_store_result(&clustrix_net); + results_create = mysql_store_result(&clustrix_net); DBUG_PRINT("show table results", - ("rows: %llu, fields: %u", mysql_num_rows(results), - mysql_num_fields(results))); + ("rows: %llu, fields: %u", mysql_num_rows(results_create), + mysql_num_fields(results_create))); - if (mysql_num_rows(results) != 1) { + if (mysql_num_rows(results_create) != 1) { error_code = HA_ERR_NO_SUCH_TABLE; goto error; } - if (mysql_num_fields(results) != 2) { + if (mysql_num_fields(results_create) != 2) { error_code = HA_ERR_CORRUPT_EVENT; goto error; } - while((row = mysql_fetch_row(results))) { + while((row = mysql_fetch_row(results_create))) { DBUG_PRINT("row", ("%s - %s", row[0], row[1])); error_code = share->init_from_sql_statement_string(thd, false, row[1], strlen(row[1])); } error: - if (results) - mysql_free_result(results); + if (results_oid) + mysql_free_result(results_oid); + + if (results_create) + mysql_free_result(results_create); DBUG_RETURN(error_code); } diff --git a/storage/clustrixdb/clustrix_connection.h b/storage/clustrixdb/clustrix_connection.h index fd39abb6e21..af9e24668a7 100644 --- a/storage/clustrixdb/clustrix_connection.h +++ b/storage/clustrixdb/clustrix_connection.h @@ -66,6 +66,7 @@ public: int create_table(String &stmt); int delete_table(String &stmt); + int rename_table(String &stmt); int write_row(ulonglong clustrix_table_oid, uchar *packed_row, size_t packed_size); diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index 5cc603f84a9..91e90fddb6a 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -148,7 +148,7 @@ int st_clustrixdb_trx::begin_trans() /**************************************************************************** ** Utility functions ****************************************************************************/ -// This is a wastefull aproach but better then fixed sized buffer.RALLEL +// This is a wastefull aproach but better then fixed sized buffer. size_t estimate_row_size(TABLE *table) { size_t row_size = 0; @@ -161,6 +161,22 @@ size_t estimate_row_size(TABLE *table) return row_size; } +/** + * @brief + * Decodes object name. + * + * @details + * Replaces the encoded object name in the path with a decoded variant, + * e.g if path contains ./test/d@0024. This f() makes it ./test/d$ + * + * Used in delete and rename DDL processing. + **/ +void decode_objectname(char *buf, const char *path, size_t buf_size) +{ + size_t new_path_len = filename_to_tablename(path, buf, buf_size); + buf[new_path_len] = '\0'; +} + /**************************************************************************** ** Class ha_clustrixdb ****************************************************************************/ @@ -220,7 +236,7 @@ int ha_clustrixdb::create(const char *name, TABLE *form, HA_CREATE_INFO *info) return error_code; } -int ha_clustrixdb::delete_table(const char *name) +int ha_clustrixdb::delete_table(const char *path) { int error_code; THD *thd = ha_thd(); @@ -228,22 +244,63 @@ int ha_clustrixdb::delete_table(const char *name) if (!trx) return error_code; - // This block isn't UTF aware yet. // The format contains './' in the beginning of a path. - char *dbname_end = (char*) name + 2; + char *dbname_end = (char*) path + 2; while (*dbname_end != '/') dbname_end++; + char decoded_tbname[FN_REFLEN]; + decode_objectname(decoded_tbname, dbname_end + 1, FN_REFLEN); + String delete_cmd; delete_cmd.append("DROP TABLE `"); - delete_cmd.append(name + 2, dbname_end - name - 2); + delete_cmd.append(path + 2, dbname_end - path - 2); delete_cmd.append("`.`"); - delete_cmd.append(dbname_end + 1); + delete_cmd.append(decoded_tbname); delete_cmd.append("`"); + return trx->clustrix_net->delete_table(delete_cmd); } +int ha_clustrixdb::rename_table(const char* from, const char* to) +{ + int error_code; + THD *thd = ha_thd(); + st_clustrixdb_trx *trx = get_trx(thd, &error_code); + if (!trx) + return error_code; + + // The format contains './' in the beginning of a path. + char *from_dbname_end = (char*) from + 2; + while (*from_dbname_end != '/') + from_dbname_end++; + + char decoded_from_tbname[FN_REFLEN]; + decode_objectname(decoded_from_tbname, from_dbname_end + 1, FN_REFLEN); + + char *to_dbname_end = (char*) to + 2; + while (*to_dbname_end != '/') + to_dbname_end++; + + char decoded_to_tbname[FN_REFLEN]; + decode_objectname(decoded_to_tbname, to_dbname_end + 1, FN_REFLEN); + + String rename_cmd; + rename_cmd.append("RENAME TABLE `"); + rename_cmd.append(from + 2, from_dbname_end - from - 2); + rename_cmd.append("`.`"); + rename_cmd.append(decoded_from_tbname); + rename_cmd.append("` TO `"); + rename_cmd.append(to + 2, to_dbname_end - to - 2); + rename_cmd.append("`.`"); + rename_cmd.append(decoded_to_tbname); + rename_cmd.append("`;"); + + return trx->clustrix_net->rename_table(rename_cmd); +} + + int ha_clustrixdb::open(const char *name, int mode, uint test_if_locked) { DBUG_ENTER("ha_clustrixdb::open"); diff --git a/storage/clustrixdb/ha_clustrixdb.h b/storage/clustrixdb/ha_clustrixdb.h index d9417b79743..45a81203aba 100644 --- a/storage/clustrixdb/ha_clustrixdb.h +++ b/storage/clustrixdb/ha_clustrixdb.h @@ -63,6 +63,7 @@ public: ~ha_clustrixdb(); int create(const char *name, TABLE *form, HA_CREATE_INFO *info); int delete_table(const char *name); + int rename_table(const char* from, const char* to); int open(const char *name, int mode, uint test_if_locked); int close(void); int reset(); -- cgit v1.2.1 From 82faccc5ba741ee6c421f93925339681117953a7 Mon Sep 17 00:00:00 2001 From: Roman Nozdrin Date: Fri, 21 Jun 2019 22:23:12 +0000 Subject: CLX-4 Basic version of MTR based test suite. --- mysql-test/suite/clustrixdb/basics.result | 13 +++++++++++++ mysql-test/suite/clustrixdb/basics.test | 19 +++++++++++++++++++ mysql-test/suite/clustrixdb/my.cnf | 4 ++++ mysql-test/suite/clustrixdb/suite.opt | 4 ++++ 4 files changed, 40 insertions(+) create mode 100644 mysql-test/suite/clustrixdb/basics.result create mode 100644 mysql-test/suite/clustrixdb/basics.test create mode 100644 mysql-test/suite/clustrixdb/my.cnf create mode 100644 mysql-test/suite/clustrixdb/suite.opt diff --git a/mysql-test/suite/clustrixdb/basics.result b/mysql-test/suite/clustrixdb/basics.result new file mode 100644 index 00000000000..ed6501643f0 --- /dev/null +++ b/mysql-test/suite/clustrixdb/basics.result @@ -0,0 +1,13 @@ +DROP TABLE IF EXISTS cx1; +Warnings: +Note 1051 Unknown table 'test.cx1' +CREATE TABLE cx1(i BIGINT)ENGINE=clustrixdb; +CREATE TABLE cx1(i BIGINT)ENGINE=clustrixdb; +ERROR 42S01: Table 'cx1' already exists +INSERT INTO cx1 VALUES (42); +SELECT * FROM cx1; +i +42 +DROP TABLE cx1; +SHOW CREATE TABLE cx1; +ERROR 42S02: Table 'test.cx1' doesn't exist diff --git a/mysql-test/suite/clustrixdb/basics.test b/mysql-test/suite/clustrixdb/basics.test new file mode 100644 index 00000000000..711b7baf459 --- /dev/null +++ b/mysql-test/suite/clustrixdb/basics.test @@ -0,0 +1,19 @@ +#CREATE DATABASE clx; +#USE clx; + +DROP TABLE IF EXISTS cx1; +CREATE TABLE cx1(i BIGINT)ENGINE=clustrixdb; +--error ER_TABLE_EXISTS_ERROR +CREATE TABLE cx1(i BIGINT)ENGINE=clustrixdb; + +INSERT INTO cx1 VALUES (42); + +SELECT * FROM cx1; + +DROP TABLE cx1; + +--error ER_NO_SUCH_TABLE +SHOW CREATE TABLE cx1; + +#USE test; +#DROP DATABASE cxl; diff --git a/mysql-test/suite/clustrixdb/my.cnf b/mysql-test/suite/clustrixdb/my.cnf new file mode 100644 index 00000000000..8105041b85c --- /dev/null +++ b/mysql-test/suite/clustrixdb/my.cnf @@ -0,0 +1,4 @@ +!include include/default_my.cnf + +[mysqld.1] +socket= /tmp/mysqld42.sock diff --git a/mysql-test/suite/clustrixdb/suite.opt b/mysql-test/suite/clustrixdb/suite.opt new file mode 100644 index 00000000000..481f692cfdd --- /dev/null +++ b/mysql-test/suite/clustrixdb/suite.opt @@ -0,0 +1,4 @@ +--plugin-load=clustrixdb=ha_clustrixdb.so +--core-file +--clustrixdb_port=3306 +--plugin-maturity=unknown -- cgit v1.2.1 From 04fc4ead51263b59f970adf94356953fbc02f970 Mon Sep 17 00:00:00 2001 From: Roman Nozdrin Date: Wed, 26 Jun 2019 20:03:30 +0000 Subject: CLX-6 Create non-existed schemas at CLX BE on CREATE TABLE to syncronize the schema list at MDB FE and CLX BE. --- mysql-test/suite/clustrixdb/basics.test | 8 ++++---- storage/clustrixdb/ha_clustrixdb.cc | 9 +++++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/mysql-test/suite/clustrixdb/basics.test b/mysql-test/suite/clustrixdb/basics.test index 711b7baf459..487295d57db 100644 --- a/mysql-test/suite/clustrixdb/basics.test +++ b/mysql-test/suite/clustrixdb/basics.test @@ -1,5 +1,5 @@ -#CREATE DATABASE clx; -#USE clx; +CREATE DATABASE clx; +USE clx; DROP TABLE IF EXISTS cx1; CREATE TABLE cx1(i BIGINT)ENGINE=clustrixdb; @@ -15,5 +15,5 @@ DROP TABLE cx1; --error ER_NO_SUCH_TABLE SHOW CREATE TABLE cx1; -#USE test; -#DROP DATABASE cxl; +USE test; +DROP DATABASE clx; diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index 91e90fddb6a..8a5be79b556 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -232,6 +232,15 @@ int ha_clustrixdb::create(const char *name, TABLE *form, HA_CREATE_INFO *info) if (error_code) return error_code; + // To syncronize the schemas of MDB FE and CLX BE. + if (form->s && form->s->db.length) { + String createdb_stmt; + createdb_stmt.append("CREATE DATABASE IF NOT EXISTS `"); + createdb_stmt.append(form->s->db.str, form->s->db.length); + createdb_stmt.append("`"); + trx->clustrix_net->create_table(createdb_stmt); + } + error_code = trx->clustrix_net->create_table(create_table_stmt); return error_code; } -- cgit v1.2.1 From 51e21d54ba9d63d71ee20d07f7e0233a71e8b168 Mon Sep 17 00:00:00 2001 From: Roman Nozdrin Date: Fri, 21 Jun 2019 22:18:43 +0000 Subject: CLX-5 Select handler framework. --- storage/clustrixdb/clustrix_connection.cc | 88 +++++++++ storage/clustrixdb/clustrix_connection.h | 7 + storage/clustrixdb/ha_clustrixdb.cc | 4 + storage/clustrixdb/ha_clustrixdb_pushdown.cc | 262 +++++++++++++++++++++++++++ storage/clustrixdb/ha_clustrixdb_pushdown.h | 42 +++++ 5 files changed, 403 insertions(+) create mode 100644 storage/clustrixdb/ha_clustrixdb_pushdown.cc create mode 100644 storage/clustrixdb/ha_clustrixdb_pushdown.h diff --git a/storage/clustrixdb/clustrix_connection.cc b/storage/clustrixdb/clustrix_connection.cc index 1c6c10a913f..f5782a7b6ee 100644 --- a/storage/clustrixdb/clustrix_connection.cc +++ b/storage/clustrixdb/clustrix_connection.cc @@ -28,6 +28,7 @@ enum clustrix_commands { CLUSTRIX_SCAN_STOP, CLUSTRIX_KEY_READ, CLUSTRIX_KEY_DELETE, + CLUSTRIX_QUERY_INIT }; /**************************************************************************** @@ -322,6 +323,70 @@ int clustrix_connection::scan_init(ulonglong clustrix_table_oid, uint index, return error_code; } +/*int clustrix_connection::scan_init_select(String &stmt) +{ + int error_code = mysql_real_query(&clustrix_net, stmt.ptr(), stmt.length()); + if (error_code) + return mysql_errno(&clustrix_net); + + results = mysql_store_result(&clustrix_net); + + return error_code; +}*/ + +/** + * @brief + * Sends a command to initiate query scan. + * @details + * Sends a command over mysql protocol connection to initiate an + * arbitrary query using a query text. + * Uses field types, field metadata and nullability to explicitly + * cast result to expected data type. Exploits RBR TABLE_MAP_EVENT + * format + sends SQL text. + * @args + * stmt& Query text to send + * fieldtype* array of byte wide field types of result projection + * null_bits* fields nullability bitmap of result projection + * field_metadata* Field metadata of result projection + * scan_refid id used to reference this scan later + * Used in pushdowns to initiate query scan. + **/ +int clustrix_connection::scan_query_init(String &stmt, uchar *fieldtype, + uint fields, uchar *null_bits, + uint null_bits_size, uchar *field_metadata, + uint field_metadata_size, ulonglong *scan_refid) +{ + int error_code; + command_length = 0; + + if ((error_code = add_command_operand_uchar(CLUSTRIX_QUERY_INIT))) + return error_code; + + if ((error_code = add_command_operand_str(fieldtype, fields))) + return error_code; + + if ((error_code = add_command_operand_str(field_metadata, field_metadata_size))) + return error_code; + + // This variable length string calls for an additional store w/o lcb lenth prefix. + if ((error_code = add_command_operand_vlstr(null_bits, null_bits_size))) + return error_code; + + if ((error_code = add_command_operand_str((uchar*)stmt.ptr(), stmt.length()))) + return error_code; + + if ((error_code = send_command())) + return error_code; + + ulong packet_length = cli_safe_read(&clustrix_net); + if (packet_length == packet_error) + return mysql_errno(&clustrix_net); + + unsigned char *pos = clustrix_net.net.read_pos; + *scan_refid = safe_net_field_length_ll(&pos, packet_length); + return error_code; +} + int clustrix_connection::scan_next(ulonglong scan_refid, uchar **rowdata, ulong *rowdata_length) { @@ -584,6 +649,29 @@ int clustrix_connection::add_command_operand_str(const uchar *str, return 0; } +/** + * @brief + * Puts variable length string into the buffer. + * @details + * Puts into the buffer variable length string the size + * of which is send by other means. For details see + * MDB Client/Server Protocol. + * @args + * str - string to send + * str_length - size + **/ +int clustrix_connection::add_command_operand_vlstr(const uchar *str, + size_t str_length) +{ + int error_code = expand_command_buffer(str_length); + if (error_code) + return error_code; + + memcpy(command_buffer + command_length, str, str_length); + command_length += str_length; + return 0; +} + int clustrix_connection::add_command_operand_lex_string(LEX_CSTRING str) { return add_command_operand_str((const uchar *)str.str, str.length); diff --git a/storage/clustrixdb/clustrix_connection.h b/storage/clustrixdb/clustrix_connection.h index af9e24668a7..87d5055ae99 100644 --- a/storage/clustrixdb/clustrix_connection.h +++ b/storage/clustrixdb/clustrix_connection.h @@ -28,6 +28,7 @@ private: # define COMMAND_BUFFER_SIZE_INCREMENT_BITS 10 MYSQL clustrix_net; + MYSQL_RES *results; uchar *command_buffer; size_t command_buffer_length; size_t command_length; @@ -68,6 +69,7 @@ public: int delete_table(String &stmt); int rename_table(String &stmt); + int write_row(ulonglong clustrix_table_oid, uchar *packed_row, size_t packed_size); int key_delete(ulonglong clustrix_table_oid, @@ -82,6 +84,10 @@ public: ulonglong *scan_refid); int scan_next(ulonglong scan_refid, uchar **rowdata, ulong *rowdata_length); int scan_end(ulonglong scan_refid); + int scan_query_init(String &stmt, uchar *fieldtype, + uint fields, uchar *null_bits, + uint null_bits_size, uchar *field_metadata, + uint field_metadata_size, ulonglong *scan_refid); int populate_table_list(LEX_CSTRING *db, handlerton::discovered_list *result); int discover_table_details(LEX_CSTRING *db, LEX_CSTRING *name, THD *thd, @@ -93,6 +99,7 @@ private: int add_command_operand_ulonglong(ulonglong value); int add_command_operand_lcb(ulonglong value); int add_command_operand_str(const uchar *str, size_t length); + int add_command_operand_vlstr(const uchar *str, size_t length); int add_command_operand_lex_string(LEX_CSTRING str); int add_command_operand_bitmap(MY_BITMAP *bitmap); int send_command(); diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index 8a5be79b556..208a138ef53 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -5,6 +5,7 @@ Copyright (c) 2019, MariaDB Corporation. /** @file ha_clustrixdb.cc */ #include "ha_clustrixdb.h" +#include "ha_clustrixdb_pushdown.h" #include "key.h" handlerton *clustrixdb_hton = NULL; @@ -1052,6 +1053,8 @@ int clustrixdb_discover_table(handlerton *hton, THD *thd, TABLE_SHARE *share) return error_code; } +#include "ha_clustrixdb_pushdown.cc" + static int clustrixdb_init(void *p) { clustrixdb_hton = (handlerton *) p; @@ -1065,6 +1068,7 @@ static int clustrixdb_init(void *p) clustrixdb_hton->show_status = clustrixdb_show_status; clustrixdb_hton->discover_table_names = clustrixdb_discover_table_names; clustrixdb_hton->discover_table = clustrixdb_discover_table; + clustrixdb_hton->create_select = create_clustrixdb_select_handler; return 0; } diff --git a/storage/clustrixdb/ha_clustrixdb_pushdown.cc b/storage/clustrixdb/ha_clustrixdb_pushdown.cc new file mode 100644 index 00000000000..0451ce9f9c6 --- /dev/null +++ b/storage/clustrixdb/ha_clustrixdb_pushdown.cc @@ -0,0 +1,262 @@ +/***************************************************************************** +Copyright (c) 2019, MariaDB Corporation. +*****************************************************************************/ + +#include "ha_clustrixdb_pushdown.h" + +/*@brief Fills up array data types, metadata and nullability*/ +/************************************************************ + * DESCRIPTION: + * Fills up three arrays with: field binlog data types, field + * metadata and nullability bitmask as in Table_map_log_event + * ctor. Internally creates a temporary table as does + * Pushdown_select. + * More details in server/sql/log_event_server.cc + * PARAMETERS: + * thd - THD* + * sl - SELECT_LEX* + * fieldtype - uchar* + * field_metadata - uchar* + * null_bits - uchar* + * num_null_bytes - null bit size + * RETURN: + * metadata_size int or -1 in case of error + ************************************************************/ +int get_field_types(THD *thd, SELECT_LEX *sl, uchar *fieldtype, + uchar *field_metadata, uchar *null_bits, const int num_null_bytes) +{ + int field_metadata_size = 0; + int metadata_index = 0; + + // Construct a tmp table with fields to find out result DTs. + // This should be reconsidered if it worths the effort. + List types; + TMP_TABLE_PARAM tmp_table_param; + sl->master_unit()->join_union_item_types(thd, types, 1); + tmp_table_param.init(); + tmp_table_param.field_count= types.elements; + + TABLE *tmp_table = create_tmp_table(thd, &tmp_table_param, types, + (ORDER *) 0, false, 0, + TMP_TABLE_ALL_COLUMNS, 1, + &empty_clex_str, true, false); + if (!tmp_table) { + field_metadata_size = -1; + goto err; + } + + for (unsigned int i = 0 ; i < tmp_table_param.field_count; ++i) { + fieldtype[i]= tmp_table->field[i]->binlog_type(); + } + + bzero(field_metadata, (tmp_table_param.field_count * 2)); + for (unsigned int i= 0 ; i < tmp_table_param.field_count ; i++) + { + metadata_index+= tmp_table->field[i]->save_field_metadata(&field_metadata[metadata_index]); + } + + if (metadata_index < 251) + field_metadata_size += metadata_index + 1; + else + field_metadata_size += metadata_index + 3; + + bzero(null_bits, num_null_bytes); + for (unsigned int i= 0 ; i < tmp_table_param.field_count ; ++i) { + if (tmp_table->field[i]->maybe_null()) { + null_bits[(i / 8)]+= 1 << (i % 8); + } + } + + free_tmp_table(thd, tmp_table); +err: + return field_metadata_size; +} + + +/*@brief create_clustrixdb_select_handler- Creates handler*/ +/************************************************************ + * DESCRIPTION: + * Creates a select handler + * More details in server/sql/select_handler.h + * PARAMETERS: + * thd - THD pointer. + * sel - SELECT_LEX* that describes the query. + * RETURN: + * select_handler if possible + * NULL otherwise + ************************************************************/ +static select_handler* +create_clustrixdb_select_handler(THD* thd, SELECT_LEX* select_lex) +{ + ha_clustrixdb_select_handler *sh = NULL; + String query; + // Print the query into a string provided + select_lex->print(thd, &query, QT_ORDINARY); + int error_code = 0; + clustrix_connection *clustrix_net = NULL; + int field_metadata_size = 0; + ulonglong scan_refid = 0; + + // We presume this number is equal to types.elements in get_field_types + uint items_number = select_lex->get_item_list()->elements; + uint num_null_bytes = (items_number + 7) / 8; + uchar *fieldtype = NULL; + uchar *null_bits = NULL; + uchar *field_metadata = NULL; + uchar *meta_memory= (uchar *)my_multi_malloc(MYF(MY_WME), &fieldtype, items_number, + &null_bits, num_null_bytes, &field_metadata, (items_number * 2), + NULL); + + if (!meta_memory) { + // The only way to say something here is to raise warning + // b/c we will fallback to other access methods: derived handler or rowstore. + goto err; + } + + if((field_metadata_size = + get_field_types(thd, select_lex, fieldtype, field_metadata, null_bits, num_null_bytes)) < 0) { + goto err; + } + // Use buffers filled by get_field_types here. + + // WIP reuse the connections + clustrix_net = new clustrix_connection(); + error_code = clustrix_net->connect(); + if (error_code) + goto err; + + if ((error_code = clustrix_net->scan_query_init(query, fieldtype, items_number, + null_bits, num_null_bytes, field_metadata, field_metadata_size, &scan_refid))) { + goto err; + } + + sh = new ha_clustrixdb_select_handler(thd, select_lex, clustrix_net); + +err: + // reuse the connection + if (!sh) + delete clustrix_net; + // deallocate buffers + if (meta_memory) + my_free(meta_memory); + + return sh; +} + +/*********************************************************** + * DESCRIPTION: + * select_handler constructor + * PARAMETERS: + * thd - THD pointer. + * select_lex - sematic tree for the query. + **********************************************************/ +ha_clustrixdb_select_handler::ha_clustrixdb_select_handler( + THD *thd, + SELECT_LEX* select_lex, + clustrix_connection* clustrix_net) + : select_handler(thd, clustrixdb_hton), clustrix_net(clustrix_net) +{ + select = select_lex; +} + +/*********************************************************** + * DESCRIPTION: + * select_handler constructor + **********************************************************/ +ha_clustrixdb_select_handler::~ha_clustrixdb_select_handler() +{ + if (clustrix_net) + delete clustrix_net; +} + +/*@brief Initiate the query for select_handler */ +/*********************************************************** + * DESCRIPTION: + * Does nothing ATM. + * * PARAMETERS: + * RETURN: + * rc as int + * ********************************************************/ +int ha_clustrixdb_select_handler::init_scan() +{ + return 0; +} + +/*@brief Fetch next row for select_handler */ +/*********************************************************** + * DESCRIPTION: + * Fetch next row for select_handler. + * PARAMETERS: + * RETURN: + * rc as int + * ********************************************************/ +int ha_clustrixdb_select_handler::next_row() +{ + int error_code = 0; + THD *thd = ha_thd(); + st_clustrixdb_trx *trx = get_trx(thd, &error_code); + if (!trx) + return error_code; + + assert(is_scan); + assert(scan_refid); + + uchar *rowdata; + ulong rowdata_length; + if ((error_code = trx->clustrix_net->scan_next(scan_refid, &rowdata, + &rowdata_length))) + return error_code; + + if (has_hidden_key) { + last_hidden_key = *(ulonglong *)rowdata; + rowdata += 8; + rowdata_length -= 8; + } + + uchar const *current_row_end; + ulong master_reclength; + + error_code = unpack_row(rgi, table, table->s->fields, rowdata, + &scan_fields, ¤t_row_end, + &master_reclength, rowdata + rowdata_length); + + if (error_code) + return error_code; + + return 0; + + //return HA_ERR_END_OF_FILE; +} + +/*@brief Finishes the scan and clean it up */ +/*********************************************************** + * DESCRIPTION: + * Finishes the scan for select handler + * ATM this function sets vtable_state and restores it + * afterwards since it reuses existed vtable code internally. + * PARAMETERS: + * RETURN: + * rc as int + ***********************************************************/ +int ha_clustrixdb_select_handler::end_scan() +{ +/* + int error_code = 0; + THD *thd = ha_thd(); + st_clustrixdb_trx *trx = get_trx(thd, &error_code); + if (!trx) + return error_code; + + my_bitmap_free(&scan_fields); + if (scan_refid && (error_code = trx->clustrix_net->scan_end(scan_refid))) + return error_code; + scan_refid = 0; + + return 0; +*/ + return 0; +} + +void ha_clustrixdb_select_handler::print_error(int, unsigned long) +{ +} diff --git a/storage/clustrixdb/ha_clustrixdb_pushdown.h b/storage/clustrixdb/ha_clustrixdb_pushdown.h new file mode 100644 index 00000000000..90ac89914b5 --- /dev/null +++ b/storage/clustrixdb/ha_clustrixdb_pushdown.h @@ -0,0 +1,42 @@ +/***************************************************************************** +Copyright (c) 2019, MariaDB Corporation. +*****************************************************************************/ +#ifndef _ha_clustrixdb_pushdown_h +#define _ha_clustrixdb_pushdown_h + +#include "select_handler.h" +#include "sql_select.h" + +/*@brief select_handler class*/ +/*********************************************************** + * DESCRIPTION: + * select_handler API methods. Could be used by the server + * tp pushdown the whole query described by SELECT_LEX. + * More details in server/sql/select_handler.h + * sel in the constructor is the semantic tree for the query. + * Methods: + * init_scan - get plan and send it to ExeMgr. Get the execution result. + * next_row - get a row back from sm. + * end_scan - finish and clean the things up. + ************************************************************/ +class ha_clustrixdb_select_handler: public select_handler +{ + public: + ha_clustrixdb_select_handler(THD* thd_arg, SELECT_LEX* sel, + clustrix_connection* clustrix_net); + ~ha_clustrixdb_select_handler(); + + int init_scan(); + int next_row(); + int end_scan(); + void print_error(int, unsigned long); + + private: + clustrix_connection *clustrix_net; + rpl_group_info *rgi; + ulonglong scan_refid; + bool has_hidden_key; + +}; + +#endif -- cgit v1.2.1 From d759acc16f8678c3ed974de0568c5ccaf48d7587 Mon Sep 17 00:00:00 2001 From: Roman Nozdrin Date: Mon, 24 Jun 2019 23:31:41 +0000 Subject: CLX-5 Add infrastructure to unpack RBR rows recieved from CX backend. Add a knob to disable Select handler. --- storage/clustrixdb/ha_clustrixdb.cc | 64 ++++++++------ storage/clustrixdb/ha_clustrixdb.h | 4 +- storage/clustrixdb/ha_clustrixdb_pushdown.cc | 122 ++++++++++++++++++++++----- storage/clustrixdb/ha_clustrixdb_pushdown.h | 15 ++-- 4 files changed, 149 insertions(+), 56 deletions(-) diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index 208a138ef53..c5c9d547bd2 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -5,7 +5,6 @@ Copyright (c) 2019, MariaDB Corporation. /** @file ha_clustrixdb.cc */ #include "ha_clustrixdb.h" -#include "ha_clustrixdb_pushdown.h" #include "key.h" handlerton *clustrixdb_hton = NULL; @@ -90,10 +89,26 @@ static MYSQL_SYSVAR_STR NULL, NULL, "" ); +// Per thread select handler knob +static MYSQL_THDVAR_BOOL( + enable_sh, + PLUGIN_VAR_NOCMDARG, + "", + NULL, + NULL, + 1 +); + +bool get_enable_sh(THD* thd) +{ + return ( thd == NULL ) ? false : THDVAR(thd, enable_sh); +} + + + /**************************************************************************** ** Class ha_clustrixdb_trx ****************************************************************************/ - st_clustrixdb_trx::st_clustrixdb_trx(THD *trx_thd) { thd = trx_thd; @@ -178,6 +193,27 @@ void decode_objectname(char *buf, const char *path, size_t buf_size) buf[new_path_len] = '\0'; } +st_clustrixdb_trx *get_trx(THD *thd, int *error_code) +{ + *error_code = 0; + st_clustrixdb_trx *trx; + if (!(trx = (st_clustrixdb_trx *)thd_get_ha_data(thd, clustrixdb_hton))) + { + if (!(trx = new st_clustrixdb_trx(thd))) { + *error_code = HA_ERR_OUT_OF_MEM; + return NULL; + } + + if ((*error_code = trx->net_init())) { + delete trx; + return NULL; + } + + thd_set_ha_data(thd, clustrixdb_hton, trx); + } + + return trx; +} /**************************************************************************** ** Class ha_clustrixdb ****************************************************************************/ @@ -322,6 +358,7 @@ int ha_clustrixdb::open(const char *name, int mode, uint test_if_locked) if (!clustrix_table_oid) clustrix_table_oid = atoll((const char *)table->s->tabledef_version.str); + // Surrogate key marker has_hidden_key = table->s->primary_key == MAX_KEY; if (has_hidden_key) { ref_length = 8; @@ -915,28 +952,6 @@ void ha_clustrixdb::remove_current_table_from_rpl_table_list() delete rgi; } -st_clustrixdb_trx *ha_clustrixdb::get_trx(THD *thd, int *error_code) -{ - *error_code = 0; - st_clustrixdb_trx *trx; - if (!(trx = (st_clustrixdb_trx *)thd_get_ha_data(thd, clustrixdb_hton))) - { - if (!(trx = new st_clustrixdb_trx(thd))) { - *error_code = HA_ERR_OUT_OF_MEM; - return NULL; - } - - if ((*error_code = trx->net_init())) { - delete trx; - return NULL; - } - - thd_set_ha_data(thd, clustrixdb_hton, trx); - } - - return trx; -} - void ha_clustrixdb::build_key_packed_row(uint index, uchar *packed_key, size_t *packed_key_len) { @@ -1088,6 +1103,7 @@ static struct st_mysql_sys_var* clustrixdb_system_variables[] = MYSQL_SYSVAR(password), MYSQL_SYSVAR(port), MYSQL_SYSVAR(socket), + MYSQL_SYSVAR(enable_sh), NULL }; diff --git a/storage/clustrixdb/ha_clustrixdb.h b/storage/clustrixdb/ha_clustrixdb.h index 45a81203aba..15311772bfe 100644 --- a/storage/clustrixdb/ha_clustrixdb.h +++ b/storage/clustrixdb/ha_clustrixdb.h @@ -21,6 +21,9 @@ Copyright (c) 2019, MariaDB Corporation. #include "../../sql/rpl_record.h" size_t estimate_row_size(TABLE *table); +class st_clustrixdb_trx; +st_clustrixdb_trx *get_trx(THD *thd, int *error_code); +bool get_enable_sh(THD* thd); class ha_clustrixdb; @@ -117,7 +120,6 @@ public: int info_push(uint info_type, void *info); private: - st_clustrixdb_trx *get_trx(THD *thd, int *error_code); void add_current_table_to_rpl_table_list(); void remove_current_table_from_rpl_table_list(); void build_key_packed_row(uint index, uchar *packed_key, diff --git a/storage/clustrixdb/ha_clustrixdb_pushdown.cc b/storage/clustrixdb/ha_clustrixdb_pushdown.cc index 0451ce9f9c6..5fe7d114845 100644 --- a/storage/clustrixdb/ha_clustrixdb_pushdown.cc +++ b/storage/clustrixdb/ha_clustrixdb_pushdown.cc @@ -89,6 +89,10 @@ static select_handler* create_clustrixdb_select_handler(THD* thd, SELECT_LEX* select_lex) { ha_clustrixdb_select_handler *sh = NULL; + if (!get_enable_sh(thd)) { + return sh; + } + String query; // Print the query into a string provided select_lex->print(thd, &query, QT_ORDINARY); @@ -127,10 +131,10 @@ create_clustrixdb_select_handler(THD* thd, SELECT_LEX* select_lex) if ((error_code = clustrix_net->scan_query_init(query, fieldtype, items_number, null_bits, num_null_bytes, field_metadata, field_metadata_size, &scan_refid))) { - goto err; + //goto err; } - sh = new ha_clustrixdb_select_handler(thd, select_lex, clustrix_net); + sh = new ha_clustrixdb_select_handler(thd, select_lex, clustrix_net, scan_refid); err: // reuse the connection @@ -153,10 +157,15 @@ err: ha_clustrixdb_select_handler::ha_clustrixdb_select_handler( THD *thd, SELECT_LEX* select_lex, - clustrix_connection* clustrix_net) - : select_handler(thd, clustrixdb_hton), clustrix_net(clustrix_net) + clustrix_connection* clustrix_net_, + ulonglong scan_refid_) + : select_handler(thd, clustrixdb_hton), clustrix_net(clustrix_net_), + scan_refid(scan_refid_) { select = select_lex; + rli = NULL; + rgi = NULL; + scan_refid = 0; } /*********************************************************** @@ -165,6 +174,9 @@ ha_clustrixdb_select_handler::ha_clustrixdb_select_handler( **********************************************************/ ha_clustrixdb_select_handler::~ha_clustrixdb_select_handler() { + remove_current_table_from_rpl_table_list(); + + // WIP reuse the connection if (clustrix_net) delete clustrix_net; } @@ -178,8 +190,16 @@ ha_clustrixdb_select_handler::~ha_clustrixdb_select_handler() * rc as int * ********************************************************/ int ha_clustrixdb_select_handler::init_scan() -{ - return 0; +{ + // need this bitmap future in next_row() + // WIP look whether table->read_set->n_bits is valid or not + if (my_bitmap_init(&scan_fields, NULL, table->read_set->n_bits, false)) + return ER_OUTOFMEMORY; + bitmap_set_all(&scan_fields); + + add_current_table_to_rpl_table_list(); + + return 0; } /*@brief Fetch next row for select_handler */ @@ -193,12 +213,10 @@ int ha_clustrixdb_select_handler::init_scan() int ha_clustrixdb_select_handler::next_row() { int error_code = 0; - THD *thd = ha_thd(); st_clustrixdb_trx *trx = get_trx(thd, &error_code); if (!trx) return error_code; - assert(is_scan); assert(scan_refid); uchar *rowdata; @@ -207,12 +225,6 @@ int ha_clustrixdb_select_handler::next_row() &rowdata_length))) return error_code; - if (has_hidden_key) { - last_hidden_key = *(ulonglong *)rowdata; - rowdata += 8; - rowdata_length -= 8; - } - uchar const *current_row_end; ulong master_reclength; @@ -225,24 +237,20 @@ int ha_clustrixdb_select_handler::next_row() return 0; - //return HA_ERR_END_OF_FILE; + //return HA_ERR_END_OF_FILE; } /*@brief Finishes the scan and clean it up */ /*********************************************************** * DESCRIPTION: * Finishes the scan for select handler - * ATM this function sets vtable_state and restores it - * afterwards since it reuses existed vtable code internally. * PARAMETERS: * RETURN: * rc as int ***********************************************************/ int ha_clustrixdb_select_handler::end_scan() { -/* int error_code = 0; - THD *thd = ha_thd(); st_clustrixdb_trx *trx = get_trx(thd, &error_code); if (!trx) return error_code; @@ -250,13 +258,81 @@ int ha_clustrixdb_select_handler::end_scan() my_bitmap_free(&scan_fields); if (scan_refid && (error_code = trx->clustrix_net->scan_end(scan_refid))) return error_code; - scan_refid = 0; - return 0; -*/ - return 0; + return error_code; } void ha_clustrixdb_select_handler::print_error(int, unsigned long) { } + +/*@brief clone of ha_clustrixdb method */ +/*********************************************************** + * DESCRIPTION: + * Creates structures to unpack RBR rows in ::next_row() + * PARAMETERS: + * RETURN: + * rc as int + ***********************************************************/ +void ha_clustrixdb_select_handler::add_current_table_to_rpl_table_list() +{ + if (rli) + return; + + rli = new Relay_log_info(FALSE); + rli->sql_driver_thd = thd; + + rgi = new rpl_group_info(rli); + rgi->thd = thd; + rgi->tables_to_lock_count = 0; + rgi->tables_to_lock = NULL; + if (rgi->tables_to_lock_count) + return; + + rgi->tables_to_lock = (RPL_TABLE_LIST *)my_malloc(sizeof(RPL_TABLE_LIST), + MYF(MY_WME)); + rgi->tables_to_lock->init_one_table(&table->s->db, &table->s->table_name, 0, + TL_READ); + rgi->tables_to_lock->table = table; + rgi->tables_to_lock->table_id = table->tablenr; + rgi->tables_to_lock->m_conv_table = NULL; + rgi->tables_to_lock->master_had_triggers = FALSE; + rgi->tables_to_lock->m_tabledef_valid = TRUE; + // We need one byte per column to save a column's binlog type. + uchar *col_type = (uchar*) my_alloca(table->s->fields); + for (uint i = 0 ; i < table->s->fields ; ++i) + col_type[i] = table->field[i]->binlog_type(); + + table_def *tabledef = &rgi->tables_to_lock->m_tabledef; + new (tabledef) table_def(col_type, table->s->fields, NULL, 0, NULL, 0); + rgi->tables_to_lock_count++; + if (col_type) + my_afree(col_type); +} + +/*@brief clone of ha_clustrixdb method */ +/*********************************************************** + * DESCRIPTION: + * Deletes structures that are used to unpack RBR rows + * in ::next_row(). Called from dtor + * PARAMETERS: + * RETURN: + * rc as int + ***********************************************************/ +void ha_clustrixdb_select_handler::remove_current_table_from_rpl_table_list() +{ + // the 2nd cond might be unnecessary + if (!rgi || !rgi->tables_to_lock) + return; + + rgi->tables_to_lock->m_tabledef.table_def::~table_def(); + rgi->tables_to_lock->m_tabledef_valid = FALSE; + my_free(rgi->tables_to_lock); + rgi->tables_to_lock_count--; + rgi->tables_to_lock = NULL; + delete rli; + delete rgi; +} + + + diff --git a/storage/clustrixdb/ha_clustrixdb_pushdown.h b/storage/clustrixdb/ha_clustrixdb_pushdown.h index 90ac89914b5..6e7aef162fc 100644 --- a/storage/clustrixdb/ha_clustrixdb_pushdown.h +++ b/storage/clustrixdb/ha_clustrixdb_pushdown.h @@ -13,17 +13,13 @@ Copyright (c) 2019, MariaDB Corporation. * select_handler API methods. Could be used by the server * tp pushdown the whole query described by SELECT_LEX. * More details in server/sql/select_handler.h - * sel in the constructor is the semantic tree for the query. - * Methods: - * init_scan - get plan and send it to ExeMgr. Get the execution result. - * next_row - get a row back from sm. - * end_scan - finish and clean the things up. + * sel semantic tree for the query in SELECT_LEX. ************************************************************/ class ha_clustrixdb_select_handler: public select_handler { public: ha_clustrixdb_select_handler(THD* thd_arg, SELECT_LEX* sel, - clustrix_connection* clustrix_net); + clustrix_connection* clustrix_net, ulonglong scan_refid); ~ha_clustrixdb_select_handler(); int init_scan(); @@ -31,12 +27,15 @@ class ha_clustrixdb_select_handler: public select_handler int end_scan(); void print_error(int, unsigned long); + MY_BITMAP scan_fields; private: clustrix_connection *clustrix_net; rpl_group_info *rgi; + Relay_log_info *rli; + RPL_TABLE_LIST *rpl_table_list; ulonglong scan_refid; - bool has_hidden_key; - + void add_current_table_to_rpl_table_list(); + void remove_current_table_from_rpl_table_list(); }; #endif -- cgit v1.2.1 From 6da15be8cfd2da63f8bd824ee442dc3f31f199a4 Mon Sep 17 00:00:00 2001 From: Roman Nozdrin Date: Thu, 27 Jun 2019 00:59:22 +0000 Subject: CLX-5 Simple SELECT/EXPLAIN works with select handler. --- storage/clustrixdb/clustrix_connection.cc | 6 +-- storage/clustrixdb/ha_clustrixdb_pushdown.cc | 59 +++++++++++----------------- storage/clustrixdb/ha_clustrixdb_pushdown.h | 9 +++-- 3 files changed, 32 insertions(+), 42 deletions(-) diff --git a/storage/clustrixdb/clustrix_connection.cc b/storage/clustrixdb/clustrix_connection.cc index f5782a7b6ee..99d2b6fd7a8 100644 --- a/storage/clustrixdb/clustrix_connection.cc +++ b/storage/clustrixdb/clustrix_connection.cc @@ -362,6 +362,9 @@ int clustrix_connection::scan_query_init(String &stmt, uchar *fieldtype, if ((error_code = add_command_operand_uchar(CLUSTRIX_QUERY_INIT))) return error_code; + if ((error_code = add_command_operand_str((uchar*)stmt.ptr(), stmt.length()))) + return error_code; + if ((error_code = add_command_operand_str(fieldtype, fields))) return error_code; @@ -372,9 +375,6 @@ int clustrix_connection::scan_query_init(String &stmt, uchar *fieldtype, if ((error_code = add_command_operand_vlstr(null_bits, null_bits_size))) return error_code; - if ((error_code = add_command_operand_str((uchar*)stmt.ptr(), stmt.length()))) - return error_code; - if ((error_code = send_command())) return error_code; diff --git a/storage/clustrixdb/ha_clustrixdb_pushdown.cc b/storage/clustrixdb/ha_clustrixdb_pushdown.cc index 5fe7d114845..4d9249d0281 100644 --- a/storage/clustrixdb/ha_clustrixdb_pushdown.cc +++ b/storage/clustrixdb/ha_clustrixdb_pushdown.cc @@ -97,9 +97,9 @@ create_clustrixdb_select_handler(THD* thd, SELECT_LEX* select_lex) // Print the query into a string provided select_lex->print(thd, &query, QT_ORDINARY); int error_code = 0; - clustrix_connection *clustrix_net = NULL; int field_metadata_size = 0; ulonglong scan_refid = 0; + st_clustrixdb_trx *trx = 0; // We presume this number is equal to types.elements in get_field_types uint items_number = select_lex->get_item_list()->elements; @@ -108,8 +108,7 @@ create_clustrixdb_select_handler(THD* thd, SELECT_LEX* select_lex) uchar *null_bits = NULL; uchar *field_metadata = NULL; uchar *meta_memory= (uchar *)my_multi_malloc(MYF(MY_WME), &fieldtype, items_number, - &null_bits, num_null_bytes, &field_metadata, (items_number * 2), - NULL); + &null_bits, num_null_bytes, &field_metadata, (items_number * 2), NULL); if (!meta_memory) { // The only way to say something here is to raise warning @@ -121,25 +120,19 @@ create_clustrixdb_select_handler(THD* thd, SELECT_LEX* select_lex) get_field_types(thd, select_lex, fieldtype, field_metadata, null_bits, num_null_bytes)) < 0) { goto err; } - // Use buffers filled by get_field_types here. - // WIP reuse the connections - clustrix_net = new clustrix_connection(); - error_code = clustrix_net->connect(); - if (error_code) + trx = get_trx(thd, &error_code); + if (!trx) goto err; - if ((error_code = clustrix_net->scan_query_init(query, fieldtype, items_number, + if ((error_code = trx->clustrix_net->scan_query_init(query, fieldtype, items_number, null_bits, num_null_bytes, field_metadata, field_metadata_size, &scan_refid))) { - //goto err; + goto err; } - sh = new ha_clustrixdb_select_handler(thd, select_lex, clustrix_net, scan_refid); + sh = new ha_clustrixdb_select_handler(thd, select_lex, scan_refid); err: - // reuse the connection - if (!sh) - delete clustrix_net; // deallocate buffers if (meta_memory) my_free(meta_memory); @@ -157,34 +150,40 @@ err: ha_clustrixdb_select_handler::ha_clustrixdb_select_handler( THD *thd, SELECT_LEX* select_lex, - clustrix_connection* clustrix_net_, ulonglong scan_refid_) - : select_handler(thd, clustrixdb_hton), clustrix_net(clustrix_net_), - scan_refid(scan_refid_) + : select_handler(thd, clustrixdb_hton), scan_refid(scan_refid_) { select = select_lex; rli = NULL; rgi = NULL; - scan_refid = 0; } /*********************************************************** * DESCRIPTION: * select_handler constructor + * This frees dynamic memory allocated for bitmap + * and disables replication to SH temp table. **********************************************************/ ha_clustrixdb_select_handler::~ha_clustrixdb_select_handler() { - remove_current_table_from_rpl_table_list(); + int error_code; + st_clustrixdb_trx *trx = get_trx(thd, &error_code); + if (!trx) { + // WIP BANG + } + if (scan_refid) + trx->clustrix_net->scan_end(scan_refid); + + my_bitmap_free(&scan_fields); - // WIP reuse the connection - if (clustrix_net) - delete clustrix_net; + remove_current_table_from_rpl_table_list(); } /*@brief Initiate the query for select_handler */ /*********************************************************** * DESCRIPTION: - * Does nothing ATM. + * Initializes dynamic structures and sets SH temp table + * as RBR replication destination to unpack rows. * * PARAMETERS: * RETURN: * rc as int @@ -192,7 +191,6 @@ ha_clustrixdb_select_handler::~ha_clustrixdb_select_handler() int ha_clustrixdb_select_handler::init_scan() { // need this bitmap future in next_row() - // WIP look whether table->read_set->n_bits is valid or not if (my_bitmap_init(&scan_fields, NULL, table->read_set->n_bits, false)) return ER_OUTOFMEMORY; bitmap_set_all(&scan_fields); @@ -236,8 +234,6 @@ int ha_clustrixdb_select_handler::next_row() return error_code; return 0; - - //return HA_ERR_END_OF_FILE; } /*@brief Finishes the scan and clean it up */ @@ -250,16 +246,7 @@ int ha_clustrixdb_select_handler::next_row() ***********************************************************/ int ha_clustrixdb_select_handler::end_scan() { - int error_code = 0; - st_clustrixdb_trx *trx = get_trx(thd, &error_code); - if (!trx) - return error_code; - - my_bitmap_free(&scan_fields); - if (scan_refid && (error_code = trx->clustrix_net->scan_end(scan_refid))) - return error_code; - - return error_code; + return 0; } void ha_clustrixdb_select_handler::print_error(int, unsigned long) diff --git a/storage/clustrixdb/ha_clustrixdb_pushdown.h b/storage/clustrixdb/ha_clustrixdb_pushdown.h index 6e7aef162fc..36a3bd4c8ac 100644 --- a/storage/clustrixdb/ha_clustrixdb_pushdown.h +++ b/storage/clustrixdb/ha_clustrixdb_pushdown.h @@ -19,7 +19,7 @@ class ha_clustrixdb_select_handler: public select_handler { public: ha_clustrixdb_select_handler(THD* thd_arg, SELECT_LEX* sel, - clustrix_connection* clustrix_net, ulonglong scan_refid); + ulonglong scan_refid); ~ha_clustrixdb_select_handler(); int init_scan(); @@ -27,13 +27,16 @@ class ha_clustrixdb_select_handler: public select_handler int end_scan(); void print_error(int, unsigned long); - MY_BITMAP scan_fields; private: - clustrix_connection *clustrix_net; + // The bitmap used to sent + MY_BITMAP scan_fields; + // Structures to unpack RBR rows from CLX BE rpl_group_info *rgi; Relay_log_info *rli; RPL_TABLE_LIST *rpl_table_list; + // CLX BE scan operation reference ulonglong scan_refid; + // To unpack rows from CLX BE void add_current_table_to_rpl_table_list(); void remove_current_table_from_rpl_table_list(); }; -- cgit v1.2.1 From 8f3d1f60506a7cdd091505ea427248f5796f5090 Mon Sep 17 00:00:00 2001 From: Roman Nozdrin Date: Sun, 30 Jun 2019 21:33:31 +0000 Subject: CLX-5 Changes in the basic MTR test. Removed unused code. --- mysql-test/suite/clustrixdb/basics.result | 8 ++++++-- storage/clustrixdb/clustrix_connection.cc | 11 ----------- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/mysql-test/suite/clustrixdb/basics.result b/mysql-test/suite/clustrixdb/basics.result index ed6501643f0..19f51315713 100644 --- a/mysql-test/suite/clustrixdb/basics.result +++ b/mysql-test/suite/clustrixdb/basics.result @@ -1,6 +1,8 @@ +CREATE DATABASE clx; +USE clx; DROP TABLE IF EXISTS cx1; Warnings: -Note 1051 Unknown table 'test.cx1' +Note 1051 Unknown table 'clx.cx1' CREATE TABLE cx1(i BIGINT)ENGINE=clustrixdb; CREATE TABLE cx1(i BIGINT)ENGINE=clustrixdb; ERROR 42S01: Table 'cx1' already exists @@ -10,4 +12,6 @@ i 42 DROP TABLE cx1; SHOW CREATE TABLE cx1; -ERROR 42S02: Table 'test.cx1' doesn't exist +ERROR 42S02: Table 'clx.cx1' doesn't exist +USE test; +DROP DATABASE clx; diff --git a/storage/clustrixdb/clustrix_connection.cc b/storage/clustrixdb/clustrix_connection.cc index 99d2b6fd7a8..d49eb553ee9 100644 --- a/storage/clustrixdb/clustrix_connection.cc +++ b/storage/clustrixdb/clustrix_connection.cc @@ -323,17 +323,6 @@ int clustrix_connection::scan_init(ulonglong clustrix_table_oid, uint index, return error_code; } -/*int clustrix_connection::scan_init_select(String &stmt) -{ - int error_code = mysql_real_query(&clustrix_net, stmt.ptr(), stmt.length()); - if (error_code) - return mysql_errno(&clustrix_net); - - results = mysql_store_result(&clustrix_net); - - return error_code; -}*/ - /** * @brief * Sends a command to initiate query scan. -- cgit v1.2.1 From d0eeb5ccd82495846b595416029b0071473e668f Mon Sep 17 00:00:00 2001 From: Roman Nozdrin Date: Sun, 30 Jun 2019 23:13:49 +0000 Subject: CLX-7 Introduce derived handler support. Renamed select handler control knob. Updated test suite. --- mysql-test/suite/clustrixdb/basics.result | Bin 394 -> 1732 bytes mysql-test/suite/clustrixdb/basics.test | 19 +++ storage/clustrixdb/ha_clustrixdb.cc | 24 ++- storage/clustrixdb/ha_clustrixdb_pushdown.cc | 226 ++++++++++++++++++++++++--- storage/clustrixdb/ha_clustrixdb_pushdown.h | 72 +++++++-- 5 files changed, 301 insertions(+), 40 deletions(-) diff --git a/mysql-test/suite/clustrixdb/basics.result b/mysql-test/suite/clustrixdb/basics.result index 19f51315713..20a158f69c9 100644 Binary files a/mysql-test/suite/clustrixdb/basics.result and b/mysql-test/suite/clustrixdb/basics.result differ diff --git a/mysql-test/suite/clustrixdb/basics.test b/mysql-test/suite/clustrixdb/basics.test index 487295d57db..e5c7ae355c5 100644 --- a/mysql-test/suite/clustrixdb/basics.test +++ b/mysql-test/suite/clustrixdb/basics.test @@ -15,5 +15,24 @@ DROP TABLE cx1; --error ER_NO_SUCH_TABLE SHOW CREATE TABLE cx1; +DROP TABLE IF EXISTS intandtext; +CREATE TABLE intandtext(i bigint, t text)ENGINE=clustrixdb; +INSERT INTO intandtext VALUES(10, 'someqwqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq'); + +SELECT i,t FROM intandtext; + +EXPLAIN SELECT i,t FROM intandtext; +SET clustrixdb_select_handler=OFF; + +SELECT i,t FROM (SELECT i,t FROM intandtext) t; +EXPLAIN SELECT i,t FROM (SELECT i,t FROM intandtext) t; +SET clustrixdb_select_handler=OFF; + +SELECT i,t FROM intandtext; +SELECT i,t FROM (SELECT i,t FROM intandtext) t; +EXPLAIN SELECT i,t FROM (SELECT i,t FROM intandtext) t; + +DROP TABLE intandtext; + USE test; DROP DATABASE clx; diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index c5c9d547bd2..74494f6db97 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -91,7 +91,16 @@ static MYSQL_SYSVAR_STR // Per thread select handler knob static MYSQL_THDVAR_BOOL( - enable_sh, + select_handler, + PLUGIN_VAR_NOCMDARG, + "", + NULL, + NULL, + 1 +); +// Per thread derived handler knob +static MYSQL_THDVAR_BOOL( + derived_handler, PLUGIN_VAR_NOCMDARG, "", NULL, @@ -99,12 +108,15 @@ static MYSQL_THDVAR_BOOL( 1 ); -bool get_enable_sh(THD* thd) +bool select_handler_setting(THD* thd) { - return ( thd == NULL ) ? false : THDVAR(thd, enable_sh); + return ( thd == NULL ) ? false : THDVAR(thd, select_handler); } - +bool derived_handler_setting(THD* thd) +{ + return ( thd == NULL ) ? false : THDVAR(thd, derived_handler); +} /**************************************************************************** ** Class ha_clustrixdb_trx @@ -1084,6 +1096,7 @@ static int clustrixdb_init(void *p) clustrixdb_hton->discover_table_names = clustrixdb_discover_table_names; clustrixdb_hton->discover_table = clustrixdb_discover_table; clustrixdb_hton->create_select = create_clustrixdb_select_handler; + clustrixdb_hton->create_derived = create_clustrixdb_derived_handler; return 0; } @@ -1103,7 +1116,8 @@ static struct st_mysql_sys_var* clustrixdb_system_variables[] = MYSQL_SYSVAR(password), MYSQL_SYSVAR(port), MYSQL_SYSVAR(socket), - MYSQL_SYSVAR(enable_sh), + MYSQL_SYSVAR(select_handler), + MYSQL_SYSVAR(derived_handler), NULL }; diff --git a/storage/clustrixdb/ha_clustrixdb_pushdown.cc b/storage/clustrixdb/ha_clustrixdb_pushdown.cc index 4d9249d0281..902d45db401 100644 --- a/storage/clustrixdb/ha_clustrixdb_pushdown.cc +++ b/storage/clustrixdb/ha_clustrixdb_pushdown.cc @@ -89,7 +89,7 @@ static select_handler* create_clustrixdb_select_handler(THD* thd, SELECT_LEX* select_lex) { ha_clustrixdb_select_handler *sh = NULL; - if (!get_enable_sh(thd)) { + if (!select_handler_setting(thd)) { return sh; } @@ -151,8 +151,10 @@ ha_clustrixdb_select_handler::ha_clustrixdb_select_handler( THD *thd, SELECT_LEX* select_lex, ulonglong scan_refid_) - : select_handler(thd, clustrixdb_hton), scan_refid(scan_refid_) + : select_handler(thd, clustrixdb_hton) { + thd__ = thd; + scan_refid = scan_refid_; select = select_lex; rli = NULL; rgi = NULL; @@ -169,12 +171,14 @@ ha_clustrixdb_select_handler::~ha_clustrixdb_select_handler() int error_code; st_clustrixdb_trx *trx = get_trx(thd, &error_code); if (!trx) { - // WIP BANG + // TBD Log this } - if (scan_refid) + if (trx && scan_refid) trx->clustrix_net->scan_end(scan_refid); - my_bitmap_free(&scan_fields); + // If the ::init_scan has been executed + if (table__) + my_bitmap_free(&scan_fields); remove_current_table_from_rpl_table_list(); } @@ -189,7 +193,9 @@ ha_clustrixdb_select_handler::~ha_clustrixdb_select_handler() * rc as int * ********************************************************/ int ha_clustrixdb_select_handler::init_scan() -{ +{ + // Save this into the base handler class attribute + table__ = table; // need this bitmap future in next_row() if (my_bitmap_init(&scan_fields, NULL, table->read_set->n_bits, false)) return ER_OUTOFMEMORY; @@ -249,8 +255,189 @@ int ha_clustrixdb_select_handler::end_scan() return 0; } -void ha_clustrixdb_select_handler::print_error(int, unsigned long) +/*@brief create_clustrixdb_derived_handler- Creates handler*/ +/************************************************************ + * DESCRIPTION: + * Creates a derived handler + * More details in server/sql/derived_handler.h + * PARAMETERS: + * thd - THD pointer. + * derived - TABLE_LIST* that describes the tables involved + * RETURN: + * derived_handler if possible + * NULL otherwise + ************************************************************/ +static derived_handler* +create_clustrixdb_derived_handler(THD* thd, TABLE_LIST *derived) +{ + ha_clustrixdb_derived_handler *dh = NULL; + if (!derived_handler_setting(thd)) { + return dh; + } + + SELECT_LEX_UNIT *unit= derived->derived; + // *DRRTUY Check for potential UNIONS in derived + SELECT_LEX *select_lex = unit->first_select(); + String query; + // Print the query into a string provided + select_lex->print(thd, &query, QT_ORDINARY); + int error_code = 0; + int field_metadata_size = 0; + ulonglong scan_refid = 0; + st_clustrixdb_trx *trx = 0; + + // We presume this number is equal to types.elements in get_field_types + uint items_number = select_lex->get_item_list()->elements; + uint num_null_bytes = (items_number + 7) / 8; + uchar *fieldtype = NULL; + uchar *null_bits = NULL; + uchar *field_metadata = NULL; + uchar *meta_memory= (uchar *)my_multi_malloc(MYF(MY_WME), &fieldtype, items_number, + &null_bits, num_null_bytes, &field_metadata, (items_number * 2), NULL); + + if (!meta_memory) { + // The only way to say something here is to raise warning + // b/c we will fallback to other access methods: derived handler or rowstore. + goto err; + } + + if((field_metadata_size = + get_field_types(thd, select_lex, fieldtype, field_metadata, null_bits, num_null_bytes)) < 0) { + goto err; + } + + trx = get_trx(thd, &error_code); + if (!trx) + goto err; + + if ((error_code = trx->clustrix_net->scan_query_init(query, fieldtype, items_number, + null_bits, num_null_bytes, field_metadata, field_metadata_size, &scan_refid))) { + goto err; + } + + dh = new ha_clustrixdb_derived_handler(thd, select_lex, scan_refid); + +err: + // deallocate buffers + if (meta_memory) + my_free(meta_memory); + + return dh; +} + +/*********************************************************** + * DESCRIPTION: + * derived_handler constructor + * PARAMETERS: + * thd - THD pointer. + * select_lex - sematic tree for the query. + **********************************************************/ +ha_clustrixdb_derived_handler::ha_clustrixdb_derived_handler( + THD *thd, + SELECT_LEX* select_lex, + ulonglong scan_refid_) + : derived_handler(thd, clustrixdb_hton) +{ + thd__ = thd; + scan_refid = scan_refid_; + select = select_lex; + rli = NULL; + rgi = NULL; +} + +/*********************************************************** + * DESCRIPTION: + * derived_handler constructor + * This frees dynamic memory allocated for bitmap + * and disables replication to SH temp table. + **********************************************************/ +ha_clustrixdb_derived_handler::~ha_clustrixdb_derived_handler() +{ + int error_code; + st_clustrixdb_trx *trx = get_trx(thd, &error_code); + if (!trx) { + // TBD Log this. + } + if (trx && scan_refid) + trx->clustrix_net->scan_end(scan_refid); + + // If the ::init_scan has been executed + if (table__) + my_bitmap_free(&scan_fields); + + remove_current_table_from_rpl_table_list(); +} + +/*@brief Initiate the query for derived_handler */ +/*********************************************************** + * DESCRIPTION: + * Initializes dynamic structures and sets SH temp table + * as RBR replication destination to unpack rows. + * * PARAMETERS: + * RETURN: + * rc as int + * ********************************************************/ +int ha_clustrixdb_derived_handler::init_scan() { + // Save this into the base handler class attribute + table__ = table; + // need this bitmap future in next_row() + if (my_bitmap_init(&scan_fields, NULL, table->read_set->n_bits, false)) + return ER_OUTOFMEMORY; + bitmap_set_all(&scan_fields); + + add_current_table_to_rpl_table_list(); + + return 0; +} + +/*@brief Fetch next row for derived_handler */ +/*********************************************************** + * DESCRIPTION: + * Fetch next row for derived_handler. + * PARAMETERS: + * RETURN: + * rc as int + * ********************************************************/ +int ha_clustrixdb_derived_handler::next_row() +{ + int error_code = 0; + st_clustrixdb_trx *trx = get_trx(thd, &error_code); + if (!trx) + return error_code; + + assert(scan_refid); + + uchar *rowdata; + ulong rowdata_length; + if ((error_code = trx->clustrix_net->scan_next(scan_refid, &rowdata, + &rowdata_length))) + return error_code; + + uchar const *current_row_end; + ulong master_reclength; + + error_code = unpack_row(rgi, table, table->s->fields, rowdata, + &scan_fields, ¤t_row_end, + &master_reclength, rowdata + rowdata_length); + + if (error_code) + return error_code; + + return 0; +} + +/*@brief Finishes the scan and clean it up */ +/*********************************************************** + * DESCRIPTION: + * Finishes the scan for derived handler + * PARAMETERS: + * RETURN: + * rc as int + ***********************************************************/ +int ha_clustrixdb_derived_handler::end_scan() +{ + return 0; } /*@brief clone of ha_clustrixdb method */ @@ -261,16 +448,16 @@ void ha_clustrixdb_select_handler::print_error(int, unsigned long) * RETURN: * rc as int ***********************************************************/ -void ha_clustrixdb_select_handler::add_current_table_to_rpl_table_list() +void ha_clustrixdb_base_handler::add_current_table_to_rpl_table_list() { if (rli) return; rli = new Relay_log_info(FALSE); - rli->sql_driver_thd = thd; + rli->sql_driver_thd = thd__; rgi = new rpl_group_info(rli); - rgi->thd = thd; + rgi->thd = thd__; rgi->tables_to_lock_count = 0; rgi->tables_to_lock = NULL; if (rgi->tables_to_lock_count) @@ -278,20 +465,20 @@ void ha_clustrixdb_select_handler::add_current_table_to_rpl_table_list() rgi->tables_to_lock = (RPL_TABLE_LIST *)my_malloc(sizeof(RPL_TABLE_LIST), MYF(MY_WME)); - rgi->tables_to_lock->init_one_table(&table->s->db, &table->s->table_name, 0, + rgi->tables_to_lock->init_one_table(&table__->s->db, &table__->s->table_name, 0, TL_READ); - rgi->tables_to_lock->table = table; - rgi->tables_to_lock->table_id = table->tablenr; + rgi->tables_to_lock->table = table__; + rgi->tables_to_lock->table_id = table__->tablenr; rgi->tables_to_lock->m_conv_table = NULL; rgi->tables_to_lock->master_had_triggers = FALSE; rgi->tables_to_lock->m_tabledef_valid = TRUE; // We need one byte per column to save a column's binlog type. - uchar *col_type = (uchar*) my_alloca(table->s->fields); - for (uint i = 0 ; i < table->s->fields ; ++i) - col_type[i] = table->field[i]->binlog_type(); + uchar *col_type = (uchar*) my_alloca(table__->s->fields); + for (uint i = 0 ; i < table__->s->fields ; ++i) + col_type[i] = table__->field[i]->binlog_type(); table_def *tabledef = &rgi->tables_to_lock->m_tabledef; - new (tabledef) table_def(col_type, table->s->fields, NULL, 0, NULL, 0); + new (tabledef) table_def(col_type, table__->s->fields, NULL, 0, NULL, 0); rgi->tables_to_lock_count++; if (col_type) my_afree(col_type); @@ -306,7 +493,7 @@ void ha_clustrixdb_select_handler::add_current_table_to_rpl_table_list() * RETURN: * rc as int ***********************************************************/ -void ha_clustrixdb_select_handler::remove_current_table_from_rpl_table_list() +void ha_clustrixdb_base_handler::remove_current_table_from_rpl_table_list() { // the 2nd cond might be unnecessary if (!rgi || !rgi->tables_to_lock) @@ -320,6 +507,3 @@ void ha_clustrixdb_select_handler::remove_current_table_from_rpl_table_list() delete rli; delete rgi; } - - - diff --git a/storage/clustrixdb/ha_clustrixdb_pushdown.h b/storage/clustrixdb/ha_clustrixdb_pushdown.h index 36a3bd4c8ac..20c01465655 100644 --- a/storage/clustrixdb/ha_clustrixdb_pushdown.h +++ b/storage/clustrixdb/ha_clustrixdb_pushdown.h @@ -5,8 +5,38 @@ Copyright (c) 2019, MariaDB Corporation. #define _ha_clustrixdb_pushdown_h #include "select_handler.h" +#include "derived_handler.h" #include "sql_select.h" +/*@brief base_handler class*/ +/*********************************************************** + * DESCRIPTION: + * To be described + ************************************************************/ +class ha_clustrixdb_base_handler +{ + // To simulate abstract class + protected: + ha_clustrixdb_base_handler(): thd__(0),table__(0) {} + ~ha_clustrixdb_base_handler() {} + + // Copies of pushdown handlers attributes + // to use them in shared methods. + THD *thd__; + TABLE *table__; + // The bitmap used to sent + MY_BITMAP scan_fields; + // Structures to unpack RBR rows from CLX BE + rpl_group_info *rgi; + Relay_log_info *rli; + RPL_TABLE_LIST *rpl_table_list; + // CLX BE scan operation reference + ulonglong scan_refid; + // To unpack rows from CLX BE + void add_current_table_to_rpl_table_list(); + void remove_current_table_from_rpl_table_list(); +}; + /*@brief select_handler class*/ /*********************************************************** * DESCRIPTION: @@ -15,7 +45,9 @@ Copyright (c) 2019, MariaDB Corporation. * More details in server/sql/select_handler.h * sel semantic tree for the query in SELECT_LEX. ************************************************************/ -class ha_clustrixdb_select_handler: public select_handler +class ha_clustrixdb_select_handler: + private ha_clustrixdb_base_handler, + public select_handler { public: ha_clustrixdb_select_handler(THD* thd_arg, SELECT_LEX* sel, @@ -25,20 +57,32 @@ class ha_clustrixdb_select_handler: public select_handler int init_scan(); int next_row(); int end_scan(); - void print_error(int, unsigned long); + void print_error(int, unsigned long) {} +}; - private: - // The bitmap used to sent - MY_BITMAP scan_fields; - // Structures to unpack RBR rows from CLX BE - rpl_group_info *rgi; - Relay_log_info *rli; - RPL_TABLE_LIST *rpl_table_list; - // CLX BE scan operation reference - ulonglong scan_refid; - // To unpack rows from CLX BE - void add_current_table_to_rpl_table_list(); - void remove_current_table_from_rpl_table_list(); +/*@brief derived_handler class*/ +/*********************************************************** + * DESCRIPTION: + * derived_handler API methods. Could be used by the server + * tp pushdown the whole query described by SELECT_LEX. + * More details in server/sql/derived_handler.h + * sel semantic tree for the query in SELECT_LEX. + ************************************************************/ +class ha_clustrixdb_derived_handler: + private ha_clustrixdb_base_handler, + public derived_handler +{ + public: + ha_clustrixdb_derived_handler(THD* thd_arg, SELECT_LEX* sel, + ulonglong scan_refid); + ~ha_clustrixdb_derived_handler(); + + int init_scan(); + int next_row(); + int end_scan(); + void print_error(int, unsigned long) {} }; + + #endif -- cgit v1.2.1 From 84cfedffd39af98b9c1804a03607d852dd644740 Mon Sep 17 00:00:00 2001 From: Roman Nozdrin Date: Wed, 3 Jul 2019 22:14:07 +0000 Subject: The fix for MDEV-17709 that removes hton::state attribute. --- storage/clustrixdb/ha_clustrixdb.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index 74494f6db97..9d217dc453b 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -1085,7 +1085,6 @@ int clustrixdb_discover_table(handlerton *hton, THD *thd, TABLE_SHARE *share) static int clustrixdb_init(void *p) { clustrixdb_hton = (handlerton *) p; - clustrixdb_hton->state = SHOW_OPTION_YES; clustrixdb_hton->flags = HTON_NO_FLAGS; clustrixdb_hton->panic = clustrixdb_panic; clustrixdb_hton->close_connection = clustrixdb_close_connection; -- cgit v1.2.1 From 6195a016d6e358511df9be20c28ef0d9e9f047ba Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Mon, 1 Jul 2019 18:32:34 -0700 Subject: Remove st_clustrixdb_trx. --- storage/clustrixdb/clustrix_connection.cc | 45 +++++- storage/clustrixdb/clustrix_connection.h | 17 +++ storage/clustrixdb/ha_clustrixdb.cc | 210 ++++++++++----------------- storage/clustrixdb/ha_clustrixdb.h | 20 +-- storage/clustrixdb/ha_clustrixdb_pushdown.cc | 26 ++-- 5 files changed, 146 insertions(+), 172 deletions(-) diff --git a/storage/clustrixdb/clustrix_connection.cc b/storage/clustrixdb/clustrix_connection.cc index d49eb553ee9..c1909a00aaa 100644 --- a/storage/clustrixdb/clustrix_connection.cc +++ b/storage/clustrixdb/clustrix_connection.cc @@ -154,10 +154,14 @@ int clustrix_connection::read_query_response() int clustrix_connection::begin_trans() { + if (has_transaction) + return 0; + const char *stmt = "BEGIN TRANSACTION"; int error_code = mysql_real_query(&clustrix_net, stmt, strlen(stmt)); if (error_code) return mysql_errno(&clustrix_net); + has_transaction = TRUE; return error_code; } @@ -167,6 +171,8 @@ int clustrix_connection::commit_trans() int error_code = mysql_real_query(&clustrix_net, stmt, strlen(stmt)); if (error_code) return mysql_errno(&clustrix_net); + has_transaction = FALSE; + has_statement_trans = FALSE; return error_code; } @@ -176,6 +182,41 @@ int clustrix_connection::rollback_trans() int error_code = mysql_real_query(&clustrix_net, stmt, strlen(stmt)); if (error_code) return mysql_errno(&clustrix_net); + has_transaction = FALSE; + has_statement_trans = FALSE; + return error_code; +} + +int clustrix_connection::begin_stmt_trans() +{ + if (has_statement_trans) + return 0; + + const char *stmt = "SAVEPOINT STMT_TRANS"; + int error_code = mysql_real_query(&clustrix_net, stmt, strlen(stmt)); + if (error_code) + return mysql_errno(&clustrix_net); + has_statement_trans = TRUE; + return error_code; +} + +int clustrix_connection::commit_stmt_trans() +{ + const char *stmt = "RELEASE SAVEPOINT STMT_TRANS"; + int error_code = mysql_real_query(&clustrix_net, stmt, strlen(stmt)); + if (error_code) + return mysql_errno(&clustrix_net); + has_statement_trans = FALSE; + return error_code; +} + +int clustrix_connection::rollback_stmt_trans() +{ + const char *stmt = "ROLLBACK TO STMT_TRANS"; + int error_code = mysql_real_query(&clustrix_net, stmt, strlen(stmt)); + if (error_code) + return mysql_errno(&clustrix_net); + has_statement_trans = FALSE; return error_code; } @@ -330,7 +371,7 @@ int clustrix_connection::scan_init(ulonglong clustrix_table_oid, uint index, * Sends a command over mysql protocol connection to initiate an * arbitrary query using a query text. * Uses field types, field metadata and nullability to explicitly - * cast result to expected data type. Exploits RBR TABLE_MAP_EVENT + * cast result to expected data type. Exploits RBR TABLE_MAP_EVENT * format + sends SQL text. * @args * stmt& Query text to send @@ -356,7 +397,7 @@ int clustrix_connection::scan_query_init(String &stmt, uchar *fieldtype, if ((error_code = add_command_operand_str(fieldtype, fields))) return error_code; - + if ((error_code = add_command_operand_str(field_metadata, field_metadata_size))) return error_code; diff --git a/storage/clustrixdb/clustrix_connection.h b/storage/clustrixdb/clustrix_connection.h index 87d5055ae99..b05f066edf7 100644 --- a/storage/clustrixdb/clustrix_connection.h +++ b/storage/clustrixdb/clustrix_connection.h @@ -36,12 +36,17 @@ private: uchar *reply_buffer; size_t reply_length; + bool has_transaction; + bool has_statement_trans; + public: ulonglong last_insert_id; clustrix_connection() : command_buffer(NULL), command_buffer_length(0), command_length(0) { memset(&clustrix_net, 0, sizeof(MYSQL)); + has_statement_trans = FALSE; + has_transaction = FALSE; } ~clustrix_connection() @@ -64,6 +69,18 @@ public: int begin_trans(); int commit_trans(); int rollback_trans(); + inline bool has_trans() + { + return has_transaction; + } + + int begin_stmt_trans(); + int commit_stmt_trans(); + int rollback_stmt_trans(); + inline bool has_stmt_trans() + { + return has_statement_trans; + } int create_table(String &stmt); int delete_table(String &stmt); diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index 9d217dc453b..9be371a06da 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -118,61 +118,6 @@ bool derived_handler_setting(THD* thd) return ( thd == NULL ) ? false : THDVAR(thd, derived_handler); } -/**************************************************************************** -** Class ha_clustrixdb_trx -****************************************************************************/ -st_clustrixdb_trx::st_clustrixdb_trx(THD *trx_thd) -{ - thd = trx_thd; - clustrix_net = NULL; - //query_id = 0; - //mem_root = NULL; - has_transaction = FALSE; -} - -st_clustrixdb_trx::~st_clustrixdb_trx() -{ - if (clustrix_net) - delete clustrix_net; -} - - -int st_clustrixdb_trx::net_init() -{ - if (!this->clustrix_net) - { - this->clustrix_net = new clustrix_connection(); - int error_code = this->clustrix_net->connect(); - if (error_code) - return error_code; - } - - return 0; -} - -int st_clustrixdb_trx::begin_trans() -{ - // XXX: What were these for? - //if (thd->transaction.stmt.trans_did_ddl() || - // thd->transaction.stmt.modified_non_trans_table) - - if (!has_transaction) { - int error_code = this->clustrix_net->begin_trans(); - if (error_code) - return error_code; - - /* Register for commit/rollback on the transaction */ - if (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) - trans_register_ha(thd, FALSE, clustrixdb_hton); - else - trans_register_ha(thd, TRUE, clustrixdb_hton); - - has_transaction = TRUE; - } - - return 0; -} - /**************************************************************************** ** Utility functions ****************************************************************************/ @@ -205,18 +150,19 @@ void decode_objectname(char *buf, const char *path, size_t buf_size) buf[new_path_len] = '\0'; } -st_clustrixdb_trx *get_trx(THD *thd, int *error_code) +clustrix_connection *get_trx(THD *thd, int *error_code) { *error_code = 0; - st_clustrixdb_trx *trx; - if (!(trx = (st_clustrixdb_trx *)thd_get_ha_data(thd, clustrixdb_hton))) + clustrix_connection *trx; + if (!(trx = (clustrix_connection *)thd_get_ha_data(thd, clustrixdb_hton))) { - if (!(trx = new st_clustrixdb_trx(thd))) { + if (!(trx = new clustrix_connection())) { *error_code = HA_ERR_OUT_OF_MEM; return NULL; } - if ((*error_code = trx->net_init())) { + *error_code = trx->connect(); + if (*error_code) { delete trx; return NULL; } @@ -251,7 +197,7 @@ int ha_clustrixdb::create(const char *name, TABLE *form, HA_CREATE_INFO *info) { int error_code; THD *thd = ha_thd(); - st_clustrixdb_trx *trx = get_trx(thd, &error_code); + clustrix_connection *trx = get_trx(thd, &error_code); if (!trx) return error_code; @@ -287,10 +233,10 @@ int ha_clustrixdb::create(const char *name, TABLE *form, HA_CREATE_INFO *info) createdb_stmt.append("CREATE DATABASE IF NOT EXISTS `"); createdb_stmt.append(form->s->db.str, form->s->db.length); createdb_stmt.append("`"); - trx->clustrix_net->create_table(createdb_stmt); + trx->create_table(createdb_stmt); } - error_code = trx->clustrix_net->create_table(create_table_stmt); + error_code = trx->create_table(create_table_stmt); return error_code; } @@ -298,7 +244,7 @@ int ha_clustrixdb::delete_table(const char *path) { int error_code; THD *thd = ha_thd(); - st_clustrixdb_trx *trx = get_trx(thd, &error_code); + clustrix_connection *trx = get_trx(thd, &error_code); if (!trx) return error_code; @@ -309,7 +255,7 @@ int ha_clustrixdb::delete_table(const char *path) char decoded_tbname[FN_REFLEN]; decode_objectname(decoded_tbname, dbname_end + 1, FN_REFLEN); - + String delete_cmd; delete_cmd.append("DROP TABLE `"); delete_cmd.append(path + 2, dbname_end - path - 2); @@ -318,14 +264,14 @@ int ha_clustrixdb::delete_table(const char *path) delete_cmd.append("`"); - return trx->clustrix_net->delete_table(delete_cmd); + return trx->delete_table(delete_cmd); } -int ha_clustrixdb::rename_table(const char* from, const char* to) +int ha_clustrixdb::rename_table(const char* from, const char* to) { int error_code; THD *thd = ha_thd(); - st_clustrixdb_trx *trx = get_trx(thd, &error_code); + clustrix_connection *trx = get_trx(thd, &error_code); if (!trx) return error_code; @@ -343,7 +289,7 @@ int ha_clustrixdb::rename_table(const char* from, const char* to) char decoded_to_tbname[FN_REFLEN]; decode_objectname(decoded_to_tbname, to_dbname_end + 1, FN_REFLEN); - + String rename_cmd; rename_cmd.append("RENAME TABLE `"); rename_cmd.append(from + 2, from_dbname_end - from - 2); @@ -355,7 +301,7 @@ int ha_clustrixdb::rename_table(const char* from, const char* to) rename_cmd.append(decoded_to_tbname); rename_cmd.append("`;"); - return trx->clustrix_net->rename_table(rename_cmd); + return trx->rename_table(rename_cmd); } @@ -398,11 +344,11 @@ int ha_clustrixdb::write_row(uchar *buf) { int error_code = 0; THD *thd = ha_thd(); - st_clustrixdb_trx *trx = get_trx(thd, &error_code); + clustrix_connection *trx = get_trx(thd, &error_code); if (!trx) return error_code; - assert(trx->has_transaction); + assert(trx->has_stmt_trans()); /* Convert the row format to binlog (packed) format */ uchar *packed_new_row = (uchar*) my_alloca(estimate_row_size(table)); @@ -410,12 +356,12 @@ int ha_clustrixdb::write_row(uchar *buf) /* XXX: Clustrix may needs to return HA_ERR_AUTOINC_ERANGE if we hit that error. */ - if ((error_code = trx->clustrix_net->write_row(clustrix_table_oid, - packed_new_row, packed_size))) + if ((error_code = trx->write_row(clustrix_table_oid, + packed_new_row, packed_size))) goto err; if (table->next_number_field) - insert_id_for_cur_row = trx->clustrix_net->last_insert_id; + insert_id_for_cur_row = trx->last_insert_id; err: if (packed_size) @@ -428,11 +374,11 @@ int ha_clustrixdb::update_row(const uchar *old_data, const uchar *new_data) { int error_code; THD *thd = ha_thd(); - st_clustrixdb_trx *trx = get_trx(thd, &error_code); + clustrix_connection *trx = get_trx(thd, &error_code); if (!trx) return error_code; - assert(trx->has_transaction); + assert(trx->has_stmt_trans()); size_t row_size = estimate_row_size(table); uchar *packed_new_row = (uchar*) my_alloca(row_size); @@ -456,19 +402,19 @@ int ha_clustrixdb::delete_row(const uchar *buf) { int error_code; THD *thd = ha_thd(); - st_clustrixdb_trx *trx = get_trx(thd, &error_code); + clustrix_connection *trx = get_trx(thd, &error_code); if (!trx) return error_code; - assert(trx->has_transaction); + assert(trx->has_stmt_trans()); // The estimate should consider only key fields widths. size_t packed_key_len; uchar *packed_key = (uchar*) my_alloca(estimate_row_size(table)); build_key_packed_row(table->s->primary_key, packed_key, &packed_key_len); - if ((error_code = trx->clustrix_net->key_delete(clustrix_table_oid, - packed_key, packed_key_len))) + if ((error_code = trx->key_delete(clustrix_table_oid, + packed_key, packed_key_len))) goto err; err: @@ -565,7 +511,7 @@ int ha_clustrixdb::index_init(uint idx, bool sorted) { int error_code = 0; THD *thd = ha_thd(); - st_clustrixdb_trx *trx = get_trx(thd, &error_code); + clustrix_connection *trx = get_trx(thd, &error_code); if (!trx) return error_code; @@ -583,7 +529,7 @@ int ha_clustrixdb::index_read(uchar * buf, const uchar * key, uint key_len, DBUG_ENTER("ha_clustrixdb::index_read"); int error_code = 0; THD *thd = ha_thd(); - st_clustrixdb_trx *trx = get_trx(thd, &error_code); + clustrix_connection *trx = get_trx(thd, &error_code); if (!trx) DBUG_RETURN(error_code); @@ -596,10 +542,9 @@ int ha_clustrixdb::index_read(uchar * buf, const uchar * key, uint key_len, uchar *rowdata; ulong rowdata_length; - if ((error_code = trx->clustrix_net->key_read(clustrix_table_oid, - active_index, table->read_set, - packed_key, packed_key_len, - &rowdata, &rowdata_length))) + if ((error_code = trx->key_read(clustrix_table_oid, active_index, + table->read_set, packed_key, packed_key_len, + &rowdata, &rowdata_length))) goto err; uchar const *current_row_end; @@ -620,7 +565,7 @@ int ha_clustrixdb::index_first(uchar *buf) { int error_code = 0; THD *thd = ha_thd(); - st_clustrixdb_trx *trx = get_trx(thd, &error_code); + clustrix_connection *trx = get_trx(thd, &error_code); if (!trx) return error_code; @@ -640,11 +585,9 @@ int ha_clustrixdb::index_first(uchar *buf) bitmap_set_all(&scan_fields); #endif - if ((error_code = trx->clustrix_net->scan_init(clustrix_table_oid, - active_index, - clustrix_connection::SORT_NONE, - &scan_fields, - &scan_refid))) + if ((error_code = trx->scan_init(clustrix_table_oid, active_index, + clustrix_connection::SORT_NONE, &scan_fields, + &scan_refid))) return error_code; @@ -655,7 +598,7 @@ int ha_clustrixdb::index_last(uchar *buf) { int error_code = 0; THD *thd = ha_thd(); - st_clustrixdb_trx *trx = get_trx(thd, &error_code); + clustrix_connection *trx = get_trx(thd, &error_code); if (!trx) return error_code; @@ -675,11 +618,9 @@ int ha_clustrixdb::index_last(uchar *buf) bitmap_set_all(&scan_fields); #endif - if ((error_code = trx->clustrix_net->scan_init(clustrix_table_oid, - active_index, - clustrix_connection::SORT_NONE, - &scan_fields, - &scan_refid))) + if ((error_code = trx->scan_init(clustrix_table_oid, active_index, + clustrix_connection::SORT_NONE, &scan_fields, + &scan_refid))) return error_code; @@ -721,7 +662,7 @@ int ha_clustrixdb::rnd_init(bool scan) { int error_code = 0; THD *thd = ha_thd(); - st_clustrixdb_trx *trx = get_trx(thd, &error_code); + clustrix_connection *trx = get_trx(thd, &error_code); if (!trx) return error_code; @@ -744,11 +685,9 @@ int ha_clustrixdb::rnd_init(bool scan) bitmap_set_all(&scan_fields); #endif - if ((error_code = trx->clustrix_net->scan_init(clustrix_table_oid, - 0, - clustrix_connection::SORT_NONE, - &scan_fields, - &scan_refid))) + if ((error_code = trx->scan_init(clustrix_table_oid, 0, + clustrix_connection::SORT_NONE, &scan_fields, + &scan_refid))) return error_code; return 0; @@ -758,7 +697,7 @@ int ha_clustrixdb::rnd_next(uchar *buf) { int error_code = 0; THD *thd = ha_thd(); - st_clustrixdb_trx *trx = get_trx(thd, &error_code); + clustrix_connection *trx = get_trx(thd, &error_code); if (!trx) return error_code; @@ -767,8 +706,7 @@ int ha_clustrixdb::rnd_next(uchar *buf) uchar *rowdata; ulong rowdata_length; - if ((error_code = trx->clustrix_net->scan_next(scan_refid, &rowdata, - &rowdata_length))) + if ((error_code = trx->scan_next(scan_refid, &rowdata, &rowdata_length))) return error_code; if (has_hidden_key) { @@ -797,7 +735,7 @@ int ha_clustrixdb::rnd_pos(uchar * buf, uchar *pos) int error_code = 0; THD *thd = ha_thd(); - st_clustrixdb_trx *trx = get_trx(thd, &error_code); + clustrix_connection *trx = get_trx(thd, &error_code); if (!trx) DBUG_RETURN(error_code); @@ -818,10 +756,9 @@ int ha_clustrixdb::rnd_pos(uchar * buf, uchar *pos) uchar *rowdata; ulong rowdata_length; - if ((error_code = trx->clustrix_net->key_read(clustrix_table_oid, 0, - table->read_set, - packed_key, packed_key_len, - &rowdata, &rowdata_length))) + if ((error_code = trx->key_read(clustrix_table_oid, 0, table->read_set, + packed_key, packed_key_len, + &rowdata, &rowdata_length))) goto err; uchar const *current_row_end; @@ -843,12 +780,12 @@ int ha_clustrixdb::rnd_end() { int error_code = 0; THD *thd = ha_thd(); - st_clustrixdb_trx *trx = get_trx(thd, &error_code); + clustrix_connection *trx = get_trx(thd, &error_code); if (!trx) return error_code; my_bitmap_free(&scan_fields); - if (scan_refid && (error_code = trx->clustrix_net->scan_end(scan_refid))) + if (scan_refid && (error_code = trx->scan_end(scan_refid))) return error_code; scan_refid = 0; @@ -885,9 +822,14 @@ THR_LOCK_DATA **ha_clustrixdb::store_lock(THD *thd, int ha_clustrixdb::external_lock(THD *thd, int lock_type) { int error_code; - st_clustrixdb_trx *trx = get_trx(thd, &error_code); - if (lock_type != F_UNLCK) + clustrix_connection *trx = get_trx(thd, &error_code); + if (lock_type != F_UNLCK) { trx->begin_trans(); + trx->begin_stmt_trans(); + trans_register_ha(thd, FALSE, clustrixdb_hton); + if (thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) + trans_register_ha(thd, TRUE, clustrixdb_hton); + } //if (lock_type != F_UNLCK) //DBUG_ASSERT(trx && trx == get_trx(thd, &error_code)); @@ -985,17 +927,14 @@ void ha_clustrixdb::build_key_packed_row(uint index, uchar *packed_key, static int clustrixdb_commit(handlerton *hton, THD *thd, bool all) { int error_code = 0; - st_clustrixdb_trx* trx = (st_clustrixdb_trx *) thd_get_ha_data(thd, hton); + clustrix_connection* trx = (clustrix_connection *) thd_get_ha_data(thd, hton); assert(trx); - if (trx->has_transaction) - { - if (all || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) - { - error_code = trx->clustrix_net->commit_trans(); - trx->has_transaction = FALSE; - } - } + if (trx->has_stmt_trans() && ((error_code = trx->commit_stmt_trans()))) + return error_code; + + if (all && trx->has_trans()) + error_code = trx->commit_trans(); return error_code; } @@ -1003,17 +942,14 @@ static int clustrixdb_commit(handlerton *hton, THD *thd, bool all) static int clustrixdb_rollback(handlerton *hton, THD *thd, bool all) { int error_code = 0; - st_clustrixdb_trx* trx = (st_clustrixdb_trx *) thd_get_ha_data(thd, hton); + clustrix_connection* trx = (clustrix_connection *) thd_get_ha_data(thd, hton); assert(trx); - if (trx->has_transaction) - { - if (all || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) - { - error_code = trx->clustrix_net->rollback_trans(); - trx->has_transaction = FALSE; - } - } + if (trx->has_stmt_trans() && ((error_code = trx->rollback_stmt_trans()))) + return error_code; + + if (all || trx->has_trans()) + error_code = trx->rollback_trans(); return error_code; } @@ -1026,11 +962,11 @@ static handler* clustrixdb_create_handler(handlerton *hton, TABLE_SHARE *table, static int clustrixdb_close_connection(handlerton* hton, THD* thd) { - st_clustrixdb_trx* trx = (st_clustrixdb_trx *) thd_get_ha_data(thd, hton); + clustrix_connection* trx = (clustrix_connection *) thd_get_ha_data(thd, hton); if (!trx) return 0; /* Transaction is not started */ - if (trx->has_transaction) + if (trx->has_stmt_trans()) clustrixdb_rollback(clustrixdb_hton, thd, TRUE); delete trx; diff --git a/storage/clustrixdb/ha_clustrixdb.h b/storage/clustrixdb/ha_clustrixdb.h index 15311772bfe..ecd312a2cce 100644 --- a/storage/clustrixdb/ha_clustrixdb.h +++ b/storage/clustrixdb/ha_clustrixdb.h @@ -21,27 +21,9 @@ Copyright (c) 2019, MariaDB Corporation. #include "../../sql/rpl_record.h" size_t estimate_row_size(TABLE *table); -class st_clustrixdb_trx; -st_clustrixdb_trx *get_trx(THD *thd, int *error_code); +clustrix_connection *get_trx(THD *thd, int *error_code); bool get_enable_sh(THD* thd); -class ha_clustrixdb; - -class st_clustrixdb_trx -{ -public: - THD *thd; - clustrix_connection *clustrix_net; - //query_id_t query_id; - //MEM_ROOT mem_root; /* Memory allocated for the executing transaction */ - bool has_transaction; - - st_clustrixdb_trx(THD* trx_thd); - ~st_clustrixdb_trx(); - int net_init(); - int begin_trans(); -}; - class ha_clustrixdb : public handler { private: diff --git a/storage/clustrixdb/ha_clustrixdb_pushdown.cc b/storage/clustrixdb/ha_clustrixdb_pushdown.cc index 902d45db401..4edced88f4a 100644 --- a/storage/clustrixdb/ha_clustrixdb_pushdown.cc +++ b/storage/clustrixdb/ha_clustrixdb_pushdown.cc @@ -99,7 +99,7 @@ create_clustrixdb_select_handler(THD* thd, SELECT_LEX* select_lex) int error_code = 0; int field_metadata_size = 0; ulonglong scan_refid = 0; - st_clustrixdb_trx *trx = 0; + clustrix_connection *trx = NULL; // We presume this number is equal to types.elements in get_field_types uint items_number = select_lex->get_item_list()->elements; @@ -125,7 +125,7 @@ create_clustrixdb_select_handler(THD* thd, SELECT_LEX* select_lex) if (!trx) goto err; - if ((error_code = trx->clustrix_net->scan_query_init(query, fieldtype, items_number, + if ((error_code = trx->scan_query_init(query, fieldtype, items_number, null_bits, num_null_bytes, field_metadata, field_metadata_size, &scan_refid))) { goto err; } @@ -169,12 +169,12 @@ ha_clustrixdb_select_handler::ha_clustrixdb_select_handler( ha_clustrixdb_select_handler::~ha_clustrixdb_select_handler() { int error_code; - st_clustrixdb_trx *trx = get_trx(thd, &error_code); + clustrix_connection *trx = get_trx(thd, &error_code); if (!trx) { // TBD Log this } if (trx && scan_refid) - trx->clustrix_net->scan_end(scan_refid); + trx->scan_end(scan_refid); // If the ::init_scan has been executed if (table__) @@ -217,7 +217,7 @@ int ha_clustrixdb_select_handler::init_scan() int ha_clustrixdb_select_handler::next_row() { int error_code = 0; - st_clustrixdb_trx *trx = get_trx(thd, &error_code); + clustrix_connection *trx = get_trx(thd, &error_code); if (!trx) return error_code; @@ -225,8 +225,7 @@ int ha_clustrixdb_select_handler::next_row() uchar *rowdata; ulong rowdata_length; - if ((error_code = trx->clustrix_net->scan_next(scan_refid, &rowdata, - &rowdata_length))) + if ((error_code = trx->scan_next(scan_refid, &rowdata, &rowdata_length))) return error_code; uchar const *current_row_end; @@ -284,7 +283,7 @@ create_clustrixdb_derived_handler(THD* thd, TABLE_LIST *derived) int error_code = 0; int field_metadata_size = 0; ulonglong scan_refid = 0; - st_clustrixdb_trx *trx = 0; + clustrix_connection *trx = NULL; // We presume this number is equal to types.elements in get_field_types uint items_number = select_lex->get_item_list()->elements; @@ -310,7 +309,7 @@ create_clustrixdb_derived_handler(THD* thd, TABLE_LIST *derived) if (!trx) goto err; - if ((error_code = trx->clustrix_net->scan_query_init(query, fieldtype, items_number, + if ((error_code = trx->scan_query_init(query, fieldtype, items_number, null_bits, num_null_bytes, field_metadata, field_metadata_size, &scan_refid))) { goto err; } @@ -354,12 +353,12 @@ ha_clustrixdb_derived_handler::ha_clustrixdb_derived_handler( ha_clustrixdb_derived_handler::~ha_clustrixdb_derived_handler() { int error_code; - st_clustrixdb_trx *trx = get_trx(thd, &error_code); + clustrix_connection *trx = get_trx(thd, &error_code); if (!trx) { // TBD Log this. } if (trx && scan_refid) - trx->clustrix_net->scan_end(scan_refid); + trx->scan_end(scan_refid); // If the ::init_scan has been executed if (table__) @@ -402,7 +401,7 @@ int ha_clustrixdb_derived_handler::init_scan() int ha_clustrixdb_derived_handler::next_row() { int error_code = 0; - st_clustrixdb_trx *trx = get_trx(thd, &error_code); + clustrix_connection *trx = get_trx(thd, &error_code); if (!trx) return error_code; @@ -410,8 +409,7 @@ int ha_clustrixdb_derived_handler::next_row() uchar *rowdata; ulong rowdata_length; - if ((error_code = trx->clustrix_net->scan_next(scan_refid, &rowdata, - &rowdata_length))) + if ((error_code = trx->scan_next(scan_refid, &rowdata, &rowdata_length))) return error_code; uchar const *current_row_end; -- cgit v1.2.1 From d94a32be7541717960c48dde59d3449017ddd4b2 Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Mon, 8 Jul 2019 13:38:18 -0700 Subject: Rename create_table() as run_query() and remove identical functions. --- storage/clustrixdb/clustrix_connection.cc | 19 +------------------ storage/clustrixdb/clustrix_connection.h | 5 +---- storage/clustrixdb/ha_clustrixdb.cc | 8 ++++---- 3 files changed, 6 insertions(+), 26 deletions(-) diff --git a/storage/clustrixdb/clustrix_connection.cc b/storage/clustrixdb/clustrix_connection.cc index c1909a00aaa..0c24b7cfc8a 100644 --- a/storage/clustrixdb/clustrix_connection.cc +++ b/storage/clustrixdb/clustrix_connection.cc @@ -220,24 +220,7 @@ int clustrix_connection::rollback_stmt_trans() return error_code; } -int clustrix_connection::create_table(String &stmt) -{ - int error_code = mysql_real_query(&clustrix_net, stmt.ptr(), stmt.length()); - if (error_code) - return mysql_errno(&clustrix_net); - - return error_code; -} - -int clustrix_connection::delete_table(String &stmt) -{ - int error_code = mysql_real_query(&clustrix_net, stmt.ptr(), stmt.length()); - if (error_code) - return mysql_errno(&clustrix_net); - return error_code; -} - -int clustrix_connection::rename_table(String &stmt) +int clustrix_connection::run_query(String &stmt) { int error_code = mysql_real_query(&clustrix_net, stmt.ptr(), stmt.length()); if (error_code) diff --git a/storage/clustrixdb/clustrix_connection.h b/storage/clustrixdb/clustrix_connection.h index b05f066edf7..4273f534f84 100644 --- a/storage/clustrixdb/clustrix_connection.h +++ b/storage/clustrixdb/clustrix_connection.h @@ -82,10 +82,7 @@ public: return has_statement_trans; } - int create_table(String &stmt); - int delete_table(String &stmt); - int rename_table(String &stmt); - + int run_query(String &stmt); int write_row(ulonglong clustrix_table_oid, uchar *packed_row, size_t packed_size); diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index 9be371a06da..91e8977cdf6 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -233,10 +233,10 @@ int ha_clustrixdb::create(const char *name, TABLE *form, HA_CREATE_INFO *info) createdb_stmt.append("CREATE DATABASE IF NOT EXISTS `"); createdb_stmt.append(form->s->db.str, form->s->db.length); createdb_stmt.append("`"); - trx->create_table(createdb_stmt); + trx->run_query(createdb_stmt); } - error_code = trx->create_table(create_table_stmt); + error_code = trx->run_query(create_table_stmt); return error_code; } @@ -264,7 +264,7 @@ int ha_clustrixdb::delete_table(const char *path) delete_cmd.append("`"); - return trx->delete_table(delete_cmd); + return trx->run_query(delete_cmd); } int ha_clustrixdb::rename_table(const char* from, const char* to) @@ -301,7 +301,7 @@ int ha_clustrixdb::rename_table(const char* from, const char* to) rename_cmd.append(decoded_to_tbname); rename_cmd.append("`;"); - return trx->rename_table(rename_cmd); + return trx->run_query(rename_cmd); } -- cgit v1.2.1 From ea5b6a6c78955310f2bcd9fcaa2af71589230283 Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Mon, 8 Jul 2019 17:35:01 -0700 Subject: Don't include ha_clustrix_pushdown.cc file in ha_clustrix.cc. --- storage/clustrixdb/CMakeLists.txt | 2 +- storage/clustrixdb/ha_clustrixdb.cc | 3 +-- storage/clustrixdb/ha_clustrixdb.h | 3 ++- storage/clustrixdb/ha_clustrixdb_pushdown.cc | 7 +++++-- storage/clustrixdb/ha_clustrixdb_pushdown.h | 5 ++++- 5 files changed, 13 insertions(+), 7 deletions(-) diff --git a/storage/clustrixdb/CMakeLists.txt b/storage/clustrixdb/CMakeLists.txt index 6cf4410c516..42237eae6e9 100644 --- a/storage/clustrixdb/CMakeLists.txt +++ b/storage/clustrixdb/CMakeLists.txt @@ -11,7 +11,7 @@ ENDIF() SET(CLUSTRIXDB_PLUGIN_STATIC "clustrixdb") SET(CLUSTRIXDB_PLUGIN_DYNAMIC "ha_clustrixdb") -SET(CLUSTRIXDB_SOURCES ha_clustrixdb.cc clustrix_connection.cc) +SET(CLUSTRIXDB_SOURCES ha_clustrixdb.cc clustrix_connection.cc ha_clustrixdb_pushdown.cc) MYSQL_ADD_PLUGIN(clustrixdb ${CLUSTRIXDB_SOURCES} STORAGE_ENGINE) IF(MSVC) diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index 91e8977cdf6..e9a767f3878 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -5,6 +5,7 @@ Copyright (c) 2019, MariaDB Corporation. /** @file ha_clustrixdb.cc */ #include "ha_clustrixdb.h" +#include "ha_clustrixdb_pushdown.h" #include "key.h" handlerton *clustrixdb_hton = NULL; @@ -1016,8 +1017,6 @@ int clustrixdb_discover_table(handlerton *hton, THD *thd, TABLE_SHARE *share) return error_code; } -#include "ha_clustrixdb_pushdown.cc" - static int clustrixdb_init(void *p) { clustrixdb_hton = (handlerton *) p; diff --git a/storage/clustrixdb/ha_clustrixdb.h b/storage/clustrixdb/ha_clustrixdb.h index ecd312a2cce..e788123efa5 100644 --- a/storage/clustrixdb/ha_clustrixdb.h +++ b/storage/clustrixdb/ha_clustrixdb.h @@ -32,7 +32,6 @@ private: ulonglong clustrix_table_oid; rpl_group_info *rgi; Relay_log_info *rli; - RPL_TABLE_LIST *rpl_table_list; Field *auto_inc_field; ulonglong auto_inc_value; @@ -108,4 +107,6 @@ private: size_t *packed_key_len); }; +bool select_handler_setting(THD* thd); +bool derived_handler_setting(THD* thd); #endif // _ha_clustrixdb_h diff --git a/storage/clustrixdb/ha_clustrixdb_pushdown.cc b/storage/clustrixdb/ha_clustrixdb_pushdown.cc index 4edced88f4a..6bcf8e15e0b 100644 --- a/storage/clustrixdb/ha_clustrixdb_pushdown.cc +++ b/storage/clustrixdb/ha_clustrixdb_pushdown.cc @@ -2,8 +2,11 @@ Copyright (c) 2019, MariaDB Corporation. *****************************************************************************/ +#include "ha_clustrixdb.h" #include "ha_clustrixdb_pushdown.h" +extern handlerton *clustrixdb_hton; + /*@brief Fills up array data types, metadata and nullability*/ /************************************************************ * DESCRIPTION: @@ -85,7 +88,7 @@ err: * select_handler if possible * NULL otherwise ************************************************************/ -static select_handler* +select_handler* create_clustrixdb_select_handler(THD* thd, SELECT_LEX* select_lex) { ha_clustrixdb_select_handler *sh = NULL; @@ -266,7 +269,7 @@ int ha_clustrixdb_select_handler::end_scan() * derived_handler if possible * NULL otherwise ************************************************************/ -static derived_handler* +derived_handler* create_clustrixdb_derived_handler(THD* thd, TABLE_LIST *derived) { ha_clustrixdb_derived_handler *dh = NULL; diff --git a/storage/clustrixdb/ha_clustrixdb_pushdown.h b/storage/clustrixdb/ha_clustrixdb_pushdown.h index 20c01465655..0b6c68e4c75 100644 --- a/storage/clustrixdb/ha_clustrixdb_pushdown.h +++ b/storage/clustrixdb/ha_clustrixdb_pushdown.h @@ -29,7 +29,6 @@ class ha_clustrixdb_base_handler // Structures to unpack RBR rows from CLX BE rpl_group_info *rgi; Relay_log_info *rli; - RPL_TABLE_LIST *rpl_table_list; // CLX BE scan operation reference ulonglong scan_refid; // To unpack rows from CLX BE @@ -84,5 +83,9 @@ class ha_clustrixdb_derived_handler: }; +select_handler *create_clustrixdb_select_handler(THD* thd, + SELECT_LEX* select_lex); +derived_handler *create_clustrixdb_derived_handler(THD* thd, + TABLE_LIST *derived); #endif -- cgit v1.2.1 From a336cb20c7b74cedfdb05f5348ee84adb2849374 Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Mon, 22 Jul 2019 12:20:52 -0700 Subject: Fix some transaction handling errors. --- mysql-test/suite/clustrixdb/basics.result | Bin 1732 -> 1731 bytes storage/clustrixdb/clustrix_connection.cc | 3 +++ storage/clustrixdb/ha_clustrixdb.cc | 33 +++++++++++++++++------------- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/mysql-test/suite/clustrixdb/basics.result b/mysql-test/suite/clustrixdb/basics.result index 20a158f69c9..3c0ea581011 100644 Binary files a/mysql-test/suite/clustrixdb/basics.result and b/mysql-test/suite/clustrixdb/basics.result differ diff --git a/storage/clustrixdb/clustrix_connection.cc b/storage/clustrixdb/clustrix_connection.cc index 0c24b7cfc8a..e0d1e1a4160 100644 --- a/storage/clustrixdb/clustrix_connection.cc +++ b/storage/clustrixdb/clustrix_connection.cc @@ -189,6 +189,7 @@ int clustrix_connection::rollback_trans() int clustrix_connection::begin_stmt_trans() { + assert(has_transaction); if (has_statement_trans) return 0; @@ -202,6 +203,7 @@ int clustrix_connection::begin_stmt_trans() int clustrix_connection::commit_stmt_trans() { + assert(has_transaction); const char *stmt = "RELEASE SAVEPOINT STMT_TRANS"; int error_code = mysql_real_query(&clustrix_net, stmt, strlen(stmt)); if (error_code) @@ -212,6 +214,7 @@ int clustrix_connection::commit_stmt_trans() int clustrix_connection::rollback_stmt_trans() { + assert(has_transaction); const char *stmt = "ROLLBACK TO STMT_TRANS"; int error_code = mysql_real_query(&clustrix_net, stmt, strlen(stmt)); if (error_code) diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index e9a767f3878..8a828dbf5b9 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -825,16 +825,17 @@ int ha_clustrixdb::external_lock(THD *thd, int lock_type) int error_code; clustrix_connection *trx = get_trx(thd, &error_code); if (lock_type != F_UNLCK) { - trx->begin_trans(); - trx->begin_stmt_trans(); + if ((error_code = trx->begin_trans())) + return error_code; + + if ((error_code = trx->begin_stmt_trans())) + return error_code; + trans_register_ha(thd, FALSE, clustrixdb_hton); if (thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) trans_register_ha(thd, TRUE, clustrixdb_hton); } - //if (lock_type != F_UNLCK) - //DBUG_ASSERT(trx && trx == get_trx(thd, &error_code)); - return 0; } @@ -931,11 +932,13 @@ static int clustrixdb_commit(handlerton *hton, THD *thd, bool all) clustrix_connection* trx = (clustrix_connection *) thd_get_ha_data(thd, hton); assert(trx); - if (trx->has_stmt_trans() && ((error_code = trx->commit_stmt_trans()))) - return error_code; - - if (all && trx->has_trans()) + if (all || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) { + if (trx->has_trans()) error_code = trx->commit_trans(); + } else { + if (trx->has_stmt_trans()) + error_code = trx->commit_stmt_trans(); + } return error_code; } @@ -946,11 +949,13 @@ static int clustrixdb_rollback(handlerton *hton, THD *thd, bool all) clustrix_connection* trx = (clustrix_connection *) thd_get_ha_data(thd, hton); assert(trx); - if (trx->has_stmt_trans() && ((error_code = trx->rollback_stmt_trans()))) - return error_code; - - if (all || trx->has_trans()) - error_code = trx->rollback_trans(); + if (all || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) { + if (trx->has_trans()) + error_code = trx->rollback_trans(); + } else { + if (trx->has_stmt_trans()) + error_code = trx->rollback_stmt_trans(); + } return error_code; } -- cgit v1.2.1 From 6c8cd22f8c48f4ed25b082196b9cbeeebc428b7b Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Tue, 6 Aug 2019 14:44:35 -0700 Subject: Rename some functions and fix formating issues. --- storage/clustrixdb/clustrix_connection.cc | 23 ++++++++++++----------- storage/clustrixdb/clustrix_connection.h | 13 ++++++------- storage/clustrixdb/ha_clustrixdb.cc | 18 +++++++++--------- storage/clustrixdb/ha_clustrixdb_pushdown.cc | 4 ++-- 4 files changed, 29 insertions(+), 29 deletions(-) diff --git a/storage/clustrixdb/clustrix_connection.cc b/storage/clustrixdb/clustrix_connection.cc index e0d1e1a4160..8bdd7c55ea8 100644 --- a/storage/clustrixdb/clustrix_connection.cc +++ b/storage/clustrixdb/clustrix_connection.cc @@ -23,12 +23,12 @@ static const char charset_name[] = "utf8"; enum clustrix_commands { CLUSTRIX_WRITE_ROW = 1, - CLUSTRIX_SCAN_INIT, + CLUSTRIX_SCAN_TABLE, CLUSTRIX_SCAN_NEXT, CLUSTRIX_SCAN_STOP, CLUSTRIX_KEY_READ, CLUSTRIX_KEY_DELETE, - CLUSTRIX_QUERY_INIT + CLUSTRIX_SCAN_QUERY }; /**************************************************************************** @@ -316,14 +316,14 @@ int clustrix_connection::key_read(ulonglong clustrix_table_oid, uint index, return 0; } -int clustrix_connection::scan_init(ulonglong clustrix_table_oid, uint index, - enum sort_order sort, MY_BITMAP *read_set, - ulonglong *scan_refid) +int clustrix_connection::scan_table(ulonglong clustrix_table_oid, uint index, + enum sort_order sort, MY_BITMAP *read_set, + ulonglong *scan_refid) { int error_code; command_length = 0; - if ((error_code = add_command_operand_uchar(CLUSTRIX_SCAN_INIT))) + if ((error_code = add_command_operand_uchar(CLUSTRIX_SCAN_TABLE))) return error_code; if ((error_code = add_command_operand_ulonglong(clustrix_table_oid))) @@ -367,15 +367,16 @@ int clustrix_connection::scan_init(ulonglong clustrix_table_oid, uint index, * scan_refid id used to reference this scan later * Used in pushdowns to initiate query scan. **/ -int clustrix_connection::scan_query_init(String &stmt, uchar *fieldtype, - uint fields, uchar *null_bits, - uint null_bits_size, uchar *field_metadata, - uint field_metadata_size, ulonglong *scan_refid) +int clustrix_connection::scan_query(String &stmt, uchar *fieldtype, uint fields, + uchar *null_bits, uint null_bits_size, + uchar *field_metadata, + uint field_metadata_size, + ulonglong *scan_refid) { int error_code; command_length = 0; - if ((error_code = add_command_operand_uchar(CLUSTRIX_QUERY_INIT))) + if ((error_code = add_command_operand_uchar(CLUSTRIX_SCAN_QUERY))) return error_code; if ((error_code = add_command_operand_str((uchar*)stmt.ptr(), stmt.length()))) diff --git a/storage/clustrixdb/clustrix_connection.h b/storage/clustrixdb/clustrix_connection.h index 4273f534f84..1f68537a870 100644 --- a/storage/clustrixdb/clustrix_connection.h +++ b/storage/clustrixdb/clustrix_connection.h @@ -93,15 +93,14 @@ public: uchar **rowdata, ulong *rowdata_length); enum sort_order {SORT_NONE = 0, SORT_ASC = 1, SORT_DESC = 2}; - int scan_init(ulonglong clustrix_table_oid, uint index, - enum sort_order sort, MY_BITMAP *read_set, - ulonglong *scan_refid); + int scan_table(ulonglong clustrix_table_oid, uint index, + enum sort_order sort, MY_BITMAP *read_set, + ulonglong *scan_refid); int scan_next(ulonglong scan_refid, uchar **rowdata, ulong *rowdata_length); int scan_end(ulonglong scan_refid); - int scan_query_init(String &stmt, uchar *fieldtype, - uint fields, uchar *null_bits, - uint null_bits_size, uchar *field_metadata, - uint field_metadata_size, ulonglong *scan_refid); + int scan_query(String &stmt, uchar *fieldtype, uint fields, uchar *null_bits, + uint null_bits_size, uchar *field_metadata, + uint field_metadata_size, ulonglong *scan_refid); int populate_table_list(LEX_CSTRING *db, handlerton::discovered_list *result); int discover_table_details(LEX_CSTRING *db, LEX_CSTRING *name, THD *thd, diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index 8a828dbf5b9..62d346dd00b 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -586,9 +586,9 @@ int ha_clustrixdb::index_first(uchar *buf) bitmap_set_all(&scan_fields); #endif - if ((error_code = trx->scan_init(clustrix_table_oid, active_index, - clustrix_connection::SORT_NONE, &scan_fields, - &scan_refid))) + if ((error_code = trx->scan_table(clustrix_table_oid, active_index, + clustrix_connection::SORT_NONE, + &scan_fields, &scan_refid))) return error_code; @@ -619,9 +619,9 @@ int ha_clustrixdb::index_last(uchar *buf) bitmap_set_all(&scan_fields); #endif - if ((error_code = trx->scan_init(clustrix_table_oid, active_index, - clustrix_connection::SORT_NONE, &scan_fields, - &scan_refid))) + if ((error_code = trx->scan_table(clustrix_table_oid, active_index, + clustrix_connection::SORT_NONE, + &scan_fields, &scan_refid))) return error_code; @@ -686,9 +686,9 @@ int ha_clustrixdb::rnd_init(bool scan) bitmap_set_all(&scan_fields); #endif - if ((error_code = trx->scan_init(clustrix_table_oid, 0, - clustrix_connection::SORT_NONE, &scan_fields, - &scan_refid))) + if ((error_code = trx->scan_table(clustrix_table_oid, 0, + clustrix_connection::SORT_NONE, + &scan_fields, &scan_refid))) return error_code; return 0; diff --git a/storage/clustrixdb/ha_clustrixdb_pushdown.cc b/storage/clustrixdb/ha_clustrixdb_pushdown.cc index 6bcf8e15e0b..224efe0dab3 100644 --- a/storage/clustrixdb/ha_clustrixdb_pushdown.cc +++ b/storage/clustrixdb/ha_clustrixdb_pushdown.cc @@ -128,7 +128,7 @@ create_clustrixdb_select_handler(THD* thd, SELECT_LEX* select_lex) if (!trx) goto err; - if ((error_code = trx->scan_query_init(query, fieldtype, items_number, + if ((error_code = trx->scan_query(query, fieldtype, items_number, null_bits, num_null_bytes, field_metadata, field_metadata_size, &scan_refid))) { goto err; } @@ -312,7 +312,7 @@ create_clustrixdb_derived_handler(THD* thd, TABLE_LIST *derived) if (!trx) goto err; - if ((error_code = trx->scan_query_init(query, fieldtype, items_number, + if ((error_code = trx->scan_query(query, fieldtype, items_number, null_bits, num_null_bytes, field_metadata, field_metadata_size, &scan_refid))) { goto err; } -- cgit v1.2.1 From 99831d700b427ff5b2f82ed8370cfcd3908ff12a Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Thu, 22 Aug 2019 15:04:21 -0700 Subject: Add row_update support. --- storage/clustrixdb/clustrix_connection.cc | 38 +++++++++++++++++++++++++++++- storage/clustrixdb/clustrix_connection.h | 4 ++++ storage/clustrixdb/ha_clustrixdb.cc | 39 ++++++++++++++++++++----------- storage/clustrixdb/ha_clustrixdb.h | 4 ++-- 4 files changed, 68 insertions(+), 17 deletions(-) diff --git a/storage/clustrixdb/clustrix_connection.cc b/storage/clustrixdb/clustrix_connection.cc index 8bdd7c55ea8..c9bfe040ab7 100644 --- a/storage/clustrixdb/clustrix_connection.cc +++ b/storage/clustrixdb/clustrix_connection.cc @@ -28,7 +28,8 @@ enum clustrix_commands { CLUSTRIX_SCAN_STOP, CLUSTRIX_KEY_READ, CLUSTRIX_KEY_DELETE, - CLUSTRIX_SCAN_QUERY + CLUSTRIX_SCAN_QUERY, + CLUSTRIX_KEY_UPDATE }; /**************************************************************************** @@ -256,6 +257,41 @@ int clustrix_connection::write_row(ulonglong clustrix_table_oid, return error_code; } +int clustrix_connection::key_update(ulonglong clustrix_table_oid, + uchar *packed_key, size_t packed_key_length, + MY_BITMAP *update_set, + uchar *packed_new_data, + size_t packed_new_length) +{ + int error_code; + command_length = 0; + + if ((error_code = add_command_operand_uchar(CLUSTRIX_KEY_UPDATE))) + return error_code; + + if ((error_code = add_command_operand_ulonglong(clustrix_table_oid))) + return error_code; + + if ((error_code = add_command_operand_str(packed_key, packed_key_length))) + return error_code; + + if ((error_code = add_command_operand_bitmap(update_set))) + return error_code; + + if ((error_code = add_command_operand_str(packed_new_data, + packed_new_length))) + return error_code; + + if ((error_code = send_command())) + return error_code; + + if ((error_code = read_query_response())) + return mysql_errno(&clustrix_net); + + return error_code; + +} + int clustrix_connection::key_delete(ulonglong clustrix_table_oid, uchar *packed_key, size_t packed_key_length) { diff --git a/storage/clustrixdb/clustrix_connection.h b/storage/clustrixdb/clustrix_connection.h index 1f68537a870..c030f5a9957 100644 --- a/storage/clustrixdb/clustrix_connection.h +++ b/storage/clustrixdb/clustrix_connection.h @@ -86,6 +86,10 @@ public: int write_row(ulonglong clustrix_table_oid, uchar *packed_row, size_t packed_size); + int key_update(ulonglong clustrix_table_oid, + uchar *packed_key, size_t packed_key_length, + MY_BITMAP *update_set, + uchar *packed_new_data, size_t packed_new_length); int key_delete(ulonglong clustrix_table_oid, uchar *packed_key, size_t packed_key_length); int key_read(ulonglong clustrix_table_oid, uint index, MY_BITMAP *read_set, diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index 62d346dd00b..5edb786747b 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -373,30 +373,37 @@ err: int ha_clustrixdb::update_row(const uchar *old_data, const uchar *new_data) { + DBUG_ENTER("ha_clustrixdb::update_row"); int error_code; THD *thd = ha_thd(); clustrix_connection *trx = get_trx(thd, &error_code); if (!trx) - return error_code; + DBUG_RETURN(error_code); assert(trx->has_stmt_trans()); size_t row_size = estimate_row_size(table); + size_t packed_key_len; + uchar *packed_key = (uchar*) my_alloca(row_size); + build_key_packed_row(table->s->primary_key, old_data, + packed_key, &packed_key_len); + uchar *packed_new_row = (uchar*) my_alloca(row_size); - // Add checks for actual size of the packed data - /*size_t packed_new_size =*/ pack_row(table, table->write_set, packed_new_row, new_data); - uchar *packed_old_row = (uchar*) my_alloca(row_size); - /*size_t packed_old_size =*/ pack_row(table, table->write_set, packed_old_row, old_data); + size_t packed_new_size = pack_row(table, table->write_set, packed_new_row, + new_data); /* Send the packed rows to Clustrix */ + error_code = trx->key_update(clustrix_table_oid, packed_key, packed_key_len, + table->write_set, + packed_new_row, packed_new_size); + + if(packed_key) + my_afree(packed_key); if(packed_new_row) my_afree(packed_new_row); - if(packed_old_row) - my_afree(packed_old_row); - - return error_code; + DBUG_RETURN(error_code); } int ha_clustrixdb::delete_row(const uchar *buf) @@ -412,7 +419,8 @@ int ha_clustrixdb::delete_row(const uchar *buf) // The estimate should consider only key fields widths. size_t packed_key_len; uchar *packed_key = (uchar*) my_alloca(estimate_row_size(table)); - build_key_packed_row(table->s->primary_key, packed_key, &packed_key_len); + build_key_packed_row(table->s->primary_key, table->record[0], + packed_key, &packed_key_len); if ((error_code = trx->key_delete(clustrix_table_oid, packed_key, packed_key_len))) @@ -539,7 +547,8 @@ int ha_clustrixdb::index_read(uchar * buf, const uchar * key, uint key_len, // The estimate should consider only key fields widths. size_t packed_key_len; uchar *packed_key = (uchar*) my_alloca(estimate_row_size(table)); - build_key_packed_row(active_index, packed_key, &packed_key_len); + build_key_packed_row(active_index, table->record[0], + packed_key, &packed_key_len); uchar *rowdata; ulong rowdata_length; @@ -753,7 +762,8 @@ int ha_clustrixdb::rnd_pos(uchar * buf, uchar *pos) // The estimate should consider only key fields widths. uchar *packed_key = (uchar*) my_alloca(estimate_row_size(table)); size_t packed_key_len; - build_key_packed_row(table->s->primary_key, packed_key, &packed_key_len); + build_key_packed_row(table->s->primary_key, table->record[0], + packed_key, &packed_key_len); uchar *rowdata; ulong rowdata_length; @@ -908,7 +918,8 @@ void ha_clustrixdb::remove_current_table_from_rpl_table_list() delete rgi; } -void ha_clustrixdb::build_key_packed_row(uint index, uchar *packed_key, +void ha_clustrixdb::build_key_packed_row(uint index, const uchar *buf, + uchar *packed_key, size_t *packed_key_len) { if (index == table->s->primary_key && has_hidden_key) { @@ -918,7 +929,7 @@ void ha_clustrixdb::build_key_packed_row(uint index, uchar *packed_key, // make a row from the table table->mark_columns_used_by_index(index, &table->tmp_set); *packed_key_len = pack_row(table, &table->tmp_set, packed_key, - table->record[0]); + buf); } } diff --git a/storage/clustrixdb/ha_clustrixdb.h b/storage/clustrixdb/ha_clustrixdb.h index e788123efa5..23646693112 100644 --- a/storage/clustrixdb/ha_clustrixdb.h +++ b/storage/clustrixdb/ha_clustrixdb.h @@ -103,8 +103,8 @@ public: private: void add_current_table_to_rpl_table_list(); void remove_current_table_from_rpl_table_list(); - void build_key_packed_row(uint index, uchar *packed_key, - size_t *packed_key_len); + void build_key_packed_row(uint index, const uchar *buf, + uchar *packed_key, size_t *packed_key_len); }; bool select_handler_setting(THD* thd); -- cgit v1.2.1 From e9c6a989c4418599dbf6eff5776f8e54903f2c1d Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Fri, 16 Aug 2019 10:54:11 -0700 Subject: Implement index_read, index_first, and index_last. --- storage/clustrixdb/clustrix_connection.cc | 53 ++++++++++++- storage/clustrixdb/clustrix_connection.h | 17 +++++ storage/clustrixdb/ha_clustrixdb.cc | 123 +++++++++++++++--------------- storage/clustrixdb/ha_clustrixdb.h | 1 + 4 files changed, 129 insertions(+), 65 deletions(-) diff --git a/storage/clustrixdb/clustrix_connection.cc b/storage/clustrixdb/clustrix_connection.cc index c9bfe040ab7..08c636c52ef 100644 --- a/storage/clustrixdb/clustrix_connection.cc +++ b/storage/clustrixdb/clustrix_connection.cc @@ -29,7 +29,8 @@ enum clustrix_commands { CLUSTRIX_KEY_READ, CLUSTRIX_KEY_DELETE, CLUSTRIX_SCAN_QUERY, - CLUSTRIX_KEY_UPDATE + CLUSTRIX_KEY_UPDATE, + CLUSTRIX_SCAN_FROM_KEY }; /**************************************************************************** @@ -38,6 +39,7 @@ enum clustrix_commands { void clustrix_connection::disconnect(bool is_destructor) { + DBUG_ENTER("clustrix_connection::disconnect"); if (is_destructor) { /* @@ -48,13 +50,14 @@ void clustrix_connection::disconnect(bool is_destructor) clustrix_net.net.thd = NULL; } mysql_close(&clustrix_net); + DBUG_VOID_RETURN; } int clustrix_connection::connect() { int error_code = 0; my_bool my_true = 1; - DBUG_ENTER("connect"); + DBUG_ENTER("clustrix_connection::connect"); /* Validate the connection parameters */ if (!strcmp(clustrix_socket, "")) @@ -440,6 +443,49 @@ int clustrix_connection::scan_query(String &stmt, uchar *fieldtype, uint fields, return error_code; } +int clustrix_connection::scan_from_key(ulonglong clustrix_table_oid, uint index, + enum scan_type scan_dir, + bool sorted_scan, MY_BITMAP *read_set, + uchar *packed_key, + ulong packed_key_length, + ulonglong *scan_refid) +{ + int error_code; + command_length = 0; + + if ((error_code = add_command_operand_uchar(CLUSTRIX_SCAN_FROM_KEY))) + return error_code; + + if ((error_code = add_command_operand_ulonglong(clustrix_table_oid))) + return error_code; + + if ((error_code = add_command_operand_uint(index))) + return error_code; + + if ((error_code = add_command_operand_uchar(scan_dir))) + return error_code; + + if ((error_code = add_command_operand_uchar(sorted_scan))) + return error_code; + + if ((error_code = add_command_operand_str(packed_key, packed_key_length))) + return error_code; + + if ((error_code = add_command_operand_bitmap(read_set))) + return error_code; + + if ((error_code = send_command())) + return error_code; + + ulong packet_length = cli_safe_read(&clustrix_net); + if (packet_length == packet_error) + return mysql_errno(&clustrix_net); + + unsigned char *pos = clustrix_net.net.read_pos; + *scan_refid = safe_net_field_length_ll(&pos, packet_length); + return error_code; +} + int clustrix_connection::scan_next(ulonglong scan_refid, uchar **rowdata, ulong *rowdata_length) { @@ -693,6 +739,9 @@ int clustrix_connection::add_command_operand_str(const uchar *str, if (error_code) return error_code; + if (!str_length) + return 0; + error_code = expand_command_buffer(str_length); if (error_code) return error_code; diff --git a/storage/clustrixdb/clustrix_connection.h b/storage/clustrixdb/clustrix_connection.h index c030f5a9957..67bd2f4f162 100644 --- a/storage/clustrixdb/clustrix_connection.h +++ b/storage/clustrixdb/clustrix_connection.h @@ -44,18 +44,22 @@ public: clustrix_connection() : command_buffer(NULL), command_buffer_length(0), command_length(0) { + DBUG_ENTER("clustrix_connection::clustrix_connection"); memset(&clustrix_net, 0, sizeof(MYSQL)); has_statement_trans = FALSE; has_transaction = FALSE; + DBUG_VOID_RETURN; } ~clustrix_connection() { + DBUG_ENTER("clustrix_connection::~clustrix_connection"); if (is_connected()) disconnect(TRUE); if (command_buffer) my_free(command_buffer); + DBUG_VOID_RETURN; } inline bool is_connected() @@ -97,6 +101,15 @@ public: uchar **rowdata, ulong *rowdata_length); enum sort_order {SORT_NONE = 0, SORT_ASC = 1, SORT_DESC = 2}; + enum scan_type { + READ_KEY_OR_NEXT, /* rows with key and greater */ + READ_KEY_OR_PREV, /* rows with key and less. */ + READ_AFTER_KEY, /* rows with keys greater than key */ + READ_BEFORE_KEY, /* rows with keys less than key */ + READ_FROM_START, /* rows with forwards from first key. */ + READ_FROM_LAST, /* rows with backwards from last key. */ + }; + int scan_table(ulonglong clustrix_table_oid, uint index, enum sort_order sort, MY_BITMAP *read_set, ulonglong *scan_refid); @@ -105,6 +118,10 @@ public: int scan_query(String &stmt, uchar *fieldtype, uint fields, uchar *null_bits, uint null_bits_size, uchar *field_metadata, uint field_metadata_size, ulonglong *scan_refid); + int scan_from_key(ulonglong clustrix_table_oid, uint index, + enum scan_type scan_dir, bool sorted_scan, + MY_BITMAP *read_set, uchar *packed_key, + ulong packed_key_length, ulonglong *scan_refid); int populate_table_list(LEX_CSTRING *db, handlerton::discovered_list *result); int discover_table_details(LEX_CSTRING *db, LEX_CSTRING *name, THD *thd, diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index 5edb786747b..215c48fe179 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -528,6 +528,13 @@ int ha_clustrixdb::index_init(uint idx, bool sorted) add_current_table_to_rpl_table_list(); scan_refid = 0; + /* Return all columns until there is a better understanding of + requirements. */ + if (my_bitmap_init(&scan_fields, NULL, table->read_set->n_bits, false)) + return ER_OUTOFMEMORY; + bitmap_set_all(&scan_fields); + sorted_scan = sorted; + return 0; } @@ -542,7 +549,7 @@ int ha_clustrixdb::index_read(uchar * buf, const uchar * key, uint key_len, if (!trx) DBUG_RETURN(error_code); - is_scan = false; + is_scan = true; key_restore(table->record[0], key, &table->key_info[active_index], key_len); // The estimate should consider only key fields widths. size_t packed_key_len; @@ -550,92 +557,82 @@ int ha_clustrixdb::index_read(uchar * buf, const uchar * key, uint key_len, build_key_packed_row(active_index, table->record[0], packed_key, &packed_key_len); - uchar *rowdata; - ulong rowdata_length; - if ((error_code = trx->key_read(clustrix_table_oid, active_index, - table->read_set, packed_key, packed_key_len, - &rowdata, &rowdata_length))) - goto err; - - uchar const *current_row_end; - ulong master_reclength; - if ((error_code = unpack_row(rgi, table, table->s->fields, rowdata, - table->read_set, ¤t_row_end, - &master_reclength, rowdata + rowdata_length))) - goto err; + //bool exact = false; + clustrix_connection::scan_type st; + switch (find_flag) { + case HA_READ_KEY_EXACT: + //exact = true; + /* fall through */ + //DBUG_RETURN(ER_NOT_SUPPORTED_YET); + case HA_READ_KEY_OR_NEXT: + st = clustrix_connection::READ_KEY_OR_NEXT; + break; + case HA_READ_KEY_OR_PREV: + st = clustrix_connection::READ_KEY_OR_PREV; + break; + case HA_READ_AFTER_KEY: + st = clustrix_connection::READ_AFTER_KEY; + break; + case HA_READ_BEFORE_KEY: + st = clustrix_connection::READ_BEFORE_KEY; + break; + case HA_READ_PREFIX: + case HA_READ_PREFIX_LAST: + case HA_READ_PREFIX_LAST_OR_PREV: + case HA_READ_MBR_CONTAIN: + case HA_READ_MBR_INTERSECT: + case HA_READ_MBR_WITHIN: + case HA_READ_MBR_DISJOINT: + case HA_READ_MBR_EQUAL: + DBUG_RETURN(ER_NOT_SUPPORTED_YET); + } -err: + error_code = trx->scan_from_key(clustrix_table_oid, active_index, st, + sorted_scan, &scan_fields, packed_key, + packed_key_len, &scan_refid); if (packed_key) my_afree(packed_key); - DBUG_RETURN(error_code); + if (error_code) + DBUG_RETURN(error_code); + + DBUG_RETURN(rnd_next(buf)); } int ha_clustrixdb::index_first(uchar *buf) { + DBUG_ENTER("ha_clustrixdb::index_read"); int error_code = 0; THD *thd = ha_thd(); clustrix_connection *trx = get_trx(thd, &error_code); if (!trx) - return error_code; - - is_scan = true; - - if (my_bitmap_init(&scan_fields, NULL, table->read_set->n_bits, false)) - return ER_OUTOFMEMORY; -#if 0 - if (table->s->keys) - table->mark_columns_used_by_index(table->s->primary_key, &scan_fields); - else - bitmap_clear_all(&scan_fields); - - bitmap_union(&scan_fields, table->read_set); -#else - /* Why is read_set not setup correctly? */ - bitmap_set_all(&scan_fields); -#endif - - if ((error_code = trx->scan_table(clustrix_table_oid, active_index, - clustrix_connection::SORT_NONE, - &scan_fields, &scan_refid))) - return error_code; + DBUG_RETURN(error_code); + if ((error_code = trx->scan_from_key(clustrix_table_oid, active_index, + clustrix_connection::READ_FROM_START, + sorted_scan, &scan_fields, NULL, 0, + &scan_refid))) + DBUG_RETURN(error_code); - return rnd_next(buf); + DBUG_RETURN(rnd_next(buf)); } int ha_clustrixdb::index_last(uchar *buf) { + DBUG_ENTER("ha_clustrixdb::index_read"); int error_code = 0; THD *thd = ha_thd(); clustrix_connection *trx = get_trx(thd, &error_code); if (!trx) - return error_code; - - is_scan = true; - - if (my_bitmap_init(&scan_fields, NULL, table->read_set->n_bits, false)) - return ER_OUTOFMEMORY; -#if 0 - if (table->s->keys) - table->mark_columns_used_by_index(table->s->primary_key, &scan_fields); - else - bitmap_clear_all(&scan_fields); - - bitmap_union(&scan_fields, table->read_set); -#else - /* Why is read_set not setup correctly? */ - bitmap_set_all(&scan_fields); -#endif - - if ((error_code = trx->scan_table(clustrix_table_oid, active_index, - clustrix_connection::SORT_NONE, - &scan_fields, &scan_refid))) - return error_code; - + DBUG_RETURN(error_code); - return rnd_next(buf); + if ((error_code = trx->scan_from_key(clustrix_table_oid, active_index, + clustrix_connection::READ_FROM_LAST, + sorted_scan, &scan_fields, NULL, 0, + &scan_refid))) + DBUG_RETURN(error_code); + DBUG_RETURN(rnd_next(buf)); } int ha_clustrixdb::index_next(uchar *buf) diff --git a/storage/clustrixdb/ha_clustrixdb.h b/storage/clustrixdb/ha_clustrixdb.h index 23646693112..2cc97165374 100644 --- a/storage/clustrixdb/ha_clustrixdb.h +++ b/storage/clustrixdb/ha_clustrixdb.h @@ -41,6 +41,7 @@ private: ulonglong scan_refid; bool is_scan; MY_BITMAP scan_fields; + bool sorted_scan; public: ha_clustrixdb(handlerton *hton, TABLE_SHARE *table_arg); -- cgit v1.2.1 From 5f33f012bb056038e5ab6acc2d789dcd68b1da1b Mon Sep 17 00:00:00 2001 From: Roman Nozdrin Date: Fri, 13 Sep 2019 14:01:17 +0000 Subject: Rebased the branch on top of 10.5 as of a039b08. --- storage/clustrixdb/ha_clustrixdb.cc | 2 +- storage/clustrixdb/ha_clustrixdb.h | 2 +- storage/clustrixdb/ha_clustrixdb_pushdown.cc | 8 +++++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index 215c48fe179..74be18ada9c 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -341,7 +341,7 @@ int ha_clustrixdb::reset() return 0; } -int ha_clustrixdb::write_row(uchar *buf) +int ha_clustrixdb::write_row(const uchar *buf) { int error_code = 0; THD *thd = ha_thd(); diff --git a/storage/clustrixdb/ha_clustrixdb.h b/storage/clustrixdb/ha_clustrixdb.h index 2cc97165374..05c3845cbb1 100644 --- a/storage/clustrixdb/ha_clustrixdb.h +++ b/storage/clustrixdb/ha_clustrixdb.h @@ -52,7 +52,7 @@ public: int open(const char *name, int mode, uint test_if_locked); int close(void); int reset(); - int write_row(uchar *buf); + int write_row(const uchar *buf); // start_bulk_update exec_bulk_update int update_row(const uchar *old_data, const uchar *new_data); // start_bulk_delete exec_bulk_delete diff --git a/storage/clustrixdb/ha_clustrixdb_pushdown.cc b/storage/clustrixdb/ha_clustrixdb_pushdown.cc index 224efe0dab3..02def2e2f4e 100644 --- a/storage/clustrixdb/ha_clustrixdb_pushdown.cc +++ b/storage/clustrixdb/ha_clustrixdb_pushdown.cc @@ -55,7 +55,13 @@ int get_field_types(THD *thd, SELECT_LEX *sl, uchar *fieldtype, bzero(field_metadata, (tmp_table_param.field_count * 2)); for (unsigned int i= 0 ; i < tmp_table_param.field_count ; i++) { - metadata_index+= tmp_table->field[i]->save_field_metadata(&field_metadata[metadata_index]); + Binlog_type_info bti= tmp_table->field[i]->binlog_type_info(); + uchar *ptr = reinterpret_cast(&bti.m_metadata); + // Binlog_type_info::m_metadata is u16 + if (bti.m_metadata_size == 1) + field_metadata[metadata_index++]= *ptr++; + if (bti.m_metadata_size == 2) + field_metadata[metadata_index++]= *ptr++; } if (metadata_index < 251) -- cgit v1.2.1 From 17ee32fbe63c75f4d36ebdf22d0a7b44c81faefe Mon Sep 17 00:00:00 2001 From: Roman Nozdrin Date: Tue, 17 Sep 2019 12:09:38 +0000 Subject: CLX-19 DH now executes a query only if SH fails. --- mysql-test/suite/clustrixdb/basics.result | 9 +- mysql-test/suite/clustrixdb/basics.test | 6 +- storage/clustrixdb/ha_clustrixdb_pushdown.cc | 148 ++++++++++++++------------- 3 files changed, 85 insertions(+), 78 deletions(-) diff --git a/mysql-test/suite/clustrixdb/basics.result b/mysql-test/suite/clustrixdb/basics.result index 3c0ea581011..04e8a942532 100644 --- a/mysql-test/suite/clustrixdb/basics.result +++ b/mysql-test/suite/clustrixdb/basics.result @@ -14,8 +14,6 @@ DROP TABLE cx1; SHOW CREATE TABLE cx1; ERROR 42S02: Table 'clx.cx1' doesn't exist DROP TABLE IF EXISTS intandtext; -Warnings: -Note 1051 Unknown table 'clx.intandtext' CREATE TABLE intandtext(i bigint, t text)ENGINE=clustrixdb; INSERT INTO intandtext VALUES(10, 'someqwqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq'); SELECT i,t FROM intandtext; @@ -24,6 +22,7 @@ i t EXPLAIN SELECT i,t FROM intandtext; id select_type table type possible_keys key key_len ref rows Extra 1 PUSHED SELECT NULL NULL NULL NULL NULL NULL NULL NULL +SET @@optimizer_switch='derived_merge=OFF'; SET clustrixdb_select_handler=OFF; SELECT i,t FROM (SELECT i,t FROM intandtext) t; i t @@ -32,17 +31,17 @@ EXPLAIN SELECT i,t FROM (SELECT i,t FROM intandtext) t; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL NULL NULL NULL NULL 10000 2 PUSHED DERIVED NULL NULL NULL NULL NULL NULL NULL NULL -SET clustrixdb_select_handler=OFF; +SET clustrixdb_derived_handler=OFF; SELECT i,t FROM intandtext; i t 10 someqwqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq SELECT i,t FROM (SELECT i,t FROM intandtext) t; i t -10 someqwqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq +10 someqwqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq EXPLAIN SELECT i,t FROM (SELECT i,t FROM intandtext) t; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL NULL NULL NULL NULL 10000 -2 PUSHED DERIVED NULL NULL NULL NULL NULL NULL NULL NULL +2 DERIVED intandtext ALL NULL NULL NULL NULL 10000 DROP TABLE intandtext; USE test; DROP DATABASE clx; diff --git a/mysql-test/suite/clustrixdb/basics.test b/mysql-test/suite/clustrixdb/basics.test index e5c7ae355c5..81a81983bf3 100644 --- a/mysql-test/suite/clustrixdb/basics.test +++ b/mysql-test/suite/clustrixdb/basics.test @@ -20,14 +20,14 @@ CREATE TABLE intandtext(i bigint, t text)ENGINE=clustrixdb; INSERT INTO intandtext VALUES(10, 'someqwqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq'); SELECT i,t FROM intandtext; - EXPLAIN SELECT i,t FROM intandtext; -SET clustrixdb_select_handler=OFF; +SET @@optimizer_switch='derived_merge=OFF'; +SET clustrixdb_select_handler=OFF; SELECT i,t FROM (SELECT i,t FROM intandtext) t; EXPLAIN SELECT i,t FROM (SELECT i,t FROM intandtext) t; -SET clustrixdb_select_handler=OFF; +SET clustrixdb_derived_handler=OFF; SELECT i,t FROM intandtext; SELECT i,t FROM (SELECT i,t FROM intandtext) t; EXPLAIN SELECT i,t FROM (SELECT i,t FROM intandtext) t; diff --git a/storage/clustrixdb/ha_clustrixdb_pushdown.cc b/storage/clustrixdb/ha_clustrixdb_pushdown.cc index 02def2e2f4e..673ef5fcc6f 100644 --- a/storage/clustrixdb/ha_clustrixdb_pushdown.cc +++ b/storage/clustrixdb/ha_clustrixdb_pushdown.cc @@ -13,55 +13,58 @@ extern handlerton *clustrixdb_hton; * Fills up three arrays with: field binlog data types, field * metadata and nullability bitmask as in Table_map_log_event * ctor. Internally creates a temporary table as does - * Pushdown_select. + * Pushdown_select. DH uses the actual temp table w/o + * b/c create_DH is called later compared to create_SH. * More details in server/sql/log_event_server.cc * PARAMETERS: * thd - THD* + * table__ - TABLE* temp table for the results * sl - SELECT_LEX* * fieldtype - uchar* * field_metadata - uchar* * null_bits - uchar* * num_null_bytes - null bit size + * fields_count - a number of fields * RETURN: * metadata_size int or -1 in case of error ************************************************************/ -int get_field_types(THD *thd, SELECT_LEX *sl, uchar *fieldtype, - uchar *field_metadata, uchar *null_bits, const int num_null_bytes) +int get_field_types(THD *thd, TABLE *table__, SELECT_LEX *sl, uchar *fieldtype, + uchar *field_metadata, uchar *null_bits, const int num_null_bytes, const uint fields_count) { int field_metadata_size = 0; int metadata_index = 0; + TABLE *tmp_table= table__; - // Construct a tmp table with fields to find out result DTs. - // This should be reconsidered if it worths the effort. - List types; - TMP_TABLE_PARAM tmp_table_param; - sl->master_unit()->join_union_item_types(thd, types, 1); - tmp_table_param.init(); - tmp_table_param.field_count= types.elements; - - TABLE *tmp_table = create_tmp_table(thd, &tmp_table_param, types, - (ORDER *) 0, false, 0, - TMP_TABLE_ALL_COLUMNS, 1, - &empty_clex_str, true, false); if (!tmp_table) { - field_metadata_size = -1; - goto err; + // Construct a tmp table with fields to find out result DTs. + // This should be reconsidered if it worths the effort. + List types; + TMP_TABLE_PARAM tmp_table_param; + sl->master_unit()->join_union_item_types(thd, types, 1); + tmp_table_param.init(); + tmp_table_param.field_count= types.elements; + + tmp_table = create_tmp_table(thd, &tmp_table_param, types, + (ORDER *) 0, false, 0, + TMP_TABLE_ALL_COLUMNS, 1, + &empty_clex_str, true, false); + if (!tmp_table) { + field_metadata_size = -1; + goto err; + } } - for (unsigned int i = 0 ; i < tmp_table_param.field_count; ++i) { + for (unsigned int i = 0 ; i < fields_count; ++i) { fieldtype[i]= tmp_table->field[i]->binlog_type(); } - bzero(field_metadata, (tmp_table_param.field_count * 2)); - for (unsigned int i= 0 ; i < tmp_table_param.field_count ; i++) + bzero(field_metadata, (fields_count * 2)); + for (unsigned int i= 0 ; i < fields_count ; i++) { Binlog_type_info bti= tmp_table->field[i]->binlog_type_info(); uchar *ptr = reinterpret_cast(&bti.m_metadata); - // Binlog_type_info::m_metadata is u16 - if (bti.m_metadata_size == 1) - field_metadata[metadata_index++]= *ptr++; - if (bti.m_metadata_size == 2) - field_metadata[metadata_index++]= *ptr++; + memcpy(&field_metadata[metadata_index], ptr, bti.m_metadata_size); + metadata_index+= bti.m_metadata_size; } if (metadata_index < 251) @@ -70,13 +73,14 @@ int get_field_types(THD *thd, SELECT_LEX *sl, uchar *fieldtype, field_metadata_size += metadata_index + 3; bzero(null_bits, num_null_bytes); - for (unsigned int i= 0 ; i < tmp_table_param.field_count ; ++i) { + for (unsigned int i= 0 ; i < fields_count ; ++i) { if (tmp_table->field[i]->maybe_null()) { null_bits[(i / 8)]+= 1 << (i % 8); } } - free_tmp_table(thd, tmp_table); + if (!table__) + free_tmp_table(thd, tmp_table); err: return field_metadata_size; } @@ -126,7 +130,7 @@ create_clustrixdb_select_handler(THD* thd, SELECT_LEX* select_lex) } if((field_metadata_size = - get_field_types(thd, select_lex, fieldtype, field_metadata, null_bits, num_null_bytes)) < 0) { + get_field_types(thd, NULL, select_lex, fieldtype, field_metadata, null_bits, num_null_bytes, items_number)) < 0) { goto err; } @@ -284,52 +288,12 @@ create_clustrixdb_derived_handler(THD* thd, TABLE_LIST *derived) } SELECT_LEX_UNIT *unit= derived->derived; - // *DRRTUY Check for potential UNIONS in derived SELECT_LEX *select_lex = unit->first_select(); String query; - // Print the query into a string provided - select_lex->print(thd, &query, QT_ORDINARY); - int error_code = 0; - int field_metadata_size = 0; ulonglong scan_refid = 0; - clustrix_connection *trx = NULL; - - // We presume this number is equal to types.elements in get_field_types - uint items_number = select_lex->get_item_list()->elements; - uint num_null_bytes = (items_number + 7) / 8; - uchar *fieldtype = NULL; - uchar *null_bits = NULL; - uchar *field_metadata = NULL; - uchar *meta_memory= (uchar *)my_multi_malloc(MYF(MY_WME), &fieldtype, items_number, - &null_bits, num_null_bytes, &field_metadata, (items_number * 2), NULL); - - if (!meta_memory) { - // The only way to say something here is to raise warning - // b/c we will fallback to other access methods: derived handler or rowstore. - goto err; - } - - if((field_metadata_size = - get_field_types(thd, select_lex, fieldtype, field_metadata, null_bits, num_null_bytes)) < 0) { - goto err; - } - - trx = get_trx(thd, &error_code); - if (!trx) - goto err; - - if ((error_code = trx->scan_query(query, fieldtype, items_number, - null_bits, num_null_bytes, field_metadata, field_metadata_size, &scan_refid))) { - goto err; - } - + dh = new ha_clustrixdb_derived_handler(thd, select_lex, scan_refid); -err: - // deallocate buffers - if (meta_memory) - my_free(meta_memory); - return dh; } @@ -362,6 +326,9 @@ ha_clustrixdb_derived_handler::ha_clustrixdb_derived_handler( ha_clustrixdb_derived_handler::~ha_clustrixdb_derived_handler() { int error_code; + + + clustrix_connection *trx = get_trx(thd, &error_code); if (!trx) { // TBD Log this. @@ -389,6 +356,42 @@ int ha_clustrixdb_derived_handler::init_scan() { // Save this into the base handler class attribute table__ = table; + String query; + // Print the query into a string provided + select->print(thd__, &query, QT_ORDINARY); + int error_code = 0; + int field_metadata_size = 0; + clustrix_connection *trx = NULL; + + // We presume this number is equal to types.elements in get_field_types + uint items_number= select->get_item_list()->elements; + uint num_null_bytes = (items_number + 7) / 8; + uchar *fieldtype = NULL; + uchar *null_bits = NULL; + uchar *field_metadata = NULL; + uchar *meta_memory= (uchar *)my_multi_malloc(MYF(MY_WME), &fieldtype, items_number, + &null_bits, num_null_bytes, &field_metadata, (items_number * 2), NULL); + + if (!meta_memory) { + // The only way to say something here is to raise warning + // b/c we will fallback to other access methods: derived handler or rowstore. + goto err; + } + + if((field_metadata_size= + get_field_types(thd__, table__, select, fieldtype, field_metadata, null_bits, num_null_bytes, items_number)) < 0) { + goto err; + } + + trx = get_trx(thd__, &error_code); + if (!trx) + goto err; + + if ((error_code = trx->scan_query(query, fieldtype, items_number, + null_bits, num_null_bytes, field_metadata, field_metadata_size, &scan_refid))) { + goto err; + } + // need this bitmap future in next_row() if (my_bitmap_init(&scan_fields, NULL, table->read_set->n_bits, false)) return ER_OUTOFMEMORY; @@ -396,7 +399,12 @@ int ha_clustrixdb_derived_handler::init_scan() add_current_table_to_rpl_table_list(); - return 0; +err: + // deallocate buffers + if (meta_memory) + my_free(meta_memory); + + return error_code; } /*@brief Fetch next row for derived_handler */ -- cgit v1.2.1 From a5ffb981620bf97c5a770fc44dc91bee880e3eb8 Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Thu, 12 Sep 2019 16:56:37 -0700 Subject: Buffer rows from Clustrix. --- storage/clustrixdb/clustrix_connection.cc | 225 +++++++++++++++++++++++---- storage/clustrixdb/clustrix_connection.h | 21 ++- storage/clustrixdb/ha_clustrixdb.cc | 52 ++++--- storage/clustrixdb/ha_clustrixdb.h | 3 +- storage/clustrixdb/ha_clustrixdb_pushdown.cc | 48 +++--- storage/clustrixdb/ha_clustrixdb_pushdown.h | 6 +- 6 files changed, 270 insertions(+), 85 deletions(-) diff --git a/storage/clustrixdb/clustrix_connection.cc b/storage/clustrixdb/clustrix_connection.cc index 08c636c52ef..e1b991a012d 100644 --- a/storage/clustrixdb/clustrix_connection.cc +++ b/storage/clustrixdb/clustrix_connection.cc @@ -355,9 +355,147 @@ int clustrix_connection::key_read(ulonglong clustrix_table_oid, uint index, return 0; } +class clustrix_connection_cursor { + struct rowdata { + ulong length; + uchar *data; + }; + + ulong current_row; + ulong last_row; + struct rowdata *rows; + uchar *outstanding_row; // to be freed on next request. + MYSQL *clustrix_net; + +public: + ulong buffer_size; + ulonglong scan_refid; + bool eof_reached; + +private: + int cache_row(uchar *rowdata, ulong rowdata_length) + { + DBUG_ENTER("clustrix_connection_cursor::cache_row"); + rows[last_row].length = rowdata_length; + rows[last_row].data = (uchar *)my_malloc(rowdata_length, MYF(MY_WME)); + if (!rows[last_row].data) + DBUG_RETURN(HA_ERR_OUT_OF_MEM); + memcpy(rows[last_row].data, rowdata, rowdata_length); + last_row++; + DBUG_RETURN(0); + } + + int load_rows_impl() + { + DBUG_ENTER("clustrix_connection_cursor::load_rows_impl"); + int error_code = 0; + ulong packet_length = cli_safe_read(clustrix_net); + if (packet_length == packet_error) { + error_code = mysql_errno(clustrix_net); + if (error_code == HA_ERR_END_OF_FILE) { + // We have read all rows for query. + eof_reached = TRUE; + DBUG_RETURN(0); + } + DBUG_RETURN(error_code); + } + + uchar *rowdata = clustrix_net->net.read_pos; + ulong rowdata_length = safe_net_field_length_ll(&rowdata, packet_length); + if (!rowdata_length) { + // We have read all rows in this batch. + DBUG_RETURN(0); + } + + if ((error_code = cache_row(rowdata, rowdata_length))) + DBUG_RETURN(error_code); + + DBUG_RETURN(load_rows_impl()); + } + +public: + clustrix_connection_cursor(MYSQL *clustrix_net_, ulong bufsize) + { + DBUG_ENTER("clustrix_connection_cursor::clustrix_connection_cursor"); + clustrix_net = clustrix_net_; + eof_reached = FALSE; + current_row = 0; + last_row = 0; + outstanding_row = NULL; + buffer_size = bufsize; + rows = NULL; + DBUG_VOID_RETURN; + } + + ~clustrix_connection_cursor() + { + DBUG_ENTER("clustrix_connection_cursor::~clustrix_connection_cursor"); + if (outstanding_row) + my_free(outstanding_row); + while (current_row < last_row) + my_free(rows[current_row++].data); + if (rows) + my_free(rows); + DBUG_VOID_RETURN; + } + + int load_rows() + { + DBUG_ENTER("clustrix_connection_cursor::load_rows"); + current_row = 0; + last_row = 0; + DBUG_RETURN(load_rows_impl()); + } + + int initialize() + { + DBUG_ENTER("clustrix_connection_cursor::initialize"); + ulong packet_length = cli_safe_read(clustrix_net); + if (packet_length == packet_error) + DBUG_RETURN(mysql_errno(clustrix_net)); + + unsigned char *pos = clustrix_net->net.read_pos; + scan_refid = safe_net_field_length_ll(&pos, packet_length); + + rows = (struct rowdata *)my_malloc(buffer_size * sizeof(struct rowdata), + MYF(MY_WME)); + if (!rows) + DBUG_RETURN(HA_ERR_OUT_OF_MEM); + + DBUG_RETURN(load_rows()); + } + + uchar *retrieve_row(ulong *rowdata_length) + { + DBUG_ENTER("clustrix_connection_cursor::retrieve_row"); + if (outstanding_row) { + my_free(outstanding_row); + outstanding_row = NULL; + } + if (current_row == last_row) + DBUG_RETURN(NULL); + *rowdata_length = rows[current_row].length; + outstanding_row = rows[current_row].data; + current_row++; + DBUG_RETURN(outstanding_row); + } +}; + +int allocate_clustrix_connection_cursor(MYSQL *clustrix_net, ulong buffer_size, + clustrix_connection_cursor **scan) +{ + DBUG_ENTER("allocate_clustrix_connection_cursor"); + *scan = new clustrix_connection_cursor(clustrix_net, buffer_size); + if (!*scan) + DBUG_RETURN(HA_ERR_OUT_OF_MEM); + + DBUG_RETURN((*scan)->initialize()); +} + int clustrix_connection::scan_table(ulonglong clustrix_table_oid, uint index, enum sort_order sort, MY_BITMAP *read_set, - ulonglong *scan_refid) + ushort row_req, + clustrix_connection_cursor **scan) { int error_code; command_length = 0; @@ -365,6 +503,9 @@ int clustrix_connection::scan_table(ulonglong clustrix_table_oid, uint index, if ((error_code = add_command_operand_uchar(CLUSTRIX_SCAN_TABLE))) return error_code; + if ((error_code = add_command_operand_ushort(row_req))) + return error_code; + if ((error_code = add_command_operand_ulonglong(clustrix_table_oid))) return error_code; @@ -380,13 +521,7 @@ int clustrix_connection::scan_table(ulonglong clustrix_table_oid, uint index, if ((error_code = send_command())) return error_code; - ulong packet_length = cli_safe_read(&clustrix_net); - if (packet_length == packet_error) - return mysql_errno(&clustrix_net); - - unsigned char *pos = clustrix_net.net.read_pos; - *scan_refid = safe_net_field_length_ll(&pos, packet_length); - return error_code; + return allocate_clustrix_connection_cursor(&clustrix_net, row_req, scan); } /** @@ -410,7 +545,8 @@ int clustrix_connection::scan_query(String &stmt, uchar *fieldtype, uint fields, uchar *null_bits, uint null_bits_size, uchar *field_metadata, uint field_metadata_size, - ulonglong *scan_refid) + ushort row_req, + clustrix_connection_cursor **scan) { int error_code; command_length = 0; @@ -418,6 +554,9 @@ int clustrix_connection::scan_query(String &stmt, uchar *fieldtype, uint fields, if ((error_code = add_command_operand_uchar(CLUSTRIX_SCAN_QUERY))) return error_code; + if ((error_code = add_command_operand_ushort(row_req))) + return error_code; + if ((error_code = add_command_operand_str((uchar*)stmt.ptr(), stmt.length()))) return error_code; @@ -434,13 +573,7 @@ int clustrix_connection::scan_query(String &stmt, uchar *fieldtype, uint fields, if ((error_code = send_command())) return error_code; - ulong packet_length = cli_safe_read(&clustrix_net); - if (packet_length == packet_error) - return mysql_errno(&clustrix_net); - - unsigned char *pos = clustrix_net.net.read_pos; - *scan_refid = safe_net_field_length_ll(&pos, packet_length); - return error_code; + return allocate_clustrix_connection_cursor(&clustrix_net, row_req, scan); } int clustrix_connection::scan_from_key(ulonglong clustrix_table_oid, uint index, @@ -448,7 +581,8 @@ int clustrix_connection::scan_from_key(ulonglong clustrix_table_oid, uint index, bool sorted_scan, MY_BITMAP *read_set, uchar *packed_key, ulong packed_key_length, - ulonglong *scan_refid) + ushort row_req, + clustrix_connection_cursor **scan) { int error_code; command_length = 0; @@ -456,6 +590,9 @@ int clustrix_connection::scan_from_key(ulonglong clustrix_table_oid, uint index, if ((error_code = add_command_operand_uchar(CLUSTRIX_SCAN_FROM_KEY))) return error_code; + if ((error_code = add_command_operand_ushort(row_req))) + return error_code; + if ((error_code = add_command_operand_ulonglong(clustrix_table_oid))) return error_code; @@ -477,44 +614,54 @@ int clustrix_connection::scan_from_key(ulonglong clustrix_table_oid, uint index, if ((error_code = send_command())) return error_code; - ulong packet_length = cli_safe_read(&clustrix_net); - if (packet_length == packet_error) - return mysql_errno(&clustrix_net); - - unsigned char *pos = clustrix_net.net.read_pos; - *scan_refid = safe_net_field_length_ll(&pos, packet_length); - return error_code; + return allocate_clustrix_connection_cursor(&clustrix_net, row_req, scan); } -int clustrix_connection::scan_next(ulonglong scan_refid, uchar **rowdata, - ulong *rowdata_length) +int clustrix_connection::scan_next(clustrix_connection_cursor *scan, + uchar **rowdata, ulong *rowdata_length) { + *rowdata = scan->retrieve_row(rowdata_length); + if (*rowdata) + return 0; + + if (scan->eof_reached) + return HA_ERR_END_OF_FILE; + int error_code; command_length = 0; if ((error_code = add_command_operand_uchar(CLUSTRIX_SCAN_NEXT))) return error_code; - if ((error_code = add_command_operand_lcb(scan_refid))) + if ((error_code = add_command_operand_ushort(scan->buffer_size))) + return error_code; + + if ((error_code = add_command_operand_lcb(scan->scan_refid))) return error_code; if ((error_code = send_command())) return error_code; - ulong packet_length = cli_safe_read(&clustrix_net); - if (packet_length == packet_error) - return mysql_errno(&clustrix_net); + if ((error_code = scan->load_rows())) + return error_code; - *rowdata = clustrix_net.net.read_pos; - *rowdata_length = safe_net_field_length_ll(rowdata, packet_length); + *rowdata = scan->retrieve_row(rowdata_length); + if (!*rowdata) + return HA_ERR_END_OF_FILE; return 0; } -int clustrix_connection::scan_end(ulonglong scan_refid) +int clustrix_connection::scan_end(clustrix_connection_cursor *scan) { int error_code; command_length = 0; + ulonglong scan_refid = scan->scan_refid; + bool eof_reached = scan->eof_reached; + delete scan; + + if (eof_reached) + return 0; if ((error_code = add_command_operand_uchar(CLUSTRIX_SCAN_STOP))) return error_code; @@ -696,6 +843,18 @@ int clustrix_connection::add_command_operand_uchar(uchar value) return 0; } +int clustrix_connection::add_command_operand_ushort(ushort value) +{ + ushort be_value = htobe16(value); + int error_code = expand_command_buffer(sizeof(be_value)); + if (error_code) + return error_code; + + memcpy(command_buffer + command_length, &be_value, sizeof(be_value)); + command_length += sizeof(be_value); + return 0; +} + int clustrix_connection::add_command_operand_uint(uint value) { uint be_value = htobe32(value); diff --git a/storage/clustrixdb/clustrix_connection.h b/storage/clustrixdb/clustrix_connection.h index 67bd2f4f162..1ba35db5766 100644 --- a/storage/clustrixdb/clustrix_connection.h +++ b/storage/clustrixdb/clustrix_connection.h @@ -21,6 +21,7 @@ Copyright (c) 2019, MariaDB Corporation. #define CLUSTRIX_SERVER_REQUEST 30 +class clustrix_connection_cursor; class clustrix_connection { private: @@ -28,7 +29,6 @@ private: # define COMMAND_BUFFER_SIZE_INCREMENT_BITS 10 MYSQL clustrix_net; - MYSQL_RES *results; uchar *command_buffer; size_t command_buffer_length; size_t command_length; @@ -111,24 +111,29 @@ public: }; int scan_table(ulonglong clustrix_table_oid, uint index, - enum sort_order sort, MY_BITMAP *read_set, - ulonglong *scan_refid); - int scan_next(ulonglong scan_refid, uchar **rowdata, ulong *rowdata_length); - int scan_end(ulonglong scan_refid); + enum sort_order sort, MY_BITMAP *read_set, ushort row_req, + clustrix_connection_cursor **scan); int scan_query(String &stmt, uchar *fieldtype, uint fields, uchar *null_bits, uint null_bits_size, uchar *field_metadata, - uint field_metadata_size, ulonglong *scan_refid); - int scan_from_key(ulonglong clustrix_table_oid, uint index, + uint field_metadata_size, ushort row_req, + clustrix_connection_cursor **scan); + int scan_from_key(ulonglong clustrix_table_oid, uint index, enum scan_type scan_dir, bool sorted_scan, MY_BITMAP *read_set, uchar *packed_key, - ulong packed_key_length, ulonglong *scan_refid); + ulong packed_key_length, ushort row_req, + clustrix_connection_cursor **scan); + int scan_next(clustrix_connection_cursor *scan, uchar **rowdata, + ulong *rowdata_length); + int scan_end(clustrix_connection_cursor *scan); int populate_table_list(LEX_CSTRING *db, handlerton::discovered_list *result); int discover_table_details(LEX_CSTRING *db, LEX_CSTRING *name, THD *thd, TABLE_SHARE *share); + private: int expand_command_buffer(size_t add_length); int add_command_operand_uchar(uchar value); + int add_command_operand_ushort(ushort value); int add_command_operand_uint(uint value); int add_command_operand_ulonglong(ulonglong value); int add_command_operand_lcb(ulonglong value); diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index 74be18ada9c..c1cab7f36d9 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -90,6 +90,14 @@ static MYSQL_SYSVAR_STR NULL, NULL, "" ); +static MYSQL_THDVAR_UINT +( + row_buffer, + PLUGIN_VAR_RQCMDARG, + "Clustrix rowstore row buffer size", + NULL, NULL, 20, 1, 65535, 0 +); + // Per thread select handler knob static MYSQL_THDVAR_BOOL( select_handler, @@ -119,6 +127,11 @@ bool derived_handler_setting(THD* thd) return ( thd == NULL ) ? false : THDVAR(thd, derived_handler); } +uint row_buffer_setting(THD* thd) +{ + return THDVAR(thd, row_buffer); +} + /**************************************************************************** ** Utility functions ****************************************************************************/ @@ -183,7 +196,7 @@ ha_clustrixdb::ha_clustrixdb(handlerton *hton, TABLE_SHARE *table_arg) DBUG_ENTER("ha_clustrixdb::ha_clustrixdb"); rli = NULL; rgi = NULL; - scan_refid = 0; + scan_cur = NULL; clustrix_table_oid = 0; DBUG_VOID_RETURN; } @@ -526,7 +539,7 @@ int ha_clustrixdb::index_init(uint idx, bool sorted) active_index = idx; add_current_table_to_rpl_table_list(); - scan_refid = 0; + scan_cur = NULL; /* Return all columns until there is a better understanding of requirements. */ @@ -562,9 +575,9 @@ int ha_clustrixdb::index_read(uchar * buf, const uchar * key, uint key_len, switch (find_flag) { case HA_READ_KEY_EXACT: //exact = true; - /* fall through */ + /* fall through */ //DBUG_RETURN(ER_NOT_SUPPORTED_YET); - case HA_READ_KEY_OR_NEXT: + case HA_READ_KEY_OR_NEXT: st = clustrix_connection::READ_KEY_OR_NEXT; break; case HA_READ_KEY_OR_PREV: @@ -589,7 +602,8 @@ int ha_clustrixdb::index_read(uchar * buf, const uchar * key, uint key_len, error_code = trx->scan_from_key(clustrix_table_oid, active_index, st, sorted_scan, &scan_fields, packed_key, - packed_key_len, &scan_refid); + packed_key_len, THDVAR(thd, row_buffer), + &scan_cur); if (packed_key) my_afree(packed_key); @@ -601,7 +615,7 @@ int ha_clustrixdb::index_read(uchar * buf, const uchar * key, uint key_len, int ha_clustrixdb::index_first(uchar *buf) { - DBUG_ENTER("ha_clustrixdb::index_read"); + DBUG_ENTER("ha_clustrixdb::index_first"); int error_code = 0; THD *thd = ha_thd(); clustrix_connection *trx = get_trx(thd, &error_code); @@ -609,9 +623,9 @@ int ha_clustrixdb::index_first(uchar *buf) DBUG_RETURN(error_code); if ((error_code = trx->scan_from_key(clustrix_table_oid, active_index, - clustrix_connection::READ_FROM_START, + clustrix_connection::READ_FROM_START, sorted_scan, &scan_fields, NULL, 0, - &scan_refid))) + THDVAR(thd, row_buffer), &scan_cur))) DBUG_RETURN(error_code); DBUG_RETURN(rnd_next(buf)); @@ -619,7 +633,7 @@ int ha_clustrixdb::index_first(uchar *buf) int ha_clustrixdb::index_last(uchar *buf) { - DBUG_ENTER("ha_clustrixdb::index_read"); + DBUG_ENTER("ha_clustrixdb::index_last"); int error_code = 0; THD *thd = ha_thd(); clustrix_connection *trx = get_trx(thd, &error_code); @@ -627,9 +641,9 @@ int ha_clustrixdb::index_last(uchar *buf) DBUG_RETURN(error_code); if ((error_code = trx->scan_from_key(clustrix_table_oid, active_index, - clustrix_connection::READ_FROM_LAST, + clustrix_connection::READ_FROM_LAST, sorted_scan, &scan_fields, NULL, 0, - &scan_refid))) + THDVAR(thd, row_buffer), &scan_cur))) DBUG_RETURN(error_code); DBUG_RETURN(rnd_next(buf)); @@ -658,7 +672,7 @@ int ha_clustrixdb::index_prev(uchar *buf) int ha_clustrixdb::index_end() { DBUG_ENTER("index_prev"); - if (scan_refid) + if (scan_cur) DBUG_RETURN(rnd_end()); else DBUG_RETURN(0); @@ -675,7 +689,7 @@ int ha_clustrixdb::rnd_init(bool scan) add_current_table_to_rpl_table_list(); is_scan = scan; - scan_refid = 0; + scan_cur = NULL; if (my_bitmap_init(&scan_fields, NULL, table->read_set->n_bits, false)) return ER_OUTOFMEMORY; @@ -694,7 +708,8 @@ int ha_clustrixdb::rnd_init(bool scan) if ((error_code = trx->scan_table(clustrix_table_oid, 0, clustrix_connection::SORT_NONE, - &scan_fields, &scan_refid))) + &scan_fields, THDVAR(thd, row_buffer), + &scan_cur))) return error_code; return 0; @@ -709,11 +724,11 @@ int ha_clustrixdb::rnd_next(uchar *buf) return error_code; assert(is_scan); - assert(scan_refid); + assert(scan_cur); uchar *rowdata; ulong rowdata_length; - if ((error_code = trx->scan_next(scan_refid, &rowdata, &rowdata_length))) + if ((error_code = trx->scan_next(scan_cur, &rowdata, &rowdata_length))) return error_code; if (has_hidden_key) { @@ -793,9 +808,9 @@ int ha_clustrixdb::rnd_end() return error_code; my_bitmap_free(&scan_fields); - if (scan_refid && (error_code = trx->scan_end(scan_refid))) + if (scan_cur && (error_code = trx->scan_end(scan_cur))) return error_code; - scan_refid = 0; + scan_cur = NULL; return 0; } @@ -1063,6 +1078,7 @@ static struct st_mysql_sys_var* clustrixdb_system_variables[] = MYSQL_SYSVAR(password), MYSQL_SYSVAR(port), MYSQL_SYSVAR(socket), + MYSQL_SYSVAR(row_buffer), MYSQL_SYSVAR(select_handler), MYSQL_SYSVAR(derived_handler), NULL diff --git a/storage/clustrixdb/ha_clustrixdb.h b/storage/clustrixdb/ha_clustrixdb.h index 05c3845cbb1..33a0c922d15 100644 --- a/storage/clustrixdb/ha_clustrixdb.h +++ b/storage/clustrixdb/ha_clustrixdb.h @@ -38,7 +38,7 @@ private: bool has_hidden_key; ulonglong last_hidden_key; - ulonglong scan_refid; + clustrix_connection_cursor *scan_cur; bool is_scan; MY_BITMAP scan_fields; bool sorted_scan; @@ -110,4 +110,5 @@ private: bool select_handler_setting(THD* thd); bool derived_handler_setting(THD* thd); +uint row_buffer_setting(THD* thd); #endif // _ha_clustrixdb_h diff --git a/storage/clustrixdb/ha_clustrixdb_pushdown.cc b/storage/clustrixdb/ha_clustrixdb_pushdown.cc index 673ef5fcc6f..15df8e652d1 100644 --- a/storage/clustrixdb/ha_clustrixdb_pushdown.cc +++ b/storage/clustrixdb/ha_clustrixdb_pushdown.cc @@ -6,6 +6,7 @@ Copyright (c) 2019, MariaDB Corporation. #include "ha_clustrixdb_pushdown.h" extern handlerton *clustrixdb_hton; +extern uint clustrix_row_buffer; /*@brief Fills up array data types, metadata and nullability*/ /************************************************************ @@ -111,7 +112,7 @@ create_clustrixdb_select_handler(THD* thd, SELECT_LEX* select_lex) select_lex->print(thd, &query, QT_ORDINARY); int error_code = 0; int field_metadata_size = 0; - ulonglong scan_refid = 0; + clustrix_connection_cursor *scan = NULL; clustrix_connection *trx = NULL; // We presume this number is equal to types.elements in get_field_types @@ -138,12 +139,14 @@ create_clustrixdb_select_handler(THD* thd, SELECT_LEX* select_lex) if (!trx) goto err; - if ((error_code = trx->scan_query(query, fieldtype, items_number, - null_bits, num_null_bytes, field_metadata, field_metadata_size, &scan_refid))) { + if ((error_code = trx->scan_query(query, fieldtype, items_number, null_bits, + num_null_bytes, field_metadata, + field_metadata_size, + row_buffer_setting(thd), &scan))) { goto err; } - sh = new ha_clustrixdb_select_handler(thd, select_lex, scan_refid); + sh = new ha_clustrixdb_select_handler(thd, select_lex, scan); err: // deallocate buffers @@ -163,11 +166,11 @@ err: ha_clustrixdb_select_handler::ha_clustrixdb_select_handler( THD *thd, SELECT_LEX* select_lex, - ulonglong scan_refid_) + clustrix_connection_cursor *scan_) : select_handler(thd, clustrixdb_hton) { thd__ = thd; - scan_refid = scan_refid_; + scan = scan_; select = select_lex; rli = NULL; rgi = NULL; @@ -186,8 +189,8 @@ ha_clustrixdb_select_handler::~ha_clustrixdb_select_handler() if (!trx) { // TBD Log this } - if (trx && scan_refid) - trx->scan_end(scan_refid); + if (trx && scan) + trx->scan_end(scan); // If the ::init_scan has been executed if (table__) @@ -234,11 +237,11 @@ int ha_clustrixdb_select_handler::next_row() if (!trx) return error_code; - assert(scan_refid); + assert(scan); uchar *rowdata; ulong rowdata_length; - if ((error_code = trx->scan_next(scan_refid, &rowdata, &rowdata_length))) + if ((error_code = trx->scan_next(scan, &rowdata, &rowdata_length))) return error_code; uchar const *current_row_end; @@ -290,9 +293,8 @@ create_clustrixdb_derived_handler(THD* thd, TABLE_LIST *derived) SELECT_LEX_UNIT *unit= derived->derived; SELECT_LEX *select_lex = unit->first_select(); String query; - ulonglong scan_refid = 0; - - dh = new ha_clustrixdb_derived_handler(thd, select_lex, scan_refid); + + dh = new ha_clustrixdb_derived_handler(thd, select_lex, NULL); return dh; } @@ -307,11 +309,11 @@ create_clustrixdb_derived_handler(THD* thd, TABLE_LIST *derived) ha_clustrixdb_derived_handler::ha_clustrixdb_derived_handler( THD *thd, SELECT_LEX* select_lex, - ulonglong scan_refid_) + clustrix_connection_cursor *scan_) : derived_handler(thd, clustrixdb_hton) { thd__ = thd; - scan_refid = scan_refid_; + scan = scan_; select = select_lex; rli = NULL; rgi = NULL; @@ -333,8 +335,8 @@ ha_clustrixdb_derived_handler::~ha_clustrixdb_derived_handler() if (!trx) { // TBD Log this. } - if (trx && scan_refid) - trx->scan_end(scan_refid); + if (trx && scan) + trx->scan_end(scan); // If the ::init_scan has been executed if (table__) @@ -387,8 +389,10 @@ int ha_clustrixdb_derived_handler::init_scan() if (!trx) goto err; - if ((error_code = trx->scan_query(query, fieldtype, items_number, - null_bits, num_null_bytes, field_metadata, field_metadata_size, &scan_refid))) { + if ((error_code = trx->scan_query(query, fieldtype, items_number, null_bits, + num_null_bytes, field_metadata, + field_metadata_size, + row_buffer_setting(thd), &scan))) { goto err; } @@ -422,11 +426,11 @@ int ha_clustrixdb_derived_handler::next_row() if (!trx) return error_code; - assert(scan_refid); + assert(scan); uchar *rowdata; ulong rowdata_length; - if ((error_code = trx->scan_next(scan_refid, &rowdata, &rowdata_length))) + if ((error_code = trx->scan_next(scan, &rowdata, &rowdata_length))) return error_code; uchar const *current_row_end; @@ -502,7 +506,7 @@ void ha_clustrixdb_base_handler::add_current_table_to_rpl_table_list() /*@brief clone of ha_clustrixdb method */ /*********************************************************** * DESCRIPTION: - * Deletes structures that are used to unpack RBR rows + * Deletes structures that are used to unpack RBR rows * in ::next_row(). Called from dtor * PARAMETERS: * RETURN: diff --git a/storage/clustrixdb/ha_clustrixdb_pushdown.h b/storage/clustrixdb/ha_clustrixdb_pushdown.h index 0b6c68e4c75..2a58f4ab04f 100644 --- a/storage/clustrixdb/ha_clustrixdb_pushdown.h +++ b/storage/clustrixdb/ha_clustrixdb_pushdown.h @@ -30,7 +30,7 @@ class ha_clustrixdb_base_handler rpl_group_info *rgi; Relay_log_info *rli; // CLX BE scan operation reference - ulonglong scan_refid; + clustrix_connection_cursor *scan; // To unpack rows from CLX BE void add_current_table_to_rpl_table_list(); void remove_current_table_from_rpl_table_list(); @@ -50,7 +50,7 @@ class ha_clustrixdb_select_handler: { public: ha_clustrixdb_select_handler(THD* thd_arg, SELECT_LEX* sel, - ulonglong scan_refid); + clustrix_connection_cursor *scan); ~ha_clustrixdb_select_handler(); int init_scan(); @@ -73,7 +73,7 @@ class ha_clustrixdb_derived_handler: { public: ha_clustrixdb_derived_handler(THD* thd_arg, SELECT_LEX* sel, - ulonglong scan_refid); + clustrix_connection_cursor *scan); ~ha_clustrixdb_derived_handler(); int init_scan(); -- cgit v1.2.1 From 069947c5a84688e82363aa72d652a8aa3e2ae40f Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Wed, 18 Sep 2019 16:59:10 -0700 Subject: Add rudimentary Clustrix connection distrubition. --- storage/clustrixdb/clustrix_connection.cc | 17 ++++++++-- storage/clustrixdb/ha_clustrixdb.cc | 53 ++++++++++++++++++++++++++++++- 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/storage/clustrixdb/clustrix_connection.cc b/storage/clustrixdb/clustrix_connection.cc index e1b991a012d..3b5009637d5 100644 --- a/storage/clustrixdb/clustrix_connection.cc +++ b/storage/clustrixdb/clustrix_connection.cc @@ -53,15 +53,26 @@ void clustrix_connection::disconnect(bool is_destructor) DBUG_VOID_RETURN; } +int host_list_next; +extern int host_list_cnt; +extern char **host_list; + int clustrix_connection::connect() { int error_code = 0; my_bool my_true = 1; DBUG_ENTER("clustrix_connection::connect"); + // cpu concurrency by damned! + int host_num = host_list_next; + host_num = host_num % host_list_cnt; + char *host = host_list[host_num]; + host_list_next = host_num + 1; + DBUG_PRINT("host", ("%s", host)); + /* Validate the connection parameters */ if (!strcmp(clustrix_socket, "")) - if (!strcmp(clustrix_host, "127.0.0.1")) + if (!strcmp(host, "127.0.0.1")) if (clustrix_port == MYSQL_PORT_DEFAULT) DBUG_RETURN(ER_CONNECT_TO_FOREIGN_DATA_SOURCE); @@ -98,7 +109,7 @@ int clustrix_connection::connect() } #endif - if (!mysql_real_connect(&clustrix_net, clustrix_host, + if (!mysql_real_connect(&clustrix_net, host, clustrix_username, clustrix_password, NULL, clustrix_port, clustrix_socket, CLIENT_MULTI_STATEMENTS)) @@ -114,7 +125,7 @@ int clustrix_connection::connect() my_error(ER_CON_COUNT_ERROR, MYF(0)); DBUG_RETURN(ER_CON_COUNT_ERROR); } - my_error(ER_CONNECT_TO_FOREIGN_DATA_SOURCE, MYF(0), clustrix_host); + my_error(ER_CONNECT_TO_FOREIGN_DATA_SOURCE, MYF(0), host); DBUG_RETURN(ER_CONNECT_TO_FOREIGN_DATA_SOURCE); } } diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index c1cab7f36d9..677f9991fda 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -40,6 +40,7 @@ static MYSQL_SYSVAR_INT NULL, NULL, -1, -1, 2147483647, 0 ); + char *clustrix_host; static MYSQL_SYSVAR_STR ( @@ -50,6 +51,53 @@ static MYSQL_SYSVAR_STR NULL, NULL, "127.0.0.1" ); +int host_list_cnt; +char **host_list; +static void update_host_list(char *clustrix_host) +{ + if (host_list) { + for (int i = 0; host_list[i]; i++) + my_free(host_list[i]); + my_free(host_list); + } + + int cnt = 0; + for (char *p = clustrix_host, *s = clustrix_host; ; p++) { + if (*p == ',' || *p == '\0') { + if (p > s) { + cnt++; + } + if (!*p) + break; + s = p + 1; + } + } + + DBUG_PRINT("host_cnt", ("%d", cnt)); + host_list = (char **)my_malloc(sizeof(char *) * cnt+1, MYF(MY_WME)); + host_list[cnt] = 0; + host_list_cnt = cnt; + + int i = 0; + for (char *p = clustrix_host, *s = clustrix_host; ; p++) { + if (*p == ',' || *p == '\0') { + if (p > s) { + char *host = (char *)my_malloc(p - s + 1, MYF(MY_WME)); + host[p-s] = '\0'; + memcpy(host, s, p-s); + DBUG_PRINT("host", ("%s", host)); + host_list[i++] = host; + } + if (!*p) + break; + s = p + 1; + } + } + + DBUG_PRINT("clustrix_host", ("%s", clustrix_host)); +} + + char *clustrix_username; static MYSQL_SYSVAR_STR ( @@ -1047,6 +1095,7 @@ int clustrixdb_discover_table(handlerton *hton, THD *thd, TABLE_SHARE *share) static int clustrixdb_init(void *p) { + DBUG_ENTER("clustrixdb_init"); clustrixdb_hton = (handlerton *) p; clustrixdb_hton->flags = HTON_NO_FLAGS; clustrixdb_hton->panic = clustrixdb_panic; @@ -1060,7 +1109,9 @@ static int clustrixdb_init(void *p) clustrixdb_hton->create_select = create_clustrixdb_select_handler; clustrixdb_hton->create_derived = create_clustrixdb_derived_handler; - return 0; + update_host_list(clustrix_host); + + DBUG_RETURN(0); } struct st_mysql_show_var clustrixdb_status_vars[] = -- cgit v1.2.1 From fa7dadc67bdf44eff27acf70a729e2b413b5956d Mon Sep 17 00:00:00 2001 From: Roman Nozdrin Date: Thu, 26 Sep 2019 14:10:39 +0000 Subject: CLX-40 direct_update implementation. It works similar to SH and DH and sends down UPDATE statement together with current database name. Add MTR test for UPDATE. Multi-UPDATE first sends SELECT to collect constrainsts for the records to be updated. By default this SELECT uses SH that doesn't suit this. Add if-block to guard against multi-UPDATE in create_SH(). --- mysql-test/suite/clustrixdb/basics.result | 2 + mysql-test/suite/clustrixdb/update.result | 26 +++++++++++++ mysql-test/suite/clustrixdb/update.test | 19 ++++++++++ storage/clustrixdb/clustrix_connection.cc | 46 ++++++++++++++++++++++- storage/clustrixdb/clustrix_connection.h | 2 + storage/clustrixdb/ha_clustrixdb.cc | 55 ++++++++++++++++++++++------ storage/clustrixdb/ha_clustrixdb.h | 4 +- storage/clustrixdb/ha_clustrixdb_pushdown.cc | 6 +++ 8 files changed, 146 insertions(+), 14 deletions(-) create mode 100644 mysql-test/suite/clustrixdb/update.result create mode 100644 mysql-test/suite/clustrixdb/update.test diff --git a/mysql-test/suite/clustrixdb/basics.result b/mysql-test/suite/clustrixdb/basics.result index 04e8a942532..2af500cf9f1 100644 --- a/mysql-test/suite/clustrixdb/basics.result +++ b/mysql-test/suite/clustrixdb/basics.result @@ -14,6 +14,8 @@ DROP TABLE cx1; SHOW CREATE TABLE cx1; ERROR 42S02: Table 'clx.cx1' doesn't exist DROP TABLE IF EXISTS intandtext; +Warnings: +Note 1051 Unknown table 'clx.intandtext' CREATE TABLE intandtext(i bigint, t text)ENGINE=clustrixdb; INSERT INTO intandtext VALUES(10, 'someqwqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq'); SELECT i,t FROM intandtext; diff --git a/mysql-test/suite/clustrixdb/update.result b/mysql-test/suite/clustrixdb/update.result new file mode 100644 index 00000000000..1ad6cdbcb02 --- /dev/null +++ b/mysql-test/suite/clustrixdb/update.result @@ -0,0 +1,26 @@ +CREATE DATABASE IF NOT EXISTS `db1`; +USE `db1`; +DROP TABLE IF EXISTS `t1`; +Warnings: +Note 1051 Unknown table 'db1.t1' +CREATE TABLE `t1`(i BIGINT, t TEXT)ENGINE=clustrixdb; +INSERT INTO `t1` (i, t) VALUES (42, 'один'); +INSERT INTO `t1` (i, t) VALUES (42, 'ноль'); +SELECT * FROM `t1`; +i t +42 один +42 ноль +UPDATE `t1` SET i=i+1,t='два' WHERE t='один'; +SELECT * FROM `t1`; +i t +42 один +42 ноль +USE test; +UPDATE `db1`.`t1` SET i=i+1,t='три' WHERE t='два'; +SELECT * FROM `db1`.`t1`; +i t +42 один +42 ноль +DROP TABLE `db1`.`t1`; +USE test; +DROP DATABASE `db1`; diff --git a/mysql-test/suite/clustrixdb/update.test b/mysql-test/suite/clustrixdb/update.test new file mode 100644 index 00000000000..10b17d19e01 --- /dev/null +++ b/mysql-test/suite/clustrixdb/update.test @@ -0,0 +1,19 @@ +CREATE DATABASE IF NOT EXISTS `db1`; +USE `db1`; +DROP TABLE IF EXISTS `t1`; +CREATE TABLE `t1`(i BIGINT, t TEXT)ENGINE=clustrixdb; +INSERT INTO `t1` (i, t) VALUES (42, 'один'); +INSERT INTO `t1` (i, t) VALUES (42, 'ноль'); +SELECT * FROM `t1`; + +UPDATE `t1` SET i=i+1,t='два' WHERE t='один'; +SELECT * FROM `t1`; + +USE test; +UPDATE `db1`.`t1` SET i=i+1,t='три' WHERE t='два'; +SELECT * FROM `db1`.`t1`; + +DROP TABLE `db1`.`t1`; + +USE test; +DROP DATABASE `db1`; diff --git a/storage/clustrixdb/clustrix_connection.cc b/storage/clustrixdb/clustrix_connection.cc index 3b5009637d5..f7bea01d604 100644 --- a/storage/clustrixdb/clustrix_connection.cc +++ b/storage/clustrixdb/clustrix_connection.cc @@ -30,7 +30,8 @@ enum clustrix_commands { CLUSTRIX_KEY_DELETE, CLUSTRIX_SCAN_QUERY, CLUSTRIX_KEY_UPDATE, - CLUSTRIX_SCAN_FROM_KEY + CLUSTRIX_SCAN_FROM_KEY, + CLUSTRIX_UPDATE_QUERY }; /**************************************************************************** @@ -246,6 +247,11 @@ int clustrix_connection::run_query(String &stmt) return error_code; } +my_ulonglong clustrix_connection::rows_affected() +{ + return clustrix_net.affected_rows; +} + int clustrix_connection::write_row(ulonglong clustrix_table_oid, uchar *packed_row, size_t packed_size) { @@ -587,6 +593,44 @@ int clustrix_connection::scan_query(String &stmt, uchar *fieldtype, uint fields, return allocate_clustrix_connection_cursor(&clustrix_net, row_req, scan); } +/** + * @brief + * Sends a command to initiate UPDATE. + * @details + * Sends a command over mysql protocol connection to initiate an + * UPDATE query using a query text. + * @args + * stmt& Query text to send + * dbname current working database + * dbname ¤t database name + **/ +int clustrix_connection::update_query(String &stmt, LEX_CSTRING &dbname, + ulonglong *affected_rows) +{ + int error_code; + command_length = 0; + + if ((error_code = add_command_operand_uchar(CLUSTRIX_UPDATE_QUERY))) + return error_code; + + if ((error_code = add_command_operand_str((uchar*)dbname.str, dbname.length))) + return error_code; + + if ((error_code = add_command_operand_str((uchar*)stmt.ptr(), stmt.length()))) + return error_code; + + if ((error_code = send_command())) + return error_code; + if ((error_code = read_query_response())) + return mysql_errno(&clustrix_net); + + *affected_rows = clustrix_net.affected_rows; + + return 0; +} + + + int clustrix_connection::scan_from_key(ulonglong clustrix_table_oid, uint index, enum scan_type scan_dir, bool sorted_scan, MY_BITMAP *read_set, diff --git a/storage/clustrixdb/clustrix_connection.h b/storage/clustrixdb/clustrix_connection.h index 1ba35db5766..e8a558d714a 100644 --- a/storage/clustrixdb/clustrix_connection.h +++ b/storage/clustrixdb/clustrix_connection.h @@ -87,6 +87,7 @@ public: } int run_query(String &stmt); + my_ulonglong rows_affected(); int write_row(ulonglong clustrix_table_oid, uchar *packed_row, size_t packed_size); @@ -117,6 +118,7 @@ public: uint null_bits_size, uchar *field_metadata, uint field_metadata_size, ushort row_req, clustrix_connection_cursor **scan); + int update_query(String &stmt, LEX_CSTRING &dbname, ulonglong *affected_rows); int scan_from_key(ulonglong clustrix_table_oid, uint index, enum scan_type scan_dir, bool sorted_scan, MY_BITMAP *read_set, uchar *packed_key, diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index 677f9991fda..4c9470bdfbd 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -310,7 +310,7 @@ int ha_clustrixdb::delete_table(const char *path) if (!trx) return error_code; - // The format contains './' in the beginning of a path. + // The format cont ains './' in the beginning of a path. char *dbname_end = (char*) path + 2; while (*dbname_end != '/') dbname_end++; @@ -325,7 +325,6 @@ int ha_clustrixdb::delete_table(const char *path) delete_cmd.append(decoded_tbname); delete_cmd.append("`"); - return trx->run_query(delete_cmd); } @@ -467,6 +466,32 @@ int ha_clustrixdb::update_row(const uchar *old_data, const uchar *new_data) DBUG_RETURN(error_code); } +int ha_clustrixdb::direct_update_rows_init(List *update_fields) +{ + DBUG_ENTER("ha_clustrixdb::direct_update_rows_init"); + int error_code= 0; + DBUG_RETURN(error_code); +} + +int ha_clustrixdb::direct_update_rows(ha_rows *update_rows) +{ + DBUG_ENTER("ha_clustrixdb::direct_update_rows"); + int error_code= 0; + THD *thd= ha_thd(); + clustrix_connection *trx= get_trx(thd, &error_code); + if (!trx) + return error_code; + + String update_stmt; + update_stmt.append(thd->query_string.str()); + + trx->update_query(update_stmt, table->s->db, update_rows); + + thd->get_stmt_da()->set_overwrite_status(true); + + DBUG_RETURN(error_code); +} + int ha_clustrixdb::delete_row(const uchar *buf) { int error_code; @@ -503,9 +528,10 @@ ha_clustrixdb::Table_flags ha_clustrixdb::table_flags(void) const HA_CAN_INDEX_BLOBS | HA_AUTO_PART_KEY | HA_CAN_SQL_HANDLER | - HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE | - HA_CAN_TABLE_CONDITION_PUSHDOWN; + HA_CAN_TABLE_CONDITION_PUSHDOWN | + HA_CAN_DIRECT_UPDATE_AND_DELETE; + return flags; } @@ -729,18 +755,21 @@ int ha_clustrixdb::index_end() int ha_clustrixdb::rnd_init(bool scan) { + DBUG_ENTER("ha_clustrixdb::rnd_init"); int error_code = 0; THD *thd = ha_thd(); + if (thd->lex->sql_command == SQLCOM_UPDATE) + DBUG_RETURN(error_code); clustrix_connection *trx = get_trx(thd, &error_code); if (!trx) - return error_code; + DBUG_RETURN(error_code); add_current_table_to_rpl_table_list(); is_scan = scan; scan_cur = NULL; if (my_bitmap_init(&scan_fields, NULL, table->read_set->n_bits, false)) - return ER_OUTOFMEMORY; + DBUG_RETURN(ER_OUTOFMEMORY); #if 0 if (table->s->keys) @@ -758,9 +787,9 @@ int ha_clustrixdb::rnd_init(bool scan) clustrix_connection::SORT_NONE, &scan_fields, THDVAR(thd, row_buffer), &scan_cur))) - return error_code; + DBUG_RETURN(error_code); - return 0; + DBUG_RETURN(0); } int ha_clustrixdb::rnd_next(uchar *buf) @@ -849,18 +878,22 @@ err: int ha_clustrixdb::rnd_end() { + DBUG_ENTER("ha_clustrixdb::rnd_end()"); int error_code = 0; THD *thd = ha_thd(); + if (thd->lex->sql_command == SQLCOM_UPDATE) + DBUG_RETURN(error_code); + clustrix_connection *trx = get_trx(thd, &error_code); if (!trx) - return error_code; + DBUG_RETURN(error_code); my_bitmap_free(&scan_fields); if (scan_cur && (error_code = trx->scan_end(scan_cur))) - return error_code; + DBUG_RETURN(error_code); scan_cur = NULL; - return 0; + DBUG_RETURN(0); } void ha_clustrixdb::position(const uchar *record) diff --git a/storage/clustrixdb/ha_clustrixdb.h b/storage/clustrixdb/ha_clustrixdb.h index 33a0c922d15..64a579b925d 100644 --- a/storage/clustrixdb/ha_clustrixdb.h +++ b/storage/clustrixdb/ha_clustrixdb.h @@ -27,8 +27,6 @@ bool get_enable_sh(THD* thd); class ha_clustrixdb : public handler { private: -# define CLUSTRIXDB_ROW_LIMIT 1024 - ulonglong clustrix_table_oid; rpl_group_info *rgi; Relay_log_info *rli; @@ -57,6 +55,8 @@ public: int update_row(const uchar *old_data, const uchar *new_data); // start_bulk_delete exec_bulk_delete int delete_row(const uchar *buf); + int direct_update_rows_init(List *update_fields); + int direct_update_rows(ha_rows *update_rows); Table_flags table_flags(void) const; ulong index_flags(uint idx, uint part, bool all_parts) const; diff --git a/storage/clustrixdb/ha_clustrixdb_pushdown.cc b/storage/clustrixdb/ha_clustrixdb_pushdown.cc index 15df8e652d1..13aaf88240b 100644 --- a/storage/clustrixdb/ha_clustrixdb_pushdown.cc +++ b/storage/clustrixdb/ha_clustrixdb_pushdown.cc @@ -107,6 +107,12 @@ create_clustrixdb_select_handler(THD* thd, SELECT_LEX* select_lex) return sh; } + // Multi-update runs an implicit query to collect constraints. + // SH couldn't be used for this. + if (thd->lex->sql_command == SQLCOM_UPDATE_MULTI) { + return sh; + } + String query; // Print the query into a string provided select_lex->print(thd, &query, QT_ORDINARY); -- cgit v1.2.1 From 66a46f5d9424d2cf5199be47d4c49fe48f4a1ec3 Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Thu, 26 Sep 2019 12:53:57 -0700 Subject: Fix error handling bugs in clustrix_connection. --- storage/clustrixdb/clustrix_connection.cc | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/storage/clustrixdb/clustrix_connection.cc b/storage/clustrixdb/clustrix_connection.cc index f7bea01d604..ae2a3610fe1 100644 --- a/storage/clustrixdb/clustrix_connection.cc +++ b/storage/clustrixdb/clustrix_connection.cc @@ -145,10 +145,11 @@ int clustrix_connection::send_command() if (com_error) { - my_printf_error(mysql_errno(&clustrix_net), + int error_code = mysql_errno(&clustrix_net); + my_printf_error(error_code, "Clustrix error: %s", MYF(0), mysql_error(&clustrix_net)); - return ER_QUERY_ON_FOREIGN_DATA_SOURCE; + return error_code; } return 0; @@ -159,10 +160,11 @@ int clustrix_connection::read_query_response() my_bool comerr = clustrix_net.methods->read_query_result(&clustrix_net); if (comerr) { - my_printf_error(mysql_errno(&clustrix_net), + int error_code = mysql_errno(&clustrix_net); + my_printf_error(error_code, "Clustrix error: %s", MYF(0), mysql_error(&clustrix_net)); - return ER_QUERY_ON_FOREIGN_DATA_SOURCE; + return error_code; } return 0; @@ -306,7 +308,7 @@ int clustrix_connection::key_update(ulonglong clustrix_table_oid, return error_code; if ((error_code = read_query_response())) - return mysql_errno(&clustrix_net); + return error_code; return error_code; @@ -331,7 +333,7 @@ int clustrix_connection::key_delete(ulonglong clustrix_table_oid, return error_code; if ((error_code = read_query_response())) - return mysql_errno(&clustrix_net); + return error_code; return error_code; } @@ -622,7 +624,7 @@ int clustrix_connection::update_query(String &stmt, LEX_CSTRING &dbname, if ((error_code = send_command())) return error_code; if ((error_code = read_query_response())) - return mysql_errno(&clustrix_net); + return error_code; *affected_rows = clustrix_net.affected_rows; -- cgit v1.2.1 From 2070b82f0eb3c67defc7522386084957f76b49c3 Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Tue, 1 Oct 2019 13:53:07 -0700 Subject: Use SHOW SIMPLE CREATE TABLE instead of normal. --- storage/clustrixdb/clustrix_connection.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/clustrixdb/clustrix_connection.cc b/storage/clustrixdb/clustrix_connection.cc index ae2a3610fe1..58ddf8cb60c 100644 --- a/storage/clustrixdb/clustrix_connection.cc +++ b/storage/clustrixdb/clustrix_connection.cc @@ -821,7 +821,7 @@ int clustrix_connection::discover_table_details(LEX_CSTRING *db, } /* get show create statement */ - show.append("show create table "); + show.append("show simple create table "); show.append(db); show.append("."); show.append(name); -- cgit v1.2.1 From 5d80d3dcbb0b3a53d2c2269c68352d57604743ea Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Tue, 1 Oct 2019 22:26:42 -0700 Subject: Remove last_insert_id field from clustrix_connection. --- storage/clustrixdb/clustrix_connection.cc | 5 +++-- storage/clustrixdb/clustrix_connection.h | 5 ++--- storage/clustrixdb/ha_clustrixdb.cc | 6 ++++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/storage/clustrixdb/clustrix_connection.cc b/storage/clustrixdb/clustrix_connection.cc index 58ddf8cb60c..d3eebb52a94 100644 --- a/storage/clustrixdb/clustrix_connection.cc +++ b/storage/clustrixdb/clustrix_connection.cc @@ -255,7 +255,8 @@ my_ulonglong clustrix_connection::rows_affected() } int clustrix_connection::write_row(ulonglong clustrix_table_oid, - uchar *packed_row, size_t packed_size) + uchar *packed_row, size_t packed_size, + ulonglong *last_insert_id) { int error_code; command_length = 0; @@ -275,7 +276,7 @@ int clustrix_connection::write_row(ulonglong clustrix_table_oid, if ((error_code = read_query_response())) return error_code; - last_insert_id = clustrix_net.insert_id; + *last_insert_id = clustrix_net.insert_id; return error_code; } diff --git a/storage/clustrixdb/clustrix_connection.h b/storage/clustrixdb/clustrix_connection.h index e8a558d714a..9469cb723b3 100644 --- a/storage/clustrixdb/clustrix_connection.h +++ b/storage/clustrixdb/clustrix_connection.h @@ -40,7 +40,6 @@ private: bool has_statement_trans; public: - ulonglong last_insert_id; clustrix_connection() : command_buffer(NULL), command_buffer_length(0), command_length(0) { @@ -89,8 +88,8 @@ public: int run_query(String &stmt); my_ulonglong rows_affected(); - int write_row(ulonglong clustrix_table_oid, - uchar *packed_row, size_t packed_size); + int write_row(ulonglong clustrix_table_oid, uchar *packed_row, + size_t packed_size, ulonglong *last_insert_id); int key_update(ulonglong clustrix_table_oid, uchar *packed_key, size_t packed_key_length, MY_BITMAP *update_set, diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index 4c9470bdfbd..aa940352eee 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -417,12 +417,14 @@ int ha_clustrixdb::write_row(const uchar *buf) /* XXX: Clustrix may needs to return HA_ERR_AUTOINC_ERANGE if we hit that error. */ + ulonglong last_insert_id = 0; if ((error_code = trx->write_row(clustrix_table_oid, - packed_new_row, packed_size))) + packed_new_row, packed_size, + &last_insert_id))) goto err; if (table->next_number_field) - insert_id_for_cur_row = trx->last_insert_id; + insert_id_for_cur_row = last_insert_id; err: if (packed_size) -- cgit v1.2.1 From 43bd32ae71d607d5fd4703975b8baac4c62b33dc Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Tue, 1 Oct 2019 22:23:29 -0700 Subject: Rework key_read to end with status. --- storage/clustrixdb/clustrix_connection.cc | 14 ++++++++++++-- storage/clustrixdb/clustrix_connection.h | 4 ++-- storage/clustrixdb/ha_clustrixdb.cc | 4 +++- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/storage/clustrixdb/clustrix_connection.cc b/storage/clustrixdb/clustrix_connection.cc index d3eebb52a94..fbcdcc3648d 100644 --- a/storage/clustrixdb/clustrix_connection.cc +++ b/storage/clustrixdb/clustrix_connection.cc @@ -369,8 +369,18 @@ int clustrix_connection::key_read(ulonglong clustrix_table_oid, uint index, if (packet_length == packet_error) return mysql_errno(&clustrix_net); - *rowdata = clustrix_net.net.read_pos; - *rowdata_length = safe_net_field_length_ll(rowdata, packet_length); + uchar *data = clustrix_net.net.read_pos; + *rowdata_length = safe_net_field_length_ll(&data, packet_length); + *rowdata = (uchar *)my_malloc(*rowdata_length, MYF(MY_WME)); + memcpy(*rowdata, data, *rowdata_length); + + packet_length = cli_safe_read(&clustrix_net); + if (packet_length == packet_error) { + my_free(*rowdata); + *rowdata = NULL; + *rowdata_length = 0; + return mysql_errno(&clustrix_net); + } return 0; } diff --git a/storage/clustrixdb/clustrix_connection.h b/storage/clustrixdb/clustrix_connection.h index 9469cb723b3..830826ebc0e 100644 --- a/storage/clustrixdb/clustrix_connection.h +++ b/storage/clustrixdb/clustrix_connection.h @@ -97,8 +97,8 @@ public: int key_delete(ulonglong clustrix_table_oid, uchar *packed_key, size_t packed_key_length); int key_read(ulonglong clustrix_table_oid, uint index, MY_BITMAP *read_set, - uchar *packed_key, ulong packed_key_length, - uchar **rowdata, ulong *rowdata_length); + uchar *packed_key, ulong packed_key_length, uchar **rowdata, + ulong *rowdata_length); enum sort_order {SORT_NONE = 0, SORT_ASC = 1, SORT_DESC = 2}; enum scan_type { diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index aa940352eee..3b7041b5720 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -856,7 +856,7 @@ int ha_clustrixdb::rnd_pos(uchar * buf, uchar *pos) build_key_packed_row(table->s->primary_key, table->record[0], packed_key, &packed_key_len); - uchar *rowdata; + uchar *rowdata = NULL; ulong rowdata_length; if ((error_code = trx->key_read(clustrix_table_oid, 0, table->read_set, packed_key, packed_key_len, @@ -871,6 +871,8 @@ int ha_clustrixdb::rnd_pos(uchar * buf, uchar *pos) goto err; err: + if (rowdata); + my_free(rowdata); if (packed_key) my_afree(packed_key); -- cgit v1.2.1 From d4480d25c4ed2f048ea13057f3e10d1f75589e69 Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Mon, 23 Sep 2019 21:35:38 -0700 Subject: Convert transactions to use flags. --- storage/clustrixdb/clustrix_connection.cc | 152 ++++++++++++++++++++---------- storage/clustrixdb/clustrix_connection.h | 17 ++-- storage/clustrixdb/ha_clustrixdb.cc | 34 +++---- 3 files changed, 131 insertions(+), 72 deletions(-) diff --git a/storage/clustrixdb/clustrix_connection.cc b/storage/clustrixdb/clustrix_connection.cc index fbcdcc3648d..a2721e9624d 100644 --- a/storage/clustrixdb/clustrix_connection.cc +++ b/storage/clustrixdb/clustrix_connection.cc @@ -31,7 +31,16 @@ enum clustrix_commands { CLUSTRIX_SCAN_QUERY, CLUSTRIX_KEY_UPDATE, CLUSTRIX_SCAN_FROM_KEY, - CLUSTRIX_UPDATE_QUERY + CLUSTRIX_UPDATE_QUERY, + CLUSTRIX_TRANSACTION_CMD +}; + +enum clustrix_transaction_flags { + CLUSTRIX_TRANS_BEGIN = 1, + CLUSTRIX_TRANS_COMMIT = 2, + CLUSTRIX_TRANS_ROLLBACK = 4, + CLUSTRIX_STMT_NEW = 8, + CLUSTRIX_STMT_ROLLBACK = 16 }; /**************************************************************************** @@ -136,6 +145,20 @@ int clustrix_connection::connect() DBUG_RETURN(0); } +int clustrix_connection::begin_command(uchar command) +{ + command_length = 0; + int error_code = 0; + if ((error_code = add_command_operand_uchar(command))) + return error_code; + + if ((error_code = add_command_operand_uchar(commit_flag_next))) + return error_code; + + commit_flag_next = 0; + return error_code; +} + int clustrix_connection::send_command() { my_bool com_error; @@ -170,75 +193,104 @@ int clustrix_connection::read_query_response() return 0; } -int clustrix_connection::begin_trans() +int clustrix_connection::send_transaction_cmd() { - if (has_transaction) - return 0; + DBUG_ENTER("clustrix_connection::send_transaction_cmd"); + if (!commit_flag_next) + DBUG_RETURN(0); - const char *stmt = "BEGIN TRANSACTION"; - int error_code = mysql_real_query(&clustrix_net, stmt, strlen(stmt)); - if (error_code) - return mysql_errno(&clustrix_net); + int error_code; + if ((error_code = begin_command(CLUSTRIX_TRANSACTION_CMD))) + DBUG_RETURN(error_code); + if ((error_code = send_command())) + DBUG_RETURN(error_code); + if ((error_code = read_query_response())) + DBUG_RETURN(mysql_errno(&clustrix_net)); + + DBUG_RETURN(error_code); +} + +bool clustrix_connection::begin_trans() +{ + DBUG_ENTER("clustrix_connection::begin_trans"); + assert(!has_transaction); + commit_flag_next |= CLUSTRIX_TRANS_BEGIN; has_transaction = TRUE; - return error_code; + DBUG_RETURN(TRUE); } -int clustrix_connection::commit_trans() +bool clustrix_connection::commit_trans() { - const char *stmt = "COMMIT TRANSACTION"; - int error_code = mysql_real_query(&clustrix_net, stmt, strlen(stmt)); - if (error_code) - return mysql_errno(&clustrix_net); + DBUG_ENTER("clustrix_connection::commit_trans"); + assert(has_transaction); + + if (commit_flag_next & CLUSTRIX_TRANS_BEGIN) { + commit_flag_next &= ~CLUSTRIX_TRANS_BEGIN; + DBUG_RETURN(FALSE); + } + + commit_flag_next |= CLUSTRIX_TRANS_COMMIT; has_transaction = FALSE; has_statement_trans = FALSE; - return error_code; + DBUG_RETURN(TRUE); } -int clustrix_connection::rollback_trans() +bool clustrix_connection::rollback_trans() { - const char *stmt = "ROLLBACK TRANSACTION"; - int error_code = mysql_real_query(&clustrix_net, stmt, strlen(stmt)); - if (error_code) - return mysql_errno(&clustrix_net); + DBUG_ENTER("clustrix_connection::rollback_trans"); + assert(has_transaction); + + if (commit_flag_next & CLUSTRIX_TRANS_BEGIN) { + commit_flag_next &= ~CLUSTRIX_TRANS_BEGIN; + DBUG_RETURN(FALSE); + } + + commit_flag_next |= CLUSTRIX_TRANS_ROLLBACK; has_transaction = FALSE; has_statement_trans = FALSE; - return error_code; + DBUG_RETURN(TRUE); } -int clustrix_connection::begin_stmt_trans() +bool clustrix_connection::begin_stmt_trans() { + DBUG_ENTER("clustrix_connection::begin_stmt_trans"); assert(has_transaction); - if (has_statement_trans) - return 0; + assert(!has_statement_trans); - const char *stmt = "SAVEPOINT STMT_TRANS"; - int error_code = mysql_real_query(&clustrix_net, stmt, strlen(stmt)); - if (error_code) - return mysql_errno(&clustrix_net); + commit_flag_next |= CLUSTRIX_STMT_NEW; has_statement_trans = TRUE; - return error_code; + DBUG_RETURN(TRUE); } -int clustrix_connection::commit_stmt_trans() +bool clustrix_connection::commit_stmt_trans() { + DBUG_ENTER("clustrix_connection::commit_stmt_trans"); assert(has_transaction); - const char *stmt = "RELEASE SAVEPOINT STMT_TRANS"; - int error_code = mysql_real_query(&clustrix_net, stmt, strlen(stmt)); - if (error_code) - return mysql_errno(&clustrix_net); + assert(has_statement_trans); + + if (commit_flag_next & CLUSTRIX_STMT_NEW) { + commit_flag_next &= ~CLUSTRIX_STMT_NEW; + DBUG_RETURN(FALSE); + } + has_statement_trans = FALSE; - return error_code; + DBUG_RETURN(TRUE); } -int clustrix_connection::rollback_stmt_trans() +bool clustrix_connection::rollback_stmt_trans() { + DBUG_ENTER("clustrix_connection::rollback_stmt_trans"); assert(has_transaction); - const char *stmt = "ROLLBACK TO STMT_TRANS"; - int error_code = mysql_real_query(&clustrix_net, stmt, strlen(stmt)); - if (error_code) - return mysql_errno(&clustrix_net); + assert(has_statement_trans); + + if (commit_flag_next & CLUSTRIX_STMT_NEW) { + commit_flag_next &= ~CLUSTRIX_STMT_NEW; + DBUG_RETURN(FALSE); + } + + commit_flag_next |= CLUSTRIX_STMT_ROLLBACK; has_statement_trans = FALSE; - return error_code; + DBUG_RETURN(TRUE); } int clustrix_connection::run_query(String &stmt) @@ -261,7 +313,7 @@ int clustrix_connection::write_row(ulonglong clustrix_table_oid, int error_code; command_length = 0; - if ((error_code = add_command_operand_uchar(CLUSTRIX_WRITE_ROW))) + if ((error_code = begin_command(CLUSTRIX_WRITE_ROW))) return error_code; if ((error_code = add_command_operand_ulonglong(clustrix_table_oid))) @@ -289,7 +341,7 @@ int clustrix_connection::key_update(ulonglong clustrix_table_oid, int error_code; command_length = 0; - if ((error_code = add_command_operand_uchar(CLUSTRIX_KEY_UPDATE))) + if ((error_code = begin_command(CLUSTRIX_KEY_UPDATE))) return error_code; if ((error_code = add_command_operand_ulonglong(clustrix_table_oid))) @@ -321,7 +373,7 @@ int clustrix_connection::key_delete(ulonglong clustrix_table_oid, int error_code; command_length = 0; - if ((error_code = add_command_operand_uchar(CLUSTRIX_KEY_DELETE))) + if ((error_code = begin_command(CLUSTRIX_KEY_DELETE))) return error_code; if ((error_code = add_command_operand_ulonglong(clustrix_table_oid))) @@ -347,7 +399,7 @@ int clustrix_connection::key_read(ulonglong clustrix_table_oid, uint index, int error_code; command_length = 0; - if ((error_code = add_command_operand_uchar(CLUSTRIX_KEY_READ))) + if ((error_code = begin_command(CLUSTRIX_KEY_READ))) return error_code; if ((error_code = add_command_operand_ulonglong(clustrix_table_oid))) @@ -530,7 +582,7 @@ int clustrix_connection::scan_table(ulonglong clustrix_table_oid, uint index, int error_code; command_length = 0; - if ((error_code = add_command_operand_uchar(CLUSTRIX_SCAN_TABLE))) + if ((error_code = begin_command(CLUSTRIX_SCAN_TABLE))) return error_code; if ((error_code = add_command_operand_ushort(row_req))) @@ -581,7 +633,7 @@ int clustrix_connection::scan_query(String &stmt, uchar *fieldtype, uint fields, int error_code; command_length = 0; - if ((error_code = add_command_operand_uchar(CLUSTRIX_SCAN_QUERY))) + if ((error_code = begin_command(CLUSTRIX_SCAN_QUERY))) return error_code; if ((error_code = add_command_operand_ushort(row_req))) @@ -655,7 +707,7 @@ int clustrix_connection::scan_from_key(ulonglong clustrix_table_oid, uint index, int error_code; command_length = 0; - if ((error_code = add_command_operand_uchar(CLUSTRIX_SCAN_FROM_KEY))) + if ((error_code = begin_command(CLUSTRIX_SCAN_FROM_KEY))) return error_code; if ((error_code = add_command_operand_ushort(row_req))) @@ -698,7 +750,7 @@ int clustrix_connection::scan_next(clustrix_connection_cursor *scan, int error_code; command_length = 0; - if ((error_code = add_command_operand_uchar(CLUSTRIX_SCAN_NEXT))) + if ((error_code = begin_command(CLUSTRIX_SCAN_NEXT))) return error_code; if ((error_code = add_command_operand_ushort(scan->buffer_size))) @@ -731,7 +783,7 @@ int clustrix_connection::scan_end(clustrix_connection_cursor *scan) if (eof_reached) return 0; - if ((error_code = add_command_operand_uchar(CLUSTRIX_SCAN_STOP))) + if ((error_code = begin_command(CLUSTRIX_SCAN_STOP))) return error_code; if ((error_code = add_command_operand_lcb(scan_refid))) diff --git a/storage/clustrixdb/clustrix_connection.h b/storage/clustrixdb/clustrix_connection.h index 830826ebc0e..1f2d89bfa51 100644 --- a/storage/clustrixdb/clustrix_connection.h +++ b/storage/clustrixdb/clustrix_connection.h @@ -38,6 +38,7 @@ private: bool has_transaction; bool has_statement_trans; + int commit_flag_next; public: clustrix_connection() @@ -47,6 +48,7 @@ public: memset(&clustrix_net, 0, sizeof(MYSQL)); has_statement_trans = FALSE; has_transaction = FALSE; + commit_flag_next = 0; DBUG_VOID_RETURN; } @@ -69,17 +71,19 @@ public: int connect(); void disconnect(bool is_destructor = FALSE); - int begin_trans(); - int commit_trans(); - int rollback_trans(); + + int send_transaction_cmd(); + bool begin_trans(); + bool commit_trans(); + bool rollback_trans(); inline bool has_trans() { return has_transaction; } - int begin_stmt_trans(); - int commit_stmt_trans(); - int rollback_stmt_trans(); + bool begin_stmt_trans(); + bool commit_stmt_trans(); + bool rollback_stmt_trans(); inline bool has_stmt_trans() { return has_statement_trans; @@ -142,6 +146,7 @@ private: int add_command_operand_vlstr(const uchar *str, size_t length); int add_command_operand_lex_string(LEX_CSTRING str); int add_command_operand_bitmap(MY_BITMAP *bitmap); + int begin_command(uchar command); int send_command(); int read_query_response(); }; diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index 3b7041b5720..5f3ec5dad31 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -932,11 +932,8 @@ int ha_clustrixdb::external_lock(THD *thd, int lock_type) int error_code; clustrix_connection *trx = get_trx(thd, &error_code); if (lock_type != F_UNLCK) { - if ((error_code = trx->begin_trans())) - return error_code; - - if ((error_code = trx->begin_stmt_trans())) - return error_code; + trx->begin_trans(); + trx->begin_stmt_trans(); trans_register_ha(thd, FALSE, clustrixdb_hton); if (thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) @@ -1036,36 +1033,42 @@ void ha_clustrixdb::build_key_packed_row(uint index, const uchar *buf, static int clustrixdb_commit(handlerton *hton, THD *thd, bool all) { - int error_code = 0; clustrix_connection* trx = (clustrix_connection *) thd_get_ha_data(thd, hton); assert(trx); + bool send_cmd; if (all || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) { if (trx->has_trans()) - error_code = trx->commit_trans(); + send_cmd = trx->commit_trans(); } else { if (trx->has_stmt_trans()) - error_code = trx->commit_stmt_trans(); + send_cmd = trx->commit_stmt_trans(); } - return error_code; + if (send_cmd) + return trx->send_transaction_cmd(); + + return 0; } static int clustrixdb_rollback(handlerton *hton, THD *thd, bool all) { - int error_code = 0; clustrix_connection* trx = (clustrix_connection *) thd_get_ha_data(thd, hton); assert(trx); + bool send_cmd; if (all || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) { if (trx->has_trans()) - error_code = trx->rollback_trans(); + send_cmd = trx->rollback_trans(); } else { if (trx->has_stmt_trans()) - error_code = trx->rollback_stmt_trans(); + send_cmd = trx->rollback_stmt_trans(); } - return error_code; + if (send_cmd) + return trx->send_transaction_cmd(); + + return 0; } static handler* clustrixdb_create_handler(handlerton *hton, TABLE_SHARE *table, @@ -1080,12 +1083,11 @@ static int clustrixdb_close_connection(handlerton* hton, THD* thd) if (!trx) return 0; /* Transaction is not started */ - if (trx->has_stmt_trans()) - clustrixdb_rollback(clustrixdb_hton, thd, TRUE); + int error_code = clustrixdb_rollback(clustrixdb_hton, thd, TRUE); delete trx; - return 0; + return error_code; } static int clustrixdb_panic(handlerton *hton, ha_panic_function type) -- cgit v1.2.1 From cce38f80f5fba5e816eb4c9c5c628a576df13116 Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Mon, 7 Oct 2019 14:37:49 -0700 Subject: Add support for commit on command completion. --- storage/clustrixdb/clustrix_connection.cc | 75 +++++++++++++++++++++------- storage/clustrixdb/clustrix_connection.h | 2 + storage/clustrixdb/ha_clustrixdb.cc | 5 +- storage/clustrixdb/ha_clustrixdb_pushdown.cc | 3 ++ 4 files changed, 66 insertions(+), 19 deletions(-) diff --git a/storage/clustrixdb/clustrix_connection.cc b/storage/clustrixdb/clustrix_connection.cc index a2721e9624d..740f55ea5f2 100644 --- a/storage/clustrixdb/clustrix_connection.cc +++ b/storage/clustrixdb/clustrix_connection.cc @@ -40,7 +40,8 @@ enum clustrix_transaction_flags { CLUSTRIX_TRANS_COMMIT = 2, CLUSTRIX_TRANS_ROLLBACK = 4, CLUSTRIX_STMT_NEW = 8, - CLUSTRIX_STMT_ROLLBACK = 16 + CLUSTRIX_STMT_ROLLBACK = 16, + CLUSTRIX_TRANS_COMMIT_ON_FINISH = 32 }; /**************************************************************************** @@ -147,6 +148,7 @@ int clustrix_connection::connect() int clustrix_connection::begin_command(uchar command) { + assert(has_transaction); command_length = 0; int error_code = 0; if ((error_code = add_command_operand_uchar(command))) @@ -155,7 +157,7 @@ int clustrix_connection::begin_command(uchar command) if ((error_code = add_command_operand_uchar(commit_flag_next))) return error_code; - commit_flag_next = 0; + commit_flag_next &= CLUSTRIX_TRANS_COMMIT_ON_FINISH; return error_code; } @@ -190,6 +192,7 @@ int clustrix_connection::read_query_response() return error_code; } + auto_commit_closed(); return 0; } @@ -251,6 +254,21 @@ bool clustrix_connection::rollback_trans() DBUG_RETURN(TRUE); } +void clustrix_connection::auto_commit_next() +{ + commit_flag_next |= CLUSTRIX_TRANS_COMMIT_ON_FINISH; +} + +void clustrix_connection::auto_commit_closed() +{ + assert(has_transaction); + if (commit_flag_next & CLUSTRIX_TRANS_COMMIT_ON_FINISH) { + has_transaction = FALSE; + has_statement_trans = FALSE; + commit_flag_next &= ~CLUSTRIX_TRANS_COMMIT_ON_FINISH; + } +} + bool clustrix_connection::begin_stmt_trans() { DBUG_ENTER("clustrix_connection::begin_stmt_trans"); @@ -421,6 +439,7 @@ int clustrix_connection::key_read(ulonglong clustrix_table_oid, uint index, if (packet_length == packet_error) return mysql_errno(&clustrix_net); + auto_commit_closed(); uchar *data = clustrix_net.net.read_pos; *rowdata_length = safe_net_field_length_ll(&data, packet_length); *rowdata = (uchar *)my_malloc(*rowdata_length, MYF(MY_WME)); @@ -467,13 +486,14 @@ private: DBUG_RETURN(0); } - int load_rows_impl() + int load_rows_impl(bool *stmt_completed) { DBUG_ENTER("clustrix_connection_cursor::load_rows_impl"); int error_code = 0; ulong packet_length = cli_safe_read(clustrix_net); if (packet_length == packet_error) { error_code = mysql_errno(clustrix_net); + *stmt_completed = TRUE; if (error_code == HA_ERR_END_OF_FILE) { // We have read all rows for query. eof_reached = TRUE; @@ -492,7 +512,7 @@ private: if ((error_code = cache_row(rowdata, rowdata_length))) DBUG_RETURN(error_code); - DBUG_RETURN(load_rows_impl()); + DBUG_RETURN(load_rows_impl(stmt_completed)); } public: @@ -521,20 +541,22 @@ public: DBUG_VOID_RETURN; } - int load_rows() + int load_rows(bool *stmt_completed) { DBUG_ENTER("clustrix_connection_cursor::load_rows"); current_row = 0; last_row = 0; - DBUG_RETURN(load_rows_impl()); + DBUG_RETURN(load_rows_impl(stmt_completed)); } - int initialize() + int initialize(bool *stmt_completed) { DBUG_ENTER("clustrix_connection_cursor::initialize"); ulong packet_length = cli_safe_read(clustrix_net); - if (packet_length == packet_error) + if (packet_length == packet_error) { + *stmt_completed = TRUE; DBUG_RETURN(mysql_errno(clustrix_net)); + } unsigned char *pos = clustrix_net->net.read_pos; scan_refid = safe_net_field_length_ll(&pos, packet_length); @@ -544,7 +566,7 @@ public: if (!rows) DBUG_RETURN(HA_ERR_OUT_OF_MEM); - DBUG_RETURN(load_rows()); + DBUG_RETURN(load_rows(stmt_completed)); } uchar *retrieve_row(ulong *rowdata_length) @@ -564,6 +586,7 @@ public: }; int allocate_clustrix_connection_cursor(MYSQL *clustrix_net, ulong buffer_size, + bool *stmt_completed, clustrix_connection_cursor **scan) { DBUG_ENTER("allocate_clustrix_connection_cursor"); @@ -571,7 +594,7 @@ int allocate_clustrix_connection_cursor(MYSQL *clustrix_net, ulong buffer_size, if (!*scan) DBUG_RETURN(HA_ERR_OUT_OF_MEM); - DBUG_RETURN((*scan)->initialize()); + DBUG_RETURN((*scan)->initialize(stmt_completed)); } int clustrix_connection::scan_table(ulonglong clustrix_table_oid, uint index, @@ -603,7 +626,12 @@ int clustrix_connection::scan_table(ulonglong clustrix_table_oid, uint index, if ((error_code = send_command())) return error_code; - return allocate_clustrix_connection_cursor(&clustrix_net, row_req, scan); + bool stmt_completed = FALSE; + error_code = allocate_clustrix_connection_cursor(&clustrix_net, row_req, + &stmt_completed, scan); + if (stmt_completed) + auto_commit_closed(); + return error_code; } /** @@ -655,7 +683,12 @@ int clustrix_connection::scan_query(String &stmt, uchar *fieldtype, uint fields, if ((error_code = send_command())) return error_code; - return allocate_clustrix_connection_cursor(&clustrix_net, row_req, scan); + bool stmt_completed = FALSE; + error_code = allocate_clustrix_connection_cursor(&clustrix_net, row_req, + &stmt_completed, scan); + if (stmt_completed) + auto_commit_closed(); + return error_code; } /** @@ -734,7 +767,12 @@ int clustrix_connection::scan_from_key(ulonglong clustrix_table_oid, uint index, if ((error_code = send_command())) return error_code; - return allocate_clustrix_connection_cursor(&clustrix_net, row_req, scan); + bool stmt_completed = FALSE; + error_code = allocate_clustrix_connection_cursor(&clustrix_net, row_req, + &stmt_completed, scan); + if (stmt_completed) + auto_commit_closed(); + return error_code; } int clustrix_connection::scan_next(clustrix_connection_cursor *scan, @@ -762,7 +800,11 @@ int clustrix_connection::scan_next(clustrix_connection_cursor *scan, if ((error_code = send_command())) return error_code; - if ((error_code = scan->load_rows())) + bool stmt_completed = FALSE; + error_code = scan->load_rows(&stmt_completed); + if (stmt_completed) + auto_commit_closed(); + if (error_code) return error_code; *rowdata = scan->retrieve_row(rowdata_length); @@ -792,9 +834,8 @@ int clustrix_connection::scan_end(clustrix_connection_cursor *scan) if ((error_code = send_command())) return error_code; - ulong packet_length = cli_safe_read(&clustrix_net); - if (packet_length == packet_error) - return mysql_errno(&clustrix_net); + if ((error_code = read_query_response())) + return error_code; return 0; } diff --git a/storage/clustrixdb/clustrix_connection.h b/storage/clustrixdb/clustrix_connection.h index 1f2d89bfa51..27f92836385 100644 --- a/storage/clustrixdb/clustrix_connection.h +++ b/storage/clustrixdb/clustrix_connection.h @@ -76,6 +76,8 @@ public: bool begin_trans(); bool commit_trans(); bool rollback_trans(); + void auto_commit_next(); + void auto_commit_closed(); inline bool has_trans() { return has_transaction; diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index 5f3ec5dad31..7c0a1691ceb 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -933,11 +933,12 @@ int ha_clustrixdb::external_lock(THD *thd, int lock_type) clustrix_connection *trx = get_trx(thd, &error_code); if (lock_type != F_UNLCK) { trx->begin_trans(); - trx->begin_stmt_trans(); trans_register_ha(thd, FALSE, clustrixdb_hton); - if (thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) + if (thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) { + trx->begin_stmt_trans(); trans_register_ha(thd, TRUE, clustrixdb_hton); + } } return 0; diff --git a/storage/clustrixdb/ha_clustrixdb_pushdown.cc b/storage/clustrixdb/ha_clustrixdb_pushdown.cc index 13aaf88240b..f20dbcf1d59 100644 --- a/storage/clustrixdb/ha_clustrixdb_pushdown.cc +++ b/storage/clustrixdb/ha_clustrixdb_pushdown.cc @@ -145,6 +145,9 @@ create_clustrixdb_select_handler(THD* thd, SELECT_LEX* select_lex) if (!trx) goto err; + if (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) + trx->auto_commit_next(); + if ((error_code = trx->scan_query(query, fieldtype, items_number, null_bits, num_null_bytes, field_metadata, field_metadata_size, -- cgit v1.2.1 From 62b8d3d4706cca9b62a1831414ac185d9392a136 Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Tue, 8 Oct 2019 14:03:17 -0700 Subject: Remove extraneous semicolon --- storage/clustrixdb/ha_clustrixdb.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index 7c0a1691ceb..3230d8e53a4 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -871,7 +871,7 @@ int ha_clustrixdb::rnd_pos(uchar * buf, uchar *pos) goto err; err: - if (rowdata); + if (rowdata) my_free(rowdata); if (packed_key) -- cgit v1.2.1 From e3bd28ff9ef41d12fe7c3c835b268567f09fbc23 Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Tue, 8 Oct 2019 14:52:33 -0700 Subject: Fix transaction assertions and rename some methods. --- storage/clustrixdb/clustrix_connection.cc | 42 +++++++++++++++---------------- storage/clustrixdb/clustrix_connection.h | 24 +++++++++--------- storage/clustrixdb/ha_clustrixdb.cc | 26 +++++++++---------- 3 files changed, 46 insertions(+), 46 deletions(-) diff --git a/storage/clustrixdb/clustrix_connection.cc b/storage/clustrixdb/clustrix_connection.cc index 740f55ea5f2..154363bf477 100644 --- a/storage/clustrixdb/clustrix_connection.cc +++ b/storage/clustrixdb/clustrix_connection.cc @@ -213,18 +213,18 @@ int clustrix_connection::send_transaction_cmd() DBUG_RETURN(error_code); } -bool clustrix_connection::begin_trans() +bool clustrix_connection::begin_transaction() { - DBUG_ENTER("clustrix_connection::begin_trans"); + DBUG_ENTER("clustrix_connection::begin_transaction"); assert(!has_transaction); commit_flag_next |= CLUSTRIX_TRANS_BEGIN; has_transaction = TRUE; DBUG_RETURN(TRUE); } -bool clustrix_connection::commit_trans() +bool clustrix_connection::commit_transaction() { - DBUG_ENTER("clustrix_connection::commit_trans"); + DBUG_ENTER("clustrix_connection::commit_transaction"); assert(has_transaction); if (commit_flag_next & CLUSTRIX_TRANS_BEGIN) { @@ -234,13 +234,13 @@ bool clustrix_connection::commit_trans() commit_flag_next |= CLUSTRIX_TRANS_COMMIT; has_transaction = FALSE; - has_statement_trans = FALSE; + has_anonymous_savepoint = FALSE; DBUG_RETURN(TRUE); } -bool clustrix_connection::rollback_trans() +bool clustrix_connection::rollback_transaction() { - DBUG_ENTER("clustrix_connection::rollback_trans"); + DBUG_ENTER("clustrix_connection::rollback_transaction"); assert(has_transaction); if (commit_flag_next & CLUSTRIX_TRANS_BEGIN) { @@ -250,7 +250,7 @@ bool clustrix_connection::rollback_trans() commit_flag_next |= CLUSTRIX_TRANS_ROLLBACK; has_transaction = FALSE; - has_statement_trans = FALSE; + has_anonymous_savepoint = FALSE; DBUG_RETURN(TRUE); } @@ -264,42 +264,42 @@ void clustrix_connection::auto_commit_closed() assert(has_transaction); if (commit_flag_next & CLUSTRIX_TRANS_COMMIT_ON_FINISH) { has_transaction = FALSE; - has_statement_trans = FALSE; + has_anonymous_savepoint = FALSE; commit_flag_next &= ~CLUSTRIX_TRANS_COMMIT_ON_FINISH; } } -bool clustrix_connection::begin_stmt_trans() +bool clustrix_connection::set_anonymous_savepoint() { - DBUG_ENTER("clustrix_connection::begin_stmt_trans"); + DBUG_ENTER("clustrix_connection::set_anonymous_savepoint"); assert(has_transaction); - assert(!has_statement_trans); + assert(!has_anonymous_savepoint); commit_flag_next |= CLUSTRIX_STMT_NEW; - has_statement_trans = TRUE; + has_anonymous_savepoint = TRUE; DBUG_RETURN(TRUE); } -bool clustrix_connection::commit_stmt_trans() +bool clustrix_connection::release_anonymous_savepoint() { - DBUG_ENTER("clustrix_connection::commit_stmt_trans"); + DBUG_ENTER("clustrix_connection::release_anonymous_savepoint"); assert(has_transaction); - assert(has_statement_trans); + assert(has_anonymous_savepoint); if (commit_flag_next & CLUSTRIX_STMT_NEW) { commit_flag_next &= ~CLUSTRIX_STMT_NEW; DBUG_RETURN(FALSE); } - has_statement_trans = FALSE; + has_anonymous_savepoint = FALSE; DBUG_RETURN(TRUE); } -bool clustrix_connection::rollback_stmt_trans() +bool clustrix_connection::rollback_to_anonymous_savepoint() { - DBUG_ENTER("clustrix_connection::rollback_stmt_trans"); + DBUG_ENTER("clustrix_connection::rollback_to_anonymous_savepoint"); assert(has_transaction); - assert(has_statement_trans); + assert(has_anonymous_savepoint); if (commit_flag_next & CLUSTRIX_STMT_NEW) { commit_flag_next &= ~CLUSTRIX_STMT_NEW; @@ -307,7 +307,7 @@ bool clustrix_connection::rollback_stmt_trans() } commit_flag_next |= CLUSTRIX_STMT_ROLLBACK; - has_statement_trans = FALSE; + has_anonymous_savepoint = FALSE; DBUG_RETURN(TRUE); } diff --git a/storage/clustrixdb/clustrix_connection.h b/storage/clustrixdb/clustrix_connection.h index 27f92836385..13c5100be64 100644 --- a/storage/clustrixdb/clustrix_connection.h +++ b/storage/clustrixdb/clustrix_connection.h @@ -37,7 +37,7 @@ private: size_t reply_length; bool has_transaction; - bool has_statement_trans; + bool has_anonymous_savepoint; int commit_flag_next; public: @@ -46,7 +46,7 @@ public: { DBUG_ENTER("clustrix_connection::clustrix_connection"); memset(&clustrix_net, 0, sizeof(MYSQL)); - has_statement_trans = FALSE; + has_anonymous_savepoint = FALSE; has_transaction = FALSE; commit_flag_next = 0; DBUG_VOID_RETURN; @@ -73,22 +73,21 @@ public: void disconnect(bool is_destructor = FALSE); int send_transaction_cmd(); - bool begin_trans(); - bool commit_trans(); - bool rollback_trans(); + bool begin_transaction(); + bool commit_transaction(); + bool rollback_transaction(); void auto_commit_next(); - void auto_commit_closed(); - inline bool has_trans() + inline bool has_open_transaction() { return has_transaction; } - bool begin_stmt_trans(); - bool commit_stmt_trans(); - bool rollback_stmt_trans(); - inline bool has_stmt_trans() + bool set_anonymous_savepoint(); + bool release_anonymous_savepoint(); + bool rollback_to_anonymous_savepoint(); + inline bool has_open_anonymous_savepoint() { - return has_statement_trans; + return has_anonymous_savepoint; } int run_query(String &stmt); @@ -151,5 +150,6 @@ private: int begin_command(uchar command); int send_command(); int read_query_response(); + void auto_commit_closed(); }; #endif // _clustrix_connection_h diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index 3230d8e53a4..8bd477b2659 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -409,7 +409,7 @@ int ha_clustrixdb::write_row(const uchar *buf) if (!trx) return error_code; - assert(trx->has_stmt_trans()); + assert(trx->has_open_transaction()); /* Convert the row format to binlog (packed) format */ uchar *packed_new_row = (uchar*) my_alloca(estimate_row_size(table)); @@ -442,7 +442,7 @@ int ha_clustrixdb::update_row(const uchar *old_data, const uchar *new_data) if (!trx) DBUG_RETURN(error_code); - assert(trx->has_stmt_trans()); + assert(trx->has_open_transaction()); size_t row_size = estimate_row_size(table); size_t packed_key_len; @@ -502,7 +502,7 @@ int ha_clustrixdb::delete_row(const uchar *buf) if (!trx) return error_code; - assert(trx->has_stmt_trans()); + assert(trx->has_open_transaction()); // The estimate should consider only key fields widths. size_t packed_key_len; @@ -932,11 +932,11 @@ int ha_clustrixdb::external_lock(THD *thd, int lock_type) int error_code; clustrix_connection *trx = get_trx(thd, &error_code); if (lock_type != F_UNLCK) { - trx->begin_trans(); + trx->begin_transaction(); trans_register_ha(thd, FALSE, clustrixdb_hton); if (thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) { - trx->begin_stmt_trans(); + trx->set_anonymous_savepoint(); trans_register_ha(thd, TRUE, clustrixdb_hton); } } @@ -1039,11 +1039,11 @@ static int clustrixdb_commit(handlerton *hton, THD *thd, bool all) bool send_cmd; if (all || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) { - if (trx->has_trans()) - send_cmd = trx->commit_trans(); + if (trx->has_open_transaction()) + send_cmd = trx->commit_transaction(); } else { - if (trx->has_stmt_trans()) - send_cmd = trx->commit_stmt_trans(); + if (trx->has_open_anonymous_savepoint()) + send_cmd = trx->release_anonymous_savepoint(); } if (send_cmd) @@ -1059,11 +1059,11 @@ static int clustrixdb_rollback(handlerton *hton, THD *thd, bool all) bool send_cmd; if (all || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) { - if (trx->has_trans()) - send_cmd = trx->rollback_trans(); + if (trx->has_open_transaction()) + send_cmd = trx->rollback_transaction(); } else { - if (trx->has_stmt_trans()) - send_cmd = trx->rollback_stmt_trans(); + if (trx->has_open_anonymous_savepoint()) + send_cmd = trx->rollback_to_anonymous_savepoint(); } if (send_cmd) -- cgit v1.2.1 From 04ca407dc0bd41f22faa1b411c8c21b8325c630a Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Tue, 8 Oct 2019 16:40:55 -0700 Subject: Fix more transaction assertions and issues. --- storage/clustrixdb/clustrix_connection.cc | 11 +++++++++-- storage/clustrixdb/ha_clustrixdb.cc | 10 ++-------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/storage/clustrixdb/clustrix_connection.cc b/storage/clustrixdb/clustrix_connection.cc index 154363bf477..af48eba10b6 100644 --- a/storage/clustrixdb/clustrix_connection.cc +++ b/storage/clustrixdb/clustrix_connection.cc @@ -148,7 +148,7 @@ int clustrix_connection::connect() int clustrix_connection::begin_command(uchar command) { - assert(has_transaction); + assert(command == CLUSTRIX_TRANSACTION_CMD || has_transaction); command_length = 0; int error_code = 0; if ((error_code = add_command_operand_uchar(command))) @@ -192,7 +192,6 @@ int clustrix_connection::read_query_response() return error_code; } - auto_commit_closed(); return 0; } @@ -205,8 +204,10 @@ int clustrix_connection::send_transaction_cmd() int error_code; if ((error_code = begin_command(CLUSTRIX_TRANSACTION_CMD))) DBUG_RETURN(error_code); + if ((error_code = send_command())) DBUG_RETURN(error_code); + if ((error_code = read_query_response())) DBUG_RETURN(mysql_errno(&clustrix_net)); @@ -346,6 +347,7 @@ int clustrix_connection::write_row(ulonglong clustrix_table_oid, if ((error_code = read_query_response())) return error_code; + auto_commit_closed(); *last_insert_id = clustrix_net.insert_id; return error_code; } @@ -381,6 +383,7 @@ int clustrix_connection::key_update(ulonglong clustrix_table_oid, if ((error_code = read_query_response())) return error_code; + auto_commit_closed(); return error_code; } @@ -406,6 +409,7 @@ int clustrix_connection::key_delete(ulonglong clustrix_table_oid, if ((error_code = read_query_response())) return error_code; + auto_commit_closed(); return error_code; } @@ -719,9 +723,11 @@ int clustrix_connection::update_query(String &stmt, LEX_CSTRING &dbname, if ((error_code = send_command())) return error_code; + if ((error_code = read_query_response())) return error_code; + auto_commit_closed(); *affected_rows = clustrix_net.affected_rows; return 0; @@ -837,6 +843,7 @@ int clustrix_connection::scan_end(clustrix_connection_cursor *scan) if ((error_code = read_query_response())) return error_code; + auto_commit_closed(); return 0; } diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index 8bd477b2659..16a593c0323 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -409,8 +409,6 @@ int ha_clustrixdb::write_row(const uchar *buf) if (!trx) return error_code; - assert(trx->has_open_transaction()); - /* Convert the row format to binlog (packed) format */ uchar *packed_new_row = (uchar*) my_alloca(estimate_row_size(table)); size_t packed_size = pack_row(table, table->write_set, packed_new_row, buf); @@ -442,8 +440,6 @@ int ha_clustrixdb::update_row(const uchar *old_data, const uchar *new_data) if (!trx) DBUG_RETURN(error_code); - assert(trx->has_open_transaction()); - size_t row_size = estimate_row_size(table); size_t packed_key_len; uchar *packed_key = (uchar*) my_alloca(row_size); @@ -502,8 +498,6 @@ int ha_clustrixdb::delete_row(const uchar *buf) if (!trx) return error_code; - assert(trx->has_open_transaction()); - // The estimate should consider only key fields widths. size_t packed_key_len; uchar *packed_key = (uchar*) my_alloca(estimate_row_size(table)); @@ -1037,7 +1031,7 @@ static int clustrixdb_commit(handlerton *hton, THD *thd, bool all) clustrix_connection* trx = (clustrix_connection *) thd_get_ha_data(thd, hton); assert(trx); - bool send_cmd; + bool send_cmd = FALSE; if (all || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) { if (trx->has_open_transaction()) send_cmd = trx->commit_transaction(); @@ -1057,7 +1051,7 @@ static int clustrixdb_rollback(handlerton *hton, THD *thd, bool all) clustrix_connection* trx = (clustrix_connection *) thd_get_ha_data(thd, hton); assert(trx); - bool send_cmd; + bool send_cmd = FALSE; if (all || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) { if (trx->has_open_transaction()) send_cmd = trx->rollback_transaction(); -- cgit v1.2.1 From aaa182b1a49fa17dc08097bfd5951953f492483f Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Wed, 9 Oct 2019 18:01:58 -0700 Subject: Fix crash with update. --- storage/clustrixdb/clustrix_connection.cc | 2 +- storage/clustrixdb/ha_clustrixdb.cc | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/storage/clustrixdb/clustrix_connection.cc b/storage/clustrixdb/clustrix_connection.cc index af48eba10b6..654cb66100a 100644 --- a/storage/clustrixdb/clustrix_connection.cc +++ b/storage/clustrixdb/clustrix_connection.cc @@ -712,7 +712,7 @@ int clustrix_connection::update_query(String &stmt, LEX_CSTRING &dbname, int error_code; command_length = 0; - if ((error_code = add_command_operand_uchar(CLUSTRIX_UPDATE_QUERY))) + if ((error_code = begin_command(CLUSTRIX_UPDATE_QUERY))) return error_code; if ((error_code = add_command_operand_str((uchar*)dbname.str, dbname.length))) diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index 16a593c0323..713985cdaea 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -483,6 +483,9 @@ int ha_clustrixdb::direct_update_rows(ha_rows *update_rows) String update_stmt; update_stmt.append(thd->query_string.str()); + if (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) + trx->auto_commit_next(); + trx->update_query(update_stmt, table->s->db, update_rows); thd->get_stmt_da()->set_overwrite_status(true); @@ -926,11 +929,13 @@ int ha_clustrixdb::external_lock(THD *thd, int lock_type) int error_code; clustrix_connection *trx = get_trx(thd, &error_code); if (lock_type != F_UNLCK) { - trx->begin_transaction(); + if (!trx->has_open_transaction()) + trx->begin_transaction(); trans_register_ha(thd, FALSE, clustrixdb_hton); if (thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) { - trx->set_anonymous_savepoint(); + if (!trx->has_open_anonymous_savepoint()) + trx->set_anonymous_savepoint(); trans_register_ha(thd, TRUE, clustrixdb_hton); } } -- cgit v1.2.1 From af2e75cd914c6fbf8fcb43809b63aa8fe85fb815 Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Thu, 10 Oct 2019 14:45:07 -0700 Subject: Clean up ClustrixDB handlerton memory. --- storage/clustrixdb/ha_clustrixdb.cc | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index 713985cdaea..4229c491f8f 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -53,13 +53,20 @@ static MYSQL_SYSVAR_STR int host_list_cnt; char **host_list; -static void update_host_list(char *clustrix_host) + +static void free_host_list() { if (host_list) { for (int i = 0; host_list[i]; i++) my_free(host_list[i]); my_free(host_list); + host_list = NULL; } +} + +static void update_host_list(char *clustrix_host) +{ + free_host_list(); int cnt = 0; for (char *p = clustrix_host, *s = clustrix_host; ; p++) { @@ -1153,6 +1160,13 @@ static int clustrixdb_init(void *p) DBUG_RETURN(0); } +static int clustrixdb_deinit(void *p) +{ + DBUG_ENTER("clustrixdb_deinit"); + free_host_list(); + DBUG_RETURN(0); +} + struct st_mysql_show_var clustrixdb_status_vars[] = { {NullS, NullS, SHOW_LONG} @@ -1186,7 +1200,7 @@ maria_declare_plugin(clustrixdb) "ClustrixDB storage engine", /* Plugin Description */ PLUGIN_LICENSE_GPL, /* Plugin Licence */ clustrixdb_init, /* Plugin Entry Point */ - NULL, /* Plugin Deinitializer */ + clustrixdb_deinit, /* Plugin Deinitializer */ 0x0001, /* Hex Version Number (0.1) */ NULL /* clustrixdb_status_vars */, /* Status Variables */ clustrixdb_system_variables, /* System Variables */ -- cgit v1.2.1 From 55f20e52c82605f3cfa204aeee6299e2853ed77b Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Fri, 11 Oct 2019 12:39:07 -0700 Subject: Free memory when allocate_clustrix_connection_cursor() fails. --- storage/clustrixdb/clustrix_connection.cc | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/storage/clustrixdb/clustrix_connection.cc b/storage/clustrixdb/clustrix_connection.cc index 654cb66100a..77955d1b7ea 100644 --- a/storage/clustrixdb/clustrix_connection.cc +++ b/storage/clustrixdb/clustrix_connection.cc @@ -538,10 +538,11 @@ public: DBUG_ENTER("clustrix_connection_cursor::~clustrix_connection_cursor"); if (outstanding_row) my_free(outstanding_row); - while (current_row < last_row) - my_free(rows[current_row++].data); - if (rows) + if (rows) { + while (current_row < last_row) + my_free(rows[current_row++].data); my_free(rows); + } DBUG_VOID_RETURN; } @@ -598,7 +599,13 @@ int allocate_clustrix_connection_cursor(MYSQL *clustrix_net, ulong buffer_size, if (!*scan) DBUG_RETURN(HA_ERR_OUT_OF_MEM); - DBUG_RETURN((*scan)->initialize(stmt_completed)); + int error_code = (*scan)->initialize(stmt_completed); + if (error_code) { + delete *scan; + *scan = NULL; + } + + DBUG_RETURN(error_code); } int clustrix_connection::scan_table(ulonglong clustrix_table_oid, uint index, -- cgit v1.2.1 From 0696d50b6875463b4593a3e9793c315407dd349f Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Fri, 11 Oct 2019 18:41:28 -0700 Subject: Free clustrix_connection objects on errors in handlerton methods. --- storage/clustrixdb/ha_clustrixdb.cc | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index 4229c491f8f..ad4e65a8761 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -1117,11 +1117,13 @@ static int clustrixdb_discover_table_names(handlerton *hton, LEX_CSTRING *db, clustrix_connection *clustrix_net = new clustrix_connection(); int error_code = clustrix_net->connect(); if (error_code) - return error_code; + goto err; - error_code = clustrix_net->populate_table_list(db, result); + clustrix_net->populate_table_list(db, result); + +err: delete clustrix_net; - return 0; // error_code; + return error_code; } int clustrixdb_discover_table(handlerton *hton, THD *thd, TABLE_SHARE *share) @@ -1129,12 +1131,13 @@ int clustrixdb_discover_table(handlerton *hton, THD *thd, TABLE_SHARE *share) clustrix_connection *clustrix_net = new clustrix_connection(); int error_code = clustrix_net->connect(); if (error_code) - return error_code; + goto err; error_code = clustrix_net->discover_table_details(&share->db, &share->table_name, thd, share); +err: delete clustrix_net; return error_code; } -- cgit v1.2.1 From aca476f5c819bd4aa8f05b7beeecc5d8e7b95c98 Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Fri, 11 Oct 2019 18:36:45 -0700 Subject: Decode database names from paths like table names. --- storage/clustrixdb/ha_clustrixdb.cc | 51 ++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index ad4e65a8761..d46789f6bb7 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -213,12 +213,32 @@ size_t estimate_row_size(TABLE *table) * * Used in delete and rename DDL processing. **/ -void decode_objectname(char *buf, const char *path, size_t buf_size) +static void decode_objectname(char *buf, const char *path, size_t buf_size) { size_t new_path_len = filename_to_tablename(path, buf, buf_size); buf[new_path_len] = '\0'; } +static void decode_file_path(const char *path, char *decoded_dbname, + char *decoded_tbname) +{ + // The format cont ains './' in the beginning of a path. + char *dbname_start = (char*) path + 2; + char *dbname_end = dbname_start; + while (*dbname_end != '/') + dbname_end++; + + int cnt = dbname_end - dbname_start; + char *dbname = (char *)my_alloca(cnt + 1); + memcpy(dbname, dbname_start, cnt); + dbname[cnt] = '\0'; + decode_objectname(decoded_dbname, dbname, FN_REFLEN); + my_afree(dbname); + + char *tbname_start = dbname_end + 1; + decode_objectname(decoded_tbname, tbname_start, FN_REFLEN); +} + clustrix_connection *get_trx(THD *thd, int *error_code) { *error_code = 0; @@ -317,17 +337,13 @@ int ha_clustrixdb::delete_table(const char *path) if (!trx) return error_code; - // The format cont ains './' in the beginning of a path. - char *dbname_end = (char*) path + 2; - while (*dbname_end != '/') - dbname_end++; - + char decoded_dbname[FN_REFLEN]; char decoded_tbname[FN_REFLEN]; - decode_objectname(decoded_tbname, dbname_end + 1, FN_REFLEN); + decode_file_path(path, decoded_dbname, decoded_tbname); String delete_cmd; delete_cmd.append("DROP TABLE `"); - delete_cmd.append(path + 2, dbname_end - path - 2); + delete_cmd.append(decoded_dbname); delete_cmd.append("`.`"); delete_cmd.append(decoded_tbname); delete_cmd.append("`"); @@ -343,28 +359,21 @@ int ha_clustrixdb::rename_table(const char* from, const char* to) if (!trx) return error_code; - // The format contains './' in the beginning of a path. - char *from_dbname_end = (char*) from + 2; - while (*from_dbname_end != '/') - from_dbname_end++; - + char decoded_from_dbname[FN_REFLEN]; char decoded_from_tbname[FN_REFLEN]; - decode_objectname(decoded_from_tbname, from_dbname_end + 1, FN_REFLEN); - - char *to_dbname_end = (char*) to + 2; - while (*to_dbname_end != '/') - to_dbname_end++; + decode_file_path(from, decoded_from_dbname, decoded_from_tbname); + char decoded_to_dbname[FN_REFLEN]; char decoded_to_tbname[FN_REFLEN]; - decode_objectname(decoded_to_tbname, to_dbname_end + 1, FN_REFLEN); + decode_file_path(to, decoded_to_dbname, decoded_to_tbname); String rename_cmd; rename_cmd.append("RENAME TABLE `"); - rename_cmd.append(from + 2, from_dbname_end - from - 2); + rename_cmd.append(decoded_from_dbname); rename_cmd.append("`.`"); rename_cmd.append(decoded_from_tbname); rename_cmd.append("` TO `"); - rename_cmd.append(to + 2, to_dbname_end - to - 2); + rename_cmd.append(decoded_to_dbname); rename_cmd.append("`.`"); rename_cmd.append(decoded_to_tbname); rename_cmd.append("`;"); -- cgit v1.2.1 From bdaffefd661ec1d9b26838530a706ddfc06cdaf0 Mon Sep 17 00:00:00 2001 From: Roman Nozdrin Date: Tue, 12 Nov 2019 18:11:08 +0000 Subject: CLX-43 An initial version of fast statement-based UPSERT that handles both single row/value UPSERT and bulk UPSERT. --- mysql-test/suite/clustrixdb/update.result | 6 +-- mysql-test/suite/clustrixdb/update.test | 6 +-- mysql-test/suite/clustrixdb/upsert.result | 72 +++++++++++++++++++++++++++ mysql-test/suite/clustrixdb/upsert.test | 49 ++++++++++++++++++ storage/clustrixdb/clustrix_connection.h | 23 +++++++++ storage/clustrixdb/ha_clustrixdb.cc | 83 ++++++++++++++++++++++++++++++- storage/clustrixdb/ha_clustrixdb.h | 3 ++ 7 files changed, 235 insertions(+), 7 deletions(-) create mode 100644 mysql-test/suite/clustrixdb/upsert.result create mode 100644 mysql-test/suite/clustrixdb/upsert.test diff --git a/mysql-test/suite/clustrixdb/update.result b/mysql-test/suite/clustrixdb/update.result index 1ad6cdbcb02..304fccee6fd 100644 --- a/mysql-test/suite/clustrixdb/update.result +++ b/mysql-test/suite/clustrixdb/update.result @@ -6,18 +6,18 @@ Note 1051 Unknown table 'db1.t1' CREATE TABLE `t1`(i BIGINT, t TEXT)ENGINE=clustrixdb; INSERT INTO `t1` (i, t) VALUES (42, 'один'); INSERT INTO `t1` (i, t) VALUES (42, 'ноль'); -SELECT * FROM `t1`; +SELECT * FROM `t1` ORDER BY `i`; i t 42 один 42 ноль UPDATE `t1` SET i=i+1,t='два' WHERE t='один'; -SELECT * FROM `t1`; +SELECT * FROM `t1` ORDER BY `i`; i t 42 один 42 ноль USE test; UPDATE `db1`.`t1` SET i=i+1,t='три' WHERE t='два'; -SELECT * FROM `db1`.`t1`; +SELECT * FROM `db1`.`t1` ORDER BY `i`; i t 42 один 42 ноль diff --git a/mysql-test/suite/clustrixdb/update.test b/mysql-test/suite/clustrixdb/update.test index 10b17d19e01..097745da051 100644 --- a/mysql-test/suite/clustrixdb/update.test +++ b/mysql-test/suite/clustrixdb/update.test @@ -4,14 +4,14 @@ DROP TABLE IF EXISTS `t1`; CREATE TABLE `t1`(i BIGINT, t TEXT)ENGINE=clustrixdb; INSERT INTO `t1` (i, t) VALUES (42, 'один'); INSERT INTO `t1` (i, t) VALUES (42, 'ноль'); -SELECT * FROM `t1`; +SELECT * FROM `t1` ORDER BY `i`; UPDATE `t1` SET i=i+1,t='два' WHERE t='один'; -SELECT * FROM `t1`; +SELECT * FROM `t1` ORDER BY `i`; USE test; UPDATE `db1`.`t1` SET i=i+1,t='три' WHERE t='два'; -SELECT * FROM `db1`.`t1`; +SELECT * FROM `db1`.`t1` ORDER BY `i`; DROP TABLE `db1`.`t1`; diff --git a/mysql-test/suite/clustrixdb/upsert.result b/mysql-test/suite/clustrixdb/upsert.result new file mode 100644 index 00000000000..f30cfe95314 --- /dev/null +++ b/mysql-test/suite/clustrixdb/upsert.result @@ -0,0 +1,72 @@ +CREATE DATABASE IF NOT EXISTS `db1`; +USE `db1`; +DROP TABLE IF EXISTS `ins_duplicate`; +Warnings: +Note 1051 Unknown table 'db1.ins_duplicate' +CREATE TABLE `ins_duplicate`(`id` INT PRIMARY KEY, `animal` VARCHAR(30)) ENGINE=clustrixdb; +INSERT INTO `ins_duplicate` VALUES (1,'Aardvark'), (2,'Cheetah'), (3,'Zebra'); +SELECT * FROM `ins_duplicate` ORDER BY `id`; +id animal +1 Aardvark +2 Cheetah +3 Zebra +INSERT INTO ins_duplicate VALUES (1,'Antelope'); +ERROR 23000: Clustrix error: [5120] Duplicate key in container: `db1`.`ins_duplicate` Primary key: (1) +INSERT INTO ins_duplicate VALUES (1,'Antelope') ON DUPLICATE KEY UPDATE animal='Banana'; +SELECT * FROM `ins_duplicate` ORDER BY `id`; +id animal +1 Banana +2 Cheetah +3 Zebra +INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah'); +ERROR 23000: Clustrix error: [5120] Duplicate key in container: `db1`.`ins_duplicate` Primary key: (1) +INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah') ON DUPLICATE KEY UPDATE animal='hybrid'; +SELECT * FROM `ins_duplicate` ORDER BY `id`; +id animal +1 hybrid +2 hybrid +3 Zebra +BEGIN; +SELECT * FROM `ins_duplicate` ORDER BY `id`; +id animal +1 hybrid +2 hybrid +3 Zebra +INSERT INTO ins_duplicate VALUES (1,'Antelope'); +ERROR 23000: Clustrix error: [5120] Duplicate key in container: `db1`.`ins_duplicate` Primary key: (1) +INSERT INTO ins_duplicate VALUES (1,'Antelope') ON DUPLICATE KEY UPDATE animal='Vegetable'; +SELECT * FROM `ins_duplicate` ORDER BY `id`; +id animal +1 Vegetable +2 hybrid +3 Zebra +INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah'); +ERROR 23000: Clustrix error: [5120] Duplicate key in container: `db1`.`ins_duplicate` Primary key: (1) +INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah') ON DUPLICATE KEY UPDATE animal='hybrid2'; +COMMIT; +BEGIN; +SELECT * FROM `ins_duplicate` ORDER BY `id`; +id animal +1 hybrid2 +2 hybrid2 +3 Zebra +INSERT INTO ins_duplicate VALUES (1,'Antelope'); +ERROR 23000: Clustrix error: [5120] Duplicate key in container: `db1`.`ins_duplicate` Primary key: (1) +INSERT INTO ins_duplicate VALUES (1,'Antelope') ON DUPLICATE KEY UPDATE animal='Vegetable'; +SELECT * FROM `ins_duplicate` ORDER BY `id`; +id animal +1 Vegetable +2 hybrid2 +3 Zebra +INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah'); +ERROR 23000: Clustrix error: [5120] Duplicate key in container: `db1`.`ins_duplicate` Primary key: (1) +INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah') ON DUPLICATE KEY UPDATE animal='hybrid3'; +ROLLBACK; +SELECT * FROM `ins_duplicate` ORDER BY `id`; +id animal +1 hybrid2 +2 hybrid2 +3 Zebra +DROP TABLE `db1`.`ins_duplicate`; +USE test; +DROP DATABASE `db1`; diff --git a/mysql-test/suite/clustrixdb/upsert.test b/mysql-test/suite/clustrixdb/upsert.test new file mode 100644 index 00000000000..badd6cb50d4 --- /dev/null +++ b/mysql-test/suite/clustrixdb/upsert.test @@ -0,0 +1,49 @@ +CREATE DATABASE IF NOT EXISTS `db1`; +USE `db1`; +DROP TABLE IF EXISTS `ins_duplicate`; +CREATE TABLE `ins_duplicate`(`id` INT PRIMARY KEY, `animal` VARCHAR(30)) ENGINE=clustrixdb; +INSERT INTO `ins_duplicate` VALUES (1,'Aardvark'), (2,'Cheetah'), (3,'Zebra'); +SELECT * FROM `ins_duplicate` ORDER BY `id`; + +--error ER_DUP_ENTRY +INSERT INTO ins_duplicate VALUES (1,'Antelope'); +INSERT INTO ins_duplicate VALUES (1,'Antelope') ON DUPLICATE KEY UPDATE animal='Banana'; +SELECT * FROM `ins_duplicate` ORDER BY `id`; + +--error ER_DUP_ENTRY +INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah'); +INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah') ON DUPLICATE KEY UPDATE animal='hybrid'; +SELECT * FROM `ins_duplicate` ORDER BY `id`; + +BEGIN; +SELECT * FROM `ins_duplicate` ORDER BY `id`; + +--error ER_DUP_ENTRY +INSERT INTO ins_duplicate VALUES (1,'Antelope'); +INSERT INTO ins_duplicate VALUES (1,'Antelope') ON DUPLICATE KEY UPDATE animal='Vegetable'; +SELECT * FROM `ins_duplicate` ORDER BY `id`; + +--error ER_DUP_ENTRY +INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah'); +INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah') ON DUPLICATE KEY UPDATE animal='hybrid2'; +COMMIT; + +BEGIN; +SELECT * FROM `ins_duplicate` ORDER BY `id`; + +--error ER_DUP_ENTRY +INSERT INTO ins_duplicate VALUES (1,'Antelope'); +INSERT INTO ins_duplicate VALUES (1,'Antelope') ON DUPLICATE KEY UPDATE animal='Vegetable'; +SELECT * FROM `ins_duplicate` ORDER BY `id`; + +--error ER_DUP_ENTRY +INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah'); +INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah') ON DUPLICATE KEY UPDATE animal='hybrid3'; +ROLLBACK; + +SELECT * FROM `ins_duplicate` ORDER BY `id`; + +DROP TABLE `db1`.`ins_duplicate`; + +USE test; +DROP DATABASE `db1`; diff --git a/storage/clustrixdb/clustrix_connection.h b/storage/clustrixdb/clustrix_connection.h index 13c5100be64..0d9408e674a 100644 --- a/storage/clustrixdb/clustrix_connection.h +++ b/storage/clustrixdb/clustrix_connection.h @@ -21,6 +21,12 @@ Copyright (c) 2019, MariaDB Corporation. #define CLUSTRIX_SERVER_REQUEST 30 +typedef enum clustrix_upsert_flags { + CLUSTRIX_HAS_UPSERT= 1, + CLUSTRIX_BULK_UPSERT= 2, + CLUSTRIX_UPSERT_SENT= 4 +} clx_upsert_flags_t; + class clustrix_connection_cursor; class clustrix_connection { @@ -37,6 +43,7 @@ private: size_t reply_length; bool has_transaction; + uint upsert_flag; bool has_anonymous_savepoint; int commit_flag_next; @@ -48,6 +55,7 @@ public: memset(&clustrix_net, 0, sizeof(MYSQL)); has_anonymous_savepoint = FALSE; has_transaction = FALSE; + upsert_flag = 0; commit_flag_next = 0; DBUG_VOID_RETURN; } @@ -82,6 +90,21 @@ public: return has_transaction; } + inline void unset_upsert(clx_upsert_flags_t state) + { + upsert_flag &= ~state; + } + + inline void set_upsert(clx_upsert_flags_t state) + { + upsert_flag |= state; + } + + inline bool check_upsert(clx_upsert_flags_t state) + { + return upsert_flag & state; + } + bool set_anonymous_savepoint(); bool release_anonymous_savepoint(); bool rollback_to_anonymous_savepoint(); diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index d46789f6bb7..54f20643469 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -417,6 +417,33 @@ int ha_clustrixdb::reset() return 0; } +int ha_clustrixdb::extra(enum ha_extra_function operation) +{ + DBUG_ENTER("ha_clustrixdb::extra"); + int error_code = 0; + THD *thd = ha_thd(); + clustrix_connection *trx = get_trx(thd, &error_code); + if (!trx) + return error_code; + + if (operation == HA_EXTRA_INSERT_WITH_UPDATE) { + trx->set_upsert(CLUSTRIX_HAS_UPSERT); + } + + DBUG_RETURN(0); +} + +/*@brief UPSERT State Machine*/ +/************************************************************* + * DESCRIPTION: + * Fasttrack for UPSERT sends queries down to a CLX backend. + * UPSERT could be of two kinds: singular and bulk. The plugin + * re-/sets CLUSTRIX_BULK_UPSERT in end|start_bulk_insert + * methods. CLUSTRIX_UPSERT_SENT is used to avoid multiple + * execution at CLX backend. + * Generic CLUSTRIX_HAS_UPSERT is set for bulk UPSERT only b/c + * MDB calls write_row only once. + ************************************************************/ int ha_clustrixdb::write_row(const uchar *buf) { int error_code = 0; @@ -425,6 +452,26 @@ int ha_clustrixdb::write_row(const uchar *buf) if (!trx) return error_code; + if (trx->check_upsert(CLUSTRIX_HAS_UPSERT)) { + if (!trx->check_upsert(CLUSTRIX_UPSERT_SENT)) { + ha_rows update_rows; + String update_stmt; + update_stmt.append(thd->query_string.str()); + + if (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) + trx->auto_commit_next(); + + error_code= trx->update_query(update_stmt, table->s->db, &update_rows); + + thd->get_stmt_da()->set_overwrite_status(true); + if (trx->check_upsert(CLUSTRIX_BULK_UPSERT)) + trx->set_upsert(CLUSTRIX_UPSERT_SENT); + else + trx->unset_upsert(CLUSTRIX_HAS_UPSERT); + } + return error_code; + } + /* Convert the row format to binlog (packed) format */ uchar *packed_new_row = (uchar*) my_alloca(estimate_row_size(table)); size_t packed_size = pack_row(table, table->write_set, packed_new_row, buf); @@ -509,6 +556,39 @@ int ha_clustrixdb::direct_update_rows(ha_rows *update_rows) DBUG_RETURN(error_code); } +void ha_clustrixdb::start_bulk_insert(ha_rows rows, uint flags) +{ + DBUG_ENTER("ha_clustrixdb::start_bulk_insert"); + int error_code= 0; + THD *thd= ha_thd(); + clustrix_connection *trx= get_trx(thd, &error_code); + if (!trx) { + // TBD log this + DBUG_VOID_RETURN; + } + + trx->set_upsert(CLUSTRIX_BULK_UPSERT); + + DBUG_VOID_RETURN; +} + +int ha_clustrixdb::end_bulk_insert() +{ + DBUG_ENTER("ha_clustrixdb::end_bulk_insert"); + int error_code= 0; + THD *thd= ha_thd(); + clustrix_connection *trx= get_trx(thd, &error_code); + if (!trx) { + DBUG_RETURN(error_code); + } + + trx->unset_upsert(CLUSTRIX_BULK_UPSERT); + trx->unset_upsert(CLUSTRIX_HAS_UPSERT); + trx->unset_upsert(CLUSTRIX_UPSERT_SENT); + + DBUG_RETURN(0); +} + int ha_clustrixdb::delete_row(const uchar *buf) { int error_code; @@ -942,6 +1022,7 @@ THR_LOCK_DATA **ha_clustrixdb::store_lock(THD *thd, int ha_clustrixdb::external_lock(THD *thd, int lock_type) { + DBUG_ENTER("ha_clustrixdb::external_lock()"); int error_code; clustrix_connection *trx = get_trx(thd, &error_code); if (lock_type != F_UNLCK) { @@ -956,7 +1037,7 @@ int ha_clustrixdb::external_lock(THD *thd, int lock_type) } } - return 0; + DBUG_RETURN(0); } /**************************************************************************** diff --git a/storage/clustrixdb/ha_clustrixdb.h b/storage/clustrixdb/ha_clustrixdb.h index 64a579b925d..4741fc02e3c 100644 --- a/storage/clustrixdb/ha_clustrixdb.h +++ b/storage/clustrixdb/ha_clustrixdb.h @@ -57,6 +57,8 @@ public: int delete_row(const uchar *buf); int direct_update_rows_init(List *update_fields); int direct_update_rows(ha_rows *update_rows); + void start_bulk_insert(ha_rows rows, uint flags = 0); + int end_bulk_insert(); Table_flags table_flags(void) const; ulong index_flags(uint idx, uint part, bool all_parts) const; @@ -67,6 +69,7 @@ public: key_range *max_key); int info(uint flag); // see my_base.h for full description + int extra(enum ha_extra_function operation); // multi_read_range // read_range -- cgit v1.2.1 From b9673a64a136533c78cf15341ba3aa7afeb49357 Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Tue, 19 Nov 2019 17:43:24 -0800 Subject: Always mark committed and rolled back transactions closed. --- mysql-test/suite/clustrixdb/update.result | 6 +++--- mysql-test/suite/clustrixdb/update.test | 6 +++--- storage/clustrixdb/clustrix_connection.cc | 12 ++++++------ 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/mysql-test/suite/clustrixdb/update.result b/mysql-test/suite/clustrixdb/update.result index 304fccee6fd..fec6a409a7b 100644 --- a/mysql-test/suite/clustrixdb/update.result +++ b/mysql-test/suite/clustrixdb/update.result @@ -6,18 +6,18 @@ Note 1051 Unknown table 'db1.t1' CREATE TABLE `t1`(i BIGINT, t TEXT)ENGINE=clustrixdb; INSERT INTO `t1` (i, t) VALUES (42, 'один'); INSERT INTO `t1` (i, t) VALUES (42, 'ноль'); -SELECT * FROM `t1` ORDER BY `i`; +SELECT * FROM `t1` ORDER BY `i` DESC, `t` DESC; i t 42 один 42 ноль UPDATE `t1` SET i=i+1,t='два' WHERE t='один'; -SELECT * FROM `t1` ORDER BY `i`; +SELECT * FROM `t1` ORDER BY `i` DESC, `t` DESC; i t 42 один 42 ноль USE test; UPDATE `db1`.`t1` SET i=i+1,t='три' WHERE t='два'; -SELECT * FROM `db1`.`t1` ORDER BY `i`; +SELECT * FROM `db1`.`t1` ORDER BY `i` DESC, `t` DESC; i t 42 один 42 ноль diff --git a/mysql-test/suite/clustrixdb/update.test b/mysql-test/suite/clustrixdb/update.test index 097745da051..599d7f348ac 100644 --- a/mysql-test/suite/clustrixdb/update.test +++ b/mysql-test/suite/clustrixdb/update.test @@ -4,14 +4,14 @@ DROP TABLE IF EXISTS `t1`; CREATE TABLE `t1`(i BIGINT, t TEXT)ENGINE=clustrixdb; INSERT INTO `t1` (i, t) VALUES (42, 'один'); INSERT INTO `t1` (i, t) VALUES (42, 'ноль'); -SELECT * FROM `t1` ORDER BY `i`; +SELECT * FROM `t1` ORDER BY `i` DESC, `t` DESC; UPDATE `t1` SET i=i+1,t='два' WHERE t='один'; -SELECT * FROM `t1` ORDER BY `i`; +SELECT * FROM `t1` ORDER BY `i` DESC, `t` DESC; USE test; UPDATE `db1`.`t1` SET i=i+1,t='три' WHERE t='два'; -SELECT * FROM `db1`.`t1` ORDER BY `i`; +SELECT * FROM `db1`.`t1` ORDER BY `i` DESC, `t` DESC; DROP TABLE `db1`.`t1`; diff --git a/storage/clustrixdb/clustrix_connection.cc b/storage/clustrixdb/clustrix_connection.cc index 77955d1b7ea..7d7848db8dc 100644 --- a/storage/clustrixdb/clustrix_connection.cc +++ b/storage/clustrixdb/clustrix_connection.cc @@ -228,14 +228,14 @@ bool clustrix_connection::commit_transaction() DBUG_ENTER("clustrix_connection::commit_transaction"); assert(has_transaction); + has_transaction = FALSE; + has_anonymous_savepoint = FALSE; if (commit_flag_next & CLUSTRIX_TRANS_BEGIN) { commit_flag_next &= ~CLUSTRIX_TRANS_BEGIN; DBUG_RETURN(FALSE); } commit_flag_next |= CLUSTRIX_TRANS_COMMIT; - has_transaction = FALSE; - has_anonymous_savepoint = FALSE; DBUG_RETURN(TRUE); } @@ -244,14 +244,14 @@ bool clustrix_connection::rollback_transaction() DBUG_ENTER("clustrix_connection::rollback_transaction"); assert(has_transaction); + has_transaction = FALSE; + has_anonymous_savepoint = FALSE; if (commit_flag_next & CLUSTRIX_TRANS_BEGIN) { commit_flag_next &= ~CLUSTRIX_TRANS_BEGIN; DBUG_RETURN(FALSE); } commit_flag_next |= CLUSTRIX_TRANS_ROLLBACK; - has_transaction = FALSE; - has_anonymous_savepoint = FALSE; DBUG_RETURN(TRUE); } @@ -287,12 +287,12 @@ bool clustrix_connection::release_anonymous_savepoint() assert(has_transaction); assert(has_anonymous_savepoint); + has_anonymous_savepoint = FALSE; if (commit_flag_next & CLUSTRIX_STMT_NEW) { commit_flag_next &= ~CLUSTRIX_STMT_NEW; DBUG_RETURN(FALSE); } - has_anonymous_savepoint = FALSE; DBUG_RETURN(TRUE); } @@ -302,13 +302,13 @@ bool clustrix_connection::rollback_to_anonymous_savepoint() assert(has_transaction); assert(has_anonymous_savepoint); + has_anonymous_savepoint = FALSE; if (commit_flag_next & CLUSTRIX_STMT_NEW) { commit_flag_next &= ~CLUSTRIX_STMT_NEW; DBUG_RETURN(FALSE); } commit_flag_next |= CLUSTRIX_STMT_ROLLBACK; - has_anonymous_savepoint = FALSE; DBUG_RETURN(TRUE); } -- cgit v1.2.1 From 225cf48623db2274c7d72eb52e5dba5167265993 Mon Sep 17 00:00:00 2001 From: Roman Nozdrin Date: Thu, 21 Nov 2019 06:53:10 +0000 Subject: Return early from init_SH for EXPLAIN to avoid needless scan. Fix for a potential null deref in DH for EXPLAIN. --- storage/clustrixdb/ha_clustrixdb_pushdown.cc | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/storage/clustrixdb/ha_clustrixdb_pushdown.cc b/storage/clustrixdb/ha_clustrixdb_pushdown.cc index f20dbcf1d59..181fb9ac561 100644 --- a/storage/clustrixdb/ha_clustrixdb_pushdown.cc +++ b/storage/clustrixdb/ha_clustrixdb_pushdown.cc @@ -107,6 +107,15 @@ create_clustrixdb_select_handler(THD* thd, SELECT_LEX* select_lex) return sh; } + // TODO Return early for EXPLAIN before we run the actual scan. + // We can send compile request when we separate compilation + // and execution. + clustrix_connection_cursor *scan = NULL; + if (thd->lex->describe) { + sh = new ha_clustrixdb_select_handler(thd, select_lex, scan); + return sh; + } + // Multi-update runs an implicit query to collect constraints. // SH couldn't be used for this. if (thd->lex->sql_command == SQLCOM_UPDATE_MULTI) { @@ -118,7 +127,6 @@ create_clustrixdb_select_handler(THD* thd, SELECT_LEX* select_lex) select_lex->print(thd, &query, QT_ORDINARY); int error_code = 0; int field_metadata_size = 0; - clustrix_connection_cursor *scan = NULL; clustrix_connection *trx = NULL; // We presume this number is equal to types.elements in get_field_types @@ -365,8 +373,6 @@ ha_clustrixdb_derived_handler::~ha_clustrixdb_derived_handler() * ********************************************************/ int ha_clustrixdb_derived_handler::init_scan() { - // Save this into the base handler class attribute - table__ = table; String query; // Print the query into a string provided select->print(thd__, &query, QT_ORDINARY); @@ -390,7 +396,7 @@ int ha_clustrixdb_derived_handler::init_scan() } if((field_metadata_size= - get_field_types(thd__, table__, select, fieldtype, field_metadata, null_bits, num_null_bytes, items_number)) < 0) { + get_field_types(thd__, table, select, fieldtype, field_metadata, null_bits, num_null_bytes, items_number)) < 0) { goto err; } @@ -405,6 +411,9 @@ int ha_clustrixdb_derived_handler::init_scan() goto err; } + // Save this into the base handler class attribute + table__ = table; + // need this bitmap future in next_row() if (my_bitmap_init(&scan_fields, NULL, table->read_set->n_bits, false)) return ER_OUTOFMEMORY; -- cgit v1.2.1 From 1de262b68506708aab3486c43a97aa6a89ddcd6e Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Mon, 2 Dec 2019 14:31:06 -0800 Subject: Fix table synchronization for rowstore operations. --- storage/clustrixdb/ha_clustrixdb.cc | 78 ++++++++++++++++++++++++++----------- 1 file changed, 56 insertions(+), 22 deletions(-) diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index 54f20643469..1a483869f25 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -381,6 +381,13 @@ int ha_clustrixdb::rename_table(const char* from, const char* to) return trx->run_query(rename_cmd); } +static void +clustrixdb_mark_table_for_discovery(TABLE *table) +{ + table->s->tabledef_version.str = NULL; + table->s->tabledef_version.length = 0; + table->m_needs_reopen = TRUE; +} int ha_clustrixdb::open(const char *name, int mode, uint test_if_locked) { @@ -389,7 +396,7 @@ int ha_clustrixdb::open(const char *name, int mode, uint test_if_locked) ("%s", table->s->tabledef_version.str)); if (!table->s->tabledef_version.str) - return HA_ERR_TABLE_DEF_CHANGED; + DBUG_RETURN(HA_ERR_TABLE_DEF_CHANGED); if (!clustrix_table_oid) clustrix_table_oid = atoll((const char *)table->s->tabledef_version.str); @@ -488,10 +495,13 @@ int ha_clustrixdb::write_row(const uchar *buf) insert_id_for_cur_row = last_insert_id; err: - if (packed_size) - my_afree(packed_new_row); + if (error_code == HA_ERR_TABLE_DEF_CHANGED) + clustrixdb_mark_table_for_discovery(table); - return error_code; + if (packed_size) + my_afree(packed_new_row); + + return error_code; } int ha_clustrixdb::update_row(const uchar *old_data, const uchar *new_data) @@ -524,6 +534,9 @@ int ha_clustrixdb::update_row(const uchar *old_data, const uchar *new_data) if(packed_new_row) my_afree(packed_new_row); + if (error_code == HA_ERR_TABLE_DEF_CHANGED) + clustrixdb_mark_table_for_discovery(table); + DBUG_RETURN(error_code); } @@ -603,13 +616,13 @@ int ha_clustrixdb::delete_row(const uchar *buf) build_key_packed_row(table->s->primary_key, table->record[0], packed_key, &packed_key_len); - if ((error_code = trx->key_delete(clustrix_table_oid, - packed_key, packed_key_len))) - goto err; + error_code = trx->key_delete(clustrix_table_oid, packed_key, packed_key_len); -err: - if (packed_key) - my_afree(packed_key); + if (error_code == HA_ERR_TABLE_DEF_CHANGED) + clustrixdb_mark_table_for_discovery(table); + + if (packed_key) + my_afree(packed_key); return error_code; } @@ -776,6 +789,9 @@ int ha_clustrixdb::index_read(uchar * buf, const uchar * key, uint key_len, if (packed_key) my_afree(packed_key); + if (error_code == HA_ERR_TABLE_DEF_CHANGED) + clustrixdb_mark_table_for_discovery(table); + if (error_code) DBUG_RETURN(error_code); @@ -791,10 +807,15 @@ int ha_clustrixdb::index_first(uchar *buf) if (!trx) DBUG_RETURN(error_code); - if ((error_code = trx->scan_from_key(clustrix_table_oid, active_index, - clustrix_connection::READ_FROM_START, - sorted_scan, &scan_fields, NULL, 0, - THDVAR(thd, row_buffer), &scan_cur))) + error_code = trx->scan_from_key(clustrix_table_oid, active_index, + clustrix_connection::READ_FROM_START, + sorted_scan, &scan_fields, NULL, 0, + THDVAR(thd, row_buffer), &scan_cur); + + if (error_code == HA_ERR_TABLE_DEF_CHANGED) + clustrixdb_mark_table_for_discovery(table); + + if (error_code) DBUG_RETURN(error_code); DBUG_RETURN(rnd_next(buf)); @@ -809,10 +830,15 @@ int ha_clustrixdb::index_last(uchar *buf) if (!trx) DBUG_RETURN(error_code); - if ((error_code = trx->scan_from_key(clustrix_table_oid, active_index, - clustrix_connection::READ_FROM_LAST, - sorted_scan, &scan_fields, NULL, 0, - THDVAR(thd, row_buffer), &scan_cur))) + error_code = trx->scan_from_key(clustrix_table_oid, active_index, + clustrix_connection::READ_FROM_LAST, + sorted_scan, &scan_fields, NULL, 0, + THDVAR(thd, row_buffer), &scan_cur); + + if (error_code == HA_ERR_TABLE_DEF_CHANGED) + clustrixdb_mark_table_for_discovery(table); + + if (error_code) DBUG_RETURN(error_code); DBUG_RETURN(rnd_next(buf)); @@ -878,10 +904,15 @@ int ha_clustrixdb::rnd_init(bool scan) bitmap_set_all(&scan_fields); #endif - if ((error_code = trx->scan_table(clustrix_table_oid, 0, - clustrix_connection::SORT_NONE, - &scan_fields, THDVAR(thd, row_buffer), - &scan_cur))) + error_code = trx->scan_table(clustrix_table_oid, 0, + clustrix_connection::SORT_NONE, + &scan_fields, THDVAR(thd, row_buffer), + &scan_cur); + + if (error_code == HA_ERR_TABLE_DEF_CHANGED) + clustrixdb_mark_table_for_discovery(table); + + if (error_code) DBUG_RETURN(error_code); DBUG_RETURN(0); @@ -970,6 +1001,9 @@ err: if (packed_key) my_afree(packed_key); + if (error_code == HA_ERR_TABLE_DEF_CHANGED) + clustrixdb_mark_table_for_discovery(table); + DBUG_RETURN(error_code); } -- cgit v1.2.1 From fac710e9174039eda901c35b11b99881bdff48d3 Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Thu, 21 Nov 2019 18:50:10 -0800 Subject: Move add_current_table_to_rpl_table_list out of ha_clustrixdb class. --- storage/clustrixdb/ha_clustrixdb.cc | 24 ++++++++++++------------ storage/clustrixdb/ha_clustrixdb.h | 6 +++--- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index 1a483869f25..aabd15a2d54 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -269,7 +269,6 @@ ha_clustrixdb::ha_clustrixdb(handlerton *hton, TABLE_SHARE *table_arg) : handler(hton, table_arg) { DBUG_ENTER("ha_clustrixdb::ha_clustrixdb"); - rli = NULL; rgi = NULL; scan_cur = NULL; clustrix_table_oid = 0; @@ -278,8 +277,8 @@ ha_clustrixdb::ha_clustrixdb(handlerton *hton, TABLE_SHARE *table_arg) ha_clustrixdb::~ha_clustrixdb() { - if (rli) - ha_clustrixdb::remove_current_table_from_rpl_table_list(); + if (rgi) + remove_current_table_from_rpl_table_list(rgi); } int ha_clustrixdb::create(const char *name, TABLE *form, HA_CREATE_INFO *info) @@ -720,7 +719,7 @@ int ha_clustrixdb::index_init(uint idx, bool sorted) return error_code; active_index = idx; - add_current_table_to_rpl_table_list(); + add_current_table_to_rpl_table_list(&rgi, thd, table); scan_cur = NULL; /* Return all columns until there is a better understanding of @@ -885,7 +884,7 @@ int ha_clustrixdb::rnd_init(bool scan) if (!trx) DBUG_RETURN(error_code); - add_current_table_to_rpl_table_list(); + add_current_table_to_rpl_table_list(&rgi, thd, table); is_scan = scan; scan_cur = NULL; @@ -1092,16 +1091,17 @@ int ha_clustrixdb::info_push(uint info_type, void *info) return 0; } -void ha_clustrixdb::add_current_table_to_rpl_table_list() +void add_current_table_to_rpl_table_list(rpl_group_info **_rgi, THD *thd, + TABLE *table) { - if (rli) + if (*_rgi) return; - THD *thd = ha_thd(); - rli = new Relay_log_info(FALSE); + Relay_log_info *rli = new Relay_log_info(FALSE); rli->sql_driver_thd = thd; - rgi = new rpl_group_info(rli); + rpl_group_info *rgi = new rpl_group_info(rli); + *_rgi = rgi; rgi->thd = thd; rgi->tables_to_lock_count = 0; rgi->tables_to_lock = NULL; @@ -1129,7 +1129,7 @@ void ha_clustrixdb::add_current_table_to_rpl_table_list() my_afree(col_type); } -void ha_clustrixdb::remove_current_table_from_rpl_table_list() +void remove_current_table_from_rpl_table_list(rpl_group_info *rgi) { if (!rgi->tables_to_lock) return; @@ -1139,7 +1139,7 @@ void ha_clustrixdb::remove_current_table_from_rpl_table_list() my_free(rgi->tables_to_lock); rgi->tables_to_lock_count--; rgi->tables_to_lock = NULL; - delete rli; + delete rgi->rli; delete rgi; } diff --git a/storage/clustrixdb/ha_clustrixdb.h b/storage/clustrixdb/ha_clustrixdb.h index 4741fc02e3c..672695448af 100644 --- a/storage/clustrixdb/ha_clustrixdb.h +++ b/storage/clustrixdb/ha_clustrixdb.h @@ -23,13 +23,15 @@ Copyright (c) 2019, MariaDB Corporation. size_t estimate_row_size(TABLE *table); clustrix_connection *get_trx(THD *thd, int *error_code); bool get_enable_sh(THD* thd); +void add_current_table_to_rpl_table_list(rpl_group_info **_rgi, THD *thd, + TABLE *table); +void remove_current_table_from_rpl_table_list(rpl_group_info *rgi); class ha_clustrixdb : public handler { private: ulonglong clustrix_table_oid; rpl_group_info *rgi; - Relay_log_info *rli; Field *auto_inc_field; ulonglong auto_inc_value; @@ -105,8 +107,6 @@ public: int info_push(uint info_type, void *info); private: - void add_current_table_to_rpl_table_list(); - void remove_current_table_from_rpl_table_list(); void build_key_packed_row(uint index, const uchar *buf, uchar *packed_key, size_t *packed_key_len); }; -- cgit v1.2.1 From 3b30a12c6602d7ef67ec6b6cf0925b33d77e4c4f Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Thu, 21 Nov 2019 18:51:08 -0800 Subject: Remove clone of add_current_table_to_rpl_table_list from ha_clustrixdb_pushdown.cc. --- storage/clustrixdb/ha_clustrixdb_pushdown.cc | 78 ++-------------------------- storage/clustrixdb/ha_clustrixdb_pushdown.h | 4 -- 2 files changed, 4 insertions(+), 78 deletions(-) diff --git a/storage/clustrixdb/ha_clustrixdb_pushdown.cc b/storage/clustrixdb/ha_clustrixdb_pushdown.cc index 181fb9ac561..60bde00ffdb 100644 --- a/storage/clustrixdb/ha_clustrixdb_pushdown.cc +++ b/storage/clustrixdb/ha_clustrixdb_pushdown.cc @@ -189,7 +189,6 @@ ha_clustrixdb_select_handler::ha_clustrixdb_select_handler( thd__ = thd; scan = scan_; select = select_lex; - rli = NULL; rgi = NULL; } @@ -213,7 +212,7 @@ ha_clustrixdb_select_handler::~ha_clustrixdb_select_handler() if (table__) my_bitmap_free(&scan_fields); - remove_current_table_from_rpl_table_list(); + remove_current_table_from_rpl_table_list(rgi); } /*@brief Initiate the query for select_handler */ @@ -234,7 +233,7 @@ int ha_clustrixdb_select_handler::init_scan() return ER_OUTOFMEMORY; bitmap_set_all(&scan_fields); - add_current_table_to_rpl_table_list(); + add_current_table_to_rpl_table_list(&rgi, thd__, table__); return 0; } @@ -332,7 +331,6 @@ ha_clustrixdb_derived_handler::ha_clustrixdb_derived_handler( thd__ = thd; scan = scan_; select = select_lex; - rli = NULL; rgi = NULL; } @@ -359,7 +357,7 @@ ha_clustrixdb_derived_handler::~ha_clustrixdb_derived_handler() if (table__) my_bitmap_free(&scan_fields); - remove_current_table_from_rpl_table_list(); + remove_current_table_from_rpl_table_list(rgi); } /*@brief Initiate the query for derived_handler */ @@ -419,7 +417,7 @@ int ha_clustrixdb_derived_handler::init_scan() return ER_OUTOFMEMORY; bitmap_set_all(&scan_fields); - add_current_table_to_rpl_table_list(); + add_current_table_to_rpl_table_list(&rgi, thd__, table__); err: // deallocate buffers @@ -476,71 +474,3 @@ int ha_clustrixdb_derived_handler::end_scan() { return 0; } - -/*@brief clone of ha_clustrixdb method */ -/*********************************************************** - * DESCRIPTION: - * Creates structures to unpack RBR rows in ::next_row() - * PARAMETERS: - * RETURN: - * rc as int - ***********************************************************/ -void ha_clustrixdb_base_handler::add_current_table_to_rpl_table_list() -{ - if (rli) - return; - - rli = new Relay_log_info(FALSE); - rli->sql_driver_thd = thd__; - - rgi = new rpl_group_info(rli); - rgi->thd = thd__; - rgi->tables_to_lock_count = 0; - rgi->tables_to_lock = NULL; - if (rgi->tables_to_lock_count) - return; - - rgi->tables_to_lock = (RPL_TABLE_LIST *)my_malloc(sizeof(RPL_TABLE_LIST), - MYF(MY_WME)); - rgi->tables_to_lock->init_one_table(&table__->s->db, &table__->s->table_name, 0, - TL_READ); - rgi->tables_to_lock->table = table__; - rgi->tables_to_lock->table_id = table__->tablenr; - rgi->tables_to_lock->m_conv_table = NULL; - rgi->tables_to_lock->master_had_triggers = FALSE; - rgi->tables_to_lock->m_tabledef_valid = TRUE; - // We need one byte per column to save a column's binlog type. - uchar *col_type = (uchar*) my_alloca(table__->s->fields); - for (uint i = 0 ; i < table__->s->fields ; ++i) - col_type[i] = table__->field[i]->binlog_type(); - - table_def *tabledef = &rgi->tables_to_lock->m_tabledef; - new (tabledef) table_def(col_type, table__->s->fields, NULL, 0, NULL, 0); - rgi->tables_to_lock_count++; - if (col_type) - my_afree(col_type); -} - -/*@brief clone of ha_clustrixdb method */ -/*********************************************************** - * DESCRIPTION: - * Deletes structures that are used to unpack RBR rows - * in ::next_row(). Called from dtor - * PARAMETERS: - * RETURN: - * rc as int - ***********************************************************/ -void ha_clustrixdb_base_handler::remove_current_table_from_rpl_table_list() -{ - // the 2nd cond might be unnecessary - if (!rgi || !rgi->tables_to_lock) - return; - - rgi->tables_to_lock->m_tabledef.table_def::~table_def(); - rgi->tables_to_lock->m_tabledef_valid = FALSE; - my_free(rgi->tables_to_lock); - rgi->tables_to_lock_count--; - rgi->tables_to_lock = NULL; - delete rli; - delete rgi; -} diff --git a/storage/clustrixdb/ha_clustrixdb_pushdown.h b/storage/clustrixdb/ha_clustrixdb_pushdown.h index 2a58f4ab04f..2f08bd427b0 100644 --- a/storage/clustrixdb/ha_clustrixdb_pushdown.h +++ b/storage/clustrixdb/ha_clustrixdb_pushdown.h @@ -28,12 +28,8 @@ class ha_clustrixdb_base_handler MY_BITMAP scan_fields; // Structures to unpack RBR rows from CLX BE rpl_group_info *rgi; - Relay_log_info *rli; // CLX BE scan operation reference clustrix_connection_cursor *scan; - // To unpack rows from CLX BE - void add_current_table_to_rpl_table_list(); - void remove_current_table_from_rpl_table_list(); }; /*@brief select_handler class*/ -- cgit v1.2.1 From af71a9cbfdbb7452e27b293532ebdd58dd688ed5 Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Thu, 9 Jan 2020 13:08:50 -0800 Subject: Check for NULL pointer before calling remove_current_table_from_rpl_table_list(). --- storage/clustrixdb/ha_clustrixdb_pushdown.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/storage/clustrixdb/ha_clustrixdb_pushdown.cc b/storage/clustrixdb/ha_clustrixdb_pushdown.cc index 60bde00ffdb..58cf01cce44 100644 --- a/storage/clustrixdb/ha_clustrixdb_pushdown.cc +++ b/storage/clustrixdb/ha_clustrixdb_pushdown.cc @@ -212,7 +212,8 @@ ha_clustrixdb_select_handler::~ha_clustrixdb_select_handler() if (table__) my_bitmap_free(&scan_fields); - remove_current_table_from_rpl_table_list(rgi); + if (rgi) + remove_current_table_from_rpl_table_list(rgi); } /*@brief Initiate the query for select_handler */ @@ -357,7 +358,8 @@ ha_clustrixdb_derived_handler::~ha_clustrixdb_derived_handler() if (table__) my_bitmap_free(&scan_fields); - remove_current_table_from_rpl_table_list(rgi); + if (rgi) + remove_current_table_from_rpl_table_list(rgi); } /*@brief Initiate the query for derived_handler */ -- cgit v1.2.1 From 36780445cffec4f792e838ca2aca9855af879a41 Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Fri, 22 Nov 2019 14:32:48 -0800 Subject: Fix table buffer handling. --- storage/clustrixdb/ha_clustrixdb.cc | 67 +++++++++++++++++++++++++------------ storage/clustrixdb/ha_clustrixdb.h | 3 ++ 2 files changed, 48 insertions(+), 22 deletions(-) diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index aabd15a2d54..d5ecbcd8144 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -612,8 +612,7 @@ int ha_clustrixdb::delete_row(const uchar *buf) // The estimate should consider only key fields widths. size_t packed_key_len; uchar *packed_key = (uchar*) my_alloca(estimate_row_size(table)); - build_key_packed_row(table->s->primary_key, table->record[0], - packed_key, &packed_key_len); + build_key_packed_row(table->s->primary_key, buf, packed_key, &packed_key_len); error_code = trx->key_delete(clustrix_table_oid, packed_key, packed_key_len); @@ -639,7 +638,6 @@ ha_clustrixdb::Table_flags ha_clustrixdb::table_flags(void) const HA_CAN_TABLE_CONDITION_PUSHDOWN | HA_CAN_DIRECT_UPDATE_AND_DELETE; - return flags; } @@ -744,12 +742,11 @@ int ha_clustrixdb::index_read(uchar * buf, const uchar * key, uint key_len, DBUG_RETURN(error_code); is_scan = true; - key_restore(table->record[0], key, &table->key_info[active_index], key_len); + key_restore(buf, key, &table->key_info[active_index], key_len); // The estimate should consider only key fields widths. size_t packed_key_len; uchar *packed_key = (uchar*) my_alloca(estimate_row_size(table)); - build_key_packed_row(active_index, table->record[0], - packed_key, &packed_key_len); + build_key_packed_row(active_index, buf, packed_key, &packed_key_len); //bool exact = false; clustrix_connection::scan_type st; @@ -939,12 +936,8 @@ int ha_clustrixdb::rnd_next(uchar *buf) rowdata_length -= 8; } - uchar const *current_row_end; - ulong master_reclength; - - error_code = unpack_row(rgi, table, table->s->fields, rowdata, - &scan_fields, ¤t_row_end, - &master_reclength, rowdata + rowdata_length); + error_code = unpack_row_to_buf(rgi, table, buf, rowdata, &scan_fields, + rowdata + rowdata_length); if (error_code) return error_code; @@ -969,15 +962,15 @@ int ha_clustrixdb::rnd_pos(uchar * buf, uchar *pos) memcpy(&last_hidden_key, pos, sizeof(ulonglong)); } else { uint keyno = table->s->primary_key; - uint len = calculate_key_len(table, keyno, pos, table->const_key_parts[keyno]); - key_restore(table->record[0], pos, &table->key_info[keyno], len); + uint len = calculate_key_len(table, keyno, pos, + table->const_key_parts[keyno]); + key_restore(buf, pos, &table->key_info[keyno], len); } // The estimate should consider only key fields widths. uchar *packed_key = (uchar*) my_alloca(estimate_row_size(table)); size_t packed_key_len; - build_key_packed_row(table->s->primary_key, table->record[0], - packed_key, &packed_key_len); + build_key_packed_row(table->s->primary_key, buf, packed_key, &packed_key_len); uchar *rowdata = NULL; ulong rowdata_length; @@ -986,11 +979,8 @@ int ha_clustrixdb::rnd_pos(uchar * buf, uchar *pos) &rowdata, &rowdata_length))) goto err; - uchar const *current_row_end; - ulong master_reclength; - if ((error_code = unpack_row(rgi, table, table->s->fields, rowdata, - table->read_set, ¤t_row_end, - &master_reclength, rowdata + rowdata_length))) + if ((error_code = unpack_row_to_buf(rgi, table, buf, rowdata, table->read_set, + rowdata + rowdata_length))) goto err; err: @@ -1013,7 +1003,7 @@ int ha_clustrixdb::rnd_end() THD *thd = ha_thd(); if (thd->lex->sql_command == SQLCOM_UPDATE) DBUG_RETURN(error_code); - + clustrix_connection *trx = get_trx(thd, &error_code); if (!trx) DBUG_RETURN(error_code); @@ -1091,6 +1081,10 @@ int ha_clustrixdb::info_push(uint info_type, void *info) return 0; } +/**************************************************************************** +** Row encoding functions +****************************************************************************/ + void add_current_table_to_rpl_table_list(rpl_group_info **_rgi, THD *thd, TABLE *table) { @@ -1158,6 +1152,35 @@ void ha_clustrixdb::build_key_packed_row(uint index, const uchar *buf, } } +int unpack_row_to_buf(rpl_group_info *rgi, TABLE *table, uchar *data, + uchar const *const row_data, MY_BITMAP const *cols, + uchar const *const row_end) +{ + /* Since unpack_row can only write to record[0], if 'data' does not point to + table->record[0], we must back it up and then restore it afterwards. */ + uchar const *current_row_end; + ulong master_reclength; + uchar *backup_row = NULL; + if (data != table->record[0]) { + /* See Update_rows_log_event::do_exec_row(rpl_group_info *rgi) + and the definitions of store_record and restore_record. */ + backup_row = (uchar*) my_alloca(table->s->reclength); + memcpy(backup_row, table->record[0], table->s->reclength); + restore_record(table, record[data == table->record[1] ? 1 : 2]); + } + + int error_code = unpack_row(rgi, table, table->s->fields, row_data, cols, + ¤t_row_end, &master_reclength, row_end); + + if (backup_row) { + store_record(table, record[data == table->record[1] ? 1 : 2]); + memcpy(table->record[0], backup_row, table->s->reclength); + my_afree(backup_row); + } + + return error_code; +} + /**************************************************************************** ** Plugin Functions ****************************************************************************/ diff --git a/storage/clustrixdb/ha_clustrixdb.h b/storage/clustrixdb/ha_clustrixdb.h index 672695448af..ff061e30a11 100644 --- a/storage/clustrixdb/ha_clustrixdb.h +++ b/storage/clustrixdb/ha_clustrixdb.h @@ -26,6 +26,9 @@ bool get_enable_sh(THD* thd); void add_current_table_to_rpl_table_list(rpl_group_info **_rgi, THD *thd, TABLE *table); void remove_current_table_from_rpl_table_list(rpl_group_info *rgi); +int unpack_row_to_buf(rpl_group_info *rgi, TABLE *table, uchar *data, + uchar const *const row_data, MY_BITMAP const *cols, + uchar const *const row_end); class ha_clustrixdb : public handler { -- cgit v1.2.1 From aaa6f13294671550bd135c9dccd0fc9c73e2b1f3 Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Thu, 19 Dec 2019 18:00:18 -0800 Subject: Support for HA_READ_KEY_EXACT. --- storage/clustrixdb/ha_clustrixdb.cc | 44 ++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index d5ecbcd8144..c0dd8fa8cf8 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -741,20 +741,18 @@ int ha_clustrixdb::index_read(uchar * buf, const uchar * key, uint key_len, if (!trx) DBUG_RETURN(error_code); - is_scan = true; key_restore(buf, key, &table->key_info[active_index], key_len); // The estimate should consider only key fields widths. size_t packed_key_len; uchar *packed_key = (uchar*) my_alloca(estimate_row_size(table)); build_key_packed_row(active_index, buf, packed_key, &packed_key_len); - //bool exact = false; + bool exact = false; clustrix_connection::scan_type st; switch (find_flag) { case HA_READ_KEY_EXACT: - //exact = true; - /* fall through */ - //DBUG_RETURN(ER_NOT_SUPPORTED_YET); + exact = true; + break; case HA_READ_KEY_OR_NEXT: st = clustrix_connection::READ_KEY_OR_NEXT; break; @@ -778,20 +776,40 @@ int ha_clustrixdb::index_read(uchar * buf, const uchar * key, uint key_len, DBUG_RETURN(ER_NOT_SUPPORTED_YET); } - error_code = trx->scan_from_key(clustrix_table_oid, active_index, st, - sorted_scan, &scan_fields, packed_key, - packed_key_len, THDVAR(thd, row_buffer), - &scan_cur); + uchar *rowdata = NULL; + if (exact) { + is_scan = false; + ulong rowdata_length; + if ((error_code = trx->key_read(clustrix_table_oid, 0, + clustrix_connection::CLUSTRIX_SHARED, + table->read_set, packed_key, packed_key_len, + &rowdata, &rowdata_length))) + goto err; + + error_code = unpack_row_to_buf(rgi, table, buf, rowdata, table->read_set, + rowdata + rowdata_length); + } else { + is_scan = true; + if ((error_code = trx->scan_from_key(clustrix_table_oid, active_index, st, + sorted_scan, &scan_fields, packed_key, + packed_key_len, + THDVAR(thd, row_buffer), &scan_cur))) + goto err; + + error_code = rnd_next(buf); + } + +err: + if (rowdata) + my_free(rowdata); + if (packed_key) my_afree(packed_key); if (error_code == HA_ERR_TABLE_DEF_CHANGED) clustrixdb_mark_table_for_discovery(table); - if (error_code) - DBUG_RETURN(error_code); - - DBUG_RETURN(rnd_next(buf)); + DBUG_RETURN(error_code); } int ha_clustrixdb::index_first(uchar *buf) -- cgit v1.2.1 From 4e45e8a217b67456195b501318826bd324418cfc Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Thu, 16 Jan 2020 11:42:50 -0800 Subject: Remove CLUSTRIX_SHARED argument to trx->key_read. --- storage/clustrixdb/ha_clustrixdb.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index c0dd8fa8cf8..328bed7fce8 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -781,7 +781,6 @@ int ha_clustrixdb::index_read(uchar * buf, const uchar * key, uint key_len, is_scan = false; ulong rowdata_length; if ((error_code = trx->key_read(clustrix_table_oid, 0, - clustrix_connection::CLUSTRIX_SHARED, table->read_set, packed_key, packed_key_len, &rowdata, &rowdata_length))) goto err; -- cgit v1.2.1 From 14c34d963a5bbf0f5d064ce8e76025b34ddebe25 Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Fri, 10 Jan 2020 14:48:39 -0800 Subject: Add session variable to enable direct update. --- storage/clustrixdb/ha_clustrixdb.cc | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index 328bed7fce8..1f548a45081 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -162,6 +162,7 @@ static MYSQL_THDVAR_BOOL( NULL, 1 ); + // Per thread derived handler knob static MYSQL_THDVAR_BOOL( derived_handler, @@ -172,6 +173,15 @@ static MYSQL_THDVAR_BOOL( 1 ); +static MYSQL_THDVAR_BOOL( + enable_direct_update, + PLUGIN_VAR_NOCMDARG, + "", + NULL, + NULL, + 1 +); + bool select_handler_setting(THD* thd) { return ( thd == NULL ) ? false : THDVAR(thd, select_handler); @@ -542,8 +552,10 @@ int ha_clustrixdb::update_row(const uchar *old_data, const uchar *new_data) int ha_clustrixdb::direct_update_rows_init(List *update_fields) { DBUG_ENTER("ha_clustrixdb::direct_update_rows_init"); - int error_code= 0; - DBUG_RETURN(error_code); + THD *thd= ha_thd(); + if (!THDVAR(thd, enable_direct_update)) + DBUG_RETURN(HA_ERR_WRONG_COMMAND); + DBUG_RETURN(0); } int ha_clustrixdb::direct_update_rows(ha_rows *update_rows) @@ -1352,6 +1364,7 @@ static struct st_mysql_sys_var* clustrixdb_system_variables[] = MYSQL_SYSVAR(row_buffer), MYSQL_SYSVAR(select_handler), MYSQL_SYSVAR(derived_handler), + MYSQL_SYSVAR(enable_direct_update), NULL }; -- cgit v1.2.1 From 0b01f9ef25532c02881bb2f080f808bd3df8f069 Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Wed, 22 Jan 2020 12:59:00 -0800 Subject: Fix direct_update error handling. --- storage/clustrixdb/clustrix_connection.cc | 9 ++++----- storage/clustrixdb/ha_clustrixdb.cc | 5 +---- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/storage/clustrixdb/clustrix_connection.cc b/storage/clustrixdb/clustrix_connection.cc index 7d7848db8dc..aca69877ef5 100644 --- a/storage/clustrixdb/clustrix_connection.cc +++ b/storage/clustrixdb/clustrix_connection.cc @@ -731,13 +731,12 @@ int clustrix_connection::update_query(String &stmt, LEX_CSTRING &dbname, if ((error_code = send_command())) return error_code; - if ((error_code = read_query_response())) - return error_code; - + error_code = read_query_response(); auto_commit_closed(); - *affected_rows = clustrix_net.affected_rows; + if (!error_code) + *affected_rows = clustrix_net.affected_rows; - return 0; + return error_code; } diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index 1f548a45081..46b72366d9a 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -573,10 +573,7 @@ int ha_clustrixdb::direct_update_rows(ha_rows *update_rows) if (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) trx->auto_commit_next(); - trx->update_query(update_stmt, table->s->db, update_rows); - - thd->get_stmt_da()->set_overwrite_status(true); - + error_code = trx->update_query(update_stmt, table->s->db, update_rows); DBUG_RETURN(error_code); } -- cgit v1.2.1 From dd450ebce7290785aca13f36527f1b2f3ca12956 Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Wed, 22 Jan 2020 12:59:00 -0800 Subject: Prevent row based commands from being called with auto-commit. This patch also fixes a bug in scan_end() and removes an unneeded call to set_overwrite_status(). --- storage/clustrixdb/clustrix_connection.cc | 49 +++++++++++++++++++------------ storage/clustrixdb/ha_clustrixdb.cc | 2 -- 2 files changed, 30 insertions(+), 21 deletions(-) diff --git a/storage/clustrixdb/clustrix_connection.cc b/storage/clustrixdb/clustrix_connection.cc index aca69877ef5..c886eefb609 100644 --- a/storage/clustrixdb/clustrix_connection.cc +++ b/storage/clustrixdb/clustrix_connection.cc @@ -332,6 +332,10 @@ int clustrix_connection::write_row(ulonglong clustrix_table_oid, int error_code; command_length = 0; + // row based commands should not be called with auto commit. + if (commit_flag_next & CLUSTRIX_TRANS_COMMIT_ON_FINISH) + return HA_ERR_INTERNAL_ERROR; + if ((error_code = begin_command(CLUSTRIX_WRITE_ROW))) return error_code; @@ -347,7 +351,6 @@ int clustrix_connection::write_row(ulonglong clustrix_table_oid, if ((error_code = read_query_response())) return error_code; - auto_commit_closed(); *last_insert_id = clustrix_net.insert_id; return error_code; } @@ -361,6 +364,10 @@ int clustrix_connection::key_update(ulonglong clustrix_table_oid, int error_code; command_length = 0; + // row based commands should not be called with auto commit. + if (commit_flag_next & CLUSTRIX_TRANS_COMMIT_ON_FINISH) + return HA_ERR_INTERNAL_ERROR; + if ((error_code = begin_command(CLUSTRIX_KEY_UPDATE))) return error_code; @@ -383,9 +390,7 @@ int clustrix_connection::key_update(ulonglong clustrix_table_oid, if ((error_code = read_query_response())) return error_code; - auto_commit_closed(); return error_code; - } int clustrix_connection::key_delete(ulonglong clustrix_table_oid, @@ -394,6 +399,10 @@ int clustrix_connection::key_delete(ulonglong clustrix_table_oid, int error_code; command_length = 0; + // row based commands should not be called with auto commit. + if (commit_flag_next & CLUSTRIX_TRANS_COMMIT_ON_FINISH) + return HA_ERR_INTERNAL_ERROR; + if ((error_code = begin_command(CLUSTRIX_KEY_DELETE))) return error_code; @@ -409,7 +418,6 @@ int clustrix_connection::key_delete(ulonglong clustrix_table_oid, if ((error_code = read_query_response())) return error_code; - auto_commit_closed(); return error_code; } @@ -421,6 +429,10 @@ int clustrix_connection::key_read(ulonglong clustrix_table_oid, uint index, int error_code; command_length = 0; + // row based commands should not be called with auto commit. + if (commit_flag_next & CLUSTRIX_TRANS_COMMIT_ON_FINISH) + return HA_ERR_INTERNAL_ERROR; + if ((error_code = begin_command(CLUSTRIX_KEY_READ))) return error_code; @@ -443,7 +455,6 @@ int clustrix_connection::key_read(ulonglong clustrix_table_oid, uint index, if (packet_length == packet_error) return mysql_errno(&clustrix_net); - auto_commit_closed(); uchar *data = clustrix_net.net.read_pos; *rowdata_length = safe_net_field_length_ll(&data, packet_length); *rowdata = (uchar *)my_malloc(*rowdata_length, MYF(MY_WME)); @@ -616,6 +627,10 @@ int clustrix_connection::scan_table(ulonglong clustrix_table_oid, uint index, int error_code; command_length = 0; + // row based commands should not be called with auto commit. + if (commit_flag_next & CLUSTRIX_TRANS_COMMIT_ON_FINISH) + return HA_ERR_INTERNAL_ERROR; + if ((error_code = begin_command(CLUSTRIX_SCAN_TABLE))) return error_code; @@ -638,11 +653,8 @@ int clustrix_connection::scan_table(ulonglong clustrix_table_oid, uint index, return error_code; bool stmt_completed = FALSE; - error_code = allocate_clustrix_connection_cursor(&clustrix_net, row_req, - &stmt_completed, scan); - if (stmt_completed) - auto_commit_closed(); - return error_code; + return allocate_clustrix_connection_cursor(&clustrix_net, row_req, + &stmt_completed, scan); } /** @@ -752,6 +764,10 @@ int clustrix_connection::scan_from_key(ulonglong clustrix_table_oid, uint index, int error_code; command_length = 0; + // row based commands should not be called with auto commit. + if (commit_flag_next & CLUSTRIX_TRANS_COMMIT_ON_FINISH) + return HA_ERR_INTERNAL_ERROR; + if ((error_code = begin_command(CLUSTRIX_SCAN_FROM_KEY))) return error_code; @@ -780,11 +796,8 @@ int clustrix_connection::scan_from_key(ulonglong clustrix_table_oid, uint index, return error_code; bool stmt_completed = FALSE; - error_code = allocate_clustrix_connection_cursor(&clustrix_net, row_req, - &stmt_completed, scan); - if (stmt_completed) - auto_commit_closed(); - return error_code; + return allocate_clustrix_connection_cursor(&clustrix_net, row_req, + &stmt_completed, scan); } int clustrix_connection::scan_next(clustrix_connection_cursor *scan, @@ -846,11 +859,9 @@ int clustrix_connection::scan_end(clustrix_connection_cursor *scan) if ((error_code = send_command())) return error_code; - if ((error_code = read_query_response())) - return error_code; - + error_code = read_query_response(); auto_commit_closed(); - return 0; + return error_code; } int clustrix_connection::populate_table_list(LEX_CSTRING *db, diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index 46b72366d9a..1d374761500 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -478,8 +478,6 @@ int ha_clustrixdb::write_row(const uchar *buf) trx->auto_commit_next(); error_code= trx->update_query(update_stmt, table->s->db, &update_rows); - - thd->get_stmt_da()->set_overwrite_status(true); if (trx->check_upsert(CLUSTRIX_BULK_UPSERT)) trx->set_upsert(CLUSTRIX_UPSERT_SENT); else -- cgit v1.2.1 From 16ee505f8899cb84cfb7853a94631f4f9da6cbf6 Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Fri, 10 Jan 2020 17:17:54 -0800 Subject: Move code track upsert commands into ha_clustrixdb. --- storage/clustrixdb/clustrix_connection.h | 23 ----------------- storage/clustrixdb/ha_clustrixdb.cc | 43 ++++++++++++-------------------- storage/clustrixdb/ha_clustrixdb.h | 11 +++++++- 3 files changed, 26 insertions(+), 51 deletions(-) diff --git a/storage/clustrixdb/clustrix_connection.h b/storage/clustrixdb/clustrix_connection.h index 0d9408e674a..13c5100be64 100644 --- a/storage/clustrixdb/clustrix_connection.h +++ b/storage/clustrixdb/clustrix_connection.h @@ -21,12 +21,6 @@ Copyright (c) 2019, MariaDB Corporation. #define CLUSTRIX_SERVER_REQUEST 30 -typedef enum clustrix_upsert_flags { - CLUSTRIX_HAS_UPSERT= 1, - CLUSTRIX_BULK_UPSERT= 2, - CLUSTRIX_UPSERT_SENT= 4 -} clx_upsert_flags_t; - class clustrix_connection_cursor; class clustrix_connection { @@ -43,7 +37,6 @@ private: size_t reply_length; bool has_transaction; - uint upsert_flag; bool has_anonymous_savepoint; int commit_flag_next; @@ -55,7 +48,6 @@ public: memset(&clustrix_net, 0, sizeof(MYSQL)); has_anonymous_savepoint = FALSE; has_transaction = FALSE; - upsert_flag = 0; commit_flag_next = 0; DBUG_VOID_RETURN; } @@ -90,21 +82,6 @@ public: return has_transaction; } - inline void unset_upsert(clx_upsert_flags_t state) - { - upsert_flag &= ~state; - } - - inline void set_upsert(clx_upsert_flags_t state) - { - upsert_flag |= state; - } - - inline bool check_upsert(clx_upsert_flags_t state) - { - return upsert_flag & state; - } - bool set_anonymous_savepoint(); bool release_anonymous_savepoint(); bool rollback_to_anonymous_savepoint(); diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index 1d374761500..9bd1708ae54 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -282,6 +282,7 @@ ha_clustrixdb::ha_clustrixdb(handlerton *hton, TABLE_SHARE *table_arg) rgi = NULL; scan_cur = NULL; clustrix_table_oid = 0; + upsert_flag = 0; DBUG_VOID_RETURN; } @@ -430,22 +431,17 @@ int ha_clustrixdb::close(void) int ha_clustrixdb::reset() { + upsert_flag &= ~CLUSTRIX_BULK_UPSERT; + upsert_flag &= ~CLUSTRIX_HAS_UPSERT; + upsert_flag &= ~CLUSTRIX_UPSERT_SENT; return 0; } int ha_clustrixdb::extra(enum ha_extra_function operation) { DBUG_ENTER("ha_clustrixdb::extra"); - int error_code = 0; - THD *thd = ha_thd(); - clustrix_connection *trx = get_trx(thd, &error_code); - if (!trx) - return error_code; - - if (operation == HA_EXTRA_INSERT_WITH_UPDATE) { - trx->set_upsert(CLUSTRIX_HAS_UPSERT); - } - + if (operation == HA_EXTRA_INSERT_WITH_UPDATE) + upsert_flag |= CLUSTRIX_HAS_UPSERT; DBUG_RETURN(0); } @@ -468,8 +464,8 @@ int ha_clustrixdb::write_row(const uchar *buf) if (!trx) return error_code; - if (trx->check_upsert(CLUSTRIX_HAS_UPSERT)) { - if (!trx->check_upsert(CLUSTRIX_UPSERT_SENT)) { + if (upsert_flag & CLUSTRIX_HAS_UPSERT) { + if (!(upsert_flag & CLUSTRIX_UPSERT_SENT)) { ha_rows update_rows; String update_stmt; update_stmt.append(thd->query_string.str()); @@ -478,11 +474,12 @@ int ha_clustrixdb::write_row(const uchar *buf) trx->auto_commit_next(); error_code= trx->update_query(update_stmt, table->s->db, &update_rows); - if (trx->check_upsert(CLUSTRIX_BULK_UPSERT)) - trx->set_upsert(CLUSTRIX_UPSERT_SENT); + if (upsert_flag & CLUSTRIX_BULK_UPSERT) + upsert_flag |= CLUSTRIX_UPSERT_SENT; else - trx->unset_upsert(CLUSTRIX_HAS_UPSERT); + upsert_flag &= ~CLUSTRIX_HAS_UPSERT; } + return error_code; } @@ -586,7 +583,7 @@ void ha_clustrixdb::start_bulk_insert(ha_rows rows, uint flags) DBUG_VOID_RETURN; } - trx->set_upsert(CLUSTRIX_BULK_UPSERT); + upsert_flag |= CLUSTRIX_BULK_UPSERT; DBUG_VOID_RETURN; } @@ -594,17 +591,9 @@ void ha_clustrixdb::start_bulk_insert(ha_rows rows, uint flags) int ha_clustrixdb::end_bulk_insert() { DBUG_ENTER("ha_clustrixdb::end_bulk_insert"); - int error_code= 0; - THD *thd= ha_thd(); - clustrix_connection *trx= get_trx(thd, &error_code); - if (!trx) { - DBUG_RETURN(error_code); - } - - trx->unset_upsert(CLUSTRIX_BULK_UPSERT); - trx->unset_upsert(CLUSTRIX_HAS_UPSERT); - trx->unset_upsert(CLUSTRIX_UPSERT_SENT); - + upsert_flag &= ~CLUSTRIX_BULK_UPSERT; + upsert_flag &= ~CLUSTRIX_HAS_UPSERT; + upsert_flag &= ~CLUSTRIX_UPSERT_SENT; DBUG_RETURN(0); } diff --git a/storage/clustrixdb/ha_clustrixdb.h b/storage/clustrixdb/ha_clustrixdb.h index ff061e30a11..6d5ddcd73e1 100644 --- a/storage/clustrixdb/ha_clustrixdb.h +++ b/storage/clustrixdb/ha_clustrixdb.h @@ -46,6 +46,15 @@ private: MY_BITMAP scan_fields; bool sorted_scan; + uint last_dup_errkey; + + typedef enum clustrix_upsert_flags { + CLUSTRIX_HAS_UPSERT= 1, + CLUSTRIX_BULK_UPSERT= 2, + CLUSTRIX_UPSERT_SENT= 4 + } clx_upsert_flags_t; + int upsert_flag; + public: ha_clustrixdb(handlerton *hton, TABLE_SHARE *table_arg); ~ha_clustrixdb(); @@ -55,6 +64,7 @@ public: int open(const char *name, int mode, uint test_if_locked); int close(void); int reset(); + int extra(enum ha_extra_function operation); int write_row(const uchar *buf); // start_bulk_update exec_bulk_update int update_row(const uchar *old_data, const uchar *new_data); @@ -74,7 +84,6 @@ public: key_range *max_key); int info(uint flag); // see my_base.h for full description - int extra(enum ha_extra_function operation); // multi_read_range // read_range -- cgit v1.2.1 From e13e6a6ec09190336cd3d252ab7e729d3fb73d9d Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Thu, 12 Dec 2019 17:17:17 -0800 Subject: Add lock support for row based select queries. --- storage/clustrixdb/clustrix_connection.cc | 23 +++++++++------ storage/clustrixdb/clustrix_connection.h | 15 ++++++++-- storage/clustrixdb/ha_clustrixdb.cc | 47 ++++++++++++++++++------------- storage/clustrixdb/ha_clustrixdb.h | 1 + 4 files changed, 54 insertions(+), 32 deletions(-) diff --git a/storage/clustrixdb/clustrix_connection.cc b/storage/clustrixdb/clustrix_connection.cc index c886eefb609..327f1037a91 100644 --- a/storage/clustrixdb/clustrix_connection.cc +++ b/storage/clustrixdb/clustrix_connection.cc @@ -210,7 +210,7 @@ int clustrix_connection::send_transaction_cmd() if ((error_code = read_query_response())) DBUG_RETURN(mysql_errno(&clustrix_net)); - + DBUG_RETURN(error_code); } @@ -422,6 +422,7 @@ int clustrix_connection::key_delete(ulonglong clustrix_table_oid, } int clustrix_connection::key_read(ulonglong clustrix_table_oid, uint index, + clustrix_lock_mode_t lock_mode, MY_BITMAP *read_set, uchar *packed_key, ulong packed_key_length, uchar **rowdata, ulong *rowdata_length) @@ -442,6 +443,9 @@ int clustrix_connection::key_read(ulonglong clustrix_table_oid, uint index, if ((error_code = add_command_operand_uint(index))) return error_code; + if ((error_code = add_command_operand_uchar((uchar)lock_mode))) + return error_code; + if ((error_code = add_command_operand_bitmap(read_set))) return error_code; @@ -458,7 +462,7 @@ int clustrix_connection::key_read(ulonglong clustrix_table_oid, uint index, uchar *data = clustrix_net.net.read_pos; *rowdata_length = safe_net_field_length_ll(&data, packet_length); *rowdata = (uchar *)my_malloc(*rowdata_length, MYF(MY_WME)); - memcpy(*rowdata, data, *rowdata_length); + memcpy(*rowdata, data, *rowdata_length); packet_length = cli_safe_read(&clustrix_net); if (packet_length == packet_error) { @@ -619,9 +623,9 @@ int allocate_clustrix_connection_cursor(MYSQL *clustrix_net, ulong buffer_size, DBUG_RETURN(error_code); } -int clustrix_connection::scan_table(ulonglong clustrix_table_oid, uint index, - enum sort_order sort, MY_BITMAP *read_set, - ushort row_req, +int clustrix_connection::scan_table(ulonglong clustrix_table_oid, + clustrix_lock_mode_t lock_mode, + MY_BITMAP *read_set, ushort row_req, clustrix_connection_cursor **scan) { int error_code; @@ -640,10 +644,7 @@ int clustrix_connection::scan_table(ulonglong clustrix_table_oid, uint index, if ((error_code = add_command_operand_ulonglong(clustrix_table_oid))) return error_code; - if ((error_code = add_command_operand_uint(index))) - return error_code; - - if ((error_code = add_command_operand_uchar(sort))) + if ((error_code = add_command_operand_uchar((uchar)lock_mode))) return error_code; if ((error_code = add_command_operand_bitmap(read_set))) @@ -754,6 +755,7 @@ int clustrix_connection::update_query(String &stmt, LEX_CSTRING &dbname, int clustrix_connection::scan_from_key(ulonglong clustrix_table_oid, uint index, + clustrix_lock_mode_t lock_mode, enum scan_type scan_dir, bool sorted_scan, MY_BITMAP *read_set, uchar *packed_key, @@ -780,6 +782,9 @@ int clustrix_connection::scan_from_key(ulonglong clustrix_table_oid, uint index, if ((error_code = add_command_operand_uint(index))) return error_code; + if ((error_code = add_command_operand_uchar((uchar)lock_mode))) + return error_code; + if ((error_code = add_command_operand_uchar(scan_dir))) return error_code; diff --git a/storage/clustrixdb/clustrix_connection.h b/storage/clustrixdb/clustrix_connection.h index 13c5100be64..5f6643b3f8b 100644 --- a/storage/clustrixdb/clustrix_connection.h +++ b/storage/clustrixdb/clustrix_connection.h @@ -21,6 +21,12 @@ Copyright (c) 2019, MariaDB Corporation. #define CLUSTRIX_SERVER_REQUEST 30 +typedef enum clustrix_lock_mode { + CLUSTRIX_NO_LOCKS, + CLUSTRIX_SHARED, + CLUSTRIX_EXCLUSIVE, +} clustrix_lock_mode_t; + class clustrix_connection_cursor; class clustrix_connection { @@ -101,7 +107,8 @@ public: uchar *packed_new_data, size_t packed_new_length); int key_delete(ulonglong clustrix_table_oid, uchar *packed_key, size_t packed_key_length); - int key_read(ulonglong clustrix_table_oid, uint index, MY_BITMAP *read_set, + int key_read(ulonglong clustrix_table_oid, uint index, + clustrix_lock_mode_t lock_mode, MY_BITMAP *read_set, uchar *packed_key, ulong packed_key_length, uchar **rowdata, ulong *rowdata_length); @@ -115,8 +122,9 @@ public: READ_FROM_LAST, /* rows with backwards from last key. */ }; - int scan_table(ulonglong clustrix_table_oid, uint index, - enum sort_order sort, MY_BITMAP *read_set, ushort row_req, + int scan_table(ulonglong clustrix_table_oid, + clustrix_lock_mode_t lock_mode, + MY_BITMAP *read_set, ushort row_req, clustrix_connection_cursor **scan); int scan_query(String &stmt, uchar *fieldtype, uint fields, uchar *null_bits, uint null_bits_size, uchar *field_metadata, @@ -124,6 +132,7 @@ public: clustrix_connection_cursor **scan); int update_query(String &stmt, LEX_CSTRING &dbname, ulonglong *affected_rows); int scan_from_key(ulonglong clustrix_table_oid, uint index, + clustrix_lock_mode_t lock_mode, enum scan_type scan_dir, bool sorted_scan, MY_BITMAP *read_set, uchar *packed_key, ulong packed_key_length, ushort row_req, diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index 9bd1708ae54..8e77e920bc4 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -434,6 +434,7 @@ int ha_clustrixdb::reset() upsert_flag &= ~CLUSTRIX_BULK_UPSERT; upsert_flag &= ~CLUSTRIX_HAS_UPSERT; upsert_flag &= ~CLUSTRIX_UPSERT_SENT; + clx_lock_type = CLUSTRIX_NO_LOCKS; return 0; } @@ -776,25 +777,23 @@ int ha_clustrixdb::index_read(uchar * buf, const uchar * key, uint key_len, if (exact) { is_scan = false; ulong rowdata_length; - if ((error_code = trx->key_read(clustrix_table_oid, 0, - table->read_set, packed_key, packed_key_len, - &rowdata, &rowdata_length))) - goto err; - - error_code = unpack_row_to_buf(rgi, table, buf, rowdata, table->read_set, - rowdata + rowdata_length); + error_code = trx->key_read(clustrix_table_oid, 0, clx_lock_type, + table->read_set, packed_key, packed_key_len, + &rowdata, &rowdata_length); + if (!error_code) + error_code = unpack_row_to_buf(rgi, table, buf, rowdata, + table->read_set, + rowdata + rowdata_length); } else { is_scan = true; - if ((error_code = trx->scan_from_key(clustrix_table_oid, active_index, st, - sorted_scan, &scan_fields, packed_key, - packed_key_len, - THDVAR(thd, row_buffer), &scan_cur))) - goto err; - - error_code = rnd_next(buf); + error_code = trx->scan_from_key(clustrix_table_oid, active_index, + clx_lock_type, st, sorted_scan, + &scan_fields, packed_key, packed_key_len, + THDVAR(thd, row_buffer), &scan_cur); + if (!error_code) + error_code = rnd_next(buf); } -err: if (rowdata) my_free(rowdata); @@ -817,6 +816,7 @@ int ha_clustrixdb::index_first(uchar *buf) DBUG_RETURN(error_code); error_code = trx->scan_from_key(clustrix_table_oid, active_index, + clx_lock_type, clustrix_connection::READ_FROM_START, sorted_scan, &scan_fields, NULL, 0, THDVAR(thd, row_buffer), &scan_cur); @@ -840,6 +840,7 @@ int ha_clustrixdb::index_last(uchar *buf) DBUG_RETURN(error_code); error_code = trx->scan_from_key(clustrix_table_oid, active_index, + clx_lock_type, clustrix_connection::READ_FROM_LAST, sorted_scan, &scan_fields, NULL, 0, THDVAR(thd, row_buffer), &scan_cur); @@ -880,7 +881,6 @@ int ha_clustrixdb::index_end() DBUG_RETURN(rnd_end()); else DBUG_RETURN(0); - } int ha_clustrixdb::rnd_init(bool scan) @@ -913,8 +913,7 @@ int ha_clustrixdb::rnd_init(bool scan) bitmap_set_all(&scan_fields); #endif - error_code = trx->scan_table(clustrix_table_oid, 0, - clustrix_connection::SORT_NONE, + error_code = trx->scan_table(clustrix_table_oid, clx_lock_type, &scan_fields, THDVAR(thd, row_buffer), &scan_cur); @@ -987,8 +986,8 @@ int ha_clustrixdb::rnd_pos(uchar * buf, uchar *pos) uchar *rowdata = NULL; ulong rowdata_length; - if ((error_code = trx->key_read(clustrix_table_oid, 0, table->read_set, - packed_key, packed_key_len, + if ((error_code = trx->key_read(clustrix_table_oid, 0, clx_lock_type, + table->read_set, packed_key, packed_key_len, &rowdata, &rowdata_length))) goto err; @@ -1061,6 +1060,14 @@ int ha_clustrixdb::external_lock(THD *thd, int lock_type) DBUG_ENTER("ha_clustrixdb::external_lock()"); int error_code; clustrix_connection *trx = get_trx(thd, &error_code); + + if (lock_type == F_WRLCK) + clx_lock_type = CLUSTRIX_EXCLUSIVE; + else if (lock_type == F_RDLCK) + clx_lock_type = CLUSTRIX_SHARED; + else if (lock_type == F_UNLCK) + clx_lock_type = CLUSTRIX_NO_LOCKS; + if (lock_type != F_UNLCK) { if (!trx->has_open_transaction()) trx->begin_transaction(); diff --git a/storage/clustrixdb/ha_clustrixdb.h b/storage/clustrixdb/ha_clustrixdb.h index 6d5ddcd73e1..ec193b1364f 100644 --- a/storage/clustrixdb/ha_clustrixdb.h +++ b/storage/clustrixdb/ha_clustrixdb.h @@ -45,6 +45,7 @@ private: bool is_scan; MY_BITMAP scan_fields; bool sorted_scan; + clustrix_lock_mode_t clx_lock_type; uint last_dup_errkey; -- cgit v1.2.1 From c8600532c9ebb7236f6db86d90c37266d0ef33d1 Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Wed, 22 Jan 2020 21:57:29 -0800 Subject: Add a partial key parameter to the scan from key command. This patch does not implement support for partial keys, it just adds the parameter for the Clustrix command. --- storage/clustrixdb/clustrix_connection.cc | 10 ++++++---- storage/clustrixdb/clustrix_connection.h | 2 +- storage/clustrixdb/ha_clustrixdb.cc | 9 +++++---- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/storage/clustrixdb/clustrix_connection.cc b/storage/clustrixdb/clustrix_connection.cc index 327f1037a91..63682acd01d 100644 --- a/storage/clustrixdb/clustrix_connection.cc +++ b/storage/clustrixdb/clustrix_connection.cc @@ -757,10 +757,9 @@ int clustrix_connection::update_query(String &stmt, LEX_CSTRING &dbname, int clustrix_connection::scan_from_key(ulonglong clustrix_table_oid, uint index, clustrix_lock_mode_t lock_mode, enum scan_type scan_dir, - bool sorted_scan, MY_BITMAP *read_set, - uchar *packed_key, - ulong packed_key_length, - ushort row_req, + int no_key_cols, bool sorted_scan, + MY_BITMAP *read_set, uchar *packed_key, + ulong packed_key_length, ushort row_req, clustrix_connection_cursor **scan) { int error_code; @@ -788,6 +787,9 @@ int clustrix_connection::scan_from_key(ulonglong clustrix_table_oid, uint index, if ((error_code = add_command_operand_uchar(scan_dir))) return error_code; + if ((error_code = add_command_operand_uint(no_key_cols))) + return error_code; + if ((error_code = add_command_operand_uchar(sorted_scan))) return error_code; diff --git a/storage/clustrixdb/clustrix_connection.h b/storage/clustrixdb/clustrix_connection.h index 5f6643b3f8b..df41e9a0c2d 100644 --- a/storage/clustrixdb/clustrix_connection.h +++ b/storage/clustrixdb/clustrix_connection.h @@ -133,7 +133,7 @@ public: int update_query(String &stmt, LEX_CSTRING &dbname, ulonglong *affected_rows); int scan_from_key(ulonglong clustrix_table_oid, uint index, clustrix_lock_mode_t lock_mode, - enum scan_type scan_dir, bool sorted_scan, + enum scan_type scan_dir, int no_key_cols, bool sorted_scan, MY_BITMAP *read_set, uchar *packed_key, ulong packed_key_length, ushort row_req, clustrix_connection_cursor **scan); diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index 8e77e920bc4..9e9490068c7 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -642,7 +642,8 @@ ulong ha_clustrixdb::index_flags(uint idx, uint part, bool all_parts) const { ulong flags = HA_READ_NEXT | HA_READ_PREV | - HA_READ_ORDER; + HA_READ_ORDER | + HA_READ_RANGE; return flags; } @@ -787,7 +788,7 @@ int ha_clustrixdb::index_read(uchar * buf, const uchar * key, uint key_len, } else { is_scan = true; error_code = trx->scan_from_key(clustrix_table_oid, active_index, - clx_lock_type, st, sorted_scan, + clx_lock_type, st, -1, sorted_scan, &scan_fields, packed_key, packed_key_len, THDVAR(thd, row_buffer), &scan_cur); if (!error_code) @@ -818,7 +819,7 @@ int ha_clustrixdb::index_first(uchar *buf) error_code = trx->scan_from_key(clustrix_table_oid, active_index, clx_lock_type, clustrix_connection::READ_FROM_START, - sorted_scan, &scan_fields, NULL, 0, + -1, sorted_scan, &scan_fields, NULL, 0, THDVAR(thd, row_buffer), &scan_cur); if (error_code == HA_ERR_TABLE_DEF_CHANGED) @@ -842,7 +843,7 @@ int ha_clustrixdb::index_last(uchar *buf) error_code = trx->scan_from_key(clustrix_table_oid, active_index, clx_lock_type, clustrix_connection::READ_FROM_LAST, - sorted_scan, &scan_fields, NULL, 0, + -1, sorted_scan, &scan_fields, NULL, 0, THDVAR(thd, row_buffer), &scan_cur); if (error_code == HA_ERR_TABLE_DEF_CHANGED) -- cgit v1.2.1 From edfb639ee698a184a7c67550cccf349f9450d018 Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Fri, 7 Feb 2020 13:20:59 -0800 Subject: Add found_rows parameter to direct_update_rows. --- storage/clustrixdb/ha_clustrixdb.cc | 3 ++- storage/clustrixdb/ha_clustrixdb.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index 9e9490068c7..7e3bffabaec 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -554,7 +554,7 @@ int ha_clustrixdb::direct_update_rows_init(List *update_fields) DBUG_RETURN(0); } -int ha_clustrixdb::direct_update_rows(ha_rows *update_rows) +int ha_clustrixdb::direct_update_rows(ha_rows *update_rows, ha_rows *found_rows) { DBUG_ENTER("ha_clustrixdb::direct_update_rows"); int error_code= 0; @@ -570,6 +570,7 @@ int ha_clustrixdb::direct_update_rows(ha_rows *update_rows) trx->auto_commit_next(); error_code = trx->update_query(update_stmt, table->s->db, update_rows); + *found_rows = *update_rows; DBUG_RETURN(error_code); } diff --git a/storage/clustrixdb/ha_clustrixdb.h b/storage/clustrixdb/ha_clustrixdb.h index ec193b1364f..461b17e4438 100644 --- a/storage/clustrixdb/ha_clustrixdb.h +++ b/storage/clustrixdb/ha_clustrixdb.h @@ -72,7 +72,7 @@ public: // start_bulk_delete exec_bulk_delete int delete_row(const uchar *buf); int direct_update_rows_init(List *update_fields); - int direct_update_rows(ha_rows *update_rows); + int direct_update_rows(ha_rows *update_rows, ha_rows *found_rows); void start_bulk_insert(ha_rows rows, uint flags = 0); int end_bulk_insert(); -- cgit v1.2.1 From 0deb740c8a0e4bd65c7f686dc5615b35f7ab1401 Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Tue, 4 Feb 2020 10:54:05 -0800 Subject: Rework transaction management. --- storage/clustrixdb/clustrix_connection.cc | 307 +++++++++++++++++------------- storage/clustrixdb/clustrix_connection.h | 67 ++----- storage/clustrixdb/ha_clustrixdb.cc | 59 +++--- 3 files changed, 212 insertions(+), 221 deletions(-) diff --git a/storage/clustrixdb/clustrix_connection.cc b/storage/clustrixdb/clustrix_connection.cc index 63682acd01d..f03f43acaeb 100644 --- a/storage/clustrixdb/clustrix_connection.cc +++ b/storage/clustrixdb/clustrix_connection.cc @@ -19,7 +19,50 @@ extern char *clustrix_password; extern uint clustrix_port; extern char *clustrix_socket; -static const char charset_name[] = "utf8"; +/* + This class implements the commands that can be sent to the cluster by the + Xpand engine. All of these commands return a status to the caller, but some + commands also create open invocations on the cluster, which must be closed by + sending additional commands. + + Transactions on the cluster are started using flags attached to commands, and + transactions are committed or rolled back using separate commands. + + Methods ending with _next affect the transaction state after the next command + is sent to the cluster. Other transaction commands are sent to the cluster + immediately, and the state is changed before they return. + + _____________________ _______________________ + | | | | | | + V | | V | | + NONE --> REQUESTED --> STARTED --> NEW_STMT | + | | + `----> ROLLBACK_STMT ---` + + The commit and rollback commands will change any other state to NONE. This + includes the REQUESTED state, for which nothing will be sent to the cluster. + The rollback statement command can likewise change the state from NEW_STMT to + STARTED without sending anything to the cluster. + + In addition, the CLUSTRIX_TRANS_AUTOCOMMIT flag will cause the transactions + for commands that complete without leaving open invocations on the cluster to + be committed if successful or rolled back if there was an error. If + auto-commit is enabled, only one open invocation may be in progress at a + time. +*/ + +enum clustrix_trans_state { + CLUSTRIX_TRANS_STARTED = 0, + CLUSTRIX_TRANS_REQUESTED = 1, + CLUSTRIX_TRANS_NEW_STMT = 2, + CLUSTRIX_TRANS_ROLLBACK_STMT = 4, + CLUSTRIX_TRANS_NONE = 32, +}; + +enum clustrix_trans_post_flags { + CLUSTRIX_TRANS_AUTOCOMMIT = 8, + CLUSTRIX_TRANS_NO_POST_FLAGS = 0, +}; enum clustrix_commands { CLUSTRIX_WRITE_ROW = 1, @@ -32,21 +75,32 @@ enum clustrix_commands { CLUSTRIX_KEY_UPDATE, CLUSTRIX_SCAN_FROM_KEY, CLUSTRIX_UPDATE_QUERY, - CLUSTRIX_TRANSACTION_CMD -}; - -enum clustrix_transaction_flags { - CLUSTRIX_TRANS_BEGIN = 1, - CLUSTRIX_TRANS_COMMIT = 2, - CLUSTRIX_TRANS_ROLLBACK = 4, - CLUSTRIX_STMT_NEW = 8, - CLUSTRIX_STMT_ROLLBACK = 16, - CLUSTRIX_TRANS_COMMIT_ON_FINISH = 32 + CLUSTRIX_COMMIT, + CLUSTRIX_ROLLBACK, }; /**************************************************************************** ** Class clustrix_connection ****************************************************************************/ +clustrix_connection::clustrix_connection() + : command_buffer(NULL), command_buffer_length(0), command_length(0), + trans_state(CLUSTRIX_TRANS_NONE), trans_flags(CLUSTRIX_TRANS_NO_POST_FLAGS) +{ + DBUG_ENTER("clustrix_connection::clustrix_connection"); + memset(&clustrix_net, 0, sizeof(MYSQL)); + DBUG_VOID_RETURN; +} + +clustrix_connection::~clustrix_connection() +{ + DBUG_ENTER("clustrix_connection::~clustrix_connection"); + if (is_connected()) + disconnect(TRUE); + + if (command_buffer) + my_free(command_buffer); + DBUG_VOID_RETURN; +} void clustrix_connection::disconnect(bool is_destructor) { @@ -100,7 +154,7 @@ int clustrix_connection::connect() &clustrix_connect_timeout); mysql_options(&clustrix_net, MYSQL_OPT_USE_REMOTE_CONNECTION, NULL); - mysql_options(&clustrix_net, MYSQL_SET_CHARSET_NAME, charset_name); + mysql_options(&clustrix_net, MYSQL_SET_CHARSET_NAME, "utf8mb4"); mysql_options(&clustrix_net, MYSQL_OPT_USE_THREAD_SPECIFIC_MEMORY, (char *) &my_true); mysql_options(&clustrix_net, MYSQL_INIT_COMMAND,"SET autocommit=0"); @@ -148,22 +202,39 @@ int clustrix_connection::connect() int clustrix_connection::begin_command(uchar command) { - assert(command == CLUSTRIX_TRANSACTION_CMD || has_transaction); + if (trans_state == CLUSTRIX_TRANS_NONE) + return HA_ERR_INTERNAL_ERROR; + command_length = 0; int error_code = 0; if ((error_code = add_command_operand_uchar(command))) return error_code; - if ((error_code = add_command_operand_uchar(commit_flag_next))) + if ((error_code = add_command_operand_uchar(trans_state | trans_flags))) return error_code; - commit_flag_next &= CLUSTRIX_TRANS_COMMIT_ON_FINISH; return error_code; } int clustrix_connection::send_command() { my_bool com_error; + + /* + Please note: + * The transaction state is set before the command is sent because rolling + back a nonexistent transaction is better than leaving a tranaction open + on the cluster. + * The state may have alreadly been STARTED. + * Commit and rollback commands update the transaction state after calling + this function. + * If auto-commit is enabled, the state may also updated after the + response has been processed. We do not clear the auto-commit flag here + because it needs to be sent with each command until the transaction is + committed or rolled back. + */ + trans_state = CLUSTRIX_TRANS_STARTED; + com_error = simple_command(&clustrix_net, (enum_server_command)CLUSTRIX_SERVER_REQUEST, command_buffer, command_length, TRUE); @@ -183,133 +254,119 @@ int clustrix_connection::send_command() int clustrix_connection::read_query_response() { my_bool comerr = clustrix_net.methods->read_query_result(&clustrix_net); + int error_code = 0; if (comerr) { - int error_code = mysql_errno(&clustrix_net); + error_code = mysql_errno(&clustrix_net); my_printf_error(error_code, "Clustrix error: %s", MYF(0), mysql_error(&clustrix_net)); - return error_code; } - return 0; + auto_commit_closed(); + return error_code; } -int clustrix_connection::send_transaction_cmd() +bool clustrix_connection::has_open_transaction() { - DBUG_ENTER("clustrix_connection::send_transaction_cmd"); - if (!commit_flag_next) - DBUG_RETURN(0); + return trans_state != CLUSTRIX_TRANS_NONE; +} + +int clustrix_connection::commit_transaction() +{ + DBUG_ENTER("clustrix_connection::commit_transaction"); + if (trans_state == CLUSTRIX_TRANS_NONE) + DBUG_RETURN(HA_ERR_INTERNAL_ERROR); + + if (trans_state == CLUSTRIX_TRANS_REQUESTED) { + trans_state = CLUSTRIX_TRANS_NONE; + trans_flags = CLUSTRIX_TRANS_NO_POST_FLAGS; + DBUG_RETURN(0); + } int error_code; - if ((error_code = begin_command(CLUSTRIX_TRANSACTION_CMD))) + if ((error_code = begin_command(CLUSTRIX_COMMIT))) DBUG_RETURN(error_code); if ((error_code = send_command())) DBUG_RETURN(error_code); if ((error_code = read_query_response())) - DBUG_RETURN(mysql_errno(&clustrix_net)); + DBUG_RETURN(error_code); + trans_state = CLUSTRIX_TRANS_NONE; + trans_flags = CLUSTRIX_TRANS_NO_POST_FLAGS; DBUG_RETURN(error_code); } -bool clustrix_connection::begin_transaction() +int clustrix_connection::rollback_transaction() { - DBUG_ENTER("clustrix_connection::begin_transaction"); - assert(!has_transaction); - commit_flag_next |= CLUSTRIX_TRANS_BEGIN; - has_transaction = TRUE; - DBUG_RETURN(TRUE); -} - -bool clustrix_connection::commit_transaction() -{ - DBUG_ENTER("clustrix_connection::commit_transaction"); - assert(has_transaction); - - has_transaction = FALSE; - has_anonymous_savepoint = FALSE; - if (commit_flag_next & CLUSTRIX_TRANS_BEGIN) { - commit_flag_next &= ~CLUSTRIX_TRANS_BEGIN; - DBUG_RETURN(FALSE); + DBUG_ENTER("clustrix_connection::rollback_transaction"); + if (trans_state == CLUSTRIX_TRANS_NONE || + trans_state == CLUSTRIX_TRANS_REQUESTED) { + trans_state = CLUSTRIX_TRANS_NONE; + DBUG_RETURN(0); } - commit_flag_next |= CLUSTRIX_TRANS_COMMIT; - DBUG_RETURN(TRUE); -} + int error_code; + if ((error_code = begin_command(CLUSTRIX_ROLLBACK))) + DBUG_RETURN(error_code); -bool clustrix_connection::rollback_transaction() -{ - DBUG_ENTER("clustrix_connection::rollback_transaction"); - assert(has_transaction); + if ((error_code = send_command())) + DBUG_RETURN(error_code); - has_transaction = FALSE; - has_anonymous_savepoint = FALSE; - if (commit_flag_next & CLUSTRIX_TRANS_BEGIN) { - commit_flag_next &= ~CLUSTRIX_TRANS_BEGIN; - DBUG_RETURN(FALSE); - } + if ((error_code = read_query_response())) + DBUG_RETURN(error_code); - commit_flag_next |= CLUSTRIX_TRANS_ROLLBACK; - DBUG_RETURN(TRUE); + trans_state = CLUSTRIX_TRANS_NONE; + trans_flags = CLUSTRIX_TRANS_NO_POST_FLAGS; + DBUG_RETURN(error_code); } -void clustrix_connection::auto_commit_next() +int clustrix_connection::begin_transaction_next() { - commit_flag_next |= CLUSTRIX_TRANS_COMMIT_ON_FINISH; + DBUG_ENTER("clustrix_connection::begin_transaction_next"); + if (trans_state != CLUSTRIX_TRANS_NONE || + trans_flags != CLUSTRIX_TRANS_NO_POST_FLAGS) + DBUG_RETURN(HA_ERR_INTERNAL_ERROR); + + trans_state = CLUSTRIX_TRANS_REQUESTED; + DBUG_RETURN(0); } -void clustrix_connection::auto_commit_closed() +int clustrix_connection::new_statement_next() { - assert(has_transaction); - if (commit_flag_next & CLUSTRIX_TRANS_COMMIT_ON_FINISH) { - has_transaction = FALSE; - has_anonymous_savepoint = FALSE; - commit_flag_next &= ~CLUSTRIX_TRANS_COMMIT_ON_FINISH; - } + DBUG_ENTER("clustrix_connection::new_statement_next"); + if (trans_state != CLUSTRIX_TRANS_STARTED || + trans_flags != CLUSTRIX_TRANS_NO_POST_FLAGS) + DBUG_RETURN(HA_ERR_INTERNAL_ERROR); + + trans_state = CLUSTRIX_TRANS_NEW_STMT; + DBUG_RETURN(0); } -bool clustrix_connection::set_anonymous_savepoint() +int clustrix_connection::rollback_statement_next() { - DBUG_ENTER("clustrix_connection::set_anonymous_savepoint"); - assert(has_transaction); - assert(!has_anonymous_savepoint); + DBUG_ENTER("clustrix_connection::rollback_statement_next"); + if (trans_state != CLUSTRIX_TRANS_STARTED || + trans_flags != CLUSTRIX_TRANS_NO_POST_FLAGS) + DBUG_RETURN(HA_ERR_INTERNAL_ERROR); - commit_flag_next |= CLUSTRIX_STMT_NEW; - has_anonymous_savepoint = TRUE; - DBUG_RETURN(TRUE); + trans_state = CLUSTRIX_TRANS_ROLLBACK_STMT; + DBUG_RETURN(0); } -bool clustrix_connection::release_anonymous_savepoint() +void clustrix_connection::auto_commit_next() { - DBUG_ENTER("clustrix_connection::release_anonymous_savepoint"); - assert(has_transaction); - assert(has_anonymous_savepoint); - - has_anonymous_savepoint = FALSE; - if (commit_flag_next & CLUSTRIX_STMT_NEW) { - commit_flag_next &= ~CLUSTRIX_STMT_NEW; - DBUG_RETURN(FALSE); - } - - DBUG_RETURN(TRUE); + trans_flags |= CLUSTRIX_TRANS_AUTOCOMMIT; } -bool clustrix_connection::rollback_to_anonymous_savepoint() +void clustrix_connection::auto_commit_closed() { - DBUG_ENTER("clustrix_connection::rollback_to_anonymous_savepoint"); - assert(has_transaction); - assert(has_anonymous_savepoint); - - has_anonymous_savepoint = FALSE; - if (commit_flag_next & CLUSTRIX_STMT_NEW) { - commit_flag_next &= ~CLUSTRIX_STMT_NEW; - DBUG_RETURN(FALSE); + if (trans_flags & CLUSTRIX_TRANS_AUTOCOMMIT) { + trans_flags &= ~CLUSTRIX_TRANS_AUTOCOMMIT; + trans_state = CLUSTRIX_TRANS_NONE; } - - commit_flag_next |= CLUSTRIX_STMT_ROLLBACK; - DBUG_RETURN(TRUE); } int clustrix_connection::run_query(String &stmt) @@ -320,11 +377,6 @@ int clustrix_connection::run_query(String &stmt) return error_code; } -my_ulonglong clustrix_connection::rows_affected() -{ - return clustrix_net.affected_rows; -} - int clustrix_connection::write_row(ulonglong clustrix_table_oid, uchar *packed_row, size_t packed_size, ulonglong *last_insert_id) @@ -333,7 +385,7 @@ int clustrix_connection::write_row(ulonglong clustrix_table_oid, command_length = 0; // row based commands should not be called with auto commit. - if (commit_flag_next & CLUSTRIX_TRANS_COMMIT_ON_FINISH) + if (trans_flags & CLUSTRIX_TRANS_AUTOCOMMIT) return HA_ERR_INTERNAL_ERROR; if ((error_code = begin_command(CLUSTRIX_WRITE_ROW))) @@ -365,7 +417,7 @@ int clustrix_connection::key_update(ulonglong clustrix_table_oid, command_length = 0; // row based commands should not be called with auto commit. - if (commit_flag_next & CLUSTRIX_TRANS_COMMIT_ON_FINISH) + if (trans_flags & CLUSTRIX_TRANS_AUTOCOMMIT) return HA_ERR_INTERNAL_ERROR; if ((error_code = begin_command(CLUSTRIX_KEY_UPDATE))) @@ -400,7 +452,7 @@ int clustrix_connection::key_delete(ulonglong clustrix_table_oid, command_length = 0; // row based commands should not be called with auto commit. - if (commit_flag_next & CLUSTRIX_TRANS_COMMIT_ON_FINISH) + if (trans_flags & CLUSTRIX_TRANS_AUTOCOMMIT) return HA_ERR_INTERNAL_ERROR; if ((error_code = begin_command(CLUSTRIX_KEY_DELETE))) @@ -431,7 +483,7 @@ int clustrix_connection::key_read(ulonglong clustrix_table_oid, uint index, command_length = 0; // row based commands should not be called with auto commit. - if (commit_flag_next & CLUSTRIX_TRANS_COMMIT_ON_FINISH) + if (trans_flags & CLUSTRIX_TRANS_AUTOCOMMIT) return HA_ERR_INTERNAL_ERROR; if ((error_code = begin_command(CLUSTRIX_KEY_READ))) @@ -605,21 +657,24 @@ public: } }; -int allocate_clustrix_connection_cursor(MYSQL *clustrix_net, ulong buffer_size, - bool *stmt_completed, - clustrix_connection_cursor **scan) +int clustrix_connection::allocate_cursor(MYSQL *clustrix_net, ulong buffer_size, + clustrix_connection_cursor **scan) { - DBUG_ENTER("allocate_clustrix_connection_cursor"); + DBUG_ENTER("clustrix_connection::allocate_cursor"); *scan = new clustrix_connection_cursor(clustrix_net, buffer_size); if (!*scan) DBUG_RETURN(HA_ERR_OUT_OF_MEM); - int error_code = (*scan)->initialize(stmt_completed); + bool stmt_completed = FALSE; + int error_code = (*scan)->initialize(&stmt_completed); if (error_code) { delete *scan; *scan = NULL; } + if (stmt_completed) + auto_commit_closed(); + DBUG_RETURN(error_code); } @@ -632,7 +687,7 @@ int clustrix_connection::scan_table(ulonglong clustrix_table_oid, command_length = 0; // row based commands should not be called with auto commit. - if (commit_flag_next & CLUSTRIX_TRANS_COMMIT_ON_FINISH) + if (trans_flags & CLUSTRIX_TRANS_AUTOCOMMIT) return HA_ERR_INTERNAL_ERROR; if ((error_code = begin_command(CLUSTRIX_SCAN_TABLE))) @@ -653,9 +708,7 @@ int clustrix_connection::scan_table(ulonglong clustrix_table_oid, if ((error_code = send_command())) return error_code; - bool stmt_completed = FALSE; - return allocate_clustrix_connection_cursor(&clustrix_net, row_req, - &stmt_completed, scan); + return allocate_cursor(&clustrix_net, row_req, scan); } /** @@ -707,12 +760,7 @@ int clustrix_connection::scan_query(String &stmt, uchar *fieldtype, uint fields, if ((error_code = send_command())) return error_code; - bool stmt_completed = FALSE; - error_code = allocate_clustrix_connection_cursor(&clustrix_net, row_req, - &stmt_completed, scan); - if (stmt_completed) - auto_commit_closed(); - return error_code; + return allocate_cursor(&clustrix_net, row_req, scan); } /** @@ -745,15 +793,12 @@ int clustrix_connection::update_query(String &stmt, LEX_CSTRING &dbname, return error_code; error_code = read_query_response(); - auto_commit_closed(); if (!error_code) *affected_rows = clustrix_net.affected_rows; return error_code; } - - int clustrix_connection::scan_from_key(ulonglong clustrix_table_oid, uint index, clustrix_lock_mode_t lock_mode, enum scan_type scan_dir, @@ -766,7 +811,7 @@ int clustrix_connection::scan_from_key(ulonglong clustrix_table_oid, uint index, command_length = 0; // row based commands should not be called with auto commit. - if (commit_flag_next & CLUSTRIX_TRANS_COMMIT_ON_FINISH) + if (trans_flags & CLUSTRIX_TRANS_AUTOCOMMIT) return HA_ERR_INTERNAL_ERROR; if ((error_code = begin_command(CLUSTRIX_SCAN_FROM_KEY))) @@ -802,9 +847,7 @@ int clustrix_connection::scan_from_key(ulonglong clustrix_table_oid, uint index, if ((error_code = send_command())) return error_code; - bool stmt_completed = FALSE; - return allocate_clustrix_connection_cursor(&clustrix_net, row_req, - &stmt_completed, scan); + return allocate_cursor(&clustrix_net, row_req, scan); } int clustrix_connection::scan_next(clustrix_connection_cursor *scan, @@ -866,9 +909,7 @@ int clustrix_connection::scan_end(clustrix_connection_cursor *scan) if ((error_code = send_command())) return error_code; - error_code = read_query_response(); - auto_commit_closed(); - return error_code; + return read_query_response(); } int clustrix_connection::populate_table_list(LEX_CSTRING *db, @@ -998,6 +1039,8 @@ error: DBUG_RETURN(error_code); } +#define COMMAND_BUFFER_SIZE_INCREMENT 1024 +#define COMMAND_BUFFER_SIZE_INCREMENT_BITS 10 int clustrix_connection::expand_command_buffer(size_t add_length) { size_t expanded_length; @@ -1114,7 +1157,7 @@ int clustrix_connection::add_command_operand_str(const uchar *str, * str_length - size **/ int clustrix_connection::add_command_operand_vlstr(const uchar *str, - size_t str_length) + size_t str_length) { int error_code = expand_command_buffer(str_length); if (error_code) diff --git a/storage/clustrixdb/clustrix_connection.h b/storage/clustrixdb/clustrix_connection.h index df41e9a0c2d..f2a48f3da6c 100644 --- a/storage/clustrixdb/clustrix_connection.h +++ b/storage/clustrixdb/clustrix_connection.h @@ -31,74 +31,36 @@ class clustrix_connection_cursor; class clustrix_connection { private: -# define COMMAND_BUFFER_SIZE_INCREMENT 1024 -# define COMMAND_BUFFER_SIZE_INCREMENT_BITS 10 - MYSQL clustrix_net; uchar *command_buffer; size_t command_buffer_length; size_t command_length; - uchar *reply_buffer; - size_t reply_length; - - bool has_transaction; - bool has_anonymous_savepoint; - int commit_flag_next; - + int trans_state; + int trans_flags; + int allocate_cursor(MYSQL *clustrix_net, ulong buffer_size, + clustrix_connection_cursor **scan); public: - clustrix_connection() - : command_buffer(NULL), command_buffer_length(0), command_length(0) - { - DBUG_ENTER("clustrix_connection::clustrix_connection"); - memset(&clustrix_net, 0, sizeof(MYSQL)); - has_anonymous_savepoint = FALSE; - has_transaction = FALSE; - commit_flag_next = 0; - DBUG_VOID_RETURN; - } - - ~clustrix_connection() - { - DBUG_ENTER("clustrix_connection::~clustrix_connection"); - if (is_connected()) - disconnect(TRUE); - - if (command_buffer) - my_free(command_buffer); - DBUG_VOID_RETURN; - } + clustrix_connection(); + ~clustrix_connection(); inline bool is_connected() { return clustrix_net.net.vio; } - int connect(); - void disconnect(bool is_destructor = FALSE); - int send_transaction_cmd(); - bool begin_transaction(); - bool commit_transaction(); - bool rollback_transaction(); + bool has_open_transaction(); + int commit_transaction(); + int rollback_transaction(); + int begin_transaction_next(); + int new_statement_next(); + int rollback_statement_next(); // also starts new statement void auto_commit_next(); - inline bool has_open_transaction() - { - return has_transaction; - } - - bool set_anonymous_savepoint(); - bool release_anonymous_savepoint(); - bool rollback_to_anonymous_savepoint(); - inline bool has_open_anonymous_savepoint() - { - return has_anonymous_savepoint; - } + void auto_commit_closed(); int run_query(String &stmt); - my_ulonglong rows_affected(); - int write_row(ulonglong clustrix_table_oid, uchar *packed_row, size_t packed_size, ulonglong *last_insert_id); int key_update(ulonglong clustrix_table_oid, @@ -111,7 +73,6 @@ public: clustrix_lock_mode_t lock_mode, MY_BITMAP *read_set, uchar *packed_key, ulong packed_key_length, uchar **rowdata, ulong *rowdata_length); - enum sort_order {SORT_NONE = 0, SORT_ASC = 1, SORT_DESC = 2}; enum scan_type { READ_KEY_OR_NEXT, /* rows with key and greater */ @@ -121,7 +82,6 @@ public: READ_FROM_START, /* rows with forwards from first key. */ READ_FROM_LAST, /* rows with backwards from last key. */ }; - int scan_table(ulonglong clustrix_table_oid, clustrix_lock_mode_t lock_mode, MY_BITMAP *read_set, ushort row_req, @@ -159,6 +119,5 @@ private: int begin_command(uchar command); int send_command(); int read_query_response(); - void auto_commit_closed(); }; #endif // _clustrix_connection_h diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc index 7e3bffabaec..d80ab91653b 100644 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ b/storage/clustrixdb/ha_clustrixdb.cc @@ -40,7 +40,6 @@ static MYSQL_SYSVAR_INT NULL, NULL, -1, -1, 2147483647, 0 ); - char *clustrix_host; static MYSQL_SYSVAR_STR ( @@ -104,7 +103,6 @@ static void update_host_list(char *clustrix_host) DBUG_PRINT("clustrix_host", ("%s", clustrix_host)); } - char *clustrix_username; static MYSQL_SYSVAR_STR ( @@ -727,7 +725,6 @@ int ha_clustrixdb::index_init(uint idx, bool sorted) sorted_scan = sorted; return 0; - } int ha_clustrixdb::index_read(uchar * buf, const uchar * key, uint key_len, @@ -1062,6 +1059,8 @@ int ha_clustrixdb::external_lock(THD *thd, int lock_type) DBUG_ENTER("ha_clustrixdb::external_lock()"); int error_code; clustrix_connection *trx = get_trx(thd, &error_code); + if (error_code) + DBUG_RETURN(error_code); if (lock_type == F_WRLCK) clx_lock_type = CLUSTRIX_EXCLUSIVE; @@ -1071,18 +1070,18 @@ int ha_clustrixdb::external_lock(THD *thd, int lock_type) clx_lock_type = CLUSTRIX_NO_LOCKS; if (lock_type != F_UNLCK) { - if (!trx->has_open_transaction()) - trx->begin_transaction(); + if (!trx->has_open_transaction()) { + error_code = trx->begin_transaction_next(); + if (error_code) + DBUG_RETURN(error_code); + } trans_register_ha(thd, FALSE, clustrixdb_hton); - if (thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) { - if (!trx->has_open_anonymous_savepoint()) - trx->set_anonymous_savepoint(); + if (thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) trans_register_ha(thd, TRUE, clustrixdb_hton); - } } - DBUG_RETURN(0); + DBUG_RETURN(error_code); } /**************************************************************************** @@ -1169,8 +1168,7 @@ void ha_clustrixdb::build_key_packed_row(uint index, const uchar *buf, } else { // make a row from the table table->mark_columns_used_by_index(index, &table->tmp_set); - *packed_key_len = pack_row(table, &table->tmp_set, packed_key, - buf); + *packed_key_len = pack_row(table, &table->tmp_set, packed_key, buf); } } @@ -1212,19 +1210,15 @@ static int clustrixdb_commit(handlerton *hton, THD *thd, bool all) clustrix_connection* trx = (clustrix_connection *) thd_get_ha_data(thd, hton); assert(trx); - bool send_cmd = FALSE; - if (all || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) { - if (trx->has_open_transaction()) - send_cmd = trx->commit_transaction(); - } else { - if (trx->has_open_anonymous_savepoint()) - send_cmd = trx->release_anonymous_savepoint(); + int error_code = 0; + if (trx->has_open_transaction()) { + if (all || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) + error_code = trx->commit_transaction(); + else + error_code = trx->new_statement_next(); } - if (send_cmd) - return trx->send_transaction_cmd(); - - return 0; + return error_code; } static int clustrixdb_rollback(handlerton *hton, THD *thd, bool all) @@ -1232,19 +1226,15 @@ static int clustrixdb_rollback(handlerton *hton, THD *thd, bool all) clustrix_connection* trx = (clustrix_connection *) thd_get_ha_data(thd, hton); assert(trx); - bool send_cmd = FALSE; - if (all || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) { - if (trx->has_open_transaction()) - send_cmd = trx->rollback_transaction(); - } else { - if (trx->has_open_anonymous_savepoint()) - send_cmd = trx->rollback_to_anonymous_savepoint(); + int error_code = 0; + if (trx->has_open_transaction()) { + if (all || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) + error_code = trx->rollback_transaction(); + else + error_code = trx->rollback_statement_next(); } - if (send_cmd) - return trx->send_transaction_cmd(); - - return 0; + return error_code; } static handler* clustrixdb_create_handler(handlerton *hton, TABLE_SHARE *table, @@ -1271,7 +1261,6 @@ static int clustrixdb_panic(handlerton *hton, ha_panic_function type) return 0; } - static bool clustrixdb_show_status(handlerton *hton, THD *thd, stat_print_fn *stat_print, enum ha_stat_type stat_type) -- cgit v1.2.1 From a24e184fa0a58d4ad1a2c20c60383011c70911d2 Mon Sep 17 00:00:00 2001 From: Michael Erickson Date: Thu, 13 Feb 2020 12:51:24 -0800 Subject: rebrand plugin from "clustrixdb" to "xpand" --- mysql-test/suite/clustrixdb/basics.result | 49 - mysql-test/suite/clustrixdb/basics.test | 38 - mysql-test/suite/clustrixdb/my.cnf | 4 - mysql-test/suite/clustrixdb/suite.opt | 4 - mysql-test/suite/clustrixdb/update.result | 26 - mysql-test/suite/clustrixdb/update.test | 19 - mysql-test/suite/clustrixdb/upsert.result | 72 -- mysql-test/suite/clustrixdb/upsert.test | 49 - mysql-test/suite/xpand/basics.result | 49 + mysql-test/suite/xpand/basics.test | 38 + mysql-test/suite/xpand/my.cnf | 4 + mysql-test/suite/xpand/suite.opt | 4 + mysql-test/suite/xpand/update.result | 26 + mysql-test/suite/xpand/update.test | 19 + mysql-test/suite/xpand/upsert.result | 72 ++ mysql-test/suite/xpand/upsert.test | 49 + storage/clustrixdb/CMakeLists.txt | 24 - storage/clustrixdb/clustrix_connection.cc | 1190 ---------------------- storage/clustrixdb/clustrix_connection.h | 123 --- storage/clustrixdb/ha_clustrixdb.cc | 1372 -------------------------- storage/clustrixdb/ha_clustrixdb.h | 130 --- storage/clustrixdb/ha_clustrixdb_pushdown.cc | 478 --------- storage/clustrixdb/ha_clustrixdb_pushdown.h | 87 -- storage/xpand/CMakeLists.txt | 24 + storage/xpand/ha_xpand.cc | 1372 ++++++++++++++++++++++++++ storage/xpand/ha_xpand.h | 130 +++ storage/xpand/ha_xpand_pushdown.cc | 478 +++++++++ storage/xpand/ha_xpand_pushdown.h | 87 ++ storage/xpand/xpand_connection.cc | 1190 ++++++++++++++++++++++ storage/xpand/xpand_connection.h | 123 +++ 30 files changed, 3665 insertions(+), 3665 deletions(-) delete mode 100644 mysql-test/suite/clustrixdb/basics.result delete mode 100644 mysql-test/suite/clustrixdb/basics.test delete mode 100644 mysql-test/suite/clustrixdb/my.cnf delete mode 100644 mysql-test/suite/clustrixdb/suite.opt delete mode 100644 mysql-test/suite/clustrixdb/update.result delete mode 100644 mysql-test/suite/clustrixdb/update.test delete mode 100644 mysql-test/suite/clustrixdb/upsert.result delete mode 100644 mysql-test/suite/clustrixdb/upsert.test create mode 100644 mysql-test/suite/xpand/basics.result create mode 100644 mysql-test/suite/xpand/basics.test create mode 100644 mysql-test/suite/xpand/my.cnf create mode 100644 mysql-test/suite/xpand/suite.opt create mode 100644 mysql-test/suite/xpand/update.result create mode 100644 mysql-test/suite/xpand/update.test create mode 100644 mysql-test/suite/xpand/upsert.result create mode 100644 mysql-test/suite/xpand/upsert.test delete mode 100644 storage/clustrixdb/CMakeLists.txt delete mode 100644 storage/clustrixdb/clustrix_connection.cc delete mode 100644 storage/clustrixdb/clustrix_connection.h delete mode 100644 storage/clustrixdb/ha_clustrixdb.cc delete mode 100644 storage/clustrixdb/ha_clustrixdb.h delete mode 100644 storage/clustrixdb/ha_clustrixdb_pushdown.cc delete mode 100644 storage/clustrixdb/ha_clustrixdb_pushdown.h create mode 100644 storage/xpand/CMakeLists.txt create mode 100644 storage/xpand/ha_xpand.cc create mode 100644 storage/xpand/ha_xpand.h create mode 100644 storage/xpand/ha_xpand_pushdown.cc create mode 100644 storage/xpand/ha_xpand_pushdown.h create mode 100644 storage/xpand/xpand_connection.cc create mode 100644 storage/xpand/xpand_connection.h diff --git a/mysql-test/suite/clustrixdb/basics.result b/mysql-test/suite/clustrixdb/basics.result deleted file mode 100644 index 2af500cf9f1..00000000000 --- a/mysql-test/suite/clustrixdb/basics.result +++ /dev/null @@ -1,49 +0,0 @@ -CREATE DATABASE clx; -USE clx; -DROP TABLE IF EXISTS cx1; -Warnings: -Note 1051 Unknown table 'clx.cx1' -CREATE TABLE cx1(i BIGINT)ENGINE=clustrixdb; -CREATE TABLE cx1(i BIGINT)ENGINE=clustrixdb; -ERROR 42S01: Table 'cx1' already exists -INSERT INTO cx1 VALUES (42); -SELECT * FROM cx1; -i -42 -DROP TABLE cx1; -SHOW CREATE TABLE cx1; -ERROR 42S02: Table 'clx.cx1' doesn't exist -DROP TABLE IF EXISTS intandtext; -Warnings: -Note 1051 Unknown table 'clx.intandtext' -CREATE TABLE intandtext(i bigint, t text)ENGINE=clustrixdb; -INSERT INTO intandtext VALUES(10, 'someqwqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq'); -SELECT i,t FROM intandtext; -i t -10 someqwqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq -EXPLAIN SELECT i,t FROM intandtext; -id select_type table type possible_keys key key_len ref rows Extra -1 PUSHED SELECT NULL NULL NULL NULL NULL NULL NULL NULL -SET @@optimizer_switch='derived_merge=OFF'; -SET clustrixdb_select_handler=OFF; -SELECT i,t FROM (SELECT i,t FROM intandtext) t; -i t -10 someqwqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq -EXPLAIN SELECT i,t FROM (SELECT i,t FROM intandtext) t; -id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY ALL NULL NULL NULL NULL 10000 -2 PUSHED DERIVED NULL NULL NULL NULL NULL NULL NULL NULL -SET clustrixdb_derived_handler=OFF; -SELECT i,t FROM intandtext; -i t -10 someqwqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq -SELECT i,t FROM (SELECT i,t FROM intandtext) t; -i t -10 someqwqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq -EXPLAIN SELECT i,t FROM (SELECT i,t FROM intandtext) t; -id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY ALL NULL NULL NULL NULL 10000 -2 DERIVED intandtext ALL NULL NULL NULL NULL 10000 -DROP TABLE intandtext; -USE test; -DROP DATABASE clx; diff --git a/mysql-test/suite/clustrixdb/basics.test b/mysql-test/suite/clustrixdb/basics.test deleted file mode 100644 index 81a81983bf3..00000000000 --- a/mysql-test/suite/clustrixdb/basics.test +++ /dev/null @@ -1,38 +0,0 @@ -CREATE DATABASE clx; -USE clx; - -DROP TABLE IF EXISTS cx1; -CREATE TABLE cx1(i BIGINT)ENGINE=clustrixdb; ---error ER_TABLE_EXISTS_ERROR -CREATE TABLE cx1(i BIGINT)ENGINE=clustrixdb; - -INSERT INTO cx1 VALUES (42); - -SELECT * FROM cx1; - -DROP TABLE cx1; - ---error ER_NO_SUCH_TABLE -SHOW CREATE TABLE cx1; - -DROP TABLE IF EXISTS intandtext; -CREATE TABLE intandtext(i bigint, t text)ENGINE=clustrixdb; -INSERT INTO intandtext VALUES(10, 'someqwqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq'); - -SELECT i,t FROM intandtext; -EXPLAIN SELECT i,t FROM intandtext; - -SET @@optimizer_switch='derived_merge=OFF'; -SET clustrixdb_select_handler=OFF; -SELECT i,t FROM (SELECT i,t FROM intandtext) t; -EXPLAIN SELECT i,t FROM (SELECT i,t FROM intandtext) t; - -SET clustrixdb_derived_handler=OFF; -SELECT i,t FROM intandtext; -SELECT i,t FROM (SELECT i,t FROM intandtext) t; -EXPLAIN SELECT i,t FROM (SELECT i,t FROM intandtext) t; - -DROP TABLE intandtext; - -USE test; -DROP DATABASE clx; diff --git a/mysql-test/suite/clustrixdb/my.cnf b/mysql-test/suite/clustrixdb/my.cnf deleted file mode 100644 index 8105041b85c..00000000000 --- a/mysql-test/suite/clustrixdb/my.cnf +++ /dev/null @@ -1,4 +0,0 @@ -!include include/default_my.cnf - -[mysqld.1] -socket= /tmp/mysqld42.sock diff --git a/mysql-test/suite/clustrixdb/suite.opt b/mysql-test/suite/clustrixdb/suite.opt deleted file mode 100644 index 481f692cfdd..00000000000 --- a/mysql-test/suite/clustrixdb/suite.opt +++ /dev/null @@ -1,4 +0,0 @@ ---plugin-load=clustrixdb=ha_clustrixdb.so ---core-file ---clustrixdb_port=3306 ---plugin-maturity=unknown diff --git a/mysql-test/suite/clustrixdb/update.result b/mysql-test/suite/clustrixdb/update.result deleted file mode 100644 index fec6a409a7b..00000000000 --- a/mysql-test/suite/clustrixdb/update.result +++ /dev/null @@ -1,26 +0,0 @@ -CREATE DATABASE IF NOT EXISTS `db1`; -USE `db1`; -DROP TABLE IF EXISTS `t1`; -Warnings: -Note 1051 Unknown table 'db1.t1' -CREATE TABLE `t1`(i BIGINT, t TEXT)ENGINE=clustrixdb; -INSERT INTO `t1` (i, t) VALUES (42, 'один'); -INSERT INTO `t1` (i, t) VALUES (42, 'ноль'); -SELECT * FROM `t1` ORDER BY `i` DESC, `t` DESC; -i t -42 один -42 ноль -UPDATE `t1` SET i=i+1,t='два' WHERE t='один'; -SELECT * FROM `t1` ORDER BY `i` DESC, `t` DESC; -i t -42 один -42 ноль -USE test; -UPDATE `db1`.`t1` SET i=i+1,t='три' WHERE t='два'; -SELECT * FROM `db1`.`t1` ORDER BY `i` DESC, `t` DESC; -i t -42 один -42 ноль -DROP TABLE `db1`.`t1`; -USE test; -DROP DATABASE `db1`; diff --git a/mysql-test/suite/clustrixdb/update.test b/mysql-test/suite/clustrixdb/update.test deleted file mode 100644 index 599d7f348ac..00000000000 --- a/mysql-test/suite/clustrixdb/update.test +++ /dev/null @@ -1,19 +0,0 @@ -CREATE DATABASE IF NOT EXISTS `db1`; -USE `db1`; -DROP TABLE IF EXISTS `t1`; -CREATE TABLE `t1`(i BIGINT, t TEXT)ENGINE=clustrixdb; -INSERT INTO `t1` (i, t) VALUES (42, 'один'); -INSERT INTO `t1` (i, t) VALUES (42, 'ноль'); -SELECT * FROM `t1` ORDER BY `i` DESC, `t` DESC; - -UPDATE `t1` SET i=i+1,t='два' WHERE t='один'; -SELECT * FROM `t1` ORDER BY `i` DESC, `t` DESC; - -USE test; -UPDATE `db1`.`t1` SET i=i+1,t='три' WHERE t='два'; -SELECT * FROM `db1`.`t1` ORDER BY `i` DESC, `t` DESC; - -DROP TABLE `db1`.`t1`; - -USE test; -DROP DATABASE `db1`; diff --git a/mysql-test/suite/clustrixdb/upsert.result b/mysql-test/suite/clustrixdb/upsert.result deleted file mode 100644 index f30cfe95314..00000000000 --- a/mysql-test/suite/clustrixdb/upsert.result +++ /dev/null @@ -1,72 +0,0 @@ -CREATE DATABASE IF NOT EXISTS `db1`; -USE `db1`; -DROP TABLE IF EXISTS `ins_duplicate`; -Warnings: -Note 1051 Unknown table 'db1.ins_duplicate' -CREATE TABLE `ins_duplicate`(`id` INT PRIMARY KEY, `animal` VARCHAR(30)) ENGINE=clustrixdb; -INSERT INTO `ins_duplicate` VALUES (1,'Aardvark'), (2,'Cheetah'), (3,'Zebra'); -SELECT * FROM `ins_duplicate` ORDER BY `id`; -id animal -1 Aardvark -2 Cheetah -3 Zebra -INSERT INTO ins_duplicate VALUES (1,'Antelope'); -ERROR 23000: Clustrix error: [5120] Duplicate key in container: `db1`.`ins_duplicate` Primary key: (1) -INSERT INTO ins_duplicate VALUES (1,'Antelope') ON DUPLICATE KEY UPDATE animal='Banana'; -SELECT * FROM `ins_duplicate` ORDER BY `id`; -id animal -1 Banana -2 Cheetah -3 Zebra -INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah'); -ERROR 23000: Clustrix error: [5120] Duplicate key in container: `db1`.`ins_duplicate` Primary key: (1) -INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah') ON DUPLICATE KEY UPDATE animal='hybrid'; -SELECT * FROM `ins_duplicate` ORDER BY `id`; -id animal -1 hybrid -2 hybrid -3 Zebra -BEGIN; -SELECT * FROM `ins_duplicate` ORDER BY `id`; -id animal -1 hybrid -2 hybrid -3 Zebra -INSERT INTO ins_duplicate VALUES (1,'Antelope'); -ERROR 23000: Clustrix error: [5120] Duplicate key in container: `db1`.`ins_duplicate` Primary key: (1) -INSERT INTO ins_duplicate VALUES (1,'Antelope') ON DUPLICATE KEY UPDATE animal='Vegetable'; -SELECT * FROM `ins_duplicate` ORDER BY `id`; -id animal -1 Vegetable -2 hybrid -3 Zebra -INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah'); -ERROR 23000: Clustrix error: [5120] Duplicate key in container: `db1`.`ins_duplicate` Primary key: (1) -INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah') ON DUPLICATE KEY UPDATE animal='hybrid2'; -COMMIT; -BEGIN; -SELECT * FROM `ins_duplicate` ORDER BY `id`; -id animal -1 hybrid2 -2 hybrid2 -3 Zebra -INSERT INTO ins_duplicate VALUES (1,'Antelope'); -ERROR 23000: Clustrix error: [5120] Duplicate key in container: `db1`.`ins_duplicate` Primary key: (1) -INSERT INTO ins_duplicate VALUES (1,'Antelope') ON DUPLICATE KEY UPDATE animal='Vegetable'; -SELECT * FROM `ins_duplicate` ORDER BY `id`; -id animal -1 Vegetable -2 hybrid2 -3 Zebra -INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah'); -ERROR 23000: Clustrix error: [5120] Duplicate key in container: `db1`.`ins_duplicate` Primary key: (1) -INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah') ON DUPLICATE KEY UPDATE animal='hybrid3'; -ROLLBACK; -SELECT * FROM `ins_duplicate` ORDER BY `id`; -id animal -1 hybrid2 -2 hybrid2 -3 Zebra -DROP TABLE `db1`.`ins_duplicate`; -USE test; -DROP DATABASE `db1`; diff --git a/mysql-test/suite/clustrixdb/upsert.test b/mysql-test/suite/clustrixdb/upsert.test deleted file mode 100644 index badd6cb50d4..00000000000 --- a/mysql-test/suite/clustrixdb/upsert.test +++ /dev/null @@ -1,49 +0,0 @@ -CREATE DATABASE IF NOT EXISTS `db1`; -USE `db1`; -DROP TABLE IF EXISTS `ins_duplicate`; -CREATE TABLE `ins_duplicate`(`id` INT PRIMARY KEY, `animal` VARCHAR(30)) ENGINE=clustrixdb; -INSERT INTO `ins_duplicate` VALUES (1,'Aardvark'), (2,'Cheetah'), (3,'Zebra'); -SELECT * FROM `ins_duplicate` ORDER BY `id`; - ---error ER_DUP_ENTRY -INSERT INTO ins_duplicate VALUES (1,'Antelope'); -INSERT INTO ins_duplicate VALUES (1,'Antelope') ON DUPLICATE KEY UPDATE animal='Banana'; -SELECT * FROM `ins_duplicate` ORDER BY `id`; - ---error ER_DUP_ENTRY -INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah'); -INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah') ON DUPLICATE KEY UPDATE animal='hybrid'; -SELECT * FROM `ins_duplicate` ORDER BY `id`; - -BEGIN; -SELECT * FROM `ins_duplicate` ORDER BY `id`; - ---error ER_DUP_ENTRY -INSERT INTO ins_duplicate VALUES (1,'Antelope'); -INSERT INTO ins_duplicate VALUES (1,'Antelope') ON DUPLICATE KEY UPDATE animal='Vegetable'; -SELECT * FROM `ins_duplicate` ORDER BY `id`; - ---error ER_DUP_ENTRY -INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah'); -INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah') ON DUPLICATE KEY UPDATE animal='hybrid2'; -COMMIT; - -BEGIN; -SELECT * FROM `ins_duplicate` ORDER BY `id`; - ---error ER_DUP_ENTRY -INSERT INTO ins_duplicate VALUES (1,'Antelope'); -INSERT INTO ins_duplicate VALUES (1,'Antelope') ON DUPLICATE KEY UPDATE animal='Vegetable'; -SELECT * FROM `ins_duplicate` ORDER BY `id`; - ---error ER_DUP_ENTRY -INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah'); -INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah') ON DUPLICATE KEY UPDATE animal='hybrid3'; -ROLLBACK; - -SELECT * FROM `ins_duplicate` ORDER BY `id`; - -DROP TABLE `db1`.`ins_duplicate`; - -USE test; -DROP DATABASE `db1`; diff --git a/mysql-test/suite/xpand/basics.result b/mysql-test/suite/xpand/basics.result new file mode 100644 index 00000000000..07fb56dc072 --- /dev/null +++ b/mysql-test/suite/xpand/basics.result @@ -0,0 +1,49 @@ +CREATE DATABASE xpd; +USE xpd; +DROP TABLE IF EXISTS cx1; +Warnings: +Note 1051 Unknown table 'xpd.cx1' +CREATE TABLE cx1(i BIGINT)ENGINE=xpand; +CREATE TABLE cx1(i BIGINT)ENGINE=xpand; +ERROR 42S01: Table 'cx1' already exists +INSERT INTO cx1 VALUES (42); +SELECT * FROM cx1; +i +42 +DROP TABLE cx1; +SHOW CREATE TABLE cx1; +ERROR 42S02: Table 'xpd.cx1' doesn't exist +DROP TABLE IF EXISTS intandtext; +Warnings: +Note 1051 Unknown table 'xpd.intandtext' +CREATE TABLE intandtext(i bigint, t text)ENGINE=xpand; +INSERT INTO intandtext VALUES(10, 'someqwqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq'); +SELECT i,t FROM intandtext; +i t +10 someqwqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq +EXPLAIN SELECT i,t FROM intandtext; +id select_type table type possible_keys key key_len ref rows Extra +1 PUSHED SELECT NULL NULL NULL NULL NULL NULL NULL NULL +SET @@optimizer_switch='derived_merge=OFF'; +SET xpand_select_handler=OFF; +SELECT i,t FROM (SELECT i,t FROM intandtext) t; +i t +10 someqwqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq +EXPLAIN SELECT i,t FROM (SELECT i,t FROM intandtext) t; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ALL NULL NULL NULL NULL 10000 +2 PUSHED DERIVED NULL NULL NULL NULL NULL NULL NULL NULL +SET xpand_derived_handler=OFF; +SELECT i,t FROM intandtext; +i t +10 someqwqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq +SELECT i,t FROM (SELECT i,t FROM intandtext) t; +i t +10 someqwqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq +EXPLAIN SELECT i,t FROM (SELECT i,t FROM intandtext) t; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ALL NULL NULL NULL NULL 10000 +2 DERIVED intandtext ALL NULL NULL NULL NULL 10000 +DROP TABLE intandtext; +USE test; +DROP DATABASE xpd; diff --git a/mysql-test/suite/xpand/basics.test b/mysql-test/suite/xpand/basics.test new file mode 100644 index 00000000000..0284086bfbd --- /dev/null +++ b/mysql-test/suite/xpand/basics.test @@ -0,0 +1,38 @@ +CREATE DATABASE xpd; +USE xpd; + +DROP TABLE IF EXISTS cx1; +CREATE TABLE cx1(i BIGINT)ENGINE=xpand; +--error ER_TABLE_EXISTS_ERROR +CREATE TABLE cx1(i BIGINT)ENGINE=xpand; + +INSERT INTO cx1 VALUES (42); + +SELECT * FROM cx1; + +DROP TABLE cx1; + +--error ER_NO_SUCH_TABLE +SHOW CREATE TABLE cx1; + +DROP TABLE IF EXISTS intandtext; +CREATE TABLE intandtext(i bigint, t text)ENGINE=xpand; +INSERT INTO intandtext VALUES(10, 'someqwqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq'); + +SELECT i,t FROM intandtext; +EXPLAIN SELECT i,t FROM intandtext; + +SET @@optimizer_switch='derived_merge=OFF'; +SET xpand_select_handler=OFF; +SELECT i,t FROM (SELECT i,t FROM intandtext) t; +EXPLAIN SELECT i,t FROM (SELECT i,t FROM intandtext) t; + +SET xpand_derived_handler=OFF; +SELECT i,t FROM intandtext; +SELECT i,t FROM (SELECT i,t FROM intandtext) t; +EXPLAIN SELECT i,t FROM (SELECT i,t FROM intandtext) t; + +DROP TABLE intandtext; + +USE test; +DROP DATABASE xpd; diff --git a/mysql-test/suite/xpand/my.cnf b/mysql-test/suite/xpand/my.cnf new file mode 100644 index 00000000000..8105041b85c --- /dev/null +++ b/mysql-test/suite/xpand/my.cnf @@ -0,0 +1,4 @@ +!include include/default_my.cnf + +[mysqld.1] +socket= /tmp/mysqld42.sock diff --git a/mysql-test/suite/xpand/suite.opt b/mysql-test/suite/xpand/suite.opt new file mode 100644 index 00000000000..1e15cb158ae --- /dev/null +++ b/mysql-test/suite/xpand/suite.opt @@ -0,0 +1,4 @@ +--plugin-load=xpand=ha_xpand.so +--core-file +--xpand_port=3306 +--plugin-maturity=unknown diff --git a/mysql-test/suite/xpand/update.result b/mysql-test/suite/xpand/update.result new file mode 100644 index 00000000000..9b39f318ca1 --- /dev/null +++ b/mysql-test/suite/xpand/update.result @@ -0,0 +1,26 @@ +CREATE DATABASE IF NOT EXISTS `db1`; +USE `db1`; +DROP TABLE IF EXISTS `t1`; +Warnings: +Note 1051 Unknown table 'db1.t1' +CREATE TABLE `t1`(i BIGINT, t TEXT)ENGINE=xpand; +INSERT INTO `t1` (i, t) VALUES (42, 'один'); +INSERT INTO `t1` (i, t) VALUES (42, 'ноль'); +SELECT * FROM `t1` ORDER BY `i` DESC, `t` DESC; +i t +42 один +42 ноль +UPDATE `t1` SET i=i+1,t='два' WHERE t='один'; +SELECT * FROM `t1` ORDER BY `i` DESC, `t` DESC; +i t +42 один +42 ноль +USE test; +UPDATE `db1`.`t1` SET i=i+1,t='три' WHERE t='два'; +SELECT * FROM `db1`.`t1` ORDER BY `i` DESC, `t` DESC; +i t +42 один +42 ноль +DROP TABLE `db1`.`t1`; +USE test; +DROP DATABASE `db1`; diff --git a/mysql-test/suite/xpand/update.test b/mysql-test/suite/xpand/update.test new file mode 100644 index 00000000000..eb40a19d7ac --- /dev/null +++ b/mysql-test/suite/xpand/update.test @@ -0,0 +1,19 @@ +CREATE DATABASE IF NOT EXISTS `db1`; +USE `db1`; +DROP TABLE IF EXISTS `t1`; +CREATE TABLE `t1`(i BIGINT, t TEXT)ENGINE=xpand; +INSERT INTO `t1` (i, t) VALUES (42, 'один'); +INSERT INTO `t1` (i, t) VALUES (42, 'ноль'); +SELECT * FROM `t1` ORDER BY `i` DESC, `t` DESC; + +UPDATE `t1` SET i=i+1,t='два' WHERE t='один'; +SELECT * FROM `t1` ORDER BY `i` DESC, `t` DESC; + +USE test; +UPDATE `db1`.`t1` SET i=i+1,t='три' WHERE t='два'; +SELECT * FROM `db1`.`t1` ORDER BY `i` DESC, `t` DESC; + +DROP TABLE `db1`.`t1`; + +USE test; +DROP DATABASE `db1`; diff --git a/mysql-test/suite/xpand/upsert.result b/mysql-test/suite/xpand/upsert.result new file mode 100644 index 00000000000..13c948c0a60 --- /dev/null +++ b/mysql-test/suite/xpand/upsert.result @@ -0,0 +1,72 @@ +CREATE DATABASE IF NOT EXISTS `db1`; +USE `db1`; +DROP TABLE IF EXISTS `ins_duplicate`; +Warnings: +Note 1051 Unknown table 'db1.ins_duplicate' +CREATE TABLE `ins_duplicate`(`id` INT PRIMARY KEY, `animal` VARCHAR(30)) ENGINE=xpand; +INSERT INTO `ins_duplicate` VALUES (1,'Aardvark'), (2,'Cheetah'), (3,'Zebra'); +SELECT * FROM `ins_duplicate` ORDER BY `id`; +id animal +1 Aardvark +2 Cheetah +3 Zebra +INSERT INTO ins_duplicate VALUES (1,'Antelope'); +ERROR 23000: Xpand error: [5120] Duplicate key in container: `db1`.`ins_duplicate` Primary key: (1) +INSERT INTO ins_duplicate VALUES (1,'Antelope') ON DUPLICATE KEY UPDATE animal='Banana'; +SELECT * FROM `ins_duplicate` ORDER BY `id`; +id animal +1 Banana +2 Cheetah +3 Zebra +INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah'); +ERROR 23000: Xpand error: [5120] Duplicate key in container: `db1`.`ins_duplicate` Primary key: (1) +INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah') ON DUPLICATE KEY UPDATE animal='hybrid'; +SELECT * FROM `ins_duplicate` ORDER BY `id`; +id animal +1 hybrid +2 hybrid +3 Zebra +BEGIN; +SELECT * FROM `ins_duplicate` ORDER BY `id`; +id animal +1 hybrid +2 hybrid +3 Zebra +INSERT INTO ins_duplicate VALUES (1,'Antelope'); +ERROR 23000: Xpand error: [5120] Duplicate key in container: `db1`.`ins_duplicate` Primary key: (1) +INSERT INTO ins_duplicate VALUES (1,'Antelope') ON DUPLICATE KEY UPDATE animal='Vegetable'; +SELECT * FROM `ins_duplicate` ORDER BY `id`; +id animal +1 Vegetable +2 hybrid +3 Zebra +INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah'); +ERROR 23000: Xpand error: [5120] Duplicate key in container: `db1`.`ins_duplicate` Primary key: (1) +INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah') ON DUPLICATE KEY UPDATE animal='hybrid2'; +COMMIT; +BEGIN; +SELECT * FROM `ins_duplicate` ORDER BY `id`; +id animal +1 hybrid2 +2 hybrid2 +3 Zebra +INSERT INTO ins_duplicate VALUES (1,'Antelope'); +ERROR 23000: Xpand error: [5120] Duplicate key in container: `db1`.`ins_duplicate` Primary key: (1) +INSERT INTO ins_duplicate VALUES (1,'Antelope') ON DUPLICATE KEY UPDATE animal='Vegetable'; +SELECT * FROM `ins_duplicate` ORDER BY `id`; +id animal +1 Vegetable +2 hybrid2 +3 Zebra +INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah'); +ERROR 23000: Xpand error: [5120] Duplicate key in container: `db1`.`ins_duplicate` Primary key: (1) +INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah') ON DUPLICATE KEY UPDATE animal='hybrid3'; +ROLLBACK; +SELECT * FROM `ins_duplicate` ORDER BY `id`; +id animal +1 hybrid2 +2 hybrid2 +3 Zebra +DROP TABLE `db1`.`ins_duplicate`; +USE test; +DROP DATABASE `db1`; diff --git a/mysql-test/suite/xpand/upsert.test b/mysql-test/suite/xpand/upsert.test new file mode 100644 index 00000000000..7763cb27d61 --- /dev/null +++ b/mysql-test/suite/xpand/upsert.test @@ -0,0 +1,49 @@ +CREATE DATABASE IF NOT EXISTS `db1`; +USE `db1`; +DROP TABLE IF EXISTS `ins_duplicate`; +CREATE TABLE `ins_duplicate`(`id` INT PRIMARY KEY, `animal` VARCHAR(30)) ENGINE=xpand; +INSERT INTO `ins_duplicate` VALUES (1,'Aardvark'), (2,'Cheetah'), (3,'Zebra'); +SELECT * FROM `ins_duplicate` ORDER BY `id`; + +--error ER_DUP_ENTRY +INSERT INTO ins_duplicate VALUES (1,'Antelope'); +INSERT INTO ins_duplicate VALUES (1,'Antelope') ON DUPLICATE KEY UPDATE animal='Banana'; +SELECT * FROM `ins_duplicate` ORDER BY `id`; + +--error ER_DUP_ENTRY +INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah'); +INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah') ON DUPLICATE KEY UPDATE animal='hybrid'; +SELECT * FROM `ins_duplicate` ORDER BY `id`; + +BEGIN; +SELECT * FROM `ins_duplicate` ORDER BY `id`; + +--error ER_DUP_ENTRY +INSERT INTO ins_duplicate VALUES (1,'Antelope'); +INSERT INTO ins_duplicate VALUES (1,'Antelope') ON DUPLICATE KEY UPDATE animal='Vegetable'; +SELECT * FROM `ins_duplicate` ORDER BY `id`; + +--error ER_DUP_ENTRY +INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah'); +INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah') ON DUPLICATE KEY UPDATE animal='hybrid2'; +COMMIT; + +BEGIN; +SELECT * FROM `ins_duplicate` ORDER BY `id`; + +--error ER_DUP_ENTRY +INSERT INTO ins_duplicate VALUES (1,'Antelope'); +INSERT INTO ins_duplicate VALUES (1,'Antelope') ON DUPLICATE KEY UPDATE animal='Vegetable'; +SELECT * FROM `ins_duplicate` ORDER BY `id`; + +--error ER_DUP_ENTRY +INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah'); +INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah') ON DUPLICATE KEY UPDATE animal='hybrid3'; +ROLLBACK; + +SELECT * FROM `ins_duplicate` ORDER BY `id`; + +DROP TABLE `db1`.`ins_duplicate`; + +USE test; +DROP DATABASE `db1`; diff --git a/storage/clustrixdb/CMakeLists.txt b/storage/clustrixdb/CMakeLists.txt deleted file mode 100644 index 42237eae6e9..00000000000 --- a/storage/clustrixdb/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -#***************************************************************************** -# Copyright (c) 2019, MariaDB Corporation. -#****************************************************************************/ - -IF(MSVC) - # Temporarily disable "conversion from size_t .." - IF(CMAKE_SIZEOF_VOID_P EQUAL 8) - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4267") - ENDIF() -ENDIF() - -SET(CLUSTRIXDB_PLUGIN_STATIC "clustrixdb") -SET(CLUSTRIXDB_PLUGIN_DYNAMIC "ha_clustrixdb") -SET(CLUSTRIXDB_SOURCES ha_clustrixdb.cc clustrix_connection.cc ha_clustrixdb_pushdown.cc) -MYSQL_ADD_PLUGIN(clustrixdb ${CLUSTRIXDB_SOURCES} STORAGE_ENGINE) - -IF(MSVC) - IF (CMAKE_BUILD_TYPE STREQUAL "Debug") - ADD_CUSTOM_COMMAND(TARGET clustrixdb - POST_BUILD - COMMAND if not exist ..\\..\\sql\\lib mkdir ..\\..\\sql\\lib\\plugin - COMMAND copy Debug\\ha_clustrixdb.dll ..\\..\\sql\\lib\\plugin\\ha_clustrixdb.dll) - ENDIF() -ENDIF() diff --git a/storage/clustrixdb/clustrix_connection.cc b/storage/clustrixdb/clustrix_connection.cc deleted file mode 100644 index f03f43acaeb..00000000000 --- a/storage/clustrixdb/clustrix_connection.cc +++ /dev/null @@ -1,1190 +0,0 @@ -/***************************************************************************** -Copyright (c) 2019, MariaDB Corporation. -*****************************************************************************/ - -/** @file clustrix_connection.cc */ - -#include "clustrix_connection.h" -#include -#include "errmsg.h" -#include "handler.h" -#include "table.h" - -extern int clustrix_connect_timeout; -extern int clustrix_read_timeout; -extern int clustrix_write_timeout; -extern char *clustrix_host; -extern char *clustrix_username; -extern char *clustrix_password; -extern uint clustrix_port; -extern char *clustrix_socket; - -/* - This class implements the commands that can be sent to the cluster by the - Xpand engine. All of these commands return a status to the caller, but some - commands also create open invocations on the cluster, which must be closed by - sending additional commands. - - Transactions on the cluster are started using flags attached to commands, and - transactions are committed or rolled back using separate commands. - - Methods ending with _next affect the transaction state after the next command - is sent to the cluster. Other transaction commands are sent to the cluster - immediately, and the state is changed before they return. - - _____________________ _______________________ - | | | | | | - V | | V | | - NONE --> REQUESTED --> STARTED --> NEW_STMT | - | | - `----> ROLLBACK_STMT ---` - - The commit and rollback commands will change any other state to NONE. This - includes the REQUESTED state, for which nothing will be sent to the cluster. - The rollback statement command can likewise change the state from NEW_STMT to - STARTED without sending anything to the cluster. - - In addition, the CLUSTRIX_TRANS_AUTOCOMMIT flag will cause the transactions - for commands that complete without leaving open invocations on the cluster to - be committed if successful or rolled back if there was an error. If - auto-commit is enabled, only one open invocation may be in progress at a - time. -*/ - -enum clustrix_trans_state { - CLUSTRIX_TRANS_STARTED = 0, - CLUSTRIX_TRANS_REQUESTED = 1, - CLUSTRIX_TRANS_NEW_STMT = 2, - CLUSTRIX_TRANS_ROLLBACK_STMT = 4, - CLUSTRIX_TRANS_NONE = 32, -}; - -enum clustrix_trans_post_flags { - CLUSTRIX_TRANS_AUTOCOMMIT = 8, - CLUSTRIX_TRANS_NO_POST_FLAGS = 0, -}; - -enum clustrix_commands { - CLUSTRIX_WRITE_ROW = 1, - CLUSTRIX_SCAN_TABLE, - CLUSTRIX_SCAN_NEXT, - CLUSTRIX_SCAN_STOP, - CLUSTRIX_KEY_READ, - CLUSTRIX_KEY_DELETE, - CLUSTRIX_SCAN_QUERY, - CLUSTRIX_KEY_UPDATE, - CLUSTRIX_SCAN_FROM_KEY, - CLUSTRIX_UPDATE_QUERY, - CLUSTRIX_COMMIT, - CLUSTRIX_ROLLBACK, -}; - -/**************************************************************************** -** Class clustrix_connection -****************************************************************************/ -clustrix_connection::clustrix_connection() - : command_buffer(NULL), command_buffer_length(0), command_length(0), - trans_state(CLUSTRIX_TRANS_NONE), trans_flags(CLUSTRIX_TRANS_NO_POST_FLAGS) -{ - DBUG_ENTER("clustrix_connection::clustrix_connection"); - memset(&clustrix_net, 0, sizeof(MYSQL)); - DBUG_VOID_RETURN; -} - -clustrix_connection::~clustrix_connection() -{ - DBUG_ENTER("clustrix_connection::~clustrix_connection"); - if (is_connected()) - disconnect(TRUE); - - if (command_buffer) - my_free(command_buffer); - DBUG_VOID_RETURN; -} - -void clustrix_connection::disconnect(bool is_destructor) -{ - DBUG_ENTER("clustrix_connection::disconnect"); - if (is_destructor) - { - /* - Connection object destruction occurs after the destruction of - the thread used by the network has begun, so usage of that - thread object now is not reliable - */ - clustrix_net.net.thd = NULL; - } - mysql_close(&clustrix_net); - DBUG_VOID_RETURN; -} - -int host_list_next; -extern int host_list_cnt; -extern char **host_list; - -int clustrix_connection::connect() -{ - int error_code = 0; - my_bool my_true = 1; - DBUG_ENTER("clustrix_connection::connect"); - - // cpu concurrency by damned! - int host_num = host_list_next; - host_num = host_num % host_list_cnt; - char *host = host_list[host_num]; - host_list_next = host_num + 1; - DBUG_PRINT("host", ("%s", host)); - - /* Validate the connection parameters */ - if (!strcmp(clustrix_socket, "")) - if (!strcmp(host, "127.0.0.1")) - if (clustrix_port == MYSQL_PORT_DEFAULT) - DBUG_RETURN(ER_CONNECT_TO_FOREIGN_DATA_SOURCE); - - //clustrix_net.methods = &connection_methods; - - if (!mysql_init(&clustrix_net)) - DBUG_RETURN(HA_ERR_OUT_OF_MEM); - - mysql_options(&clustrix_net, MYSQL_OPT_READ_TIMEOUT, - &clustrix_read_timeout); - mysql_options(&clustrix_net, MYSQL_OPT_WRITE_TIMEOUT, - &clustrix_write_timeout); - mysql_options(&clustrix_net, MYSQL_OPT_CONNECT_TIMEOUT, - &clustrix_connect_timeout); - mysql_options(&clustrix_net, MYSQL_OPT_USE_REMOTE_CONNECTION, - NULL); - mysql_options(&clustrix_net, MYSQL_SET_CHARSET_NAME, "utf8mb4"); - mysql_options(&clustrix_net, MYSQL_OPT_USE_THREAD_SPECIFIC_MEMORY, - (char *) &my_true); - mysql_options(&clustrix_net, MYSQL_INIT_COMMAND,"SET autocommit=0"); - -#ifdef CLUSTRIX_CONNECTION_SSL - if (opt_ssl_ca_length | conn->tgt_ssl_capath_length | - conn->tgt_ssl_cert_length | conn->tgt_ssl_key_length) - { - mysql_ssl_set(&clustrix_net, conn->tgt_ssl_key, conn->tgt_ssl_cert, - conn->tgt_ssl_ca, conn->tgt_ssl_capath, conn->tgt_ssl_cipher); - if (conn->tgt_ssl_vsc) - { - my_bool verify_flg = TRUE; - mysql_options(&clustrix_net, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, - &verify_flg); - } - } -#endif - - if (!mysql_real_connect(&clustrix_net, host, - clustrix_username, clustrix_password, - NULL, clustrix_port, clustrix_socket, - CLIENT_MULTI_STATEMENTS)) - { - error_code = mysql_errno(&clustrix_net); - disconnect(); - - if (error_code != CR_CONN_HOST_ERROR && - error_code != CR_CONNECTION_ERROR) - { - if (error_code == ER_CON_COUNT_ERROR) - { - my_error(ER_CON_COUNT_ERROR, MYF(0)); - DBUG_RETURN(ER_CON_COUNT_ERROR); - } - my_error(ER_CONNECT_TO_FOREIGN_DATA_SOURCE, MYF(0), host); - DBUG_RETURN(ER_CONNECT_TO_FOREIGN_DATA_SOURCE); - } - } - - clustrix_net.reconnect = 1; - - DBUG_RETURN(0); -} - -int clustrix_connection::begin_command(uchar command) -{ - if (trans_state == CLUSTRIX_TRANS_NONE) - return HA_ERR_INTERNAL_ERROR; - - command_length = 0; - int error_code = 0; - if ((error_code = add_command_operand_uchar(command))) - return error_code; - - if ((error_code = add_command_operand_uchar(trans_state | trans_flags))) - return error_code; - - return error_code; -} - -int clustrix_connection::send_command() -{ - my_bool com_error; - - /* - Please note: - * The transaction state is set before the command is sent because rolling - back a nonexistent transaction is better than leaving a tranaction open - on the cluster. - * The state may have alreadly been STARTED. - * Commit and rollback commands update the transaction state after calling - this function. - * If auto-commit is enabled, the state may also updated after the - response has been processed. We do not clear the auto-commit flag here - because it needs to be sent with each command until the transaction is - committed or rolled back. - */ - trans_state = CLUSTRIX_TRANS_STARTED; - - com_error = simple_command(&clustrix_net, - (enum_server_command)CLUSTRIX_SERVER_REQUEST, - command_buffer, command_length, TRUE); - - if (com_error) - { - int error_code = mysql_errno(&clustrix_net); - my_printf_error(error_code, - "Clustrix error: %s", MYF(0), - mysql_error(&clustrix_net)); - return error_code; - } - - return 0; -} - -int clustrix_connection::read_query_response() -{ - my_bool comerr = clustrix_net.methods->read_query_result(&clustrix_net); - int error_code = 0; - if (comerr) - { - error_code = mysql_errno(&clustrix_net); - my_printf_error(error_code, - "Clustrix error: %s", MYF(0), - mysql_error(&clustrix_net)); - } - - auto_commit_closed(); - return error_code; -} - -bool clustrix_connection::has_open_transaction() -{ - return trans_state != CLUSTRIX_TRANS_NONE; -} - -int clustrix_connection::commit_transaction() -{ - DBUG_ENTER("clustrix_connection::commit_transaction"); - if (trans_state == CLUSTRIX_TRANS_NONE) - DBUG_RETURN(HA_ERR_INTERNAL_ERROR); - - if (trans_state == CLUSTRIX_TRANS_REQUESTED) { - trans_state = CLUSTRIX_TRANS_NONE; - trans_flags = CLUSTRIX_TRANS_NO_POST_FLAGS; - DBUG_RETURN(0); - } - - int error_code; - if ((error_code = begin_command(CLUSTRIX_COMMIT))) - DBUG_RETURN(error_code); - - if ((error_code = send_command())) - DBUG_RETURN(error_code); - - if ((error_code = read_query_response())) - DBUG_RETURN(error_code); - - trans_state = CLUSTRIX_TRANS_NONE; - trans_flags = CLUSTRIX_TRANS_NO_POST_FLAGS; - DBUG_RETURN(error_code); -} - -int clustrix_connection::rollback_transaction() -{ - DBUG_ENTER("clustrix_connection::rollback_transaction"); - if (trans_state == CLUSTRIX_TRANS_NONE || - trans_state == CLUSTRIX_TRANS_REQUESTED) { - trans_state = CLUSTRIX_TRANS_NONE; - DBUG_RETURN(0); - } - - int error_code; - if ((error_code = begin_command(CLUSTRIX_ROLLBACK))) - DBUG_RETURN(error_code); - - if ((error_code = send_command())) - DBUG_RETURN(error_code); - - if ((error_code = read_query_response())) - DBUG_RETURN(error_code); - - trans_state = CLUSTRIX_TRANS_NONE; - trans_flags = CLUSTRIX_TRANS_NO_POST_FLAGS; - DBUG_RETURN(error_code); -} - -int clustrix_connection::begin_transaction_next() -{ - DBUG_ENTER("clustrix_connection::begin_transaction_next"); - if (trans_state != CLUSTRIX_TRANS_NONE || - trans_flags != CLUSTRIX_TRANS_NO_POST_FLAGS) - DBUG_RETURN(HA_ERR_INTERNAL_ERROR); - - trans_state = CLUSTRIX_TRANS_REQUESTED; - DBUG_RETURN(0); -} - -int clustrix_connection::new_statement_next() -{ - DBUG_ENTER("clustrix_connection::new_statement_next"); - if (trans_state != CLUSTRIX_TRANS_STARTED || - trans_flags != CLUSTRIX_TRANS_NO_POST_FLAGS) - DBUG_RETURN(HA_ERR_INTERNAL_ERROR); - - trans_state = CLUSTRIX_TRANS_NEW_STMT; - DBUG_RETURN(0); -} - -int clustrix_connection::rollback_statement_next() -{ - DBUG_ENTER("clustrix_connection::rollback_statement_next"); - if (trans_state != CLUSTRIX_TRANS_STARTED || - trans_flags != CLUSTRIX_TRANS_NO_POST_FLAGS) - DBUG_RETURN(HA_ERR_INTERNAL_ERROR); - - trans_state = CLUSTRIX_TRANS_ROLLBACK_STMT; - DBUG_RETURN(0); -} - -void clustrix_connection::auto_commit_next() -{ - trans_flags |= CLUSTRIX_TRANS_AUTOCOMMIT; -} - -void clustrix_connection::auto_commit_closed() -{ - if (trans_flags & CLUSTRIX_TRANS_AUTOCOMMIT) { - trans_flags &= ~CLUSTRIX_TRANS_AUTOCOMMIT; - trans_state = CLUSTRIX_TRANS_NONE; - } -} - -int clustrix_connection::run_query(String &stmt) -{ - int error_code = mysql_real_query(&clustrix_net, stmt.ptr(), stmt.length()); - if (error_code) - return mysql_errno(&clustrix_net); - return error_code; -} - -int clustrix_connection::write_row(ulonglong clustrix_table_oid, - uchar *packed_row, size_t packed_size, - ulonglong *last_insert_id) -{ - int error_code; - command_length = 0; - - // row based commands should not be called with auto commit. - if (trans_flags & CLUSTRIX_TRANS_AUTOCOMMIT) - return HA_ERR_INTERNAL_ERROR; - - if ((error_code = begin_command(CLUSTRIX_WRITE_ROW))) - return error_code; - - if ((error_code = add_command_operand_ulonglong(clustrix_table_oid))) - return error_code; - - if ((error_code = add_command_operand_str(packed_row, packed_size))) - return error_code; - - if ((error_code = send_command())) - return error_code; - - if ((error_code = read_query_response())) - return error_code; - - *last_insert_id = clustrix_net.insert_id; - return error_code; -} - -int clustrix_connection::key_update(ulonglong clustrix_table_oid, - uchar *packed_key, size_t packed_key_length, - MY_BITMAP *update_set, - uchar *packed_new_data, - size_t packed_new_length) -{ - int error_code; - command_length = 0; - - // row based commands should not be called with auto commit. - if (trans_flags & CLUSTRIX_TRANS_AUTOCOMMIT) - return HA_ERR_INTERNAL_ERROR; - - if ((error_code = begin_command(CLUSTRIX_KEY_UPDATE))) - return error_code; - - if ((error_code = add_command_operand_ulonglong(clustrix_table_oid))) - return error_code; - - if ((error_code = add_command_operand_str(packed_key, packed_key_length))) - return error_code; - - if ((error_code = add_command_operand_bitmap(update_set))) - return error_code; - - if ((error_code = add_command_operand_str(packed_new_data, - packed_new_length))) - return error_code; - - if ((error_code = send_command())) - return error_code; - - if ((error_code = read_query_response())) - return error_code; - - return error_code; -} - -int clustrix_connection::key_delete(ulonglong clustrix_table_oid, - uchar *packed_key, size_t packed_key_length) -{ - int error_code; - command_length = 0; - - // row based commands should not be called with auto commit. - if (trans_flags & CLUSTRIX_TRANS_AUTOCOMMIT) - return HA_ERR_INTERNAL_ERROR; - - if ((error_code = begin_command(CLUSTRIX_KEY_DELETE))) - return error_code; - - if ((error_code = add_command_operand_ulonglong(clustrix_table_oid))) - return error_code; - - if ((error_code = add_command_operand_str(packed_key, packed_key_length))) - return error_code; - - if ((error_code = send_command())) - return error_code; - - if ((error_code = read_query_response())) - return error_code; - - return error_code; -} - -int clustrix_connection::key_read(ulonglong clustrix_table_oid, uint index, - clustrix_lock_mode_t lock_mode, - MY_BITMAP *read_set, uchar *packed_key, - ulong packed_key_length, uchar **rowdata, - ulong *rowdata_length) -{ - int error_code; - command_length = 0; - - // row based commands should not be called with auto commit. - if (trans_flags & CLUSTRIX_TRANS_AUTOCOMMIT) - return HA_ERR_INTERNAL_ERROR; - - if ((error_code = begin_command(CLUSTRIX_KEY_READ))) - return error_code; - - if ((error_code = add_command_operand_ulonglong(clustrix_table_oid))) - return error_code; - - if ((error_code = add_command_operand_uint(index))) - return error_code; - - if ((error_code = add_command_operand_uchar((uchar)lock_mode))) - return error_code; - - if ((error_code = add_command_operand_bitmap(read_set))) - return error_code; - - if ((error_code = add_command_operand_str(packed_key, packed_key_length))) - return error_code; - - if ((error_code = send_command())) - return error_code; - - ulong packet_length = cli_safe_read(&clustrix_net); - if (packet_length == packet_error) - return mysql_errno(&clustrix_net); - - uchar *data = clustrix_net.net.read_pos; - *rowdata_length = safe_net_field_length_ll(&data, packet_length); - *rowdata = (uchar *)my_malloc(*rowdata_length, MYF(MY_WME)); - memcpy(*rowdata, data, *rowdata_length); - - packet_length = cli_safe_read(&clustrix_net); - if (packet_length == packet_error) { - my_free(*rowdata); - *rowdata = NULL; - *rowdata_length = 0; - return mysql_errno(&clustrix_net); - } - - return 0; -} - -class clustrix_connection_cursor { - struct rowdata { - ulong length; - uchar *data; - }; - - ulong current_row; - ulong last_row; - struct rowdata *rows; - uchar *outstanding_row; // to be freed on next request. - MYSQL *clustrix_net; - -public: - ulong buffer_size; - ulonglong scan_refid; - bool eof_reached; - -private: - int cache_row(uchar *rowdata, ulong rowdata_length) - { - DBUG_ENTER("clustrix_connection_cursor::cache_row"); - rows[last_row].length = rowdata_length; - rows[last_row].data = (uchar *)my_malloc(rowdata_length, MYF(MY_WME)); - if (!rows[last_row].data) - DBUG_RETURN(HA_ERR_OUT_OF_MEM); - memcpy(rows[last_row].data, rowdata, rowdata_length); - last_row++; - DBUG_RETURN(0); - } - - int load_rows_impl(bool *stmt_completed) - { - DBUG_ENTER("clustrix_connection_cursor::load_rows_impl"); - int error_code = 0; - ulong packet_length = cli_safe_read(clustrix_net); - if (packet_length == packet_error) { - error_code = mysql_errno(clustrix_net); - *stmt_completed = TRUE; - if (error_code == HA_ERR_END_OF_FILE) { - // We have read all rows for query. - eof_reached = TRUE; - DBUG_RETURN(0); - } - DBUG_RETURN(error_code); - } - - uchar *rowdata = clustrix_net->net.read_pos; - ulong rowdata_length = safe_net_field_length_ll(&rowdata, packet_length); - if (!rowdata_length) { - // We have read all rows in this batch. - DBUG_RETURN(0); - } - - if ((error_code = cache_row(rowdata, rowdata_length))) - DBUG_RETURN(error_code); - - DBUG_RETURN(load_rows_impl(stmt_completed)); - } - -public: - clustrix_connection_cursor(MYSQL *clustrix_net_, ulong bufsize) - { - DBUG_ENTER("clustrix_connection_cursor::clustrix_connection_cursor"); - clustrix_net = clustrix_net_; - eof_reached = FALSE; - current_row = 0; - last_row = 0; - outstanding_row = NULL; - buffer_size = bufsize; - rows = NULL; - DBUG_VOID_RETURN; - } - - ~clustrix_connection_cursor() - { - DBUG_ENTER("clustrix_connection_cursor::~clustrix_connection_cursor"); - if (outstanding_row) - my_free(outstanding_row); - if (rows) { - while (current_row < last_row) - my_free(rows[current_row++].data); - my_free(rows); - } - DBUG_VOID_RETURN; - } - - int load_rows(bool *stmt_completed) - { - DBUG_ENTER("clustrix_connection_cursor::load_rows"); - current_row = 0; - last_row = 0; - DBUG_RETURN(load_rows_impl(stmt_completed)); - } - - int initialize(bool *stmt_completed) - { - DBUG_ENTER("clustrix_connection_cursor::initialize"); - ulong packet_length = cli_safe_read(clustrix_net); - if (packet_length == packet_error) { - *stmt_completed = TRUE; - DBUG_RETURN(mysql_errno(clustrix_net)); - } - - unsigned char *pos = clustrix_net->net.read_pos; - scan_refid = safe_net_field_length_ll(&pos, packet_length); - - rows = (struct rowdata *)my_malloc(buffer_size * sizeof(struct rowdata), - MYF(MY_WME)); - if (!rows) - DBUG_RETURN(HA_ERR_OUT_OF_MEM); - - DBUG_RETURN(load_rows(stmt_completed)); - } - - uchar *retrieve_row(ulong *rowdata_length) - { - DBUG_ENTER("clustrix_connection_cursor::retrieve_row"); - if (outstanding_row) { - my_free(outstanding_row); - outstanding_row = NULL; - } - if (current_row == last_row) - DBUG_RETURN(NULL); - *rowdata_length = rows[current_row].length; - outstanding_row = rows[current_row].data; - current_row++; - DBUG_RETURN(outstanding_row); - } -}; - -int clustrix_connection::allocate_cursor(MYSQL *clustrix_net, ulong buffer_size, - clustrix_connection_cursor **scan) -{ - DBUG_ENTER("clustrix_connection::allocate_cursor"); - *scan = new clustrix_connection_cursor(clustrix_net, buffer_size); - if (!*scan) - DBUG_RETURN(HA_ERR_OUT_OF_MEM); - - bool stmt_completed = FALSE; - int error_code = (*scan)->initialize(&stmt_completed); - if (error_code) { - delete *scan; - *scan = NULL; - } - - if (stmt_completed) - auto_commit_closed(); - - DBUG_RETURN(error_code); -} - -int clustrix_connection::scan_table(ulonglong clustrix_table_oid, - clustrix_lock_mode_t lock_mode, - MY_BITMAP *read_set, ushort row_req, - clustrix_connection_cursor **scan) -{ - int error_code; - command_length = 0; - - // row based commands should not be called with auto commit. - if (trans_flags & CLUSTRIX_TRANS_AUTOCOMMIT) - return HA_ERR_INTERNAL_ERROR; - - if ((error_code = begin_command(CLUSTRIX_SCAN_TABLE))) - return error_code; - - if ((error_code = add_command_operand_ushort(row_req))) - return error_code; - - if ((error_code = add_command_operand_ulonglong(clustrix_table_oid))) - return error_code; - - if ((error_code = add_command_operand_uchar((uchar)lock_mode))) - return error_code; - - if ((error_code = add_command_operand_bitmap(read_set))) - return error_code; - - if ((error_code = send_command())) - return error_code; - - return allocate_cursor(&clustrix_net, row_req, scan); -} - -/** - * @brief - * Sends a command to initiate query scan. - * @details - * Sends a command over mysql protocol connection to initiate an - * arbitrary query using a query text. - * Uses field types, field metadata and nullability to explicitly - * cast result to expected data type. Exploits RBR TABLE_MAP_EVENT - * format + sends SQL text. - * @args - * stmt& Query text to send - * fieldtype* array of byte wide field types of result projection - * null_bits* fields nullability bitmap of result projection - * field_metadata* Field metadata of result projection - * scan_refid id used to reference this scan later - * Used in pushdowns to initiate query scan. - **/ -int clustrix_connection::scan_query(String &stmt, uchar *fieldtype, uint fields, - uchar *null_bits, uint null_bits_size, - uchar *field_metadata, - uint field_metadata_size, - ushort row_req, - clustrix_connection_cursor **scan) -{ - int error_code; - command_length = 0; - - if ((error_code = begin_command(CLUSTRIX_SCAN_QUERY))) - return error_code; - - if ((error_code = add_command_operand_ushort(row_req))) - return error_code; - - if ((error_code = add_command_operand_str((uchar*)stmt.ptr(), stmt.length()))) - return error_code; - - if ((error_code = add_command_operand_str(fieldtype, fields))) - return error_code; - - if ((error_code = add_command_operand_str(field_metadata, field_metadata_size))) - return error_code; - - // This variable length string calls for an additional store w/o lcb lenth prefix. - if ((error_code = add_command_operand_vlstr(null_bits, null_bits_size))) - return error_code; - - if ((error_code = send_command())) - return error_code; - - return allocate_cursor(&clustrix_net, row_req, scan); -} - -/** - * @brief - * Sends a command to initiate UPDATE. - * @details - * Sends a command over mysql protocol connection to initiate an - * UPDATE query using a query text. - * @args - * stmt& Query text to send - * dbname current working database - * dbname ¤t database name - **/ -int clustrix_connection::update_query(String &stmt, LEX_CSTRING &dbname, - ulonglong *affected_rows) -{ - int error_code; - command_length = 0; - - if ((error_code = begin_command(CLUSTRIX_UPDATE_QUERY))) - return error_code; - - if ((error_code = add_command_operand_str((uchar*)dbname.str, dbname.length))) - return error_code; - - if ((error_code = add_command_operand_str((uchar*)stmt.ptr(), stmt.length()))) - return error_code; - - if ((error_code = send_command())) - return error_code; - - error_code = read_query_response(); - if (!error_code) - *affected_rows = clustrix_net.affected_rows; - - return error_code; -} - -int clustrix_connection::scan_from_key(ulonglong clustrix_table_oid, uint index, - clustrix_lock_mode_t lock_mode, - enum scan_type scan_dir, - int no_key_cols, bool sorted_scan, - MY_BITMAP *read_set, uchar *packed_key, - ulong packed_key_length, ushort row_req, - clustrix_connection_cursor **scan) -{ - int error_code; - command_length = 0; - - // row based commands should not be called with auto commit. - if (trans_flags & CLUSTRIX_TRANS_AUTOCOMMIT) - return HA_ERR_INTERNAL_ERROR; - - if ((error_code = begin_command(CLUSTRIX_SCAN_FROM_KEY))) - return error_code; - - if ((error_code = add_command_operand_ushort(row_req))) - return error_code; - - if ((error_code = add_command_operand_ulonglong(clustrix_table_oid))) - return error_code; - - if ((error_code = add_command_operand_uint(index))) - return error_code; - - if ((error_code = add_command_operand_uchar((uchar)lock_mode))) - return error_code; - - if ((error_code = add_command_operand_uchar(scan_dir))) - return error_code; - - if ((error_code = add_command_operand_uint(no_key_cols))) - return error_code; - - if ((error_code = add_command_operand_uchar(sorted_scan))) - return error_code; - - if ((error_code = add_command_operand_str(packed_key, packed_key_length))) - return error_code; - - if ((error_code = add_command_operand_bitmap(read_set))) - return error_code; - - if ((error_code = send_command())) - return error_code; - - return allocate_cursor(&clustrix_net, row_req, scan); -} - -int clustrix_connection::scan_next(clustrix_connection_cursor *scan, - uchar **rowdata, ulong *rowdata_length) -{ - *rowdata = scan->retrieve_row(rowdata_length); - if (*rowdata) - return 0; - - if (scan->eof_reached) - return HA_ERR_END_OF_FILE; - - int error_code; - command_length = 0; - - if ((error_code = begin_command(CLUSTRIX_SCAN_NEXT))) - return error_code; - - if ((error_code = add_command_operand_ushort(scan->buffer_size))) - return error_code; - - if ((error_code = add_command_operand_lcb(scan->scan_refid))) - return error_code; - - if ((error_code = send_command())) - return error_code; - - bool stmt_completed = FALSE; - error_code = scan->load_rows(&stmt_completed); - if (stmt_completed) - auto_commit_closed(); - if (error_code) - return error_code; - - *rowdata = scan->retrieve_row(rowdata_length); - if (!*rowdata) - return HA_ERR_END_OF_FILE; - - return 0; -} - -int clustrix_connection::scan_end(clustrix_connection_cursor *scan) -{ - int error_code; - command_length = 0; - ulonglong scan_refid = scan->scan_refid; - bool eof_reached = scan->eof_reached; - delete scan; - - if (eof_reached) - return 0; - - if ((error_code = begin_command(CLUSTRIX_SCAN_STOP))) - return error_code; - - if ((error_code = add_command_operand_lcb(scan_refid))) - return error_code; - - if ((error_code = send_command())) - return error_code; - - return read_query_response(); -} - -int clustrix_connection::populate_table_list(LEX_CSTRING *db, - handlerton::discovered_list *result) -{ - int error_code = 0; - String stmt; - stmt.append("SHOW FULL TABLES FROM "); - stmt.append(db); - stmt.append(" WHERE table_type = 'BASE TABLE'"); - - if (mysql_real_query(&clustrix_net, stmt.c_ptr(), stmt.length())) { - int error_code = mysql_errno(&clustrix_net); - if (error_code == ER_BAD_DB_ERROR) - return 0; - else - return error_code; - } - - MYSQL_RES *results = mysql_store_result(&clustrix_net); - if (mysql_num_fields(results) != 2) { - error_code = HA_ERR_CORRUPT_EVENT; - goto error; - } - - MYSQL_ROW row; - while((row = mysql_fetch_row(results))) - result->add_table(row[0], strlen(row[0])); - -error: - mysql_free_result(results); - return error_code; -} - -int clustrix_connection::discover_table_details(LEX_CSTRING *db, - LEX_CSTRING *name, THD *thd, - TABLE_SHARE *share) -{ - DBUG_ENTER("clustrix_connection::discover_table_details"); - int error_code = 0; - MYSQL_RES *results_oid = NULL; - MYSQL_RES *results_create = NULL; - MYSQL_ROW row; - String get_oid, show; - - /* get oid */ - get_oid.append("select r.table " - "from system.databases d " - " inner join ""system.relations r on d.db = r.db " - "where d.name = '"); - get_oid.append(db); - get_oid.append("' and r.name = '"); - get_oid.append(name); - get_oid.append("'"); - - if (mysql_real_query(&clustrix_net, get_oid.c_ptr(), get_oid.length())) { - if ((error_code = mysql_errno(&clustrix_net))) { - DBUG_PRINT("mysql_real_query returns ", ("%d", error_code)); - error_code = HA_ERR_NO_SUCH_TABLE; - goto error; - } - } - - results_oid = mysql_store_result(&clustrix_net); - DBUG_PRINT("oid results", - ("rows: %llu, fields: %u", mysql_num_rows(results_oid), - mysql_num_fields(results_oid))); - - if (mysql_num_rows(results_oid) != 1) { - error_code = HA_ERR_NO_SUCH_TABLE; - goto error; - } - - while((row = mysql_fetch_row(results_oid))) { - DBUG_PRINT("row", ("%s", row[0])); - uchar *to = (uchar*)alloc_root(&share->mem_root, strlen(row[0]) + 1); - if (!to) { - error_code = HA_ERR_OUT_OF_MEM; - goto error; - } - - strcpy((char *)to, (char *)row[0]); - share->tabledef_version.str = to; - share->tabledef_version.length = strlen(row[0]); - } - - /* get show create statement */ - show.append("show simple create table "); - show.append(db); - show.append("."); - show.append(name); - if (mysql_real_query(&clustrix_net, show.c_ptr(), show.length())) { - if ((error_code = mysql_errno(&clustrix_net))) { - DBUG_PRINT("mysql_real_query returns ", ("%d", error_code)); - error_code = HA_ERR_NO_SUCH_TABLE; - goto error; - } - } - - results_create = mysql_store_result(&clustrix_net); - DBUG_PRINT("show table results", - ("rows: %llu, fields: %u", mysql_num_rows(results_create), - mysql_num_fields(results_create))); - - if (mysql_num_rows(results_create) != 1) { - error_code = HA_ERR_NO_SUCH_TABLE; - goto error; - } - - if (mysql_num_fields(results_create) != 2) { - error_code = HA_ERR_CORRUPT_EVENT; - goto error; - } - - while((row = mysql_fetch_row(results_create))) { - DBUG_PRINT("row", ("%s - %s", row[0], row[1])); - error_code = share->init_from_sql_statement_string(thd, false, row[1], - strlen(row[1])); - } - -error: - if (results_oid) - mysql_free_result(results_oid); - - if (results_create) - mysql_free_result(results_create); - DBUG_RETURN(error_code); -} - -#define COMMAND_BUFFER_SIZE_INCREMENT 1024 -#define COMMAND_BUFFER_SIZE_INCREMENT_BITS 10 -int clustrix_connection::expand_command_buffer(size_t add_length) -{ - size_t expanded_length; - - if (command_buffer_length >= command_length + add_length) - return 0; - - expanded_length = command_buffer_length + - ((add_length >> COMMAND_BUFFER_SIZE_INCREMENT_BITS) - << COMMAND_BUFFER_SIZE_INCREMENT_BITS) + - COMMAND_BUFFER_SIZE_INCREMENT; - - if (!command_buffer_length) - command_buffer = (uchar *) my_malloc(expanded_length, MYF(MY_WME)); - else - command_buffer = (uchar *) my_realloc(command_buffer, expanded_length, - MYF(MY_WME)); - if (!command_buffer) - return HA_ERR_OUT_OF_MEM; - - command_buffer_length = expanded_length; - - return 0; -} - -int clustrix_connection::add_command_operand_uchar(uchar value) -{ - int error_code = expand_command_buffer(sizeof(value)); - if (error_code) - return error_code; - - memcpy(command_buffer + command_length, &value, sizeof(value)); - command_length += sizeof(value); - - return 0; -} - -int clustrix_connection::add_command_operand_ushort(ushort value) -{ - ushort be_value = htobe16(value); - int error_code = expand_command_buffer(sizeof(be_value)); - if (error_code) - return error_code; - - memcpy(command_buffer + command_length, &be_value, sizeof(be_value)); - command_length += sizeof(be_value); - return 0; -} - -int clustrix_connection::add_command_operand_uint(uint value) -{ - uint be_value = htobe32(value); - int error_code = expand_command_buffer(sizeof(be_value)); - if (error_code) - return error_code; - - memcpy(command_buffer + command_length, &be_value, sizeof(be_value)); - command_length += sizeof(be_value); - return 0; -} - -int clustrix_connection::add_command_operand_ulonglong(ulonglong value) -{ - ulonglong be_value = htobe64(value); - int error_code = expand_command_buffer(sizeof(be_value)); - if (error_code) - return error_code; - - memcpy(command_buffer + command_length, &be_value, sizeof(be_value)); - command_length += sizeof(be_value); - return 0; -} - -int clustrix_connection::add_command_operand_lcb(ulonglong value) -{ - int len = net_length_size(value); - int error_code = expand_command_buffer(len); - if (error_code) - return error_code; - - net_store_length(command_buffer + command_length, value); - command_length += len; - return 0; -} - -int clustrix_connection::add_command_operand_str(const uchar *str, - size_t str_length) -{ - int error_code = add_command_operand_lcb(str_length); - if (error_code) - return error_code; - - if (!str_length) - return 0; - - error_code = expand_command_buffer(str_length); - if (error_code) - return error_code; - - memcpy(command_buffer + command_length, str, str_length); - command_length += str_length; - return 0; -} - -/** - * @brief - * Puts variable length string into the buffer. - * @details - * Puts into the buffer variable length string the size - * of which is send by other means. For details see - * MDB Client/Server Protocol. - * @args - * str - string to send - * str_length - size - **/ -int clustrix_connection::add_command_operand_vlstr(const uchar *str, - size_t str_length) -{ - int error_code = expand_command_buffer(str_length); - if (error_code) - return error_code; - - memcpy(command_buffer + command_length, str, str_length); - command_length += str_length; - return 0; -} - -int clustrix_connection::add_command_operand_lex_string(LEX_CSTRING str) -{ - return add_command_operand_str((const uchar *)str.str, str.length); -} - -int clustrix_connection::add_command_operand_bitmap(MY_BITMAP *bitmap) -{ - int error_code = add_command_operand_lcb(bitmap->n_bits); - if (error_code) - return error_code; - - int no_bytes = no_bytes_in_map(bitmap); - error_code = expand_command_buffer(no_bytes); - if (error_code) - return error_code; - - memcpy(command_buffer + command_length, bitmap->bitmap, no_bytes); - command_length += no_bytes; - return 0; -} diff --git a/storage/clustrixdb/clustrix_connection.h b/storage/clustrixdb/clustrix_connection.h deleted file mode 100644 index f2a48f3da6c..00000000000 --- a/storage/clustrixdb/clustrix_connection.h +++ /dev/null @@ -1,123 +0,0 @@ -/***************************************************************************** -Copyright (c) 2019, MariaDB Corporation. -*****************************************************************************/ - -#ifndef _clustrix_connection_h -#define _clustrix_connection_h - -#ifdef USE_PRAGMA_INTERFACE -#pragma interface /* gcc class implementation */ -#endif - -#define MYSQL_SERVER 1 -#include "my_global.h" -#include "m_string.h" -#include "mysql.h" -#include "sql_common.h" -#include "my_base.h" -#include "mysqld_error.h" -#include "my_bitmap.h" -#include "handler.h" - -#define CLUSTRIX_SERVER_REQUEST 30 - -typedef enum clustrix_lock_mode { - CLUSTRIX_NO_LOCKS, - CLUSTRIX_SHARED, - CLUSTRIX_EXCLUSIVE, -} clustrix_lock_mode_t; - -class clustrix_connection_cursor; -class clustrix_connection -{ -private: - MYSQL clustrix_net; - uchar *command_buffer; - size_t command_buffer_length; - size_t command_length; - - int trans_state; - int trans_flags; - int allocate_cursor(MYSQL *clustrix_net, ulong buffer_size, - clustrix_connection_cursor **scan); -public: - clustrix_connection(); - ~clustrix_connection(); - - inline bool is_connected() - { - return clustrix_net.net.vio; - } - int connect(); - void disconnect(bool is_destructor = FALSE); - - bool has_open_transaction(); - int commit_transaction(); - int rollback_transaction(); - int begin_transaction_next(); - int new_statement_next(); - int rollback_statement_next(); // also starts new statement - void auto_commit_next(); - void auto_commit_closed(); - - int run_query(String &stmt); - int write_row(ulonglong clustrix_table_oid, uchar *packed_row, - size_t packed_size, ulonglong *last_insert_id); - int key_update(ulonglong clustrix_table_oid, - uchar *packed_key, size_t packed_key_length, - MY_BITMAP *update_set, - uchar *packed_new_data, size_t packed_new_length); - int key_delete(ulonglong clustrix_table_oid, - uchar *packed_key, size_t packed_key_length); - int key_read(ulonglong clustrix_table_oid, uint index, - clustrix_lock_mode_t lock_mode, MY_BITMAP *read_set, - uchar *packed_key, ulong packed_key_length, uchar **rowdata, - ulong *rowdata_length); - enum sort_order {SORT_NONE = 0, SORT_ASC = 1, SORT_DESC = 2}; - enum scan_type { - READ_KEY_OR_NEXT, /* rows with key and greater */ - READ_KEY_OR_PREV, /* rows with key and less. */ - READ_AFTER_KEY, /* rows with keys greater than key */ - READ_BEFORE_KEY, /* rows with keys less than key */ - READ_FROM_START, /* rows with forwards from first key. */ - READ_FROM_LAST, /* rows with backwards from last key. */ - }; - int scan_table(ulonglong clustrix_table_oid, - clustrix_lock_mode_t lock_mode, - MY_BITMAP *read_set, ushort row_req, - clustrix_connection_cursor **scan); - int scan_query(String &stmt, uchar *fieldtype, uint fields, uchar *null_bits, - uint null_bits_size, uchar *field_metadata, - uint field_metadata_size, ushort row_req, - clustrix_connection_cursor **scan); - int update_query(String &stmt, LEX_CSTRING &dbname, ulonglong *affected_rows); - int scan_from_key(ulonglong clustrix_table_oid, uint index, - clustrix_lock_mode_t lock_mode, - enum scan_type scan_dir, int no_key_cols, bool sorted_scan, - MY_BITMAP *read_set, uchar *packed_key, - ulong packed_key_length, ushort row_req, - clustrix_connection_cursor **scan); - int scan_next(clustrix_connection_cursor *scan, uchar **rowdata, - ulong *rowdata_length); - int scan_end(clustrix_connection_cursor *scan); - - int populate_table_list(LEX_CSTRING *db, handlerton::discovered_list *result); - int discover_table_details(LEX_CSTRING *db, LEX_CSTRING *name, THD *thd, - TABLE_SHARE *share); - -private: - int expand_command_buffer(size_t add_length); - int add_command_operand_uchar(uchar value); - int add_command_operand_ushort(ushort value); - int add_command_operand_uint(uint value); - int add_command_operand_ulonglong(ulonglong value); - int add_command_operand_lcb(ulonglong value); - int add_command_operand_str(const uchar *str, size_t length); - int add_command_operand_vlstr(const uchar *str, size_t length); - int add_command_operand_lex_string(LEX_CSTRING str); - int add_command_operand_bitmap(MY_BITMAP *bitmap); - int begin_command(uchar command); - int send_command(); - int read_query_response(); -}; -#endif // _clustrix_connection_h diff --git a/storage/clustrixdb/ha_clustrixdb.cc b/storage/clustrixdb/ha_clustrixdb.cc deleted file mode 100644 index d80ab91653b..00000000000 --- a/storage/clustrixdb/ha_clustrixdb.cc +++ /dev/null @@ -1,1372 +0,0 @@ -/***************************************************************************** -Copyright (c) 2019, MariaDB Corporation. -*****************************************************************************/ - -/** @file ha_clustrixdb.cc */ - -#include "ha_clustrixdb.h" -#include "ha_clustrixdb_pushdown.h" -#include "key.h" - -handlerton *clustrixdb_hton = NULL; - -int clustrix_connect_timeout; -static MYSQL_SYSVAR_INT -( - connect_timeout, - clustrix_connect_timeout, - PLUGIN_VAR_OPCMDARG, - "Timeout for connecting to Clustrix", - NULL, NULL, -1, -1, 2147483647, 0 -); - -int clustrix_read_timeout; -static MYSQL_SYSVAR_INT -( - read_timeout, - clustrix_read_timeout, - PLUGIN_VAR_OPCMDARG, - "Timeout for receiving data from Clustrix", - NULL, NULL, -1, -1, 2147483647, 0 -); - -int clustrix_write_timeout; -static MYSQL_SYSVAR_INT -( - write_timeout, - clustrix_write_timeout, - PLUGIN_VAR_OPCMDARG, - "Timeout for sending data to Clustrix", - NULL, NULL, -1, -1, 2147483647, 0 -); - -char *clustrix_host; -static MYSQL_SYSVAR_STR -( - host, - clustrix_host, - PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_MEMALLOC, - "Clustrix host", - NULL, NULL, "127.0.0.1" -); - -int host_list_cnt; -char **host_list; - -static void free_host_list() -{ - if (host_list) { - for (int i = 0; host_list[i]; i++) - my_free(host_list[i]); - my_free(host_list); - host_list = NULL; - } -} - -static void update_host_list(char *clustrix_host) -{ - free_host_list(); - - int cnt = 0; - for (char *p = clustrix_host, *s = clustrix_host; ; p++) { - if (*p == ',' || *p == '\0') { - if (p > s) { - cnt++; - } - if (!*p) - break; - s = p + 1; - } - } - - DBUG_PRINT("host_cnt", ("%d", cnt)); - host_list = (char **)my_malloc(sizeof(char *) * cnt+1, MYF(MY_WME)); - host_list[cnt] = 0; - host_list_cnt = cnt; - - int i = 0; - for (char *p = clustrix_host, *s = clustrix_host; ; p++) { - if (*p == ',' || *p == '\0') { - if (p > s) { - char *host = (char *)my_malloc(p - s + 1, MYF(MY_WME)); - host[p-s] = '\0'; - memcpy(host, s, p-s); - DBUG_PRINT("host", ("%s", host)); - host_list[i++] = host; - } - if (!*p) - break; - s = p + 1; - } - } - - DBUG_PRINT("clustrix_host", ("%s", clustrix_host)); -} - -char *clustrix_username; -static MYSQL_SYSVAR_STR -( - username, - clustrix_username, - PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_MEMALLOC, - "Clustrix user name", - NULL, NULL, "root" -); - -char *clustrix_password; -static MYSQL_SYSVAR_STR -( - password, - clustrix_password, - PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_MEMALLOC, - "Clustrix password", - NULL, NULL, "" -); - -uint clustrix_port; -static MYSQL_SYSVAR_UINT -( - port, - clustrix_port, - PLUGIN_VAR_RQCMDARG, - "Clustrix port", - NULL, NULL, MYSQL_PORT_DEFAULT, MYSQL_PORT_DEFAULT, 65535, 0 -); - -char *clustrix_socket; -static MYSQL_SYSVAR_STR -( - socket, - clustrix_socket, - PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_MEMALLOC, - "Clustrix socket", - NULL, NULL, "" -); - -static MYSQL_THDVAR_UINT -( - row_buffer, - PLUGIN_VAR_RQCMDARG, - "Clustrix rowstore row buffer size", - NULL, NULL, 20, 1, 65535, 0 -); - -// Per thread select handler knob -static MYSQL_THDVAR_BOOL( - select_handler, - PLUGIN_VAR_NOCMDARG, - "", - NULL, - NULL, - 1 -); - -// Per thread derived handler knob -static MYSQL_THDVAR_BOOL( - derived_handler, - PLUGIN_VAR_NOCMDARG, - "", - NULL, - NULL, - 1 -); - -static MYSQL_THDVAR_BOOL( - enable_direct_update, - PLUGIN_VAR_NOCMDARG, - "", - NULL, - NULL, - 1 -); - -bool select_handler_setting(THD* thd) -{ - return ( thd == NULL ) ? false : THDVAR(thd, select_handler); -} - -bool derived_handler_setting(THD* thd) -{ - return ( thd == NULL ) ? false : THDVAR(thd, derived_handler); -} - -uint row_buffer_setting(THD* thd) -{ - return THDVAR(thd, row_buffer); -} - -/**************************************************************************** -** Utility functions -****************************************************************************/ -// This is a wastefull aproach but better then fixed sized buffer. -size_t estimate_row_size(TABLE *table) -{ - size_t row_size = 0; - size_t null_byte_count = (bitmap_bits_set(table->write_set) + 7) / 8; - row_size += null_byte_count; - Field **p_field= table->field, *field; - for ( ; (field= *p_field) ; p_field++) { - row_size += field->max_data_length(); - } - return row_size; -} - -/** - * @brief - * Decodes object name. - * - * @details - * Replaces the encoded object name in the path with a decoded variant, - * e.g if path contains ./test/d@0024. This f() makes it ./test/d$ - * - * Used in delete and rename DDL processing. - **/ -static void decode_objectname(char *buf, const char *path, size_t buf_size) -{ - size_t new_path_len = filename_to_tablename(path, buf, buf_size); - buf[new_path_len] = '\0'; -} - -static void decode_file_path(const char *path, char *decoded_dbname, - char *decoded_tbname) -{ - // The format cont ains './' in the beginning of a path. - char *dbname_start = (char*) path + 2; - char *dbname_end = dbname_start; - while (*dbname_end != '/') - dbname_end++; - - int cnt = dbname_end - dbname_start; - char *dbname = (char *)my_alloca(cnt + 1); - memcpy(dbname, dbname_start, cnt); - dbname[cnt] = '\0'; - decode_objectname(decoded_dbname, dbname, FN_REFLEN); - my_afree(dbname); - - char *tbname_start = dbname_end + 1; - decode_objectname(decoded_tbname, tbname_start, FN_REFLEN); -} - -clustrix_connection *get_trx(THD *thd, int *error_code) -{ - *error_code = 0; - clustrix_connection *trx; - if (!(trx = (clustrix_connection *)thd_get_ha_data(thd, clustrixdb_hton))) - { - if (!(trx = new clustrix_connection())) { - *error_code = HA_ERR_OUT_OF_MEM; - return NULL; - } - - *error_code = trx->connect(); - if (*error_code) { - delete trx; - return NULL; - } - - thd_set_ha_data(thd, clustrixdb_hton, trx); - } - - return trx; -} -/**************************************************************************** -** Class ha_clustrixdb -****************************************************************************/ - -ha_clustrixdb::ha_clustrixdb(handlerton *hton, TABLE_SHARE *table_arg) - : handler(hton, table_arg) -{ - DBUG_ENTER("ha_clustrixdb::ha_clustrixdb"); - rgi = NULL; - scan_cur = NULL; - clustrix_table_oid = 0; - upsert_flag = 0; - DBUG_VOID_RETURN; -} - -ha_clustrixdb::~ha_clustrixdb() -{ - if (rgi) - remove_current_table_from_rpl_table_list(rgi); -} - -int ha_clustrixdb::create(const char *name, TABLE *form, HA_CREATE_INFO *info) -{ - int error_code; - THD *thd = ha_thd(); - clustrix_connection *trx = get_trx(thd, &error_code); - if (!trx) - return error_code; - - enum tmp_table_type saved_tmp_table_type = form->s->tmp_table; - Table_specification_st *create_info = &thd->lex->create_info; - const bool is_tmp_table = info->options & HA_LEX_CREATE_TMP_TABLE; - String create_table_stmt; - - /* Create a copy of the CREATE TABLE statement */ - if (!is_tmp_table) - form->s->tmp_table = NO_TMP_TABLE; - const char *old_dbstr = thd->db.str; - thd->db.str = NULL; - ulong old = create_info->used_fields; - create_info->used_fields &= ~HA_CREATE_USED_ENGINE; - - TABLE_LIST table_list; - memset(&table_list, 0, sizeof(table_list)); - table_list.table = form; - error_code = show_create_table(thd, &table_list, &create_table_stmt, - create_info, WITH_DB_NAME); - - if (!is_tmp_table) - form->s->tmp_table = saved_tmp_table_type; - create_info->used_fields = old; - thd->db.str = old_dbstr; - if (error_code) - return error_code; - - // To syncronize the schemas of MDB FE and CLX BE. - if (form->s && form->s->db.length) { - String createdb_stmt; - createdb_stmt.append("CREATE DATABASE IF NOT EXISTS `"); - createdb_stmt.append(form->s->db.str, form->s->db.length); - createdb_stmt.append("`"); - trx->run_query(createdb_stmt); - } - - error_code = trx->run_query(create_table_stmt); - return error_code; -} - -int ha_clustrixdb::delete_table(const char *path) -{ - int error_code; - THD *thd = ha_thd(); - clustrix_connection *trx = get_trx(thd, &error_code); - if (!trx) - return error_code; - - char decoded_dbname[FN_REFLEN]; - char decoded_tbname[FN_REFLEN]; - decode_file_path(path, decoded_dbname, decoded_tbname); - - String delete_cmd; - delete_cmd.append("DROP TABLE `"); - delete_cmd.append(decoded_dbname); - delete_cmd.append("`.`"); - delete_cmd.append(decoded_tbname); - delete_cmd.append("`"); - - return trx->run_query(delete_cmd); -} - -int ha_clustrixdb::rename_table(const char* from, const char* to) -{ - int error_code; - THD *thd = ha_thd(); - clustrix_connection *trx = get_trx(thd, &error_code); - if (!trx) - return error_code; - - char decoded_from_dbname[FN_REFLEN]; - char decoded_from_tbname[FN_REFLEN]; - decode_file_path(from, decoded_from_dbname, decoded_from_tbname); - - char decoded_to_dbname[FN_REFLEN]; - char decoded_to_tbname[FN_REFLEN]; - decode_file_path(to, decoded_to_dbname, decoded_to_tbname); - - String rename_cmd; - rename_cmd.append("RENAME TABLE `"); - rename_cmd.append(decoded_from_dbname); - rename_cmd.append("`.`"); - rename_cmd.append(decoded_from_tbname); - rename_cmd.append("` TO `"); - rename_cmd.append(decoded_to_dbname); - rename_cmd.append("`.`"); - rename_cmd.append(decoded_to_tbname); - rename_cmd.append("`;"); - - return trx->run_query(rename_cmd); -} - -static void -clustrixdb_mark_table_for_discovery(TABLE *table) -{ - table->s->tabledef_version.str = NULL; - table->s->tabledef_version.length = 0; - table->m_needs_reopen = TRUE; -} - -int ha_clustrixdb::open(const char *name, int mode, uint test_if_locked) -{ - DBUG_ENTER("ha_clustrixdb::open"); - DBUG_PRINT("oid", - ("%s", table->s->tabledef_version.str)); - - if (!table->s->tabledef_version.str) - DBUG_RETURN(HA_ERR_TABLE_DEF_CHANGED); - if (!clustrix_table_oid) - clustrix_table_oid = atoll((const char *)table->s->tabledef_version.str); - - // Surrogate key marker - has_hidden_key = table->s->primary_key == MAX_KEY; - if (has_hidden_key) { - ref_length = 8; - } else { - KEY* key_info = table->key_info + table->s->primary_key; - ref_length = key_info->key_length; - } - - DBUG_PRINT("open finished", - ("oid: %llu, ref_length: %u", clustrix_table_oid, ref_length)); - DBUG_RETURN(0); -} - -int ha_clustrixdb::close(void) -{ - return 0; -} - -int ha_clustrixdb::reset() -{ - upsert_flag &= ~CLUSTRIX_BULK_UPSERT; - upsert_flag &= ~CLUSTRIX_HAS_UPSERT; - upsert_flag &= ~CLUSTRIX_UPSERT_SENT; - clx_lock_type = CLUSTRIX_NO_LOCKS; - return 0; -} - -int ha_clustrixdb::extra(enum ha_extra_function operation) -{ - DBUG_ENTER("ha_clustrixdb::extra"); - if (operation == HA_EXTRA_INSERT_WITH_UPDATE) - upsert_flag |= CLUSTRIX_HAS_UPSERT; - DBUG_RETURN(0); -} - -/*@brief UPSERT State Machine*/ -/************************************************************* - * DESCRIPTION: - * Fasttrack for UPSERT sends queries down to a CLX backend. - * UPSERT could be of two kinds: singular and bulk. The plugin - * re-/sets CLUSTRIX_BULK_UPSERT in end|start_bulk_insert - * methods. CLUSTRIX_UPSERT_SENT is used to avoid multiple - * execution at CLX backend. - * Generic CLUSTRIX_HAS_UPSERT is set for bulk UPSERT only b/c - * MDB calls write_row only once. - ************************************************************/ -int ha_clustrixdb::write_row(const uchar *buf) -{ - int error_code = 0; - THD *thd = ha_thd(); - clustrix_connection *trx = get_trx(thd, &error_code); - if (!trx) - return error_code; - - if (upsert_flag & CLUSTRIX_HAS_UPSERT) { - if (!(upsert_flag & CLUSTRIX_UPSERT_SENT)) { - ha_rows update_rows; - String update_stmt; - update_stmt.append(thd->query_string.str()); - - if (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) - trx->auto_commit_next(); - - error_code= trx->update_query(update_stmt, table->s->db, &update_rows); - if (upsert_flag & CLUSTRIX_BULK_UPSERT) - upsert_flag |= CLUSTRIX_UPSERT_SENT; - else - upsert_flag &= ~CLUSTRIX_HAS_UPSERT; - } - - return error_code; - } - - /* Convert the row format to binlog (packed) format */ - uchar *packed_new_row = (uchar*) my_alloca(estimate_row_size(table)); - size_t packed_size = pack_row(table, table->write_set, packed_new_row, buf); - - /* XXX: Clustrix may needs to return HA_ERR_AUTOINC_ERANGE if we hit that - error. */ - ulonglong last_insert_id = 0; - if ((error_code = trx->write_row(clustrix_table_oid, - packed_new_row, packed_size, - &last_insert_id))) - goto err; - - if (table->next_number_field) - insert_id_for_cur_row = last_insert_id; - -err: - if (error_code == HA_ERR_TABLE_DEF_CHANGED) - clustrixdb_mark_table_for_discovery(table); - - if (packed_size) - my_afree(packed_new_row); - - return error_code; -} - -int ha_clustrixdb::update_row(const uchar *old_data, const uchar *new_data) -{ - DBUG_ENTER("ha_clustrixdb::update_row"); - int error_code; - THD *thd = ha_thd(); - clustrix_connection *trx = get_trx(thd, &error_code); - if (!trx) - DBUG_RETURN(error_code); - - size_t row_size = estimate_row_size(table); - size_t packed_key_len; - uchar *packed_key = (uchar*) my_alloca(row_size); - build_key_packed_row(table->s->primary_key, old_data, - packed_key, &packed_key_len); - - uchar *packed_new_row = (uchar*) my_alloca(row_size); - size_t packed_new_size = pack_row(table, table->write_set, packed_new_row, - new_data); - - /* Send the packed rows to Clustrix */ - error_code = trx->key_update(clustrix_table_oid, packed_key, packed_key_len, - table->write_set, - packed_new_row, packed_new_size); - - if(packed_key) - my_afree(packed_key); - - if(packed_new_row) - my_afree(packed_new_row); - - if (error_code == HA_ERR_TABLE_DEF_CHANGED) - clustrixdb_mark_table_for_discovery(table); - - DBUG_RETURN(error_code); -} - -int ha_clustrixdb::direct_update_rows_init(List *update_fields) -{ - DBUG_ENTER("ha_clustrixdb::direct_update_rows_init"); - THD *thd= ha_thd(); - if (!THDVAR(thd, enable_direct_update)) - DBUG_RETURN(HA_ERR_WRONG_COMMAND); - DBUG_RETURN(0); -} - -int ha_clustrixdb::direct_update_rows(ha_rows *update_rows, ha_rows *found_rows) -{ - DBUG_ENTER("ha_clustrixdb::direct_update_rows"); - int error_code= 0; - THD *thd= ha_thd(); - clustrix_connection *trx= get_trx(thd, &error_code); - if (!trx) - return error_code; - - String update_stmt; - update_stmt.append(thd->query_string.str()); - - if (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) - trx->auto_commit_next(); - - error_code = trx->update_query(update_stmt, table->s->db, update_rows); - *found_rows = *update_rows; - DBUG_RETURN(error_code); -} - -void ha_clustrixdb::start_bulk_insert(ha_rows rows, uint flags) -{ - DBUG_ENTER("ha_clustrixdb::start_bulk_insert"); - int error_code= 0; - THD *thd= ha_thd(); - clustrix_connection *trx= get_trx(thd, &error_code); - if (!trx) { - // TBD log this - DBUG_VOID_RETURN; - } - - upsert_flag |= CLUSTRIX_BULK_UPSERT; - - DBUG_VOID_RETURN; -} - -int ha_clustrixdb::end_bulk_insert() -{ - DBUG_ENTER("ha_clustrixdb::end_bulk_insert"); - upsert_flag &= ~CLUSTRIX_BULK_UPSERT; - upsert_flag &= ~CLUSTRIX_HAS_UPSERT; - upsert_flag &= ~CLUSTRIX_UPSERT_SENT; - DBUG_RETURN(0); -} - -int ha_clustrixdb::delete_row(const uchar *buf) -{ - int error_code; - THD *thd = ha_thd(); - clustrix_connection *trx = get_trx(thd, &error_code); - if (!trx) - return error_code; - - // The estimate should consider only key fields widths. - size_t packed_key_len; - uchar *packed_key = (uchar*) my_alloca(estimate_row_size(table)); - build_key_packed_row(table->s->primary_key, buf, packed_key, &packed_key_len); - - error_code = trx->key_delete(clustrix_table_oid, packed_key, packed_key_len); - - if (error_code == HA_ERR_TABLE_DEF_CHANGED) - clustrixdb_mark_table_for_discovery(table); - - if (packed_key) - my_afree(packed_key); - - return error_code; -} - -ha_clustrixdb::Table_flags ha_clustrixdb::table_flags(void) const -{ - Table_flags flags = HA_PARTIAL_COLUMN_READ | - HA_REC_NOT_IN_SEQ | - HA_FAST_KEY_READ | - HA_NULL_IN_KEY | - HA_CAN_INDEX_BLOBS | - HA_AUTO_PART_KEY | - HA_CAN_SQL_HANDLER | - HA_BINLOG_STMT_CAPABLE | - HA_CAN_TABLE_CONDITION_PUSHDOWN | - HA_CAN_DIRECT_UPDATE_AND_DELETE; - - return flags; -} - -ulong ha_clustrixdb::index_flags(uint idx, uint part, bool all_parts) const -{ - ulong flags = HA_READ_NEXT | - HA_READ_PREV | - HA_READ_ORDER | - HA_READ_RANGE; - - return flags; -} - -ha_rows ha_clustrixdb::records() -{ - return 10000; -} - -ha_rows ha_clustrixdb::records_in_range(uint inx, key_range *min_key, - key_range *max_key) -{ - return 2; -} - -int ha_clustrixdb::info(uint flag) -{ - //THD *thd = ha_thd(); - if (flag & HA_STATUS_TIME) - { - /* Retrieve the time of the most recent update to the table */ - // stats.update_time = - } - - if (flag & HA_STATUS_AUTO) - { - /* Retrieve the latest auto_increment value */ - stats.auto_increment_value = next_insert_id; - } - - if (flag & HA_STATUS_VARIABLE) - { - /* Retrieve variable info, such as row counts and file lengths */ - stats.records = records(); - stats.deleted = 0; - // stats.data_file_length = - // stats.index_file_length = - // stats.delete_length = - stats.check_time = 0; - // stats.mrr_length_per_rec = - - if (stats.records == 0) - stats.mean_rec_length = 0; - else - stats.mean_rec_length = (ulong) - (stats.data_file_length / stats.records); - } - - if (flag & HA_STATUS_CONST) - { - /* - Retrieve constant info, such as file names, max file lengths, - create time, block size - */ - // stats.max_data_file_length = - // stats.create_time = - // stats.block_size = - } - - return 0; -} - -int ha_clustrixdb::index_init(uint idx, bool sorted) -{ - int error_code = 0; - THD *thd = ha_thd(); - clustrix_connection *trx = get_trx(thd, &error_code); - if (!trx) - return error_code; - - active_index = idx; - add_current_table_to_rpl_table_list(&rgi, thd, table); - scan_cur = NULL; - - /* Return all columns until there is a better understanding of - requirements. */ - if (my_bitmap_init(&scan_fields, NULL, table->read_set->n_bits, false)) - return ER_OUTOFMEMORY; - bitmap_set_all(&scan_fields); - sorted_scan = sorted; - - return 0; -} - -int ha_clustrixdb::index_read(uchar * buf, const uchar * key, uint key_len, - enum ha_rkey_function find_flag) -{ - DBUG_ENTER("ha_clustrixdb::index_read"); - int error_code = 0; - THD *thd = ha_thd(); - clustrix_connection *trx = get_trx(thd, &error_code); - if (!trx) - DBUG_RETURN(error_code); - - key_restore(buf, key, &table->key_info[active_index], key_len); - // The estimate should consider only key fields widths. - size_t packed_key_len; - uchar *packed_key = (uchar*) my_alloca(estimate_row_size(table)); - build_key_packed_row(active_index, buf, packed_key, &packed_key_len); - - bool exact = false; - clustrix_connection::scan_type st; - switch (find_flag) { - case HA_READ_KEY_EXACT: - exact = true; - break; - case HA_READ_KEY_OR_NEXT: - st = clustrix_connection::READ_KEY_OR_NEXT; - break; - case HA_READ_KEY_OR_PREV: - st = clustrix_connection::READ_KEY_OR_PREV; - break; - case HA_READ_AFTER_KEY: - st = clustrix_connection::READ_AFTER_KEY; - break; - case HA_READ_BEFORE_KEY: - st = clustrix_connection::READ_BEFORE_KEY; - break; - case HA_READ_PREFIX: - case HA_READ_PREFIX_LAST: - case HA_READ_PREFIX_LAST_OR_PREV: - case HA_READ_MBR_CONTAIN: - case HA_READ_MBR_INTERSECT: - case HA_READ_MBR_WITHIN: - case HA_READ_MBR_DISJOINT: - case HA_READ_MBR_EQUAL: - DBUG_RETURN(ER_NOT_SUPPORTED_YET); - } - - uchar *rowdata = NULL; - if (exact) { - is_scan = false; - ulong rowdata_length; - error_code = trx->key_read(clustrix_table_oid, 0, clx_lock_type, - table->read_set, packed_key, packed_key_len, - &rowdata, &rowdata_length); - if (!error_code) - error_code = unpack_row_to_buf(rgi, table, buf, rowdata, - table->read_set, - rowdata + rowdata_length); - } else { - is_scan = true; - error_code = trx->scan_from_key(clustrix_table_oid, active_index, - clx_lock_type, st, -1, sorted_scan, - &scan_fields, packed_key, packed_key_len, - THDVAR(thd, row_buffer), &scan_cur); - if (!error_code) - error_code = rnd_next(buf); - } - - if (rowdata) - my_free(rowdata); - - if (packed_key) - my_afree(packed_key); - - if (error_code == HA_ERR_TABLE_DEF_CHANGED) - clustrixdb_mark_table_for_discovery(table); - - DBUG_RETURN(error_code); -} - -int ha_clustrixdb::index_first(uchar *buf) -{ - DBUG_ENTER("ha_clustrixdb::index_first"); - int error_code = 0; - THD *thd = ha_thd(); - clustrix_connection *trx = get_trx(thd, &error_code); - if (!trx) - DBUG_RETURN(error_code); - - error_code = trx->scan_from_key(clustrix_table_oid, active_index, - clx_lock_type, - clustrix_connection::READ_FROM_START, - -1, sorted_scan, &scan_fields, NULL, 0, - THDVAR(thd, row_buffer), &scan_cur); - - if (error_code == HA_ERR_TABLE_DEF_CHANGED) - clustrixdb_mark_table_for_discovery(table); - - if (error_code) - DBUG_RETURN(error_code); - - DBUG_RETURN(rnd_next(buf)); -} - -int ha_clustrixdb::index_last(uchar *buf) -{ - DBUG_ENTER("ha_clustrixdb::index_last"); - int error_code = 0; - THD *thd = ha_thd(); - clustrix_connection *trx = get_trx(thd, &error_code); - if (!trx) - DBUG_RETURN(error_code); - - error_code = trx->scan_from_key(clustrix_table_oid, active_index, - clx_lock_type, - clustrix_connection::READ_FROM_LAST, - -1, sorted_scan, &scan_fields, NULL, 0, - THDVAR(thd, row_buffer), &scan_cur); - - if (error_code == HA_ERR_TABLE_DEF_CHANGED) - clustrixdb_mark_table_for_discovery(table); - - if (error_code) - DBUG_RETURN(error_code); - - DBUG_RETURN(rnd_next(buf)); -} - -int ha_clustrixdb::index_next(uchar *buf) -{ - DBUG_ENTER("index_next"); - DBUG_RETURN(rnd_next(buf)); -} - -#if 0 -int ha_clustrixdb::index_next_same(uchar *buf, const uchar *key, uint keylen) -{ - DBUG_ENTER("index_next_same"); - DBUG_RETURN(rnd_next(buf)); -} -#endif - -int ha_clustrixdb::index_prev(uchar *buf) -{ - DBUG_ENTER("index_prev"); - DBUG_RETURN(rnd_next(buf)); -} - -int ha_clustrixdb::index_end() -{ - DBUG_ENTER("index_prev"); - if (scan_cur) - DBUG_RETURN(rnd_end()); - else - DBUG_RETURN(0); -} - -int ha_clustrixdb::rnd_init(bool scan) -{ - DBUG_ENTER("ha_clustrixdb::rnd_init"); - int error_code = 0; - THD *thd = ha_thd(); - if (thd->lex->sql_command == SQLCOM_UPDATE) - DBUG_RETURN(error_code); - clustrix_connection *trx = get_trx(thd, &error_code); - if (!trx) - DBUG_RETURN(error_code); - - add_current_table_to_rpl_table_list(&rgi, thd, table); - is_scan = scan; - scan_cur = NULL; - - if (my_bitmap_init(&scan_fields, NULL, table->read_set->n_bits, false)) - DBUG_RETURN(ER_OUTOFMEMORY); - -#if 0 - if (table->s->keys) - table->mark_columns_used_by_index(table->s->primary_key, &scan_fields); - else - bitmap_clear_all(&scan_fields); - - bitmap_union(&scan_fields, table->read_set); -#else - /* Why is read_set not setup correctly? */ - bitmap_set_all(&scan_fields); -#endif - - error_code = trx->scan_table(clustrix_table_oid, clx_lock_type, - &scan_fields, THDVAR(thd, row_buffer), - &scan_cur); - - if (error_code == HA_ERR_TABLE_DEF_CHANGED) - clustrixdb_mark_table_for_discovery(table); - - if (error_code) - DBUG_RETURN(error_code); - - DBUG_RETURN(0); -} - -int ha_clustrixdb::rnd_next(uchar *buf) -{ - int error_code = 0; - THD *thd = ha_thd(); - clustrix_connection *trx = get_trx(thd, &error_code); - if (!trx) - return error_code; - - assert(is_scan); - assert(scan_cur); - - uchar *rowdata; - ulong rowdata_length; - if ((error_code = trx->scan_next(scan_cur, &rowdata, &rowdata_length))) - return error_code; - - if (has_hidden_key) { - last_hidden_key = *(ulonglong *)rowdata; - rowdata += 8; - rowdata_length -= 8; - } - - error_code = unpack_row_to_buf(rgi, table, buf, rowdata, &scan_fields, - rowdata + rowdata_length); - - if (error_code) - return error_code; - - return 0; -} - -int ha_clustrixdb::rnd_pos(uchar * buf, uchar *pos) -{ - DBUG_ENTER("clx_rnd_pos"); - DBUG_DUMP("pos", pos, ref_length); - - int error_code = 0; - THD *thd = ha_thd(); - clustrix_connection *trx = get_trx(thd, &error_code); - if (!trx) - DBUG_RETURN(error_code); - - /* WDD: We need a way to convert key buffers directy to rbr buffers. */ - - if (has_hidden_key) { - memcpy(&last_hidden_key, pos, sizeof(ulonglong)); - } else { - uint keyno = table->s->primary_key; - uint len = calculate_key_len(table, keyno, pos, - table->const_key_parts[keyno]); - key_restore(buf, pos, &table->key_info[keyno], len); - } - - // The estimate should consider only key fields widths. - uchar *packed_key = (uchar*) my_alloca(estimate_row_size(table)); - size_t packed_key_len; - build_key_packed_row(table->s->primary_key, buf, packed_key, &packed_key_len); - - uchar *rowdata = NULL; - ulong rowdata_length; - if ((error_code = trx->key_read(clustrix_table_oid, 0, clx_lock_type, - table->read_set, packed_key, packed_key_len, - &rowdata, &rowdata_length))) - goto err; - - if ((error_code = unpack_row_to_buf(rgi, table, buf, rowdata, table->read_set, - rowdata + rowdata_length))) - goto err; - -err: - if (rowdata) - my_free(rowdata); - - if (packed_key) - my_afree(packed_key); - - if (error_code == HA_ERR_TABLE_DEF_CHANGED) - clustrixdb_mark_table_for_discovery(table); - - DBUG_RETURN(error_code); -} - -int ha_clustrixdb::rnd_end() -{ - DBUG_ENTER("ha_clustrixdb::rnd_end()"); - int error_code = 0; - THD *thd = ha_thd(); - if (thd->lex->sql_command == SQLCOM_UPDATE) - DBUG_RETURN(error_code); - - clustrix_connection *trx = get_trx(thd, &error_code); - if (!trx) - DBUG_RETURN(error_code); - - my_bitmap_free(&scan_fields); - if (scan_cur && (error_code = trx->scan_end(scan_cur))) - DBUG_RETURN(error_code); - scan_cur = NULL; - - DBUG_RETURN(0); -} - -void ha_clustrixdb::position(const uchar *record) -{ - DBUG_ENTER("clx_position"); - if (has_hidden_key) { - memcpy(ref, &last_hidden_key, sizeof(ulonglong)); - } else { - KEY* key_info = table->key_info + table->s->primary_key; - key_copy(ref, record, key_info, key_info->key_length); - } - DBUG_DUMP("key", ref, ref_length); - DBUG_VOID_RETURN; -} - -uint ha_clustrixdb::lock_count(void) const -{ - /* Hopefully, we don't need to use thread locks */ - return 0; -} - -THR_LOCK_DATA **ha_clustrixdb::store_lock(THD *thd, - THR_LOCK_DATA **to, - enum thr_lock_type lock_type) -{ - /* Hopefully, we don't need to use thread locks */ - return to; -} - -int ha_clustrixdb::external_lock(THD *thd, int lock_type) -{ - DBUG_ENTER("ha_clustrixdb::external_lock()"); - int error_code; - clustrix_connection *trx = get_trx(thd, &error_code); - if (error_code) - DBUG_RETURN(error_code); - - if (lock_type == F_WRLCK) - clx_lock_type = CLUSTRIX_EXCLUSIVE; - else if (lock_type == F_RDLCK) - clx_lock_type = CLUSTRIX_SHARED; - else if (lock_type == F_UNLCK) - clx_lock_type = CLUSTRIX_NO_LOCKS; - - if (lock_type != F_UNLCK) { - if (!trx->has_open_transaction()) { - error_code = trx->begin_transaction_next(); - if (error_code) - DBUG_RETURN(error_code); - } - - trans_register_ha(thd, FALSE, clustrixdb_hton); - if (thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) - trans_register_ha(thd, TRUE, clustrixdb_hton); - } - - DBUG_RETURN(error_code); -} - -/**************************************************************************** - Engine Condition Pushdown -****************************************************************************/ - -const COND *ha_clustrixdb::cond_push(const COND *cond) -{ - return cond; -} - -void ha_clustrixdb::cond_pop() -{ -} - -int ha_clustrixdb::info_push(uint info_type, void *info) -{ - return 0; -} - -/**************************************************************************** -** Row encoding functions -****************************************************************************/ - -void add_current_table_to_rpl_table_list(rpl_group_info **_rgi, THD *thd, - TABLE *table) -{ - if (*_rgi) - return; - - Relay_log_info *rli = new Relay_log_info(FALSE); - rli->sql_driver_thd = thd; - - rpl_group_info *rgi = new rpl_group_info(rli); - *_rgi = rgi; - rgi->thd = thd; - rgi->tables_to_lock_count = 0; - rgi->tables_to_lock = NULL; - if (rgi->tables_to_lock_count) - return; - - rgi->tables_to_lock = (RPL_TABLE_LIST *)my_malloc(sizeof(RPL_TABLE_LIST), - MYF(MY_WME)); - rgi->tables_to_lock->init_one_table(&table->s->db, &table->s->table_name, 0, - TL_READ); - rgi->tables_to_lock->table = table; - rgi->tables_to_lock->table_id = table->tablenr; - rgi->tables_to_lock->m_conv_table = NULL; - rgi->tables_to_lock->master_had_triggers = FALSE; - rgi->tables_to_lock->m_tabledef_valid = TRUE; - // We need one byte per column to save a column's binlog type. - uchar *col_type = (uchar*) my_alloca(table->s->fields); - for (uint i = 0 ; i < table->s->fields ; ++i) - col_type[i] = table->field[i]->binlog_type(); - - table_def *tabledef = &rgi->tables_to_lock->m_tabledef; - new (tabledef) table_def(col_type, table->s->fields, NULL, 0, NULL, 0); - rgi->tables_to_lock_count++; - if (col_type) - my_afree(col_type); -} - -void remove_current_table_from_rpl_table_list(rpl_group_info *rgi) -{ - if (!rgi->tables_to_lock) - return; - - rgi->tables_to_lock->m_tabledef.table_def::~table_def(); - rgi->tables_to_lock->m_tabledef_valid = FALSE; - my_free(rgi->tables_to_lock); - rgi->tables_to_lock_count--; - rgi->tables_to_lock = NULL; - delete rgi->rli; - delete rgi; -} - -void ha_clustrixdb::build_key_packed_row(uint index, const uchar *buf, - uchar *packed_key, - size_t *packed_key_len) -{ - if (index == table->s->primary_key && has_hidden_key) { - memcpy(packed_key, &last_hidden_key, sizeof(ulonglong)); - *packed_key_len = sizeof(ulonglong); - } else { - // make a row from the table - table->mark_columns_used_by_index(index, &table->tmp_set); - *packed_key_len = pack_row(table, &table->tmp_set, packed_key, buf); - } -} - -int unpack_row_to_buf(rpl_group_info *rgi, TABLE *table, uchar *data, - uchar const *const row_data, MY_BITMAP const *cols, - uchar const *const row_end) -{ - /* Since unpack_row can only write to record[0], if 'data' does not point to - table->record[0], we must back it up and then restore it afterwards. */ - uchar const *current_row_end; - ulong master_reclength; - uchar *backup_row = NULL; - if (data != table->record[0]) { - /* See Update_rows_log_event::do_exec_row(rpl_group_info *rgi) - and the definitions of store_record and restore_record. */ - backup_row = (uchar*) my_alloca(table->s->reclength); - memcpy(backup_row, table->record[0], table->s->reclength); - restore_record(table, record[data == table->record[1] ? 1 : 2]); - } - - int error_code = unpack_row(rgi, table, table->s->fields, row_data, cols, - ¤t_row_end, &master_reclength, row_end); - - if (backup_row) { - store_record(table, record[data == table->record[1] ? 1 : 2]); - memcpy(table->record[0], backup_row, table->s->reclength); - my_afree(backup_row); - } - - return error_code; -} - -/**************************************************************************** -** Plugin Functions -****************************************************************************/ - -static int clustrixdb_commit(handlerton *hton, THD *thd, bool all) -{ - clustrix_connection* trx = (clustrix_connection *) thd_get_ha_data(thd, hton); - assert(trx); - - int error_code = 0; - if (trx->has_open_transaction()) { - if (all || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) - error_code = trx->commit_transaction(); - else - error_code = trx->new_statement_next(); - } - - return error_code; -} - -static int clustrixdb_rollback(handlerton *hton, THD *thd, bool all) -{ - clustrix_connection* trx = (clustrix_connection *) thd_get_ha_data(thd, hton); - assert(trx); - - int error_code = 0; - if (trx->has_open_transaction()) { - if (all || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) - error_code = trx->rollback_transaction(); - else - error_code = trx->rollback_statement_next(); - } - - return error_code; -} - -static handler* clustrixdb_create_handler(handlerton *hton, TABLE_SHARE *table, - MEM_ROOT *mem_root) -{ - return new (mem_root) ha_clustrixdb(hton, table); -} - -static int clustrixdb_close_connection(handlerton* hton, THD* thd) -{ - clustrix_connection* trx = (clustrix_connection *) thd_get_ha_data(thd, hton); - if (!trx) - return 0; /* Transaction is not started */ - - int error_code = clustrixdb_rollback(clustrixdb_hton, thd, TRUE); - - delete trx; - - return error_code; -} - -static int clustrixdb_panic(handlerton *hton, ha_panic_function type) -{ - return 0; -} - -static bool clustrixdb_show_status(handlerton *hton, THD *thd, - stat_print_fn *stat_print, - enum ha_stat_type stat_type) -{ - return FALSE; -} - -static int clustrixdb_discover_table_names(handlerton *hton, LEX_CSTRING *db, - MY_DIR *dir, - handlerton::discovered_list *result) -{ - clustrix_connection *clustrix_net = new clustrix_connection(); - int error_code = clustrix_net->connect(); - if (error_code) - goto err; - - clustrix_net->populate_table_list(db, result); - -err: - delete clustrix_net; - return error_code; -} - -int clustrixdb_discover_table(handlerton *hton, THD *thd, TABLE_SHARE *share) -{ - clustrix_connection *clustrix_net = new clustrix_connection(); - int error_code = clustrix_net->connect(); - if (error_code) - goto err; - - error_code = clustrix_net->discover_table_details(&share->db, - &share->table_name, - thd, share); - -err: - delete clustrix_net; - return error_code; -} - -static int clustrixdb_init(void *p) -{ - DBUG_ENTER("clustrixdb_init"); - clustrixdb_hton = (handlerton *) p; - clustrixdb_hton->flags = HTON_NO_FLAGS; - clustrixdb_hton->panic = clustrixdb_panic; - clustrixdb_hton->close_connection = clustrixdb_close_connection; - clustrixdb_hton->commit = clustrixdb_commit; - clustrixdb_hton->rollback = clustrixdb_rollback; - clustrixdb_hton->create = clustrixdb_create_handler; - clustrixdb_hton->show_status = clustrixdb_show_status; - clustrixdb_hton->discover_table_names = clustrixdb_discover_table_names; - clustrixdb_hton->discover_table = clustrixdb_discover_table; - clustrixdb_hton->create_select = create_clustrixdb_select_handler; - clustrixdb_hton->create_derived = create_clustrixdb_derived_handler; - - update_host_list(clustrix_host); - - DBUG_RETURN(0); -} - -static int clustrixdb_deinit(void *p) -{ - DBUG_ENTER("clustrixdb_deinit"); - free_host_list(); - DBUG_RETURN(0); -} - -struct st_mysql_show_var clustrixdb_status_vars[] = -{ - {NullS, NullS, SHOW_LONG} -}; - -static struct st_mysql_sys_var* clustrixdb_system_variables[] = -{ - MYSQL_SYSVAR(connect_timeout), - MYSQL_SYSVAR(read_timeout), - MYSQL_SYSVAR(write_timeout), - MYSQL_SYSVAR(host), - MYSQL_SYSVAR(username), - MYSQL_SYSVAR(password), - MYSQL_SYSVAR(port), - MYSQL_SYSVAR(socket), - MYSQL_SYSVAR(row_buffer), - MYSQL_SYSVAR(select_handler), - MYSQL_SYSVAR(derived_handler), - MYSQL_SYSVAR(enable_direct_update), - NULL -}; - -static struct st_mysql_storage_engine clustrixdb_storage_engine = - {MYSQL_HANDLERTON_INTERFACE_VERSION}; - -maria_declare_plugin(clustrixdb) -{ - MYSQL_STORAGE_ENGINE_PLUGIN, /* Plugin Type */ - &clustrixdb_storage_engine, /* Plugin Descriptor */ - "CLUSTRIXDB", /* Plugin Name */ - "MariaDB", /* Plugin Author */ - "ClustrixDB storage engine", /* Plugin Description */ - PLUGIN_LICENSE_GPL, /* Plugin Licence */ - clustrixdb_init, /* Plugin Entry Point */ - clustrixdb_deinit, /* Plugin Deinitializer */ - 0x0001, /* Hex Version Number (0.1) */ - NULL /* clustrixdb_status_vars */, /* Status Variables */ - clustrixdb_system_variables, /* System Variables */ - "0.1", /* String Version */ - MariaDB_PLUGIN_MATURITY_EXPERIMENTAL /* Maturity Level */ -} -maria_declare_plugin_end; diff --git a/storage/clustrixdb/ha_clustrixdb.h b/storage/clustrixdb/ha_clustrixdb.h deleted file mode 100644 index 461b17e4438..00000000000 --- a/storage/clustrixdb/ha_clustrixdb.h +++ /dev/null @@ -1,130 +0,0 @@ -/***************************************************************************** -Copyright (c) 2019, MariaDB Corporation. -*****************************************************************************/ - -#ifndef _ha_clustrixdb_h -#define _ha_clustrixdb_h - -#ifdef USE_PRAGMA_INTERFACE -#pragma interface /* gcc class implementation */ -#endif - -#define MYSQL_SERVER 1 -#include "clustrix_connection.h" -#include "my_bitmap.h" -#include "table.h" -#include "rpl_rli.h" -#include "handler.h" -#include "sql_class.h" -#include "sql_show.h" -#include "mysql.h" -#include "../../sql/rpl_record.h" - -size_t estimate_row_size(TABLE *table); -clustrix_connection *get_trx(THD *thd, int *error_code); -bool get_enable_sh(THD* thd); -void add_current_table_to_rpl_table_list(rpl_group_info **_rgi, THD *thd, - TABLE *table); -void remove_current_table_from_rpl_table_list(rpl_group_info *rgi); -int unpack_row_to_buf(rpl_group_info *rgi, TABLE *table, uchar *data, - uchar const *const row_data, MY_BITMAP const *cols, - uchar const *const row_end); - -class ha_clustrixdb : public handler -{ -private: - ulonglong clustrix_table_oid; - rpl_group_info *rgi; - - Field *auto_inc_field; - ulonglong auto_inc_value; - - bool has_hidden_key; - ulonglong last_hidden_key; - clustrix_connection_cursor *scan_cur; - bool is_scan; - MY_BITMAP scan_fields; - bool sorted_scan; - clustrix_lock_mode_t clx_lock_type; - - uint last_dup_errkey; - - typedef enum clustrix_upsert_flags { - CLUSTRIX_HAS_UPSERT= 1, - CLUSTRIX_BULK_UPSERT= 2, - CLUSTRIX_UPSERT_SENT= 4 - } clx_upsert_flags_t; - int upsert_flag; - -public: - ha_clustrixdb(handlerton *hton, TABLE_SHARE *table_arg); - ~ha_clustrixdb(); - int create(const char *name, TABLE *form, HA_CREATE_INFO *info); - int delete_table(const char *name); - int rename_table(const char* from, const char* to); - int open(const char *name, int mode, uint test_if_locked); - int close(void); - int reset(); - int extra(enum ha_extra_function operation); - int write_row(const uchar *buf); - // start_bulk_update exec_bulk_update - int update_row(const uchar *old_data, const uchar *new_data); - // start_bulk_delete exec_bulk_delete - int delete_row(const uchar *buf); - int direct_update_rows_init(List *update_fields); - int direct_update_rows(ha_rows *update_rows, ha_rows *found_rows); - void start_bulk_insert(ha_rows rows, uint flags = 0); - int end_bulk_insert(); - - Table_flags table_flags(void) const; - ulong index_flags(uint idx, uint part, bool all_parts) const; - uint max_supported_keys() const { return MAX_KEY; } - - ha_rows records(); - ha_rows records_in_range(uint inx, key_range *min_key, - key_range *max_key); - - int info(uint flag); // see my_base.h for full description - - // multi_read_range - // read_range - int index_init(uint idx, bool sorted); - int index_read(uchar * buf, const uchar * key, uint key_len, - enum ha_rkey_function find_flag); - int index_first(uchar *buf); - int index_prev(uchar *buf); - int index_last(uchar *buf); - int index_next(uchar *buf); - //int index_next_same(uchar *buf, const uchar *key, uint keylen); - int index_end(); - - int rnd_init(bool scan); - int rnd_next(uchar *buf); - int rnd_pos(uchar * buf, uchar *pos); - int rnd_end(); - - void position(const uchar *record); - uint lock_count(void) const; - THR_LOCK_DATA **store_lock(THD *thd, - THR_LOCK_DATA **to, - enum thr_lock_type lock_type); - int external_lock(THD *thd, int lock_type); - - uint8 table_cache_type() - { - return(HA_CACHE_TBL_NOCACHE); - } - - const COND *cond_push(const COND *cond); - void cond_pop(); - int info_push(uint info_type, void *info); - -private: - void build_key_packed_row(uint index, const uchar *buf, - uchar *packed_key, size_t *packed_key_len); -}; - -bool select_handler_setting(THD* thd); -bool derived_handler_setting(THD* thd); -uint row_buffer_setting(THD* thd); -#endif // _ha_clustrixdb_h diff --git a/storage/clustrixdb/ha_clustrixdb_pushdown.cc b/storage/clustrixdb/ha_clustrixdb_pushdown.cc deleted file mode 100644 index 58cf01cce44..00000000000 --- a/storage/clustrixdb/ha_clustrixdb_pushdown.cc +++ /dev/null @@ -1,478 +0,0 @@ -/***************************************************************************** -Copyright (c) 2019, MariaDB Corporation. -*****************************************************************************/ - -#include "ha_clustrixdb.h" -#include "ha_clustrixdb_pushdown.h" - -extern handlerton *clustrixdb_hton; -extern uint clustrix_row_buffer; - -/*@brief Fills up array data types, metadata and nullability*/ -/************************************************************ - * DESCRIPTION: - * Fills up three arrays with: field binlog data types, field - * metadata and nullability bitmask as in Table_map_log_event - * ctor. Internally creates a temporary table as does - * Pushdown_select. DH uses the actual temp table w/o - * b/c create_DH is called later compared to create_SH. - * More details in server/sql/log_event_server.cc - * PARAMETERS: - * thd - THD* - * table__ - TABLE* temp table for the results - * sl - SELECT_LEX* - * fieldtype - uchar* - * field_metadata - uchar* - * null_bits - uchar* - * num_null_bytes - null bit size - * fields_count - a number of fields - * RETURN: - * metadata_size int or -1 in case of error - ************************************************************/ -int get_field_types(THD *thd, TABLE *table__, SELECT_LEX *sl, uchar *fieldtype, - uchar *field_metadata, uchar *null_bits, const int num_null_bytes, const uint fields_count) -{ - int field_metadata_size = 0; - int metadata_index = 0; - TABLE *tmp_table= table__; - - if (!tmp_table) { - // Construct a tmp table with fields to find out result DTs. - // This should be reconsidered if it worths the effort. - List types; - TMP_TABLE_PARAM tmp_table_param; - sl->master_unit()->join_union_item_types(thd, types, 1); - tmp_table_param.init(); - tmp_table_param.field_count= types.elements; - - tmp_table = create_tmp_table(thd, &tmp_table_param, types, - (ORDER *) 0, false, 0, - TMP_TABLE_ALL_COLUMNS, 1, - &empty_clex_str, true, false); - if (!tmp_table) { - field_metadata_size = -1; - goto err; - } - } - - for (unsigned int i = 0 ; i < fields_count; ++i) { - fieldtype[i]= tmp_table->field[i]->binlog_type(); - } - - bzero(field_metadata, (fields_count * 2)); - for (unsigned int i= 0 ; i < fields_count ; i++) - { - Binlog_type_info bti= tmp_table->field[i]->binlog_type_info(); - uchar *ptr = reinterpret_cast(&bti.m_metadata); - memcpy(&field_metadata[metadata_index], ptr, bti.m_metadata_size); - metadata_index+= bti.m_metadata_size; - } - - if (metadata_index < 251) - field_metadata_size += metadata_index + 1; - else - field_metadata_size += metadata_index + 3; - - bzero(null_bits, num_null_bytes); - for (unsigned int i= 0 ; i < fields_count ; ++i) { - if (tmp_table->field[i]->maybe_null()) { - null_bits[(i / 8)]+= 1 << (i % 8); - } - } - - if (!table__) - free_tmp_table(thd, tmp_table); -err: - return field_metadata_size; -} - - -/*@brief create_clustrixdb_select_handler- Creates handler*/ -/************************************************************ - * DESCRIPTION: - * Creates a select handler - * More details in server/sql/select_handler.h - * PARAMETERS: - * thd - THD pointer. - * sel - SELECT_LEX* that describes the query. - * RETURN: - * select_handler if possible - * NULL otherwise - ************************************************************/ -select_handler* -create_clustrixdb_select_handler(THD* thd, SELECT_LEX* select_lex) -{ - ha_clustrixdb_select_handler *sh = NULL; - if (!select_handler_setting(thd)) { - return sh; - } - - // TODO Return early for EXPLAIN before we run the actual scan. - // We can send compile request when we separate compilation - // and execution. - clustrix_connection_cursor *scan = NULL; - if (thd->lex->describe) { - sh = new ha_clustrixdb_select_handler(thd, select_lex, scan); - return sh; - } - - // Multi-update runs an implicit query to collect constraints. - // SH couldn't be used for this. - if (thd->lex->sql_command == SQLCOM_UPDATE_MULTI) { - return sh; - } - - String query; - // Print the query into a string provided - select_lex->print(thd, &query, QT_ORDINARY); - int error_code = 0; - int field_metadata_size = 0; - clustrix_connection *trx = NULL; - - // We presume this number is equal to types.elements in get_field_types - uint items_number = select_lex->get_item_list()->elements; - uint num_null_bytes = (items_number + 7) / 8; - uchar *fieldtype = NULL; - uchar *null_bits = NULL; - uchar *field_metadata = NULL; - uchar *meta_memory= (uchar *)my_multi_malloc(MYF(MY_WME), &fieldtype, items_number, - &null_bits, num_null_bytes, &field_metadata, (items_number * 2), NULL); - - if (!meta_memory) { - // The only way to say something here is to raise warning - // b/c we will fallback to other access methods: derived handler or rowstore. - goto err; - } - - if((field_metadata_size = - get_field_types(thd, NULL, select_lex, fieldtype, field_metadata, null_bits, num_null_bytes, items_number)) < 0) { - goto err; - } - - trx = get_trx(thd, &error_code); - if (!trx) - goto err; - - if (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) - trx->auto_commit_next(); - - if ((error_code = trx->scan_query(query, fieldtype, items_number, null_bits, - num_null_bytes, field_metadata, - field_metadata_size, - row_buffer_setting(thd), &scan))) { - goto err; - } - - sh = new ha_clustrixdb_select_handler(thd, select_lex, scan); - -err: - // deallocate buffers - if (meta_memory) - my_free(meta_memory); - - return sh; -} - -/*********************************************************** - * DESCRIPTION: - * select_handler constructor - * PARAMETERS: - * thd - THD pointer. - * select_lex - sematic tree for the query. - **********************************************************/ -ha_clustrixdb_select_handler::ha_clustrixdb_select_handler( - THD *thd, - SELECT_LEX* select_lex, - clustrix_connection_cursor *scan_) - : select_handler(thd, clustrixdb_hton) -{ - thd__ = thd; - scan = scan_; - select = select_lex; - rgi = NULL; -} - -/*********************************************************** - * DESCRIPTION: - * select_handler constructor - * This frees dynamic memory allocated for bitmap - * and disables replication to SH temp table. - **********************************************************/ -ha_clustrixdb_select_handler::~ha_clustrixdb_select_handler() -{ - int error_code; - clustrix_connection *trx = get_trx(thd, &error_code); - if (!trx) { - // TBD Log this - } - if (trx && scan) - trx->scan_end(scan); - - // If the ::init_scan has been executed - if (table__) - my_bitmap_free(&scan_fields); - - if (rgi) - remove_current_table_from_rpl_table_list(rgi); -} - -/*@brief Initiate the query for select_handler */ -/*********************************************************** - * DESCRIPTION: - * Initializes dynamic structures and sets SH temp table - * as RBR replication destination to unpack rows. - * * PARAMETERS: - * RETURN: - * rc as int - * ********************************************************/ -int ha_clustrixdb_select_handler::init_scan() -{ - // Save this into the base handler class attribute - table__ = table; - // need this bitmap future in next_row() - if (my_bitmap_init(&scan_fields, NULL, table->read_set->n_bits, false)) - return ER_OUTOFMEMORY; - bitmap_set_all(&scan_fields); - - add_current_table_to_rpl_table_list(&rgi, thd__, table__); - - return 0; -} - -/*@brief Fetch next row for select_handler */ -/*********************************************************** - * DESCRIPTION: - * Fetch next row for select_handler. - * PARAMETERS: - * RETURN: - * rc as int - * ********************************************************/ -int ha_clustrixdb_select_handler::next_row() -{ - int error_code = 0; - clustrix_connection *trx = get_trx(thd, &error_code); - if (!trx) - return error_code; - - assert(scan); - - uchar *rowdata; - ulong rowdata_length; - if ((error_code = trx->scan_next(scan, &rowdata, &rowdata_length))) - return error_code; - - uchar const *current_row_end; - ulong master_reclength; - - error_code = unpack_row(rgi, table, table->s->fields, rowdata, - &scan_fields, ¤t_row_end, - &master_reclength, rowdata + rowdata_length); - - if (error_code) - return error_code; - - return 0; -} - -/*@brief Finishes the scan and clean it up */ -/*********************************************************** - * DESCRIPTION: - * Finishes the scan for select handler - * PARAMETERS: - * RETURN: - * rc as int - ***********************************************************/ -int ha_clustrixdb_select_handler::end_scan() -{ - return 0; -} - -/*@brief create_clustrixdb_derived_handler- Creates handler*/ -/************************************************************ - * DESCRIPTION: - * Creates a derived handler - * More details in server/sql/derived_handler.h - * PARAMETERS: - * thd - THD pointer. - * derived - TABLE_LIST* that describes the tables involved - * RETURN: - * derived_handler if possible - * NULL otherwise - ************************************************************/ -derived_handler* -create_clustrixdb_derived_handler(THD* thd, TABLE_LIST *derived) -{ - ha_clustrixdb_derived_handler *dh = NULL; - if (!derived_handler_setting(thd)) { - return dh; - } - - SELECT_LEX_UNIT *unit= derived->derived; - SELECT_LEX *select_lex = unit->first_select(); - String query; - - dh = new ha_clustrixdb_derived_handler(thd, select_lex, NULL); - - return dh; -} - -/*********************************************************** - * DESCRIPTION: - * derived_handler constructor - * PARAMETERS: - * thd - THD pointer. - * select_lex - sematic tree for the query. - **********************************************************/ -ha_clustrixdb_derived_handler::ha_clustrixdb_derived_handler( - THD *thd, - SELECT_LEX* select_lex, - clustrix_connection_cursor *scan_) - : derived_handler(thd, clustrixdb_hton) -{ - thd__ = thd; - scan = scan_; - select = select_lex; - rgi = NULL; -} - -/*********************************************************** - * DESCRIPTION: - * derived_handler constructor - * This frees dynamic memory allocated for bitmap - * and disables replication to SH temp table. - **********************************************************/ -ha_clustrixdb_derived_handler::~ha_clustrixdb_derived_handler() -{ - int error_code; - - - - clustrix_connection *trx = get_trx(thd, &error_code); - if (!trx) { - // TBD Log this. - } - if (trx && scan) - trx->scan_end(scan); - - // If the ::init_scan has been executed - if (table__) - my_bitmap_free(&scan_fields); - - if (rgi) - remove_current_table_from_rpl_table_list(rgi); -} - -/*@brief Initiate the query for derived_handler */ -/*********************************************************** - * DESCRIPTION: - * Initializes dynamic structures and sets SH temp table - * as RBR replication destination to unpack rows. - * * PARAMETERS: - * RETURN: - * rc as int - * ********************************************************/ -int ha_clustrixdb_derived_handler::init_scan() -{ - String query; - // Print the query into a string provided - select->print(thd__, &query, QT_ORDINARY); - int error_code = 0; - int field_metadata_size = 0; - clustrix_connection *trx = NULL; - - // We presume this number is equal to types.elements in get_field_types - uint items_number= select->get_item_list()->elements; - uint num_null_bytes = (items_number + 7) / 8; - uchar *fieldtype = NULL; - uchar *null_bits = NULL; - uchar *field_metadata = NULL; - uchar *meta_memory= (uchar *)my_multi_malloc(MYF(MY_WME), &fieldtype, items_number, - &null_bits, num_null_bytes, &field_metadata, (items_number * 2), NULL); - - if (!meta_memory) { - // The only way to say something here is to raise warning - // b/c we will fallback to other access methods: derived handler or rowstore. - goto err; - } - - if((field_metadata_size= - get_field_types(thd__, table, select, fieldtype, field_metadata, null_bits, num_null_bytes, items_number)) < 0) { - goto err; - } - - trx = get_trx(thd__, &error_code); - if (!trx) - goto err; - - if ((error_code = trx->scan_query(query, fieldtype, items_number, null_bits, - num_null_bytes, field_metadata, - field_metadata_size, - row_buffer_setting(thd), &scan))) { - goto err; - } - - // Save this into the base handler class attribute - table__ = table; - - // need this bitmap future in next_row() - if (my_bitmap_init(&scan_fields, NULL, table->read_set->n_bits, false)) - return ER_OUTOFMEMORY; - bitmap_set_all(&scan_fields); - - add_current_table_to_rpl_table_list(&rgi, thd__, table__); - -err: - // deallocate buffers - if (meta_memory) - my_free(meta_memory); - - return error_code; -} - -/*@brief Fetch next row for derived_handler */ -/*********************************************************** - * DESCRIPTION: - * Fetch next row for derived_handler. - * PARAMETERS: - * RETURN: - * rc as int - * ********************************************************/ -int ha_clustrixdb_derived_handler::next_row() -{ - int error_code = 0; - clustrix_connection *trx = get_trx(thd, &error_code); - if (!trx) - return error_code; - - assert(scan); - - uchar *rowdata; - ulong rowdata_length; - if ((error_code = trx->scan_next(scan, &rowdata, &rowdata_length))) - return error_code; - - uchar const *current_row_end; - ulong master_reclength; - - error_code = unpack_row(rgi, table, table->s->fields, rowdata, - &scan_fields, ¤t_row_end, - &master_reclength, rowdata + rowdata_length); - - if (error_code) - return error_code; - - return 0; -} - -/*@brief Finishes the scan and clean it up */ -/*********************************************************** - * DESCRIPTION: - * Finishes the scan for derived handler - * PARAMETERS: - * RETURN: - * rc as int - ***********************************************************/ -int ha_clustrixdb_derived_handler::end_scan() -{ - return 0; -} diff --git a/storage/clustrixdb/ha_clustrixdb_pushdown.h b/storage/clustrixdb/ha_clustrixdb_pushdown.h deleted file mode 100644 index 2f08bd427b0..00000000000 --- a/storage/clustrixdb/ha_clustrixdb_pushdown.h +++ /dev/null @@ -1,87 +0,0 @@ -/***************************************************************************** -Copyright (c) 2019, MariaDB Corporation. -*****************************************************************************/ -#ifndef _ha_clustrixdb_pushdown_h -#define _ha_clustrixdb_pushdown_h - -#include "select_handler.h" -#include "derived_handler.h" -#include "sql_select.h" - -/*@brief base_handler class*/ -/*********************************************************** - * DESCRIPTION: - * To be described - ************************************************************/ -class ha_clustrixdb_base_handler -{ - // To simulate abstract class - protected: - ha_clustrixdb_base_handler(): thd__(0),table__(0) {} - ~ha_clustrixdb_base_handler() {} - - // Copies of pushdown handlers attributes - // to use them in shared methods. - THD *thd__; - TABLE *table__; - // The bitmap used to sent - MY_BITMAP scan_fields; - // Structures to unpack RBR rows from CLX BE - rpl_group_info *rgi; - // CLX BE scan operation reference - clustrix_connection_cursor *scan; -}; - -/*@brief select_handler class*/ -/*********************************************************** - * DESCRIPTION: - * select_handler API methods. Could be used by the server - * tp pushdown the whole query described by SELECT_LEX. - * More details in server/sql/select_handler.h - * sel semantic tree for the query in SELECT_LEX. - ************************************************************/ -class ha_clustrixdb_select_handler: - private ha_clustrixdb_base_handler, - public select_handler -{ - public: - ha_clustrixdb_select_handler(THD* thd_arg, SELECT_LEX* sel, - clustrix_connection_cursor *scan); - ~ha_clustrixdb_select_handler(); - - int init_scan(); - int next_row(); - int end_scan(); - void print_error(int, unsigned long) {} -}; - -/*@brief derived_handler class*/ -/*********************************************************** - * DESCRIPTION: - * derived_handler API methods. Could be used by the server - * tp pushdown the whole query described by SELECT_LEX. - * More details in server/sql/derived_handler.h - * sel semantic tree for the query in SELECT_LEX. - ************************************************************/ -class ha_clustrixdb_derived_handler: - private ha_clustrixdb_base_handler, - public derived_handler -{ - public: - ha_clustrixdb_derived_handler(THD* thd_arg, SELECT_LEX* sel, - clustrix_connection_cursor *scan); - ~ha_clustrixdb_derived_handler(); - - int init_scan(); - int next_row(); - int end_scan(); - void print_error(int, unsigned long) {} -}; - - -select_handler *create_clustrixdb_select_handler(THD* thd, - SELECT_LEX* select_lex); -derived_handler *create_clustrixdb_derived_handler(THD* thd, - TABLE_LIST *derived); - -#endif diff --git a/storage/xpand/CMakeLists.txt b/storage/xpand/CMakeLists.txt new file mode 100644 index 00000000000..78fe16c0525 --- /dev/null +++ b/storage/xpand/CMakeLists.txt @@ -0,0 +1,24 @@ +#***************************************************************************** +# Copyright (c) 2019, MariaDB Corporation. +#****************************************************************************/ + +IF(MSVC) + # Temporarily disable "conversion from size_t .." + IF(CMAKE_SIZEOF_VOID_P EQUAL 8) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4267") + ENDIF() +ENDIF() + +SET(XPAND_PLUGIN_STATIC "xpand") +SET(XPAND_PLUGIN_DYNAMIC "ha_xpand") +SET(XPAND_SOURCES ha_xpand.cc xpand_connection.cc ha_xpand_pushdown.cc) +MYSQL_ADD_PLUGIN(xpand ${XPAND_SOURCES} STORAGE_ENGINE) + +IF(MSVC) + IF (CMAKE_BUILD_TYPE STREQUAL "Debug") + ADD_CUSTOM_COMMAND(TARGET xpand + POST_BUILD + COMMAND if not exist ..\\..\\sql\\lib mkdir ..\\..\\sql\\lib\\plugin + COMMAND copy Debug\\ha_xpand.dll ..\\..\\sql\\lib\\plugin\\ha_xpand.dll) + ENDIF() +ENDIF() diff --git a/storage/xpand/ha_xpand.cc b/storage/xpand/ha_xpand.cc new file mode 100644 index 00000000000..8a8366fa9f7 --- /dev/null +++ b/storage/xpand/ha_xpand.cc @@ -0,0 +1,1372 @@ +/***************************************************************************** +Copyright (c) 2019, MariaDB Corporation. +*****************************************************************************/ + +/** @file ha_xpand.cc */ + +#include "ha_xpand.h" +#include "ha_xpand_pushdown.h" +#include "key.h" + +handlerton *xpand_hton = NULL; + +int xpand_connect_timeout; +static MYSQL_SYSVAR_INT +( + connect_timeout, + xpand_connect_timeout, + PLUGIN_VAR_OPCMDARG, + "Timeout for connecting to Xpand", + NULL, NULL, -1, -1, 2147483647, 0 +); + +int xpand_read_timeout; +static MYSQL_SYSVAR_INT +( + read_timeout, + xpand_read_timeout, + PLUGIN_VAR_OPCMDARG, + "Timeout for receiving data from Xpand", + NULL, NULL, -1, -1, 2147483647, 0 +); + +int xpand_write_timeout; +static MYSQL_SYSVAR_INT +( + write_timeout, + xpand_write_timeout, + PLUGIN_VAR_OPCMDARG, + "Timeout for sending data to Xpand", + NULL, NULL, -1, -1, 2147483647, 0 +); + +char *xpand_host; +static MYSQL_SYSVAR_STR +( + host, + xpand_host, + PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_MEMALLOC, + "Xpand host", + NULL, NULL, "127.0.0.1" +); + +int host_list_cnt; +char **host_list; + +static void free_host_list() +{ + if (host_list) { + for (int i = 0; host_list[i]; i++) + my_free(host_list[i]); + my_free(host_list); + host_list = NULL; + } +} + +static void update_host_list(char *xpand_host) +{ + free_host_list(); + + int cnt = 0; + for (char *p = xpand_host, *s = xpand_host; ; p++) { + if (*p == ',' || *p == '\0') { + if (p > s) { + cnt++; + } + if (!*p) + break; + s = p + 1; + } + } + + DBUG_PRINT("host_cnt", ("%d", cnt)); + host_list = (char **)my_malloc(sizeof(char *) * cnt+1, MYF(MY_WME)); + host_list[cnt] = 0; + host_list_cnt = cnt; + + int i = 0; + for (char *p = xpand_host, *s = xpand_host; ; p++) { + if (*p == ',' || *p == '\0') { + if (p > s) { + char *host = (char *)my_malloc(p - s + 1, MYF(MY_WME)); + host[p-s] = '\0'; + memcpy(host, s, p-s); + DBUG_PRINT("host", ("%s", host)); + host_list[i++] = host; + } + if (!*p) + break; + s = p + 1; + } + } + + DBUG_PRINT("xpand_host", ("%s", xpand_host)); +} + +char *xpand_username; +static MYSQL_SYSVAR_STR +( + username, + xpand_username, + PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_MEMALLOC, + "Xpand user name", + NULL, NULL, "root" +); + +char *xpand_password; +static MYSQL_SYSVAR_STR +( + password, + xpand_password, + PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_MEMALLOC, + "Xpand password", + NULL, NULL, "" +); + +uint xpand_port; +static MYSQL_SYSVAR_UINT +( + port, + xpand_port, + PLUGIN_VAR_RQCMDARG, + "Xpand port", + NULL, NULL, MYSQL_PORT_DEFAULT, MYSQL_PORT_DEFAULT, 65535, 0 +); + +char *xpand_socket; +static MYSQL_SYSVAR_STR +( + socket, + xpand_socket, + PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_MEMALLOC, + "Xpand socket", + NULL, NULL, "" +); + +static MYSQL_THDVAR_UINT +( + row_buffer, + PLUGIN_VAR_RQCMDARG, + "Xpand rowstore row buffer size", + NULL, NULL, 20, 1, 65535, 0 +); + +// Per thread select handler knob +static MYSQL_THDVAR_BOOL( + select_handler, + PLUGIN_VAR_NOCMDARG, + "", + NULL, + NULL, + 1 +); + +// Per thread derived handler knob +static MYSQL_THDVAR_BOOL( + derived_handler, + PLUGIN_VAR_NOCMDARG, + "", + NULL, + NULL, + 1 +); + +static MYSQL_THDVAR_BOOL( + enable_direct_update, + PLUGIN_VAR_NOCMDARG, + "", + NULL, + NULL, + 1 +); + +bool select_handler_setting(THD* thd) +{ + return ( thd == NULL ) ? false : THDVAR(thd, select_handler); +} + +bool derived_handler_setting(THD* thd) +{ + return ( thd == NULL ) ? false : THDVAR(thd, derived_handler); +} + +uint row_buffer_setting(THD* thd) +{ + return THDVAR(thd, row_buffer); +} + +/**************************************************************************** +** Utility functions +****************************************************************************/ +// This is a wastefull aproach but better then fixed sized buffer. +size_t estimate_row_size(TABLE *table) +{ + size_t row_size = 0; + size_t null_byte_count = (bitmap_bits_set(table->write_set) + 7) / 8; + row_size += null_byte_count; + Field **p_field= table->field, *field; + for ( ; (field= *p_field) ; p_field++) { + row_size += field->max_data_length(); + } + return row_size; +} + +/** + * @brief + * Decodes object name. + * + * @details + * Replaces the encoded object name in the path with a decoded variant, + * e.g if path contains ./test/d@0024. This f() makes it ./test/d$ + * + * Used in delete and rename DDL processing. + **/ +static void decode_objectname(char *buf, const char *path, size_t buf_size) +{ + size_t new_path_len = filename_to_tablename(path, buf, buf_size); + buf[new_path_len] = '\0'; +} + +static void decode_file_path(const char *path, char *decoded_dbname, + char *decoded_tbname) +{ + // The format cont ains './' in the beginning of a path. + char *dbname_start = (char*) path + 2; + char *dbname_end = dbname_start; + while (*dbname_end != '/') + dbname_end++; + + int cnt = dbname_end - dbname_start; + char *dbname = (char *)my_alloca(cnt + 1); + memcpy(dbname, dbname_start, cnt); + dbname[cnt] = '\0'; + decode_objectname(decoded_dbname, dbname, FN_REFLEN); + my_afree(dbname); + + char *tbname_start = dbname_end + 1; + decode_objectname(decoded_tbname, tbname_start, FN_REFLEN); +} + +xpand_connection *get_trx(THD *thd, int *error_code) +{ + *error_code = 0; + xpand_connection *trx; + if (!(trx = (xpand_connection *)thd_get_ha_data(thd, xpand_hton))) + { + if (!(trx = new xpand_connection())) { + *error_code = HA_ERR_OUT_OF_MEM; + return NULL; + } + + *error_code = trx->connect(); + if (*error_code) { + delete trx; + return NULL; + } + + thd_set_ha_data(thd, xpand_hton, trx); + } + + return trx; +} +/**************************************************************************** +** Class ha_xpand +****************************************************************************/ + +ha_xpand::ha_xpand(handlerton *hton, TABLE_SHARE *table_arg) + : handler(hton, table_arg) +{ + DBUG_ENTER("ha_xpand::ha_xpand"); + rgi = NULL; + scan_cur = NULL; + xpand_table_oid = 0; + upsert_flag = 0; + DBUG_VOID_RETURN; +} + +ha_xpand::~ha_xpand() +{ + if (rgi) + remove_current_table_from_rpl_table_list(rgi); +} + +int ha_xpand::create(const char *name, TABLE *form, HA_CREATE_INFO *info) +{ + int error_code; + THD *thd = ha_thd(); + xpand_connection *trx = get_trx(thd, &error_code); + if (!trx) + return error_code; + + enum tmp_table_type saved_tmp_table_type = form->s->tmp_table; + Table_specification_st *create_info = &thd->lex->create_info; + const bool is_tmp_table = info->options & HA_LEX_CREATE_TMP_TABLE; + String create_table_stmt; + + /* Create a copy of the CREATE TABLE statement */ + if (!is_tmp_table) + form->s->tmp_table = NO_TMP_TABLE; + const char *old_dbstr = thd->db.str; + thd->db.str = NULL; + ulong old = create_info->used_fields; + create_info->used_fields &= ~HA_CREATE_USED_ENGINE; + + TABLE_LIST table_list; + memset(&table_list, 0, sizeof(table_list)); + table_list.table = form; + error_code = show_create_table(thd, &table_list, &create_table_stmt, + create_info, WITH_DB_NAME); + + if (!is_tmp_table) + form->s->tmp_table = saved_tmp_table_type; + create_info->used_fields = old; + thd->db.str = old_dbstr; + if (error_code) + return error_code; + + // To syncronize the schemas of MDB FE and XPD BE. + if (form->s && form->s->db.length) { + String createdb_stmt; + createdb_stmt.append("CREATE DATABASE IF NOT EXISTS `"); + createdb_stmt.append(form->s->db.str, form->s->db.length); + createdb_stmt.append("`"); + trx->run_query(createdb_stmt); + } + + error_code = trx->run_query(create_table_stmt); + return error_code; +} + +int ha_xpand::delete_table(const char *path) +{ + int error_code; + THD *thd = ha_thd(); + xpand_connection *trx = get_trx(thd, &error_code); + if (!trx) + return error_code; + + char decoded_dbname[FN_REFLEN]; + char decoded_tbname[FN_REFLEN]; + decode_file_path(path, decoded_dbname, decoded_tbname); + + String delete_cmd; + delete_cmd.append("DROP TABLE `"); + delete_cmd.append(decoded_dbname); + delete_cmd.append("`.`"); + delete_cmd.append(decoded_tbname); + delete_cmd.append("`"); + + return trx->run_query(delete_cmd); +} + +int ha_xpand::rename_table(const char* from, const char* to) +{ + int error_code; + THD *thd = ha_thd(); + xpand_connection *trx = get_trx(thd, &error_code); + if (!trx) + return error_code; + + char decoded_from_dbname[FN_REFLEN]; + char decoded_from_tbname[FN_REFLEN]; + decode_file_path(from, decoded_from_dbname, decoded_from_tbname); + + char decoded_to_dbname[FN_REFLEN]; + char decoded_to_tbname[FN_REFLEN]; + decode_file_path(to, decoded_to_dbname, decoded_to_tbname); + + String rename_cmd; + rename_cmd.append("RENAME TABLE `"); + rename_cmd.append(decoded_from_dbname); + rename_cmd.append("`.`"); + rename_cmd.append(decoded_from_tbname); + rename_cmd.append("` TO `"); + rename_cmd.append(decoded_to_dbname); + rename_cmd.append("`.`"); + rename_cmd.append(decoded_to_tbname); + rename_cmd.append("`;"); + + return trx->run_query(rename_cmd); +} + +static void +xpand_mark_table_for_discovery(TABLE *table) +{ + table->s->tabledef_version.str = NULL; + table->s->tabledef_version.length = 0; + table->m_needs_reopen = TRUE; +} + +int ha_xpand::open(const char *name, int mode, uint test_if_locked) +{ + DBUG_ENTER("ha_xpand::open"); + DBUG_PRINT("oid", + ("%s", table->s->tabledef_version.str)); + + if (!table->s->tabledef_version.str) + DBUG_RETURN(HA_ERR_TABLE_DEF_CHANGED); + if (!xpand_table_oid) + xpand_table_oid = atoll((const char *)table->s->tabledef_version.str); + + // Surrogate key marker + has_hidden_key = table->s->primary_key == MAX_KEY; + if (has_hidden_key) { + ref_length = 8; + } else { + KEY* key_info = table->key_info + table->s->primary_key; + ref_length = key_info->key_length; + } + + DBUG_PRINT("open finished", + ("oid: %llu, ref_length: %u", xpand_table_oid, ref_length)); + DBUG_RETURN(0); +} + +int ha_xpand::close(void) +{ + return 0; +} + +int ha_xpand::reset() +{ + upsert_flag &= ~XPAND_BULK_UPSERT; + upsert_flag &= ~XPAND_HAS_UPSERT; + upsert_flag &= ~XPAND_UPSERT_SENT; + xpd_lock_type = XPAND_NO_LOCKS; + return 0; +} + +int ha_xpand::extra(enum ha_extra_function operation) +{ + DBUG_ENTER("ha_xpand::extra"); + if (operation == HA_EXTRA_INSERT_WITH_UPDATE) + upsert_flag |= XPAND_HAS_UPSERT; + DBUG_RETURN(0); +} + +/*@brief UPSERT State Machine*/ +/************************************************************* + * DESCRIPTION: + * Fasttrack for UPSERT sends queries down to a XPD backend. + * UPSERT could be of two kinds: singular and bulk. The plugin + * re-/sets XPAND_BULK_UPSERT in end|start_bulk_insert + * methods. XPAND_UPSERT_SENT is used to avoid multiple + * execution at XPD backend. + * Generic XPAND_HAS_UPSERT is set for bulk UPSERT only b/c + * MDB calls write_row only once. + ************************************************************/ +int ha_xpand::write_row(const uchar *buf) +{ + int error_code = 0; + THD *thd = ha_thd(); + xpand_connection *trx = get_trx(thd, &error_code); + if (!trx) + return error_code; + + if (upsert_flag & XPAND_HAS_UPSERT) { + if (!(upsert_flag & XPAND_UPSERT_SENT)) { + ha_rows update_rows; + String update_stmt; + update_stmt.append(thd->query_string.str()); + + if (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) + trx->auto_commit_next(); + + error_code= trx->update_query(update_stmt, table->s->db, &update_rows); + if (upsert_flag & XPAND_BULK_UPSERT) + upsert_flag |= XPAND_UPSERT_SENT; + else + upsert_flag &= ~XPAND_HAS_UPSERT; + } + + return error_code; + } + + /* Convert the row format to binlog (packed) format */ + uchar *packed_new_row = (uchar*) my_alloca(estimate_row_size(table)); + size_t packed_size = pack_row(table, table->write_set, packed_new_row, buf); + + /* XXX: Xpand may needs to return HA_ERR_AUTOINC_ERANGE if we hit that + error. */ + ulonglong last_insert_id = 0; + if ((error_code = trx->write_row(xpand_table_oid, + packed_new_row, packed_size, + &last_insert_id))) + goto err; + + if (table->next_number_field) + insert_id_for_cur_row = last_insert_id; + +err: + if (error_code == HA_ERR_TABLE_DEF_CHANGED) + xpand_mark_table_for_discovery(table); + + if (packed_size) + my_afree(packed_new_row); + + return error_code; +} + +int ha_xpand::update_row(const uchar *old_data, const uchar *new_data) +{ + DBUG_ENTER("ha_xpand::update_row"); + int error_code; + THD *thd = ha_thd(); + xpand_connection *trx = get_trx(thd, &error_code); + if (!trx) + DBUG_RETURN(error_code); + + size_t row_size = estimate_row_size(table); + size_t packed_key_len; + uchar *packed_key = (uchar*) my_alloca(row_size); + build_key_packed_row(table->s->primary_key, old_data, + packed_key, &packed_key_len); + + uchar *packed_new_row = (uchar*) my_alloca(row_size); + size_t packed_new_size = pack_row(table, table->write_set, packed_new_row, + new_data); + + /* Send the packed rows to Xpand */ + error_code = trx->key_update(xpand_table_oid, packed_key, packed_key_len, + table->write_set, + packed_new_row, packed_new_size); + + if(packed_key) + my_afree(packed_key); + + if(packed_new_row) + my_afree(packed_new_row); + + if (error_code == HA_ERR_TABLE_DEF_CHANGED) + xpand_mark_table_for_discovery(table); + + DBUG_RETURN(error_code); +} + +int ha_xpand::direct_update_rows_init(List *update_fields) +{ + DBUG_ENTER("ha_xpand::direct_update_rows_init"); + THD *thd= ha_thd(); + if (!THDVAR(thd, enable_direct_update)) + DBUG_RETURN(HA_ERR_WRONG_COMMAND); + DBUG_RETURN(0); +} + +int ha_xpand::direct_update_rows(ha_rows *update_rows, ha_rows *found_rows) +{ + DBUG_ENTER("ha_xpand::direct_update_rows"); + int error_code= 0; + THD *thd= ha_thd(); + xpand_connection *trx= get_trx(thd, &error_code); + if (!trx) + return error_code; + + String update_stmt; + update_stmt.append(thd->query_string.str()); + + if (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) + trx->auto_commit_next(); + + error_code = trx->update_query(update_stmt, table->s->db, update_rows); + *found_rows = *update_rows; + DBUG_RETURN(error_code); +} + +void ha_xpand::start_bulk_insert(ha_rows rows, uint flags) +{ + DBUG_ENTER("ha_xpand::start_bulk_insert"); + int error_code= 0; + THD *thd= ha_thd(); + xpand_connection *trx= get_trx(thd, &error_code); + if (!trx) { + // TBD log this + DBUG_VOID_RETURN; + } + + upsert_flag |= XPAND_BULK_UPSERT; + + DBUG_VOID_RETURN; +} + +int ha_xpand::end_bulk_insert() +{ + DBUG_ENTER("ha_xpand::end_bulk_insert"); + upsert_flag &= ~XPAND_BULK_UPSERT; + upsert_flag &= ~XPAND_HAS_UPSERT; + upsert_flag &= ~XPAND_UPSERT_SENT; + DBUG_RETURN(0); +} + +int ha_xpand::delete_row(const uchar *buf) +{ + int error_code; + THD *thd = ha_thd(); + xpand_connection *trx = get_trx(thd, &error_code); + if (!trx) + return error_code; + + // The estimate should consider only key fields widths. + size_t packed_key_len; + uchar *packed_key = (uchar*) my_alloca(estimate_row_size(table)); + build_key_packed_row(table->s->primary_key, buf, packed_key, &packed_key_len); + + error_code = trx->key_delete(xpand_table_oid, packed_key, packed_key_len); + + if (error_code == HA_ERR_TABLE_DEF_CHANGED) + xpand_mark_table_for_discovery(table); + + if (packed_key) + my_afree(packed_key); + + return error_code; +} + +ha_xpand::Table_flags ha_xpand::table_flags(void) const +{ + Table_flags flags = HA_PARTIAL_COLUMN_READ | + HA_REC_NOT_IN_SEQ | + HA_FAST_KEY_READ | + HA_NULL_IN_KEY | + HA_CAN_INDEX_BLOBS | + HA_AUTO_PART_KEY | + HA_CAN_SQL_HANDLER | + HA_BINLOG_STMT_CAPABLE | + HA_CAN_TABLE_CONDITION_PUSHDOWN | + HA_CAN_DIRECT_UPDATE_AND_DELETE; + + return flags; +} + +ulong ha_xpand::index_flags(uint idx, uint part, bool all_parts) const +{ + ulong flags = HA_READ_NEXT | + HA_READ_PREV | + HA_READ_ORDER | + HA_READ_RANGE; + + return flags; +} + +ha_rows ha_xpand::records() +{ + return 10000; +} + +ha_rows ha_xpand::records_in_range(uint inx, key_range *min_key, + key_range *max_key) +{ + return 2; +} + +int ha_xpand::info(uint flag) +{ + //THD *thd = ha_thd(); + if (flag & HA_STATUS_TIME) + { + /* Retrieve the time of the most recent update to the table */ + // stats.update_time = + } + + if (flag & HA_STATUS_AUTO) + { + /* Retrieve the latest auto_increment value */ + stats.auto_increment_value = next_insert_id; + } + + if (flag & HA_STATUS_VARIABLE) + { + /* Retrieve variable info, such as row counts and file lengths */ + stats.records = records(); + stats.deleted = 0; + // stats.data_file_length = + // stats.index_file_length = + // stats.delete_length = + stats.check_time = 0; + // stats.mrr_length_per_rec = + + if (stats.records == 0) + stats.mean_rec_length = 0; + else + stats.mean_rec_length = (ulong) + (stats.data_file_length / stats.records); + } + + if (flag & HA_STATUS_CONST) + { + /* + Retrieve constant info, such as file names, max file lengths, + create time, block size + */ + // stats.max_data_file_length = + // stats.create_time = + // stats.block_size = + } + + return 0; +} + +int ha_xpand::index_init(uint idx, bool sorted) +{ + int error_code = 0; + THD *thd = ha_thd(); + xpand_connection *trx = get_trx(thd, &error_code); + if (!trx) + return error_code; + + active_index = idx; + add_current_table_to_rpl_table_list(&rgi, thd, table); + scan_cur = NULL; + + /* Return all columns until there is a better understanding of + requirements. */ + if (my_bitmap_init(&scan_fields, NULL, table->read_set->n_bits, false)) + return ER_OUTOFMEMORY; + bitmap_set_all(&scan_fields); + sorted_scan = sorted; + + return 0; +} + +int ha_xpand::index_read(uchar * buf, const uchar * key, uint key_len, + enum ha_rkey_function find_flag) +{ + DBUG_ENTER("ha_xpand::index_read"); + int error_code = 0; + THD *thd = ha_thd(); + xpand_connection *trx = get_trx(thd, &error_code); + if (!trx) + DBUG_RETURN(error_code); + + key_restore(buf, key, &table->key_info[active_index], key_len); + // The estimate should consider only key fields widths. + size_t packed_key_len; + uchar *packed_key = (uchar*) my_alloca(estimate_row_size(table)); + build_key_packed_row(active_index, buf, packed_key, &packed_key_len); + + bool exact = false; + xpand_connection::scan_type st; + switch (find_flag) { + case HA_READ_KEY_EXACT: + exact = true; + break; + case HA_READ_KEY_OR_NEXT: + st = xpand_connection::READ_KEY_OR_NEXT; + break; + case HA_READ_KEY_OR_PREV: + st = xpand_connection::READ_KEY_OR_PREV; + break; + case HA_READ_AFTER_KEY: + st = xpand_connection::READ_AFTER_KEY; + break; + case HA_READ_BEFORE_KEY: + st = xpand_connection::READ_BEFORE_KEY; + break; + case HA_READ_PREFIX: + case HA_READ_PREFIX_LAST: + case HA_READ_PREFIX_LAST_OR_PREV: + case HA_READ_MBR_CONTAIN: + case HA_READ_MBR_INTERSECT: + case HA_READ_MBR_WITHIN: + case HA_READ_MBR_DISJOINT: + case HA_READ_MBR_EQUAL: + DBUG_RETURN(ER_NOT_SUPPORTED_YET); + } + + uchar *rowdata = NULL; + if (exact) { + is_scan = false; + ulong rowdata_length; + error_code = trx->key_read(xpand_table_oid, 0, xpd_lock_type, + table->read_set, packed_key, packed_key_len, + &rowdata, &rowdata_length); + if (!error_code) + error_code = unpack_row_to_buf(rgi, table, buf, rowdata, + table->read_set, + rowdata + rowdata_length); + } else { + is_scan = true; + error_code = trx->scan_from_key(xpand_table_oid, active_index, + xpd_lock_type, st, -1, sorted_scan, + &scan_fields, packed_key, packed_key_len, + THDVAR(thd, row_buffer), &scan_cur); + if (!error_code) + error_code = rnd_next(buf); + } + + if (rowdata) + my_free(rowdata); + + if (packed_key) + my_afree(packed_key); + + if (error_code == HA_ERR_TABLE_DEF_CHANGED) + xpand_mark_table_for_discovery(table); + + DBUG_RETURN(error_code); +} + +int ha_xpand::index_first(uchar *buf) +{ + DBUG_ENTER("ha_xpand::index_first"); + int error_code = 0; + THD *thd = ha_thd(); + xpand_connection *trx = get_trx(thd, &error_code); + if (!trx) + DBUG_RETURN(error_code); + + error_code = trx->scan_from_key(xpand_table_oid, active_index, + xpd_lock_type, + xpand_connection::READ_FROM_START, + -1, sorted_scan, &scan_fields, NULL, 0, + THDVAR(thd, row_buffer), &scan_cur); + + if (error_code == HA_ERR_TABLE_DEF_CHANGED) + xpand_mark_table_for_discovery(table); + + if (error_code) + DBUG_RETURN(error_code); + + DBUG_RETURN(rnd_next(buf)); +} + +int ha_xpand::index_last(uchar *buf) +{ + DBUG_ENTER("ha_xpand::index_last"); + int error_code = 0; + THD *thd = ha_thd(); + xpand_connection *trx = get_trx(thd, &error_code); + if (!trx) + DBUG_RETURN(error_code); + + error_code = trx->scan_from_key(xpand_table_oid, active_index, + xpd_lock_type, + xpand_connection::READ_FROM_LAST, + -1, sorted_scan, &scan_fields, NULL, 0, + THDVAR(thd, row_buffer), &scan_cur); + + if (error_code == HA_ERR_TABLE_DEF_CHANGED) + xpand_mark_table_for_discovery(table); + + if (error_code) + DBUG_RETURN(error_code); + + DBUG_RETURN(rnd_next(buf)); +} + +int ha_xpand::index_next(uchar *buf) +{ + DBUG_ENTER("index_next"); + DBUG_RETURN(rnd_next(buf)); +} + +#if 0 +int ha_xpand::index_next_same(uchar *buf, const uchar *key, uint keylen) +{ + DBUG_ENTER("index_next_same"); + DBUG_RETURN(rnd_next(buf)); +} +#endif + +int ha_xpand::index_prev(uchar *buf) +{ + DBUG_ENTER("index_prev"); + DBUG_RETURN(rnd_next(buf)); +} + +int ha_xpand::index_end() +{ + DBUG_ENTER("index_prev"); + if (scan_cur) + DBUG_RETURN(rnd_end()); + else + DBUG_RETURN(0); +} + +int ha_xpand::rnd_init(bool scan) +{ + DBUG_ENTER("ha_xpand::rnd_init"); + int error_code = 0; + THD *thd = ha_thd(); + if (thd->lex->sql_command == SQLCOM_UPDATE) + DBUG_RETURN(error_code); + xpand_connection *trx = get_trx(thd, &error_code); + if (!trx) + DBUG_RETURN(error_code); + + add_current_table_to_rpl_table_list(&rgi, thd, table); + is_scan = scan; + scan_cur = NULL; + + if (my_bitmap_init(&scan_fields, NULL, table->read_set->n_bits, false)) + DBUG_RETURN(ER_OUTOFMEMORY); + +#if 0 + if (table->s->keys) + table->mark_columns_used_by_index(table->s->primary_key, &scan_fields); + else + bitmap_clear_all(&scan_fields); + + bitmap_union(&scan_fields, table->read_set); +#else + /* Why is read_set not setup correctly? */ + bitmap_set_all(&scan_fields); +#endif + + error_code = trx->scan_table(xpand_table_oid, xpd_lock_type, + &scan_fields, THDVAR(thd, row_buffer), + &scan_cur); + + if (error_code == HA_ERR_TABLE_DEF_CHANGED) + xpand_mark_table_for_discovery(table); + + if (error_code) + DBUG_RETURN(error_code); + + DBUG_RETURN(0); +} + +int ha_xpand::rnd_next(uchar *buf) +{ + int error_code = 0; + THD *thd = ha_thd(); + xpand_connection *trx = get_trx(thd, &error_code); + if (!trx) + return error_code; + + assert(is_scan); + assert(scan_cur); + + uchar *rowdata; + ulong rowdata_length; + if ((error_code = trx->scan_next(scan_cur, &rowdata, &rowdata_length))) + return error_code; + + if (has_hidden_key) { + last_hidden_key = *(ulonglong *)rowdata; + rowdata += 8; + rowdata_length -= 8; + } + + error_code = unpack_row_to_buf(rgi, table, buf, rowdata, &scan_fields, + rowdata + rowdata_length); + + if (error_code) + return error_code; + + return 0; +} + +int ha_xpand::rnd_pos(uchar * buf, uchar *pos) +{ + DBUG_ENTER("xpd_rnd_pos"); + DBUG_DUMP("pos", pos, ref_length); + + int error_code = 0; + THD *thd = ha_thd(); + xpand_connection *trx = get_trx(thd, &error_code); + if (!trx) + DBUG_RETURN(error_code); + + /* WDD: We need a way to convert key buffers directy to rbr buffers. */ + + if (has_hidden_key) { + memcpy(&last_hidden_key, pos, sizeof(ulonglong)); + } else { + uint keyno = table->s->primary_key; + uint len = calculate_key_len(table, keyno, pos, + table->const_key_parts[keyno]); + key_restore(buf, pos, &table->key_info[keyno], len); + } + + // The estimate should consider only key fields widths. + uchar *packed_key = (uchar*) my_alloca(estimate_row_size(table)); + size_t packed_key_len; + build_key_packed_row(table->s->primary_key, buf, packed_key, &packed_key_len); + + uchar *rowdata = NULL; + ulong rowdata_length; + if ((error_code = trx->key_read(xpand_table_oid, 0, xpd_lock_type, + table->read_set, packed_key, packed_key_len, + &rowdata, &rowdata_length))) + goto err; + + if ((error_code = unpack_row_to_buf(rgi, table, buf, rowdata, table->read_set, + rowdata + rowdata_length))) + goto err; + +err: + if (rowdata) + my_free(rowdata); + + if (packed_key) + my_afree(packed_key); + + if (error_code == HA_ERR_TABLE_DEF_CHANGED) + xpand_mark_table_for_discovery(table); + + DBUG_RETURN(error_code); +} + +int ha_xpand::rnd_end() +{ + DBUG_ENTER("ha_xpand::rnd_end()"); + int error_code = 0; + THD *thd = ha_thd(); + if (thd->lex->sql_command == SQLCOM_UPDATE) + DBUG_RETURN(error_code); + + xpand_connection *trx = get_trx(thd, &error_code); + if (!trx) + DBUG_RETURN(error_code); + + my_bitmap_free(&scan_fields); + if (scan_cur && (error_code = trx->scan_end(scan_cur))) + DBUG_RETURN(error_code); + scan_cur = NULL; + + DBUG_RETURN(0); +} + +void ha_xpand::position(const uchar *record) +{ + DBUG_ENTER("xpd_position"); + if (has_hidden_key) { + memcpy(ref, &last_hidden_key, sizeof(ulonglong)); + } else { + KEY* key_info = table->key_info + table->s->primary_key; + key_copy(ref, record, key_info, key_info->key_length); + } + DBUG_DUMP("key", ref, ref_length); + DBUG_VOID_RETURN; +} + +uint ha_xpand::lock_count(void) const +{ + /* Hopefully, we don't need to use thread locks */ + return 0; +} + +THR_LOCK_DATA **ha_xpand::store_lock(THD *thd, + THR_LOCK_DATA **to, + enum thr_lock_type lock_type) +{ + /* Hopefully, we don't need to use thread locks */ + return to; +} + +int ha_xpand::external_lock(THD *thd, int lock_type) +{ + DBUG_ENTER("ha_xpand::external_lock()"); + int error_code; + xpand_connection *trx = get_trx(thd, &error_code); + if (error_code) + DBUG_RETURN(error_code); + + if (lock_type == F_WRLCK) + xpd_lock_type = XPAND_EXCLUSIVE; + else if (lock_type == F_RDLCK) + xpd_lock_type = XPAND_SHARED; + else if (lock_type == F_UNLCK) + xpd_lock_type = XPAND_NO_LOCKS; + + if (lock_type != F_UNLCK) { + if (!trx->has_open_transaction()) { + error_code = trx->begin_transaction_next(); + if (error_code) + DBUG_RETURN(error_code); + } + + trans_register_ha(thd, FALSE, xpand_hton); + if (thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) + trans_register_ha(thd, TRUE, xpand_hton); + } + + DBUG_RETURN(error_code); +} + +/**************************************************************************** + Engine Condition Pushdown +****************************************************************************/ + +const COND *ha_xpand::cond_push(const COND *cond) +{ + return cond; +} + +void ha_xpand::cond_pop() +{ +} + +int ha_xpand::info_push(uint info_type, void *info) +{ + return 0; +} + +/**************************************************************************** +** Row encoding functions +****************************************************************************/ + +void add_current_table_to_rpl_table_list(rpl_group_info **_rgi, THD *thd, + TABLE *table) +{ + if (*_rgi) + return; + + Relay_log_info *rli = new Relay_log_info(FALSE); + rli->sql_driver_thd = thd; + + rpl_group_info *rgi = new rpl_group_info(rli); + *_rgi = rgi; + rgi->thd = thd; + rgi->tables_to_lock_count = 0; + rgi->tables_to_lock = NULL; + if (rgi->tables_to_lock_count) + return; + + rgi->tables_to_lock = (RPL_TABLE_LIST *)my_malloc(sizeof(RPL_TABLE_LIST), + MYF(MY_WME)); + rgi->tables_to_lock->init_one_table(&table->s->db, &table->s->table_name, 0, + TL_READ); + rgi->tables_to_lock->table = table; + rgi->tables_to_lock->table_id = table->tablenr; + rgi->tables_to_lock->m_conv_table = NULL; + rgi->tables_to_lock->master_had_triggers = FALSE; + rgi->tables_to_lock->m_tabledef_valid = TRUE; + // We need one byte per column to save a column's binlog type. + uchar *col_type = (uchar*) my_alloca(table->s->fields); + for (uint i = 0 ; i < table->s->fields ; ++i) + col_type[i] = table->field[i]->binlog_type(); + + table_def *tabledef = &rgi->tables_to_lock->m_tabledef; + new (tabledef) table_def(col_type, table->s->fields, NULL, 0, NULL, 0); + rgi->tables_to_lock_count++; + if (col_type) + my_afree(col_type); +} + +void remove_current_table_from_rpl_table_list(rpl_group_info *rgi) +{ + if (!rgi->tables_to_lock) + return; + + rgi->tables_to_lock->m_tabledef.table_def::~table_def(); + rgi->tables_to_lock->m_tabledef_valid = FALSE; + my_free(rgi->tables_to_lock); + rgi->tables_to_lock_count--; + rgi->tables_to_lock = NULL; + delete rgi->rli; + delete rgi; +} + +void ha_xpand::build_key_packed_row(uint index, const uchar *buf, + uchar *packed_key, + size_t *packed_key_len) +{ + if (index == table->s->primary_key && has_hidden_key) { + memcpy(packed_key, &last_hidden_key, sizeof(ulonglong)); + *packed_key_len = sizeof(ulonglong); + } else { + // make a row from the table + table->mark_columns_used_by_index(index, &table->tmp_set); + *packed_key_len = pack_row(table, &table->tmp_set, packed_key, buf); + } +} + +int unpack_row_to_buf(rpl_group_info *rgi, TABLE *table, uchar *data, + uchar const *const row_data, MY_BITMAP const *cols, + uchar const *const row_end) +{ + /* Since unpack_row can only write to record[0], if 'data' does not point to + table->record[0], we must back it up and then restore it afterwards. */ + uchar const *current_row_end; + ulong master_reclength; + uchar *backup_row = NULL; + if (data != table->record[0]) { + /* See Update_rows_log_event::do_exec_row(rpl_group_info *rgi) + and the definitions of store_record and restore_record. */ + backup_row = (uchar*) my_alloca(table->s->reclength); + memcpy(backup_row, table->record[0], table->s->reclength); + restore_record(table, record[data == table->record[1] ? 1 : 2]); + } + + int error_code = unpack_row(rgi, table, table->s->fields, row_data, cols, + ¤t_row_end, &master_reclength, row_end); + + if (backup_row) { + store_record(table, record[data == table->record[1] ? 1 : 2]); + memcpy(table->record[0], backup_row, table->s->reclength); + my_afree(backup_row); + } + + return error_code; +} + +/**************************************************************************** +** Plugin Functions +****************************************************************************/ + +static int xpand_commit(handlerton *hton, THD *thd, bool all) +{ + xpand_connection* trx = (xpand_connection *) thd_get_ha_data(thd, hton); + assert(trx); + + int error_code = 0; + if (trx->has_open_transaction()) { + if (all || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) + error_code = trx->commit_transaction(); + else + error_code = trx->new_statement_next(); + } + + return error_code; +} + +static int xpand_rollback(handlerton *hton, THD *thd, bool all) +{ + xpand_connection* trx = (xpand_connection *) thd_get_ha_data(thd, hton); + assert(trx); + + int error_code = 0; + if (trx->has_open_transaction()) { + if (all || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) + error_code = trx->rollback_transaction(); + else + error_code = trx->rollback_statement_next(); + } + + return error_code; +} + +static handler* xpand_create_handler(handlerton *hton, TABLE_SHARE *table, + MEM_ROOT *mem_root) +{ + return new (mem_root) ha_xpand(hton, table); +} + +static int xpand_close_connection(handlerton* hton, THD* thd) +{ + xpand_connection* trx = (xpand_connection *) thd_get_ha_data(thd, hton); + if (!trx) + return 0; /* Transaction is not started */ + + int error_code = xpand_rollback(xpand_hton, thd, TRUE); + + delete trx; + + return error_code; +} + +static int xpand_panic(handlerton *hton, ha_panic_function type) +{ + return 0; +} + +static bool xpand_show_status(handlerton *hton, THD *thd, + stat_print_fn *stat_print, + enum ha_stat_type stat_type) +{ + return FALSE; +} + +static int xpand_discover_table_names(handlerton *hton, LEX_CSTRING *db, + MY_DIR *dir, + handlerton::discovered_list *result) +{ + xpand_connection *xpand_net = new xpand_connection(); + int error_code = xpand_net->connect(); + if (error_code) + goto err; + + xpand_net->populate_table_list(db, result); + +err: + delete xpand_net; + return error_code; +} + +int xpand_discover_table(handlerton *hton, THD *thd, TABLE_SHARE *share) +{ + xpand_connection *xpand_net = new xpand_connection(); + int error_code = xpand_net->connect(); + if (error_code) + goto err; + + error_code = xpand_net->discover_table_details(&share->db, + &share->table_name, + thd, share); + +err: + delete xpand_net; + return error_code; +} + +static int xpand_init(void *p) +{ + DBUG_ENTER("xpand_init"); + xpand_hton = (handlerton *) p; + xpand_hton->flags = HTON_NO_FLAGS; + xpand_hton->panic = xpand_panic; + xpand_hton->close_connection = xpand_close_connection; + xpand_hton->commit = xpand_commit; + xpand_hton->rollback = xpand_rollback; + xpand_hton->create = xpand_create_handler; + xpand_hton->show_status = xpand_show_status; + xpand_hton->discover_table_names = xpand_discover_table_names; + xpand_hton->discover_table = xpand_discover_table; + xpand_hton->create_select = create_xpand_select_handler; + xpand_hton->create_derived = create_xpand_derived_handler; + + update_host_list(xpand_host); + + DBUG_RETURN(0); +} + +static int xpand_deinit(void *p) +{ + DBUG_ENTER("xpand_deinit"); + free_host_list(); + DBUG_RETURN(0); +} + +struct st_mysql_show_var xpand_status_vars[] = +{ + {NullS, NullS, SHOW_LONG} +}; + +static struct st_mysql_sys_var* xpand_system_variables[] = +{ + MYSQL_SYSVAR(connect_timeout), + MYSQL_SYSVAR(read_timeout), + MYSQL_SYSVAR(write_timeout), + MYSQL_SYSVAR(host), + MYSQL_SYSVAR(username), + MYSQL_SYSVAR(password), + MYSQL_SYSVAR(port), + MYSQL_SYSVAR(socket), + MYSQL_SYSVAR(row_buffer), + MYSQL_SYSVAR(select_handler), + MYSQL_SYSVAR(derived_handler), + MYSQL_SYSVAR(enable_direct_update), + NULL +}; + +static struct st_mysql_storage_engine xpand_storage_engine = + {MYSQL_HANDLERTON_INTERFACE_VERSION}; + +maria_declare_plugin(xpand) +{ + MYSQL_STORAGE_ENGINE_PLUGIN, /* Plugin Type */ + &xpand_storage_engine, /* Plugin Descriptor */ + "XPAND", /* Plugin Name */ + "MariaDB", /* Plugin Author */ + "Xpand storage engine", /* Plugin Description */ + PLUGIN_LICENSE_GPL, /* Plugin Licence */ + xpand_init, /* Plugin Entry Point */ + xpand_deinit, /* Plugin Deinitializer */ + 0x0001, /* Hex Version Number (0.1) */ + NULL /* xpand_status_vars */, /* Status Variables */ + xpand_system_variables, /* System Variables */ + "0.1", /* String Version */ + MariaDB_PLUGIN_MATURITY_EXPERIMENTAL /* Maturity Level */ +} +maria_declare_plugin_end; diff --git a/storage/xpand/ha_xpand.h b/storage/xpand/ha_xpand.h new file mode 100644 index 00000000000..48359af6470 --- /dev/null +++ b/storage/xpand/ha_xpand.h @@ -0,0 +1,130 @@ +/***************************************************************************** +Copyright (c) 2019, MariaDB Corporation. +*****************************************************************************/ + +#ifndef _ha_xpand_h +#define _ha_xpand_h + +#ifdef USE_PRAGMA_INTERFACE +#pragma interface /* gcc class implementation */ +#endif + +#define MYSQL_SERVER 1 +#include "xpand_connection.h" +#include "my_bitmap.h" +#include "table.h" +#include "rpl_rli.h" +#include "handler.h" +#include "sql_class.h" +#include "sql_show.h" +#include "mysql.h" +#include "../../sql/rpl_record.h" + +size_t estimate_row_size(TABLE *table); +xpand_connection *get_trx(THD *thd, int *error_code); +bool get_enable_sh(THD* thd); +void add_current_table_to_rpl_table_list(rpl_group_info **_rgi, THD *thd, + TABLE *table); +void remove_current_table_from_rpl_table_list(rpl_group_info *rgi); +int unpack_row_to_buf(rpl_group_info *rgi, TABLE *table, uchar *data, + uchar const *const row_data, MY_BITMAP const *cols, + uchar const *const row_end); + +class ha_xpand : public handler +{ +private: + ulonglong xpand_table_oid; + rpl_group_info *rgi; + + Field *auto_inc_field; + ulonglong auto_inc_value; + + bool has_hidden_key; + ulonglong last_hidden_key; + xpand_connection_cursor *scan_cur; + bool is_scan; + MY_BITMAP scan_fields; + bool sorted_scan; + xpand_lock_mode_t xpd_lock_type; + + uint last_dup_errkey; + + typedef enum xpand_upsert_flags { + XPAND_HAS_UPSERT= 1, + XPAND_BULK_UPSERT= 2, + XPAND_UPSERT_SENT= 4 + } xpd_upsert_flags_t; + int upsert_flag; + +public: + ha_xpand(handlerton *hton, TABLE_SHARE *table_arg); + ~ha_xpand(); + int create(const char *name, TABLE *form, HA_CREATE_INFO *info); + int delete_table(const char *name); + int rename_table(const char* from, const char* to); + int open(const char *name, int mode, uint test_if_locked); + int close(void); + int reset(); + int extra(enum ha_extra_function operation); + int write_row(const uchar *buf); + // start_bulk_update exec_bulk_update + int update_row(const uchar *old_data, const uchar *new_data); + // start_bulk_delete exec_bulk_delete + int delete_row(const uchar *buf); + int direct_update_rows_init(List *update_fields); + int direct_update_rows(ha_rows *update_rows, ha_rows *found_rows); + void start_bulk_insert(ha_rows rows, uint flags = 0); + int end_bulk_insert(); + + Table_flags table_flags(void) const; + ulong index_flags(uint idx, uint part, bool all_parts) const; + uint max_supported_keys() const { return MAX_KEY; } + + ha_rows records(); + ha_rows records_in_range(uint inx, key_range *min_key, + key_range *max_key); + + int info(uint flag); // see my_base.h for full description + + // multi_read_range + // read_range + int index_init(uint idx, bool sorted); + int index_read(uchar * buf, const uchar * key, uint key_len, + enum ha_rkey_function find_flag); + int index_first(uchar *buf); + int index_prev(uchar *buf); + int index_last(uchar *buf); + int index_next(uchar *buf); + //int index_next_same(uchar *buf, const uchar *key, uint keylen); + int index_end(); + + int rnd_init(bool scan); + int rnd_next(uchar *buf); + int rnd_pos(uchar * buf, uchar *pos); + int rnd_end(); + + void position(const uchar *record); + uint lock_count(void) const; + THR_LOCK_DATA **store_lock(THD *thd, + THR_LOCK_DATA **to, + enum thr_lock_type lock_type); + int external_lock(THD *thd, int lock_type); + + uint8 table_cache_type() + { + return(HA_CACHE_TBL_NOCACHE); + } + + const COND *cond_push(const COND *cond); + void cond_pop(); + int info_push(uint info_type, void *info); + +private: + void build_key_packed_row(uint index, const uchar *buf, + uchar *packed_key, size_t *packed_key_len); +}; + +bool select_handler_setting(THD* thd); +bool derived_handler_setting(THD* thd); +uint row_buffer_setting(THD* thd); +#endif // _ha_xpand_h diff --git a/storage/xpand/ha_xpand_pushdown.cc b/storage/xpand/ha_xpand_pushdown.cc new file mode 100644 index 00000000000..e53c4f445fa --- /dev/null +++ b/storage/xpand/ha_xpand_pushdown.cc @@ -0,0 +1,478 @@ +/***************************************************************************** +Copyright (c) 2019, MariaDB Corporation. +*****************************************************************************/ + +#include "ha_xpand.h" +#include "ha_xpand_pushdown.h" + +extern handlerton *xpand_hton; +extern uint xpand_row_buffer; + +/*@brief Fills up array data types, metadata and nullability*/ +/************************************************************ + * DESCRIPTION: + * Fills up three arrays with: field binlog data types, field + * metadata and nullability bitmask as in Table_map_log_event + * ctor. Internally creates a temporary table as does + * Pushdown_select. DH uses the actual temp table w/o + * b/c create_DH is called later compared to create_SH. + * More details in server/sql/log_event_server.cc + * PARAMETERS: + * thd - THD* + * table__ - TABLE* temp table for the results + * sl - SELECT_LEX* + * fieldtype - uchar* + * field_metadata - uchar* + * null_bits - uchar* + * num_null_bytes - null bit size + * fields_count - a number of fields + * RETURN: + * metadata_size int or -1 in case of error + ************************************************************/ +int get_field_types(THD *thd, TABLE *table__, SELECT_LEX *sl, uchar *fieldtype, + uchar *field_metadata, uchar *null_bits, const int num_null_bytes, const uint fields_count) +{ + int field_metadata_size = 0; + int metadata_index = 0; + TABLE *tmp_table= table__; + + if (!tmp_table) { + // Construct a tmp table with fields to find out result DTs. + // This should be reconsidered if it worths the effort. + List types; + TMP_TABLE_PARAM tmp_table_param; + sl->master_unit()->join_union_item_types(thd, types, 1); + tmp_table_param.init(); + tmp_table_param.field_count= types.elements; + + tmp_table = create_tmp_table(thd, &tmp_table_param, types, + (ORDER *) 0, false, 0, + TMP_TABLE_ALL_COLUMNS, 1, + &empty_clex_str, true, false); + if (!tmp_table) { + field_metadata_size = -1; + goto err; + } + } + + for (unsigned int i = 0 ; i < fields_count; ++i) { + fieldtype[i]= tmp_table->field[i]->binlog_type(); + } + + bzero(field_metadata, (fields_count * 2)); + for (unsigned int i= 0 ; i < fields_count ; i++) + { + Binlog_type_info bti= tmp_table->field[i]->binlog_type_info(); + uchar *ptr = reinterpret_cast(&bti.m_metadata); + memcpy(&field_metadata[metadata_index], ptr, bti.m_metadata_size); + metadata_index+= bti.m_metadata_size; + } + + if (metadata_index < 251) + field_metadata_size += metadata_index + 1; + else + field_metadata_size += metadata_index + 3; + + bzero(null_bits, num_null_bytes); + for (unsigned int i= 0 ; i < fields_count ; ++i) { + if (tmp_table->field[i]->maybe_null()) { + null_bits[(i / 8)]+= 1 << (i % 8); + } + } + + if (!table__) + free_tmp_table(thd, tmp_table); +err: + return field_metadata_size; +} + + +/*@brief create_xpand_select_handler- Creates handler*/ +/************************************************************ + * DESCRIPTION: + * Creates a select handler + * More details in server/sql/select_handler.h + * PARAMETERS: + * thd - THD pointer. + * sel - SELECT_LEX* that describes the query. + * RETURN: + * select_handler if possible + * NULL otherwise + ************************************************************/ +select_handler* +create_xpand_select_handler(THD* thd, SELECT_LEX* select_lex) +{ + ha_xpand_select_handler *sh = NULL; + if (!select_handler_setting(thd)) { + return sh; + } + + // TODO Return early for EXPLAIN before we run the actual scan. + // We can send compile request when we separate compilation + // and execution. + xpand_connection_cursor *scan = NULL; + if (thd->lex->describe) { + sh = new ha_xpand_select_handler(thd, select_lex, scan); + return sh; + } + + // Multi-update runs an implicit query to collect constraints. + // SH couldn't be used for this. + if (thd->lex->sql_command == SQLCOM_UPDATE_MULTI) { + return sh; + } + + String query; + // Print the query into a string provided + select_lex->print(thd, &query, QT_ORDINARY); + int error_code = 0; + int field_metadata_size = 0; + xpand_connection *trx = NULL; + + // We presume this number is equal to types.elements in get_field_types + uint items_number = select_lex->get_item_list()->elements; + uint num_null_bytes = (items_number + 7) / 8; + uchar *fieldtype = NULL; + uchar *null_bits = NULL; + uchar *field_metadata = NULL; + uchar *meta_memory= (uchar *)my_multi_malloc(MYF(MY_WME), &fieldtype, items_number, + &null_bits, num_null_bytes, &field_metadata, (items_number * 2), NULL); + + if (!meta_memory) { + // The only way to say something here is to raise warning + // b/c we will fallback to other access methods: derived handler or rowstore. + goto err; + } + + if((field_metadata_size = + get_field_types(thd, NULL, select_lex, fieldtype, field_metadata, null_bits, num_null_bytes, items_number)) < 0) { + goto err; + } + + trx = get_trx(thd, &error_code); + if (!trx) + goto err; + + if (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) + trx->auto_commit_next(); + + if ((error_code = trx->scan_query(query, fieldtype, items_number, null_bits, + num_null_bytes, field_metadata, + field_metadata_size, + row_buffer_setting(thd), &scan))) { + goto err; + } + + sh = new ha_xpand_select_handler(thd, select_lex, scan); + +err: + // deallocate buffers + if (meta_memory) + my_free(meta_memory); + + return sh; +} + +/*********************************************************** + * DESCRIPTION: + * select_handler constructor + * PARAMETERS: + * thd - THD pointer. + * select_lex - sematic tree for the query. + **********************************************************/ +ha_xpand_select_handler::ha_xpand_select_handler( + THD *thd, + SELECT_LEX* select_lex, + xpand_connection_cursor *scan_) + : select_handler(thd, xpand_hton) +{ + thd__ = thd; + scan = scan_; + select = select_lex; + rgi = NULL; +} + +/*********************************************************** + * DESCRIPTION: + * select_handler constructor + * This frees dynamic memory allocated for bitmap + * and disables replication to SH temp table. + **********************************************************/ +ha_xpand_select_handler::~ha_xpand_select_handler() +{ + int error_code; + xpand_connection *trx = get_trx(thd, &error_code); + if (!trx) { + // TBD Log this + } + if (trx && scan) + trx->scan_end(scan); + + // If the ::init_scan has been executed + if (table__) + my_bitmap_free(&scan_fields); + + if (rgi) + remove_current_table_from_rpl_table_list(rgi); +} + +/*@brief Initiate the query for select_handler */ +/*********************************************************** + * DESCRIPTION: + * Initializes dynamic structures and sets SH temp table + * as RBR replication destination to unpack rows. + * * PARAMETERS: + * RETURN: + * rc as int + * ********************************************************/ +int ha_xpand_select_handler::init_scan() +{ + // Save this into the base handler class attribute + table__ = table; + // need this bitmap future in next_row() + if (my_bitmap_init(&scan_fields, NULL, table->read_set->n_bits, false)) + return ER_OUTOFMEMORY; + bitmap_set_all(&scan_fields); + + add_current_table_to_rpl_table_list(&rgi, thd__, table__); + + return 0; +} + +/*@brief Fetch next row for select_handler */ +/*********************************************************** + * DESCRIPTION: + * Fetch next row for select_handler. + * PARAMETERS: + * RETURN: + * rc as int + * ********************************************************/ +int ha_xpand_select_handler::next_row() +{ + int error_code = 0; + xpand_connection *trx = get_trx(thd, &error_code); + if (!trx) + return error_code; + + assert(scan); + + uchar *rowdata; + ulong rowdata_length; + if ((error_code = trx->scan_next(scan, &rowdata, &rowdata_length))) + return error_code; + + uchar const *current_row_end; + ulong master_reclength; + + error_code = unpack_row(rgi, table, table->s->fields, rowdata, + &scan_fields, ¤t_row_end, + &master_reclength, rowdata + rowdata_length); + + if (error_code) + return error_code; + + return 0; +} + +/*@brief Finishes the scan and clean it up */ +/*********************************************************** + * DESCRIPTION: + * Finishes the scan for select handler + * PARAMETERS: + * RETURN: + * rc as int + ***********************************************************/ +int ha_xpand_select_handler::end_scan() +{ + return 0; +} + +/*@brief create_xpand_derived_handler- Creates handler*/ +/************************************************************ + * DESCRIPTION: + * Creates a derived handler + * More details in server/sql/derived_handler.h + * PARAMETERS: + * thd - THD pointer. + * derived - TABLE_LIST* that describes the tables involved + * RETURN: + * derived_handler if possible + * NULL otherwise + ************************************************************/ +derived_handler* +create_xpand_derived_handler(THD* thd, TABLE_LIST *derived) +{ + ha_xpand_derived_handler *dh = NULL; + if (!derived_handler_setting(thd)) { + return dh; + } + + SELECT_LEX_UNIT *unit= derived->derived; + SELECT_LEX *select_lex = unit->first_select(); + String query; + + dh = new ha_xpand_derived_handler(thd, select_lex, NULL); + + return dh; +} + +/*********************************************************** + * DESCRIPTION: + * derived_handler constructor + * PARAMETERS: + * thd - THD pointer. + * select_lex - sematic tree for the query. + **********************************************************/ +ha_xpand_derived_handler::ha_xpand_derived_handler( + THD *thd, + SELECT_LEX* select_lex, + xpand_connection_cursor *scan_) + : derived_handler(thd, xpand_hton) +{ + thd__ = thd; + scan = scan_; + select = select_lex; + rgi = NULL; +} + +/*********************************************************** + * DESCRIPTION: + * derived_handler constructor + * This frees dynamic memory allocated for bitmap + * and disables replication to SH temp table. + **********************************************************/ +ha_xpand_derived_handler::~ha_xpand_derived_handler() +{ + int error_code; + + + + xpand_connection *trx = get_trx(thd, &error_code); + if (!trx) { + // TBD Log this. + } + if (trx && scan) + trx->scan_end(scan); + + // If the ::init_scan has been executed + if (table__) + my_bitmap_free(&scan_fields); + + if (rgi) + remove_current_table_from_rpl_table_list(rgi); +} + +/*@brief Initiate the query for derived_handler */ +/*********************************************************** + * DESCRIPTION: + * Initializes dynamic structures and sets SH temp table + * as RBR replication destination to unpack rows. + * * PARAMETERS: + * RETURN: + * rc as int + * ********************************************************/ +int ha_xpand_derived_handler::init_scan() +{ + String query; + // Print the query into a string provided + select->print(thd__, &query, QT_ORDINARY); + int error_code = 0; + int field_metadata_size = 0; + xpand_connection *trx = NULL; + + // We presume this number is equal to types.elements in get_field_types + uint items_number= select->get_item_list()->elements; + uint num_null_bytes = (items_number + 7) / 8; + uchar *fieldtype = NULL; + uchar *null_bits = NULL; + uchar *field_metadata = NULL; + uchar *meta_memory= (uchar *)my_multi_malloc(MYF(MY_WME), &fieldtype, items_number, + &null_bits, num_null_bytes, &field_metadata, (items_number * 2), NULL); + + if (!meta_memory) { + // The only way to say something here is to raise warning + // b/c we will fallback to other access methods: derived handler or rowstore. + goto err; + } + + if((field_metadata_size= + get_field_types(thd__, table, select, fieldtype, field_metadata, null_bits, num_null_bytes, items_number)) < 0) { + goto err; + } + + trx = get_trx(thd__, &error_code); + if (!trx) + goto err; + + if ((error_code = trx->scan_query(query, fieldtype, items_number, null_bits, + num_null_bytes, field_metadata, + field_metadata_size, + row_buffer_setting(thd), &scan))) { + goto err; + } + + // Save this into the base handler class attribute + table__ = table; + + // need this bitmap future in next_row() + if (my_bitmap_init(&scan_fields, NULL, table->read_set->n_bits, false)) + return ER_OUTOFMEMORY; + bitmap_set_all(&scan_fields); + + add_current_table_to_rpl_table_list(&rgi, thd__, table__); + +err: + // deallocate buffers + if (meta_memory) + my_free(meta_memory); + + return error_code; +} + +/*@brief Fetch next row for derived_handler */ +/*********************************************************** + * DESCRIPTION: + * Fetch next row for derived_handler. + * PARAMETERS: + * RETURN: + * rc as int + * ********************************************************/ +int ha_xpand_derived_handler::next_row() +{ + int error_code = 0; + xpand_connection *trx = get_trx(thd, &error_code); + if (!trx) + return error_code; + + assert(scan); + + uchar *rowdata; + ulong rowdata_length; + if ((error_code = trx->scan_next(scan, &rowdata, &rowdata_length))) + return error_code; + + uchar const *current_row_end; + ulong master_reclength; + + error_code = unpack_row(rgi, table, table->s->fields, rowdata, + &scan_fields, ¤t_row_end, + &master_reclength, rowdata + rowdata_length); + + if (error_code) + return error_code; + + return 0; +} + +/*@brief Finishes the scan and clean it up */ +/*********************************************************** + * DESCRIPTION: + * Finishes the scan for derived handler + * PARAMETERS: + * RETURN: + * rc as int + ***********************************************************/ +int ha_xpand_derived_handler::end_scan() +{ + return 0; +} diff --git a/storage/xpand/ha_xpand_pushdown.h b/storage/xpand/ha_xpand_pushdown.h new file mode 100644 index 00000000000..3fd234131c9 --- /dev/null +++ b/storage/xpand/ha_xpand_pushdown.h @@ -0,0 +1,87 @@ +/***************************************************************************** +Copyright (c) 2019, MariaDB Corporation. +*****************************************************************************/ +#ifndef _ha_xpand_pushdown_h +#define _ha_xpand_pushdown_h + +#include "select_handler.h" +#include "derived_handler.h" +#include "sql_select.h" + +/*@brief base_handler class*/ +/*********************************************************** + * DESCRIPTION: + * To be described + ************************************************************/ +class ha_xpand_base_handler +{ + // To simulate abstract class + protected: + ha_xpand_base_handler(): thd__(0),table__(0) {} + ~ha_xpand_base_handler() {} + + // Copies of pushdown handlers attributes + // to use them in shared methods. + THD *thd__; + TABLE *table__; + // The bitmap used to sent + MY_BITMAP scan_fields; + // Structures to unpack RBR rows from XPD BE + rpl_group_info *rgi; + // XPD BE scan operation reference + xpand_connection_cursor *scan; +}; + +/*@brief select_handler class*/ +/*********************************************************** + * DESCRIPTION: + * select_handler API methods. Could be used by the server + * tp pushdown the whole query described by SELECT_LEX. + * More details in server/sql/select_handler.h + * sel semantic tree for the query in SELECT_LEX. + ************************************************************/ +class ha_xpand_select_handler: + private ha_xpand_base_handler, + public select_handler +{ + public: + ha_xpand_select_handler(THD* thd_arg, SELECT_LEX* sel, + xpand_connection_cursor *scan); + ~ha_xpand_select_handler(); + + int init_scan(); + int next_row(); + int end_scan(); + void print_error(int, unsigned long) {} +}; + +/*@brief derived_handler class*/ +/*********************************************************** + * DESCRIPTION: + * derived_handler API methods. Could be used by the server + * tp pushdown the whole query described by SELECT_LEX. + * More details in server/sql/derived_handler.h + * sel semantic tree for the query in SELECT_LEX. + ************************************************************/ +class ha_xpand_derived_handler: + private ha_xpand_base_handler, + public derived_handler +{ + public: + ha_xpand_derived_handler(THD* thd_arg, SELECT_LEX* sel, + xpand_connection_cursor *scan); + ~ha_xpand_derived_handler(); + + int init_scan(); + int next_row(); + int end_scan(); + void print_error(int, unsigned long) {} +}; + + +select_handler *create_xpand_select_handler(THD* thd, + SELECT_LEX* select_lex); +derived_handler *create_xpand_derived_handler(THD* thd, + TABLE_LIST *derived); + +#endif diff --git a/storage/xpand/xpand_connection.cc b/storage/xpand/xpand_connection.cc new file mode 100644 index 00000000000..fac728f291c --- /dev/null +++ b/storage/xpand/xpand_connection.cc @@ -0,0 +1,1190 @@ +/***************************************************************************** +Copyright (c) 2019, MariaDB Corporation. +*****************************************************************************/ + +/** @file xpand_connection.cc */ + +#include "xpand_connection.h" +#include +#include "errmsg.h" +#include "handler.h" +#include "table.h" + +extern int xpand_connect_timeout; +extern int xpand_read_timeout; +extern int xpand_write_timeout; +extern char *xpand_host; +extern char *xpand_username; +extern char *xpand_password; +extern uint xpand_port; +extern char *xpand_socket; + +/* + This class implements the commands that can be sent to the cluster by the + Xpand engine. All of these commands return a status to the caller, but some + commands also create open invocations on the cluster, which must be closed by + sending additional commands. + + Transactions on the cluster are started using flags attached to commands, and + transactions are committed or rolled back using separate commands. + + Methods ending with _next affect the transaction state after the next command + is sent to the cluster. Other transaction commands are sent to the cluster + immediately, and the state is changed before they return. + + _____________________ _______________________ + | | | | | | + V | | V | | + NONE --> REQUESTED --> STARTED --> NEW_STMT | + | | + `----> ROLLBACK_STMT ---` + + The commit and rollback commands will change any other state to NONE. This + includes the REQUESTED state, for which nothing will be sent to the cluster. + The rollback statement command can likewise change the state from NEW_STMT to + STARTED without sending anything to the cluster. + + In addition, the XPAND_TRANS_AUTOCOMMIT flag will cause the transactions + for commands that complete without leaving open invocations on the cluster to + be committed if successful or rolled back if there was an error. If + auto-commit is enabled, only one open invocation may be in progress at a + time. +*/ + +enum xpand_trans_state { + XPAND_TRANS_STARTED = 0, + XPAND_TRANS_REQUESTED = 1, + XPAND_TRANS_NEW_STMT = 2, + XPAND_TRANS_ROLLBACK_STMT = 4, + XPAND_TRANS_NONE = 32, +}; + +enum xpand_trans_post_flags { + XPAND_TRANS_AUTOCOMMIT = 8, + XPAND_TRANS_NO_POST_FLAGS = 0, +}; + +enum xpand_commands { + XPAND_WRITE_ROW = 1, + XPAND_SCAN_TABLE, + XPAND_SCAN_NEXT, + XPAND_SCAN_STOP, + XPAND_KEY_READ, + XPAND_KEY_DELETE, + XPAND_SCAN_QUERY, + XPAND_KEY_UPDATE, + XPAND_SCAN_FROM_KEY, + XPAND_UPDATE_QUERY, + XPAND_COMMIT, + XPAND_ROLLBACK, +}; + +/**************************************************************************** +** Class xpand_connection +****************************************************************************/ +xpand_connection::xpand_connection() + : command_buffer(NULL), command_buffer_length(0), command_length(0), + trans_state(XPAND_TRANS_NONE), trans_flags(XPAND_TRANS_NO_POST_FLAGS) +{ + DBUG_ENTER("xpand_connection::xpand_connection"); + memset(&xpand_net, 0, sizeof(MYSQL)); + DBUG_VOID_RETURN; +} + +xpand_connection::~xpand_connection() +{ + DBUG_ENTER("xpand_connection::~xpand_connection"); + if (is_connected()) + disconnect(TRUE); + + if (command_buffer) + my_free(command_buffer); + DBUG_VOID_RETURN; +} + +void xpand_connection::disconnect(bool is_destructor) +{ + DBUG_ENTER("xpand_connection::disconnect"); + if (is_destructor) + { + /* + Connection object destruction occurs after the destruction of + the thread used by the network has begun, so usage of that + thread object now is not reliable + */ + xpand_net.net.thd = NULL; + } + mysql_close(&xpand_net); + DBUG_VOID_RETURN; +} + +int host_list_next; +extern int host_list_cnt; +extern char **host_list; + +int xpand_connection::connect() +{ + int error_code = 0; + my_bool my_true = 1; + DBUG_ENTER("xpand_connection::connect"); + + // cpu concurrency by damned! + int host_num = host_list_next; + host_num = host_num % host_list_cnt; + char *host = host_list[host_num]; + host_list_next = host_num + 1; + DBUG_PRINT("host", ("%s", host)); + + /* Validate the connection parameters */ + if (!strcmp(xpand_socket, "")) + if (!strcmp(host, "127.0.0.1")) + if (xpand_port == MYSQL_PORT_DEFAULT) + DBUG_RETURN(ER_CONNECT_TO_FOREIGN_DATA_SOURCE); + + //xpand_net.methods = &connection_methods; + + if (!mysql_init(&xpand_net)) + DBUG_RETURN(HA_ERR_OUT_OF_MEM); + + mysql_options(&xpand_net, MYSQL_OPT_READ_TIMEOUT, + &xpand_read_timeout); + mysql_options(&xpand_net, MYSQL_OPT_WRITE_TIMEOUT, + &xpand_write_timeout); + mysql_options(&xpand_net, MYSQL_OPT_CONNECT_TIMEOUT, + &xpand_connect_timeout); + mysql_options(&xpand_net, MYSQL_OPT_USE_REMOTE_CONNECTION, + NULL); + mysql_options(&xpand_net, MYSQL_SET_CHARSET_NAME, "utf8mb4"); + mysql_options(&xpand_net, MYSQL_OPT_USE_THREAD_SPECIFIC_MEMORY, + (char *) &my_true); + mysql_options(&xpand_net, MYSQL_INIT_COMMAND,"SET autocommit=0"); + +#ifdef XPAND_CONNECTION_SSL + if (opt_ssl_ca_length | conn->tgt_ssl_capath_length | + conn->tgt_ssl_cert_length | conn->tgt_ssl_key_length) + { + mysql_ssl_set(&xpand_net, conn->tgt_ssl_key, conn->tgt_ssl_cert, + conn->tgt_ssl_ca, conn->tgt_ssl_capath, conn->tgt_ssl_cipher); + if (conn->tgt_ssl_vsc) + { + my_bool verify_flg = TRUE; + mysql_options(&xpand_net, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, + &verify_flg); + } + } +#endif + + if (!mysql_real_connect(&xpand_net, host, + xpand_username, xpand_password, + NULL, xpand_port, xpand_socket, + CLIENT_MULTI_STATEMENTS)) + { + error_code = mysql_errno(&xpand_net); + disconnect(); + + if (error_code != CR_CONN_HOST_ERROR && + error_code != CR_CONNECTION_ERROR) + { + if (error_code == ER_CON_COUNT_ERROR) + { + my_error(ER_CON_COUNT_ERROR, MYF(0)); + DBUG_RETURN(ER_CON_COUNT_ERROR); + } + my_error(ER_CONNECT_TO_FOREIGN_DATA_SOURCE, MYF(0), host); + DBUG_RETURN(ER_CONNECT_TO_FOREIGN_DATA_SOURCE); + } + } + + xpand_net.reconnect = 1; + + DBUG_RETURN(0); +} + +int xpand_connection::begin_command(uchar command) +{ + if (trans_state == XPAND_TRANS_NONE) + return HA_ERR_INTERNAL_ERROR; + + command_length = 0; + int error_code = 0; + if ((error_code = add_command_operand_uchar(command))) + return error_code; + + if ((error_code = add_command_operand_uchar(trans_state | trans_flags))) + return error_code; + + return error_code; +} + +int xpand_connection::send_command() +{ + my_bool com_error; + + /* + Please note: + * The transaction state is set before the command is sent because rolling + back a nonexistent transaction is better than leaving a tranaction open + on the cluster. + * The state may have alreadly been STARTED. + * Commit and rollback commands update the transaction state after calling + this function. + * If auto-commit is enabled, the state may also updated after the + response has been processed. We do not clear the auto-commit flag here + because it needs to be sent with each command until the transaction is + committed or rolled back. + */ + trans_state = XPAND_TRANS_STARTED; + + com_error = simple_command(&xpand_net, + (enum_server_command)XPAND_SERVER_REQUEST, + command_buffer, command_length, TRUE); + + if (com_error) + { + int error_code = mysql_errno(&xpand_net); + my_printf_error(error_code, + "Xpand error: %s", MYF(0), + mysql_error(&xpand_net)); + return error_code; + } + + return 0; +} + +int xpand_connection::read_query_response() +{ + my_bool comerr = xpand_net.methods->read_query_result(&xpand_net); + int error_code = 0; + if (comerr) + { + error_code = mysql_errno(&xpand_net); + my_printf_error(error_code, + "Xpand error: %s", MYF(0), + mysql_error(&xpand_net)); + } + + auto_commit_closed(); + return error_code; +} + +bool xpand_connection::has_open_transaction() +{ + return trans_state != XPAND_TRANS_NONE; +} + +int xpand_connection::commit_transaction() +{ + DBUG_ENTER("xpand_connection::commit_transaction"); + if (trans_state == XPAND_TRANS_NONE) + DBUG_RETURN(HA_ERR_INTERNAL_ERROR); + + if (trans_state == XPAND_TRANS_REQUESTED) { + trans_state = XPAND_TRANS_NONE; + trans_flags = XPAND_TRANS_NO_POST_FLAGS; + DBUG_RETURN(0); + } + + int error_code; + if ((error_code = begin_command(XPAND_COMMIT))) + DBUG_RETURN(error_code); + + if ((error_code = send_command())) + DBUG_RETURN(error_code); + + if ((error_code = read_query_response())) + DBUG_RETURN(error_code); + + trans_state = XPAND_TRANS_NONE; + trans_flags = XPAND_TRANS_NO_POST_FLAGS; + DBUG_RETURN(error_code); +} + +int xpand_connection::rollback_transaction() +{ + DBUG_ENTER("xpand_connection::rollback_transaction"); + if (trans_state == XPAND_TRANS_NONE || + trans_state == XPAND_TRANS_REQUESTED) { + trans_state = XPAND_TRANS_NONE; + DBUG_RETURN(0); + } + + int error_code; + if ((error_code = begin_command(XPAND_ROLLBACK))) + DBUG_RETURN(error_code); + + if ((error_code = send_command())) + DBUG_RETURN(error_code); + + if ((error_code = read_query_response())) + DBUG_RETURN(error_code); + + trans_state = XPAND_TRANS_NONE; + trans_flags = XPAND_TRANS_NO_POST_FLAGS; + DBUG_RETURN(error_code); +} + +int xpand_connection::begin_transaction_next() +{ + DBUG_ENTER("xpand_connection::begin_transaction_next"); + if (trans_state != XPAND_TRANS_NONE || + trans_flags != XPAND_TRANS_NO_POST_FLAGS) + DBUG_RETURN(HA_ERR_INTERNAL_ERROR); + + trans_state = XPAND_TRANS_REQUESTED; + DBUG_RETURN(0); +} + +int xpand_connection::new_statement_next() +{ + DBUG_ENTER("xpand_connection::new_statement_next"); + if (trans_state != XPAND_TRANS_STARTED || + trans_flags != XPAND_TRANS_NO_POST_FLAGS) + DBUG_RETURN(HA_ERR_INTERNAL_ERROR); + + trans_state = XPAND_TRANS_NEW_STMT; + DBUG_RETURN(0); +} + +int xpand_connection::rollback_statement_next() +{ + DBUG_ENTER("xpand_connection::rollback_statement_next"); + if (trans_state != XPAND_TRANS_STARTED || + trans_flags != XPAND_TRANS_NO_POST_FLAGS) + DBUG_RETURN(HA_ERR_INTERNAL_ERROR); + + trans_state = XPAND_TRANS_ROLLBACK_STMT; + DBUG_RETURN(0); +} + +void xpand_connection::auto_commit_next() +{ + trans_flags |= XPAND_TRANS_AUTOCOMMIT; +} + +void xpand_connection::auto_commit_closed() +{ + if (trans_flags & XPAND_TRANS_AUTOCOMMIT) { + trans_flags &= ~XPAND_TRANS_AUTOCOMMIT; + trans_state = XPAND_TRANS_NONE; + } +} + +int xpand_connection::run_query(String &stmt) +{ + int error_code = mysql_real_query(&xpand_net, stmt.ptr(), stmt.length()); + if (error_code) + return mysql_errno(&xpand_net); + return error_code; +} + +int xpand_connection::write_row(ulonglong xpand_table_oid, + uchar *packed_row, size_t packed_size, + ulonglong *last_insert_id) +{ + int error_code; + command_length = 0; + + // row based commands should not be called with auto commit. + if (trans_flags & XPAND_TRANS_AUTOCOMMIT) + return HA_ERR_INTERNAL_ERROR; + + if ((error_code = begin_command(XPAND_WRITE_ROW))) + return error_code; + + if ((error_code = add_command_operand_ulonglong(xpand_table_oid))) + return error_code; + + if ((error_code = add_command_operand_str(packed_row, packed_size))) + return error_code; + + if ((error_code = send_command())) + return error_code; + + if ((error_code = read_query_response())) + return error_code; + + *last_insert_id = xpand_net.insert_id; + return error_code; +} + +int xpand_connection::key_update(ulonglong xpand_table_oid, + uchar *packed_key, size_t packed_key_length, + MY_BITMAP *update_set, + uchar *packed_new_data, + size_t packed_new_length) +{ + int error_code; + command_length = 0; + + // row based commands should not be called with auto commit. + if (trans_flags & XPAND_TRANS_AUTOCOMMIT) + return HA_ERR_INTERNAL_ERROR; + + if ((error_code = begin_command(XPAND_KEY_UPDATE))) + return error_code; + + if ((error_code = add_command_operand_ulonglong(xpand_table_oid))) + return error_code; + + if ((error_code = add_command_operand_str(packed_key, packed_key_length))) + return error_code; + + if ((error_code = add_command_operand_bitmap(update_set))) + return error_code; + + if ((error_code = add_command_operand_str(packed_new_data, + packed_new_length))) + return error_code; + + if ((error_code = send_command())) + return error_code; + + if ((error_code = read_query_response())) + return error_code; + + return error_code; +} + +int xpand_connection::key_delete(ulonglong xpand_table_oid, + uchar *packed_key, size_t packed_key_length) +{ + int error_code; + command_length = 0; + + // row based commands should not be called with auto commit. + if (trans_flags & XPAND_TRANS_AUTOCOMMIT) + return HA_ERR_INTERNAL_ERROR; + + if ((error_code = begin_command(XPAND_KEY_DELETE))) + return error_code; + + if ((error_code = add_command_operand_ulonglong(xpand_table_oid))) + return error_code; + + if ((error_code = add_command_operand_str(packed_key, packed_key_length))) + return error_code; + + if ((error_code = send_command())) + return error_code; + + if ((error_code = read_query_response())) + return error_code; + + return error_code; +} + +int xpand_connection::key_read(ulonglong xpand_table_oid, uint index, + xpand_lock_mode_t lock_mode, + MY_BITMAP *read_set, uchar *packed_key, + ulong packed_key_length, uchar **rowdata, + ulong *rowdata_length) +{ + int error_code; + command_length = 0; + + // row based commands should not be called with auto commit. + if (trans_flags & XPAND_TRANS_AUTOCOMMIT) + return HA_ERR_INTERNAL_ERROR; + + if ((error_code = begin_command(XPAND_KEY_READ))) + return error_code; + + if ((error_code = add_command_operand_ulonglong(xpand_table_oid))) + return error_code; + + if ((error_code = add_command_operand_uint(index))) + return error_code; + + if ((error_code = add_command_operand_uchar((uchar)lock_mode))) + return error_code; + + if ((error_code = add_command_operand_bitmap(read_set))) + return error_code; + + if ((error_code = add_command_operand_str(packed_key, packed_key_length))) + return error_code; + + if ((error_code = send_command())) + return error_code; + + ulong packet_length = cli_safe_read(&xpand_net); + if (packet_length == packet_error) + return mysql_errno(&xpand_net); + + uchar *data = xpand_net.net.read_pos; + *rowdata_length = safe_net_field_length_ll(&data, packet_length); + *rowdata = (uchar *)my_malloc(*rowdata_length, MYF(MY_WME)); + memcpy(*rowdata, data, *rowdata_length); + + packet_length = cli_safe_read(&xpand_net); + if (packet_length == packet_error) { + my_free(*rowdata); + *rowdata = NULL; + *rowdata_length = 0; + return mysql_errno(&xpand_net); + } + + return 0; +} + +class xpand_connection_cursor { + struct rowdata { + ulong length; + uchar *data; + }; + + ulong current_row; + ulong last_row; + struct rowdata *rows; + uchar *outstanding_row; // to be freed on next request. + MYSQL *xpand_net; + +public: + ulong buffer_size; + ulonglong scan_refid; + bool eof_reached; + +private: + int cache_row(uchar *rowdata, ulong rowdata_length) + { + DBUG_ENTER("xpand_connection_cursor::cache_row"); + rows[last_row].length = rowdata_length; + rows[last_row].data = (uchar *)my_malloc(rowdata_length, MYF(MY_WME)); + if (!rows[last_row].data) + DBUG_RETURN(HA_ERR_OUT_OF_MEM); + memcpy(rows[last_row].data, rowdata, rowdata_length); + last_row++; + DBUG_RETURN(0); + } + + int load_rows_impl(bool *stmt_completed) + { + DBUG_ENTER("xpand_connection_cursor::load_rows_impl"); + int error_code = 0; + ulong packet_length = cli_safe_read(xpand_net); + if (packet_length == packet_error) { + error_code = mysql_errno(xpand_net); + *stmt_completed = TRUE; + if (error_code == HA_ERR_END_OF_FILE) { + // We have read all rows for query. + eof_reached = TRUE; + DBUG_RETURN(0); + } + DBUG_RETURN(error_code); + } + + uchar *rowdata = xpand_net->net.read_pos; + ulong rowdata_length = safe_net_field_length_ll(&rowdata, packet_length); + if (!rowdata_length) { + // We have read all rows in this batch. + DBUG_RETURN(0); + } + + if ((error_code = cache_row(rowdata, rowdata_length))) + DBUG_RETURN(error_code); + + DBUG_RETURN(load_rows_impl(stmt_completed)); + } + +public: + xpand_connection_cursor(MYSQL *xpand_net_, ulong bufsize) + { + DBUG_ENTER("xpand_connection_cursor::xpand_connection_cursor"); + xpand_net = xpand_net_; + eof_reached = FALSE; + current_row = 0; + last_row = 0; + outstanding_row = NULL; + buffer_size = bufsize; + rows = NULL; + DBUG_VOID_RETURN; + } + + ~xpand_connection_cursor() + { + DBUG_ENTER("xpand_connection_cursor::~xpand_connection_cursor"); + if (outstanding_row) + my_free(outstanding_row); + if (rows) { + while (current_row < last_row) + my_free(rows[current_row++].data); + my_free(rows); + } + DBUG_VOID_RETURN; + } + + int load_rows(bool *stmt_completed) + { + DBUG_ENTER("xpand_connection_cursor::load_rows"); + current_row = 0; + last_row = 0; + DBUG_RETURN(load_rows_impl(stmt_completed)); + } + + int initialize(bool *stmt_completed) + { + DBUG_ENTER("xpand_connection_cursor::initialize"); + ulong packet_length = cli_safe_read(xpand_net); + if (packet_length == packet_error) { + *stmt_completed = TRUE; + DBUG_RETURN(mysql_errno(xpand_net)); + } + + unsigned char *pos = xpand_net->net.read_pos; + scan_refid = safe_net_field_length_ll(&pos, packet_length); + + rows = (struct rowdata *)my_malloc(buffer_size * sizeof(struct rowdata), + MYF(MY_WME)); + if (!rows) + DBUG_RETURN(HA_ERR_OUT_OF_MEM); + + DBUG_RETURN(load_rows(stmt_completed)); + } + + uchar *retrieve_row(ulong *rowdata_length) + { + DBUG_ENTER("xpand_connection_cursor::retrieve_row"); + if (outstanding_row) { + my_free(outstanding_row); + outstanding_row = NULL; + } + if (current_row == last_row) + DBUG_RETURN(NULL); + *rowdata_length = rows[current_row].length; + outstanding_row = rows[current_row].data; + current_row++; + DBUG_RETURN(outstanding_row); + } +}; + +int xpand_connection::allocate_cursor(MYSQL *xpand_net, ulong buffer_size, + xpand_connection_cursor **scan) +{ + DBUG_ENTER("xpand_connection::allocate_cursor"); + *scan = new xpand_connection_cursor(xpand_net, buffer_size); + if (!*scan) + DBUG_RETURN(HA_ERR_OUT_OF_MEM); + + bool stmt_completed = FALSE; + int error_code = (*scan)->initialize(&stmt_completed); + if (error_code) { + delete *scan; + *scan = NULL; + } + + if (stmt_completed) + auto_commit_closed(); + + DBUG_RETURN(error_code); +} + +int xpand_connection::scan_table(ulonglong xpand_table_oid, + xpand_lock_mode_t lock_mode, + MY_BITMAP *read_set, ushort row_req, + xpand_connection_cursor **scan) +{ + int error_code; + command_length = 0; + + // row based commands should not be called with auto commit. + if (trans_flags & XPAND_TRANS_AUTOCOMMIT) + return HA_ERR_INTERNAL_ERROR; + + if ((error_code = begin_command(XPAND_SCAN_TABLE))) + return error_code; + + if ((error_code = add_command_operand_ushort(row_req))) + return error_code; + + if ((error_code = add_command_operand_ulonglong(xpand_table_oid))) + return error_code; + + if ((error_code = add_command_operand_uchar((uchar)lock_mode))) + return error_code; + + if ((error_code = add_command_operand_bitmap(read_set))) + return error_code; + + if ((error_code = send_command())) + return error_code; + + return allocate_cursor(&xpand_net, row_req, scan); +} + +/** + * @brief + * Sends a command to initiate query scan. + * @details + * Sends a command over mysql protocol connection to initiate an + * arbitrary query using a query text. + * Uses field types, field metadata and nullability to explicitly + * cast result to expected data type. Exploits RBR TABLE_MAP_EVENT + * format + sends SQL text. + * @args + * stmt& Query text to send + * fieldtype* array of byte wide field types of result projection + * null_bits* fields nullability bitmap of result projection + * field_metadata* Field metadata of result projection + * scan_refid id used to reference this scan later + * Used in pushdowns to initiate query scan. + **/ +int xpand_connection::scan_query(String &stmt, uchar *fieldtype, uint fields, + uchar *null_bits, uint null_bits_size, + uchar *field_metadata, + uint field_metadata_size, + ushort row_req, + xpand_connection_cursor **scan) +{ + int error_code; + command_length = 0; + + if ((error_code = begin_command(XPAND_SCAN_QUERY))) + return error_code; + + if ((error_code = add_command_operand_ushort(row_req))) + return error_code; + + if ((error_code = add_command_operand_str((uchar*)stmt.ptr(), stmt.length()))) + return error_code; + + if ((error_code = add_command_operand_str(fieldtype, fields))) + return error_code; + + if ((error_code = add_command_operand_str(field_metadata, field_metadata_size))) + return error_code; + + // This variable length string calls for an additional store w/o lcb lenth prefix. + if ((error_code = add_command_operand_vlstr(null_bits, null_bits_size))) + return error_code; + + if ((error_code = send_command())) + return error_code; + + return allocate_cursor(&xpand_net, row_req, scan); +} + +/** + * @brief + * Sends a command to initiate UPDATE. + * @details + * Sends a command over mysql protocol connection to initiate an + * UPDATE query using a query text. + * @args + * stmt& Query text to send + * dbname current working database + * dbname ¤t database name + **/ +int xpand_connection::update_query(String &stmt, LEX_CSTRING &dbname, + ulonglong *affected_rows) +{ + int error_code; + command_length = 0; + + if ((error_code = begin_command(XPAND_UPDATE_QUERY))) + return error_code; + + if ((error_code = add_command_operand_str((uchar*)dbname.str, dbname.length))) + return error_code; + + if ((error_code = add_command_operand_str((uchar*)stmt.ptr(), stmt.length()))) + return error_code; + + if ((error_code = send_command())) + return error_code; + + error_code = read_query_response(); + if (!error_code) + *affected_rows = xpand_net.affected_rows; + + return error_code; +} + +int xpand_connection::scan_from_key(ulonglong xpand_table_oid, uint index, + xpand_lock_mode_t lock_mode, + enum scan_type scan_dir, + int no_key_cols, bool sorted_scan, + MY_BITMAP *read_set, uchar *packed_key, + ulong packed_key_length, ushort row_req, + xpand_connection_cursor **scan) +{ + int error_code; + command_length = 0; + + // row based commands should not be called with auto commit. + if (trans_flags & XPAND_TRANS_AUTOCOMMIT) + return HA_ERR_INTERNAL_ERROR; + + if ((error_code = begin_command(XPAND_SCAN_FROM_KEY))) + return error_code; + + if ((error_code = add_command_operand_ushort(row_req))) + return error_code; + + if ((error_code = add_command_operand_ulonglong(xpand_table_oid))) + return error_code; + + if ((error_code = add_command_operand_uint(index))) + return error_code; + + if ((error_code = add_command_operand_uchar((uchar)lock_mode))) + return error_code; + + if ((error_code = add_command_operand_uchar(scan_dir))) + return error_code; + + if ((error_code = add_command_operand_uint(no_key_cols))) + return error_code; + + if ((error_code = add_command_operand_uchar(sorted_scan))) + return error_code; + + if ((error_code = add_command_operand_str(packed_key, packed_key_length))) + return error_code; + + if ((error_code = add_command_operand_bitmap(read_set))) + return error_code; + + if ((error_code = send_command())) + return error_code; + + return allocate_cursor(&xpand_net, row_req, scan); +} + +int xpand_connection::scan_next(xpand_connection_cursor *scan, + uchar **rowdata, ulong *rowdata_length) +{ + *rowdata = scan->retrieve_row(rowdata_length); + if (*rowdata) + return 0; + + if (scan->eof_reached) + return HA_ERR_END_OF_FILE; + + int error_code; + command_length = 0; + + if ((error_code = begin_command(XPAND_SCAN_NEXT))) + return error_code; + + if ((error_code = add_command_operand_ushort(scan->buffer_size))) + return error_code; + + if ((error_code = add_command_operand_lcb(scan->scan_refid))) + return error_code; + + if ((error_code = send_command())) + return error_code; + + bool stmt_completed = FALSE; + error_code = scan->load_rows(&stmt_completed); + if (stmt_completed) + auto_commit_closed(); + if (error_code) + return error_code; + + *rowdata = scan->retrieve_row(rowdata_length); + if (!*rowdata) + return HA_ERR_END_OF_FILE; + + return 0; +} + +int xpand_connection::scan_end(xpand_connection_cursor *scan) +{ + int error_code; + command_length = 0; + ulonglong scan_refid = scan->scan_refid; + bool eof_reached = scan->eof_reached; + delete scan; + + if (eof_reached) + return 0; + + if ((error_code = begin_command(XPAND_SCAN_STOP))) + return error_code; + + if ((error_code = add_command_operand_lcb(scan_refid))) + return error_code; + + if ((error_code = send_command())) + return error_code; + + return read_query_response(); +} + +int xpand_connection::populate_table_list(LEX_CSTRING *db, + handlerton::discovered_list *result) +{ + int error_code = 0; + String stmt; + stmt.append("SHOW FULL TABLES FROM "); + stmt.append(db); + stmt.append(" WHERE table_type = 'BASE TABLE'"); + + if (mysql_real_query(&xpand_net, stmt.c_ptr(), stmt.length())) { + int error_code = mysql_errno(&xpand_net); + if (error_code == ER_BAD_DB_ERROR) + return 0; + else + return error_code; + } + + MYSQL_RES *results = mysql_store_result(&xpand_net); + if (mysql_num_fields(results) != 2) { + error_code = HA_ERR_CORRUPT_EVENT; + goto error; + } + + MYSQL_ROW row; + while((row = mysql_fetch_row(results))) + result->add_table(row[0], strlen(row[0])); + +error: + mysql_free_result(results); + return error_code; +} + +int xpand_connection::discover_table_details(LEX_CSTRING *db, + LEX_CSTRING *name, THD *thd, + TABLE_SHARE *share) +{ + DBUG_ENTER("xpand_connection::discover_table_details"); + int error_code = 0; + MYSQL_RES *results_oid = NULL; + MYSQL_RES *results_create = NULL; + MYSQL_ROW row; + String get_oid, show; + + /* get oid */ + get_oid.append("select r.table " + "from system.databases d " + " inner join ""system.relations r on d.db = r.db " + "where d.name = '"); + get_oid.append(db); + get_oid.append("' and r.name = '"); + get_oid.append(name); + get_oid.append("'"); + + if (mysql_real_query(&xpand_net, get_oid.c_ptr(), get_oid.length())) { + if ((error_code = mysql_errno(&xpand_net))) { + DBUG_PRINT("mysql_real_query returns ", ("%d", error_code)); + error_code = HA_ERR_NO_SUCH_TABLE; + goto error; + } + } + + results_oid = mysql_store_result(&xpand_net); + DBUG_PRINT("oid results", + ("rows: %llu, fields: %u", mysql_num_rows(results_oid), + mysql_num_fields(results_oid))); + + if (mysql_num_rows(results_oid) != 1) { + error_code = HA_ERR_NO_SUCH_TABLE; + goto error; + } + + while((row = mysql_fetch_row(results_oid))) { + DBUG_PRINT("row", ("%s", row[0])); + uchar *to = (uchar*)alloc_root(&share->mem_root, strlen(row[0]) + 1); + if (!to) { + error_code = HA_ERR_OUT_OF_MEM; + goto error; + } + + strcpy((char *)to, (char *)row[0]); + share->tabledef_version.str = to; + share->tabledef_version.length = strlen(row[0]); + } + + /* get show create statement */ + show.append("show simple create table "); + show.append(db); + show.append("."); + show.append(name); + if (mysql_real_query(&xpand_net, show.c_ptr(), show.length())) { + if ((error_code = mysql_errno(&xpand_net))) { + DBUG_PRINT("mysql_real_query returns ", ("%d", error_code)); + error_code = HA_ERR_NO_SUCH_TABLE; + goto error; + } + } + + results_create = mysql_store_result(&xpand_net); + DBUG_PRINT("show table results", + ("rows: %llu, fields: %u", mysql_num_rows(results_create), + mysql_num_fields(results_create))); + + if (mysql_num_rows(results_create) != 1) { + error_code = HA_ERR_NO_SUCH_TABLE; + goto error; + } + + if (mysql_num_fields(results_create) != 2) { + error_code = HA_ERR_CORRUPT_EVENT; + goto error; + } + + while((row = mysql_fetch_row(results_create))) { + DBUG_PRINT("row", ("%s - %s", row[0], row[1])); + error_code = share->init_from_sql_statement_string(thd, false, row[1], + strlen(row[1])); + } + +error: + if (results_oid) + mysql_free_result(results_oid); + + if (results_create) + mysql_free_result(results_create); + DBUG_RETURN(error_code); +} + +#define COMMAND_BUFFER_SIZE_INCREMENT 1024 +#define COMMAND_BUFFER_SIZE_INCREMENT_BITS 10 +int xpand_connection::expand_command_buffer(size_t add_length) +{ + size_t expanded_length; + + if (command_buffer_length >= command_length + add_length) + return 0; + + expanded_length = command_buffer_length + + ((add_length >> COMMAND_BUFFER_SIZE_INCREMENT_BITS) + << COMMAND_BUFFER_SIZE_INCREMENT_BITS) + + COMMAND_BUFFER_SIZE_INCREMENT; + + if (!command_buffer_length) + command_buffer = (uchar *) my_malloc(expanded_length, MYF(MY_WME)); + else + command_buffer = (uchar *) my_realloc(command_buffer, expanded_length, + MYF(MY_WME)); + if (!command_buffer) + return HA_ERR_OUT_OF_MEM; + + command_buffer_length = expanded_length; + + return 0; +} + +int xpand_connection::add_command_operand_uchar(uchar value) +{ + int error_code = expand_command_buffer(sizeof(value)); + if (error_code) + return error_code; + + memcpy(command_buffer + command_length, &value, sizeof(value)); + command_length += sizeof(value); + + return 0; +} + +int xpand_connection::add_command_operand_ushort(ushort value) +{ + ushort be_value = htobe16(value); + int error_code = expand_command_buffer(sizeof(be_value)); + if (error_code) + return error_code; + + memcpy(command_buffer + command_length, &be_value, sizeof(be_value)); + command_length += sizeof(be_value); + return 0; +} + +int xpand_connection::add_command_operand_uint(uint value) +{ + uint be_value = htobe32(value); + int error_code = expand_command_buffer(sizeof(be_value)); + if (error_code) + return error_code; + + memcpy(command_buffer + command_length, &be_value, sizeof(be_value)); + command_length += sizeof(be_value); + return 0; +} + +int xpand_connection::add_command_operand_ulonglong(ulonglong value) +{ + ulonglong be_value = htobe64(value); + int error_code = expand_command_buffer(sizeof(be_value)); + if (error_code) + return error_code; + + memcpy(command_buffer + command_length, &be_value, sizeof(be_value)); + command_length += sizeof(be_value); + return 0; +} + +int xpand_connection::add_command_operand_lcb(ulonglong value) +{ + int len = net_length_size(value); + int error_code = expand_command_buffer(len); + if (error_code) + return error_code; + + net_store_length(command_buffer + command_length, value); + command_length += len; + return 0; +} + +int xpand_connection::add_command_operand_str(const uchar *str, + size_t str_length) +{ + int error_code = add_command_operand_lcb(str_length); + if (error_code) + return error_code; + + if (!str_length) + return 0; + + error_code = expand_command_buffer(str_length); + if (error_code) + return error_code; + + memcpy(command_buffer + command_length, str, str_length); + command_length += str_length; + return 0; +} + +/** + * @brief + * Puts variable length string into the buffer. + * @details + * Puts into the buffer variable length string the size + * of which is send by other means. For details see + * MDB Client/Server Protocol. + * @args + * str - string to send + * str_length - size + **/ +int xpand_connection::add_command_operand_vlstr(const uchar *str, + size_t str_length) +{ + int error_code = expand_command_buffer(str_length); + if (error_code) + return error_code; + + memcpy(command_buffer + command_length, str, str_length); + command_length += str_length; + return 0; +} + +int xpand_connection::add_command_operand_lex_string(LEX_CSTRING str) +{ + return add_command_operand_str((const uchar *)str.str, str.length); +} + +int xpand_connection::add_command_operand_bitmap(MY_BITMAP *bitmap) +{ + int error_code = add_command_operand_lcb(bitmap->n_bits); + if (error_code) + return error_code; + + int no_bytes = no_bytes_in_map(bitmap); + error_code = expand_command_buffer(no_bytes); + if (error_code) + return error_code; + + memcpy(command_buffer + command_length, bitmap->bitmap, no_bytes); + command_length += no_bytes; + return 0; +} diff --git a/storage/xpand/xpand_connection.h b/storage/xpand/xpand_connection.h new file mode 100644 index 00000000000..c07d8da5f5b --- /dev/null +++ b/storage/xpand/xpand_connection.h @@ -0,0 +1,123 @@ +/***************************************************************************** +Copyright (c) 2019, MariaDB Corporation. +*****************************************************************************/ + +#ifndef _xpand_connection_h +#define _xpand_connection_h + +#ifdef USE_PRAGMA_INTERFACE +#pragma interface /* gcc class implementation */ +#endif + +#define MYSQL_SERVER 1 +#include "my_global.h" +#include "m_string.h" +#include "mysql.h" +#include "sql_common.h" +#include "my_base.h" +#include "mysqld_error.h" +#include "my_bitmap.h" +#include "handler.h" + +#define XPAND_SERVER_REQUEST 30 + +typedef enum xpand_lock_mode { + XPAND_NO_LOCKS, + XPAND_SHARED, + XPAND_EXCLUSIVE, +} xpand_lock_mode_t; + +class xpand_connection_cursor; +class xpand_connection +{ +private: + MYSQL xpand_net; + uchar *command_buffer; + size_t command_buffer_length; + size_t command_length; + + int trans_state; + int trans_flags; + int allocate_cursor(MYSQL *xpand_net, ulong buffer_size, + xpand_connection_cursor **scan); +public: + xpand_connection(); + ~xpand_connection(); + + inline bool is_connected() + { + return xpand_net.net.vio; + } + int connect(); + void disconnect(bool is_destructor = FALSE); + + bool has_open_transaction(); + int commit_transaction(); + int rollback_transaction(); + int begin_transaction_next(); + int new_statement_next(); + int rollback_statement_next(); // also starts new statement + void auto_commit_next(); + void auto_commit_closed(); + + int run_query(String &stmt); + int write_row(ulonglong xpand_table_oid, uchar *packed_row, + size_t packed_size, ulonglong *last_insert_id); + int key_update(ulonglong xpand_table_oid, + uchar *packed_key, size_t packed_key_length, + MY_BITMAP *update_set, + uchar *packed_new_data, size_t packed_new_length); + int key_delete(ulonglong xpand_table_oid, + uchar *packed_key, size_t packed_key_length); + int key_read(ulonglong xpand_table_oid, uint index, + xpand_lock_mode_t lock_mode, MY_BITMAP *read_set, + uchar *packed_key, ulong packed_key_length, uchar **rowdata, + ulong *rowdata_length); + enum sort_order {SORT_NONE = 0, SORT_ASC = 1, SORT_DESC = 2}; + enum scan_type { + READ_KEY_OR_NEXT, /* rows with key and greater */ + READ_KEY_OR_PREV, /* rows with key and less. */ + READ_AFTER_KEY, /* rows with keys greater than key */ + READ_BEFORE_KEY, /* rows with keys less than key */ + READ_FROM_START, /* rows with forwards from first key. */ + READ_FROM_LAST, /* rows with backwards from last key. */ + }; + int scan_table(ulonglong xpand_table_oid, + xpand_lock_mode_t lock_mode, + MY_BITMAP *read_set, ushort row_req, + xpand_connection_cursor **scan); + int scan_query(String &stmt, uchar *fieldtype, uint fields, uchar *null_bits, + uint null_bits_size, uchar *field_metadata, + uint field_metadata_size, ushort row_req, + xpand_connection_cursor **scan); + int update_query(String &stmt, LEX_CSTRING &dbname, ulonglong *affected_rows); + int scan_from_key(ulonglong xpand_table_oid, uint index, + xpand_lock_mode_t lock_mode, + enum scan_type scan_dir, int no_key_cols, bool sorted_scan, + MY_BITMAP *read_set, uchar *packed_key, + ulong packed_key_length, ushort row_req, + xpand_connection_cursor **scan); + int scan_next(xpand_connection_cursor *scan, uchar **rowdata, + ulong *rowdata_length); + int scan_end(xpand_connection_cursor *scan); + + int populate_table_list(LEX_CSTRING *db, handlerton::discovered_list *result); + int discover_table_details(LEX_CSTRING *db, LEX_CSTRING *name, THD *thd, + TABLE_SHARE *share); + +private: + int expand_command_buffer(size_t add_length); + int add_command_operand_uchar(uchar value); + int add_command_operand_ushort(ushort value); + int add_command_operand_uint(uint value); + int add_command_operand_ulonglong(ulonglong value); + int add_command_operand_lcb(ulonglong value); + int add_command_operand_str(const uchar *str, size_t length); + int add_command_operand_vlstr(const uchar *str, size_t length); + int add_command_operand_lex_string(LEX_CSTRING str); + int add_command_operand_bitmap(MY_BITMAP *bitmap); + int begin_command(uchar command); + int send_command(); + int read_query_response(); +}; +#endif // _xpand_connection_h -- cgit v1.2.1 From e176abf37eac4c9aace1cf1f3c34852564a99aab Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Tue, 11 Feb 2020 21:27:29 -0800 Subject: Fix spacing in xpand files after Clustrix to Xpand rename. --- storage/xpand/ha_xpand.cc | 60 +++++++++++++++----------------- storage/xpand/ha_xpand_pushdown.cc | 47 ++++++++++++------------- storage/xpand/ha_xpand_pushdown.h | 10 +++--- storage/xpand/xpand_connection.cc | 71 ++++++++++++++++++-------------------- 4 files changed, 87 insertions(+), 101 deletions(-) diff --git a/storage/xpand/ha_xpand.cc b/storage/xpand/ha_xpand.cc index 8a8366fa9f7..d19e117d1c8 100644 --- a/storage/xpand/ha_xpand.cc +++ b/storage/xpand/ha_xpand.cc @@ -653,7 +653,7 @@ ha_rows ha_xpand::records() } ha_rows ha_xpand::records_in_range(uint inx, key_range *min_key, - key_range *max_key) + key_range *max_key) { return 2; } @@ -728,7 +728,7 @@ int ha_xpand::index_init(uint idx, bool sorted) } int ha_xpand::index_read(uchar * buf, const uchar * key, uint key_len, - enum ha_rkey_function find_flag) + enum ha_rkey_function find_flag) { DBUG_ENTER("ha_xpand::index_read"); int error_code = 0; @@ -814,10 +814,9 @@ int ha_xpand::index_first(uchar *buf) if (!trx) DBUG_RETURN(error_code); - error_code = trx->scan_from_key(xpand_table_oid, active_index, - xpd_lock_type, - xpand_connection::READ_FROM_START, - -1, sorted_scan, &scan_fields, NULL, 0, + error_code = trx->scan_from_key(xpand_table_oid, active_index, xpd_lock_type, + xpand_connection::READ_FROM_START, -1, + sorted_scan, &scan_fields, NULL, 0, THDVAR(thd, row_buffer), &scan_cur); if (error_code == HA_ERR_TABLE_DEF_CHANGED) @@ -838,10 +837,9 @@ int ha_xpand::index_last(uchar *buf) if (!trx) DBUG_RETURN(error_code); - error_code = trx->scan_from_key(xpand_table_oid, active_index, - xpd_lock_type, - xpand_connection::READ_FROM_LAST, - -1, sorted_scan, &scan_fields, NULL, 0, + error_code = trx->scan_from_key(xpand_table_oid, active_index, xpd_lock_type, + xpand_connection::READ_FROM_LAST, -1, + sorted_scan, &scan_fields, NULL, 0, THDVAR(thd, row_buffer), &scan_cur); if (error_code == HA_ERR_TABLE_DEF_CHANGED) @@ -912,9 +910,8 @@ int ha_xpand::rnd_init(bool scan) bitmap_set_all(&scan_fields); #endif - error_code = trx->scan_table(xpand_table_oid, xpd_lock_type, - &scan_fields, THDVAR(thd, row_buffer), - &scan_cur); + error_code = trx->scan_table(xpand_table_oid, xpd_lock_type, &scan_fields, + THDVAR(thd, row_buffer), &scan_cur); if (error_code == HA_ERR_TABLE_DEF_CHANGED) xpand_mark_table_for_discovery(table); @@ -1046,9 +1043,8 @@ uint ha_xpand::lock_count(void) const return 0; } -THR_LOCK_DATA **ha_xpand::store_lock(THD *thd, - THR_LOCK_DATA **to, - enum thr_lock_type lock_type) +THR_LOCK_DATA **ha_xpand::store_lock(THD *thd, THR_LOCK_DATA **to, + enum thr_lock_type lock_type) { /* Hopefully, we don't need to use thread locks */ return to; @@ -1159,8 +1155,7 @@ void remove_current_table_from_rpl_table_list(rpl_group_info *rgi) } void ha_xpand::build_key_packed_row(uint index, const uchar *buf, - uchar *packed_key, - size_t *packed_key_len) + uchar *packed_key, size_t *packed_key_len) { if (index == table->s->primary_key && has_hidden_key) { memcpy(packed_key, &last_hidden_key, sizeof(ulonglong)); @@ -1238,7 +1233,7 @@ static int xpand_rollback(handlerton *hton, THD *thd, bool all) } static handler* xpand_create_handler(handlerton *hton, TABLE_SHARE *table, - MEM_ROOT *mem_root) + MEM_ROOT *mem_root) { return new (mem_root) ha_xpand(hton, table); } @@ -1262,15 +1257,15 @@ static int xpand_panic(handlerton *hton, ha_panic_function type) } static bool xpand_show_status(handlerton *hton, THD *thd, - stat_print_fn *stat_print, - enum ha_stat_type stat_type) + stat_print_fn *stat_print, + enum ha_stat_type stat_type) { return FALSE; } static int xpand_discover_table_names(handlerton *hton, LEX_CSTRING *db, - MY_DIR *dir, - handlerton::discovered_list *result) + MY_DIR *dir, + handlerton::discovered_list *result) { xpand_connection *xpand_net = new xpand_connection(); int error_code = xpand_net->connect(); @@ -1291,9 +1286,8 @@ int xpand_discover_table(handlerton *hton, THD *thd, TABLE_SHARE *share) if (error_code) goto err; - error_code = xpand_net->discover_table_details(&share->db, - &share->table_name, - thd, share); + error_code = xpand_net->discover_table_details(&share->db, &share->table_name, + thd, share); err: delete xpand_net; @@ -1356,16 +1350,16 @@ static struct st_mysql_storage_engine xpand_storage_engine = maria_declare_plugin(xpand) { MYSQL_STORAGE_ENGINE_PLUGIN, /* Plugin Type */ - &xpand_storage_engine, /* Plugin Descriptor */ - "XPAND", /* Plugin Name */ + &xpand_storage_engine, /* Plugin Descriptor */ + "XPAND", /* Plugin Name */ "MariaDB", /* Plugin Author */ - "Xpand storage engine", /* Plugin Description */ + "Xpand storage engine", /* Plugin Description */ PLUGIN_LICENSE_GPL, /* Plugin Licence */ - xpand_init, /* Plugin Entry Point */ - xpand_deinit, /* Plugin Deinitializer */ + xpand_init, /* Plugin Entry Point */ + xpand_deinit, /* Plugin Deinitializer */ 0x0001, /* Hex Version Number (0.1) */ - NULL /* xpand_status_vars */, /* Status Variables */ - xpand_system_variables, /* System Variables */ + NULL /* xpand_status_vars */, /* Status Variables */ + xpand_system_variables, /* System Variables */ "0.1", /* String Version */ MariaDB_PLUGIN_MATURITY_EXPERIMENTAL /* Maturity Level */ } diff --git a/storage/xpand/ha_xpand_pushdown.cc b/storage/xpand/ha_xpand_pushdown.cc index e53c4f445fa..cd4291ce08e 100644 --- a/storage/xpand/ha_xpand_pushdown.cc +++ b/storage/xpand/ha_xpand_pushdown.cc @@ -37,22 +37,21 @@ int get_field_types(THD *thd, TABLE *table__, SELECT_LEX *sl, uchar *fieldtype, TABLE *tmp_table= table__; if (!tmp_table) { - // Construct a tmp table with fields to find out result DTs. - // This should be reconsidered if it worths the effort. - List types; - TMP_TABLE_PARAM tmp_table_param; - sl->master_unit()->join_union_item_types(thd, types, 1); - tmp_table_param.init(); - tmp_table_param.field_count= types.elements; - - tmp_table = create_tmp_table(thd, &tmp_table_param, types, - (ORDER *) 0, false, 0, - TMP_TABLE_ALL_COLUMNS, 1, - &empty_clex_str, true, false); - if (!tmp_table) { - field_metadata_size = -1; - goto err; - } + // Construct a tmp table with fields to find out result DTs. + // This should be reconsidered if it worths the effort. + List types; + TMP_TABLE_PARAM tmp_table_param; + sl->master_unit()->join_union_item_types(thd, types, 1); + tmp_table_param.init(); + tmp_table_param.field_count= types.elements; + + tmp_table = create_tmp_table(thd, &tmp_table_param, types, (ORDER *) 0, + false, 0, TMP_TABLE_ALL_COLUMNS, 1, + &empty_clex_str, true, false); + if (!tmp_table) { + field_metadata_size = -1; + goto err; + } } for (unsigned int i = 0 ; i < fields_count; ++i) { @@ -213,7 +212,7 @@ ha_xpand_select_handler::~ha_xpand_select_handler() my_bitmap_free(&scan_fields); if (rgi) - remove_current_table_from_rpl_table_list(rgi); + remove_current_table_from_rpl_table_list(rgi); } /*@brief Initiate the query for select_handler */ @@ -284,7 +283,7 @@ int ha_xpand_select_handler::next_row() ***********************************************************/ int ha_xpand_select_handler::end_scan() { - return 0; + return 0; } /*@brief create_xpand_derived_handler- Creates handler*/ @@ -359,7 +358,7 @@ ha_xpand_derived_handler::~ha_xpand_derived_handler() my_bitmap_free(&scan_fields); if (rgi) - remove_current_table_from_rpl_table_list(rgi); + remove_current_table_from_rpl_table_list(rgi); } /*@brief Initiate the query for derived_handler */ @@ -390,14 +389,14 @@ int ha_xpand_derived_handler::init_scan() &null_bits, num_null_bytes, &field_metadata, (items_number * 2), NULL); if (!meta_memory) { - // The only way to say something here is to raise warning - // b/c we will fallback to other access methods: derived handler or rowstore. - goto err; + // The only way to say something here is to raise warning + // b/c we will fallback to other access methods: derived handler or rowstore. + goto err; } if((field_metadata_size= get_field_types(thd__, table, select, fieldtype, field_metadata, null_bits, num_null_bytes, items_number)) < 0) { - goto err; + goto err; } trx = get_trx(thd__, &error_code); @@ -474,5 +473,5 @@ int ha_xpand_derived_handler::next_row() ***********************************************************/ int ha_xpand_derived_handler::end_scan() { - return 0; + return 0; } diff --git a/storage/xpand/ha_xpand_pushdown.h b/storage/xpand/ha_xpand_pushdown.h index 3fd234131c9..8eb1e0dd0d8 100644 --- a/storage/xpand/ha_xpand_pushdown.h +++ b/storage/xpand/ha_xpand_pushdown.h @@ -46,7 +46,7 @@ class ha_xpand_select_handler: { public: ha_xpand_select_handler(THD* thd_arg, SELECT_LEX* sel, - xpand_connection_cursor *scan); + xpand_connection_cursor *scan); ~ha_xpand_select_handler(); int init_scan(); @@ -69,7 +69,7 @@ class ha_xpand_derived_handler: { public: ha_xpand_derived_handler(THD* thd_arg, SELECT_LEX* sel, - xpand_connection_cursor *scan); + xpand_connection_cursor *scan); ~ha_xpand_derived_handler(); int init_scan(); @@ -79,9 +79,7 @@ class ha_xpand_derived_handler: }; -select_handler *create_xpand_select_handler(THD* thd, - SELECT_LEX* select_lex); -derived_handler *create_xpand_derived_handler(THD* thd, - TABLE_LIST *derived); +select_handler *create_xpand_select_handler(THD* thd, SELECT_LEX* select_lex); +derived_handler *create_xpand_derived_handler(THD* thd, TABLE_LIST *derived); #endif diff --git a/storage/xpand/xpand_connection.cc b/storage/xpand/xpand_connection.cc index fac728f291c..41e0abac815 100644 --- a/storage/xpand/xpand_connection.cc +++ b/storage/xpand/xpand_connection.cc @@ -52,16 +52,16 @@ extern char *xpand_socket; */ enum xpand_trans_state { - XPAND_TRANS_STARTED = 0, - XPAND_TRANS_REQUESTED = 1, - XPAND_TRANS_NEW_STMT = 2, - XPAND_TRANS_ROLLBACK_STMT = 4, - XPAND_TRANS_NONE = 32, + XPAND_TRANS_STARTED = 0, + XPAND_TRANS_REQUESTED = 1, + XPAND_TRANS_NEW_STMT = 2, + XPAND_TRANS_ROLLBACK_STMT = 4, + XPAND_TRANS_NONE = 32, }; enum xpand_trans_post_flags { - XPAND_TRANS_AUTOCOMMIT = 8, - XPAND_TRANS_NO_POST_FLAGS = 0, + XPAND_TRANS_AUTOCOMMIT = 8, + XPAND_TRANS_NO_POST_FLAGS = 0, }; enum xpand_commands { @@ -168,14 +168,12 @@ int xpand_connection::connect() if (conn->tgt_ssl_vsc) { my_bool verify_flg = TRUE; - mysql_options(&xpand_net, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, - &verify_flg); + mysql_options(&xpand_net, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, &verify_flg); } } #endif - if (!mysql_real_connect(&xpand_net, host, - xpand_username, xpand_password, + if (!mysql_real_connect(&xpand_net, host, xpand_username, xpand_password, NULL, xpand_port, xpand_socket, CLIENT_MULTI_STATEMENTS)) { @@ -474,10 +472,9 @@ int xpand_connection::key_delete(ulonglong xpand_table_oid, } int xpand_connection::key_read(ulonglong xpand_table_oid, uint index, - xpand_lock_mode_t lock_mode, - MY_BITMAP *read_set, uchar *packed_key, - ulong packed_key_length, uchar **rowdata, - ulong *rowdata_length) + xpand_lock_mode_t lock_mode, MY_BITMAP *read_set, + uchar *packed_key, ulong packed_key_length, + uchar **rowdata, ulong *rowdata_length) { int error_code; command_length = 0; @@ -658,7 +655,7 @@ public: }; int xpand_connection::allocate_cursor(MYSQL *xpand_net, ulong buffer_size, - xpand_connection_cursor **scan) + xpand_connection_cursor **scan) { DBUG_ENTER("xpand_connection::allocate_cursor"); *scan = new xpand_connection_cursor(xpand_net, buffer_size); @@ -679,9 +676,9 @@ int xpand_connection::allocate_cursor(MYSQL *xpand_net, ulong buffer_size, } int xpand_connection::scan_table(ulonglong xpand_table_oid, - xpand_lock_mode_t lock_mode, - MY_BITMAP *read_set, ushort row_req, - xpand_connection_cursor **scan) + xpand_lock_mode_t lock_mode, + MY_BITMAP *read_set, ushort row_req, + xpand_connection_cursor **scan) { int error_code; command_length = 0; @@ -729,11 +726,10 @@ int xpand_connection::scan_table(ulonglong xpand_table_oid, * Used in pushdowns to initiate query scan. **/ int xpand_connection::scan_query(String &stmt, uchar *fieldtype, uint fields, - uchar *null_bits, uint null_bits_size, - uchar *field_metadata, - uint field_metadata_size, - ushort row_req, - xpand_connection_cursor **scan) + uchar *null_bits, uint null_bits_size, + uchar *field_metadata, + uint field_metadata_size, ushort row_req, + xpand_connection_cursor **scan) { int error_code; command_length = 0; @@ -775,7 +771,7 @@ int xpand_connection::scan_query(String &stmt, uchar *fieldtype, uint fields, * dbname ¤t database name **/ int xpand_connection::update_query(String &stmt, LEX_CSTRING &dbname, - ulonglong *affected_rows) + ulonglong *affected_rows) { int error_code; command_length = 0; @@ -800,12 +796,12 @@ int xpand_connection::update_query(String &stmt, LEX_CSTRING &dbname, } int xpand_connection::scan_from_key(ulonglong xpand_table_oid, uint index, - xpand_lock_mode_t lock_mode, - enum scan_type scan_dir, - int no_key_cols, bool sorted_scan, - MY_BITMAP *read_set, uchar *packed_key, - ulong packed_key_length, ushort row_req, - xpand_connection_cursor **scan) + xpand_lock_mode_t lock_mode, + enum scan_type scan_dir, + int no_key_cols, bool sorted_scan, + MY_BITMAP *read_set, uchar *packed_key, + ulong packed_key_length, ushort row_req, + xpand_connection_cursor **scan) { int error_code; command_length = 0; @@ -851,7 +847,7 @@ int xpand_connection::scan_from_key(ulonglong xpand_table_oid, uint index, } int xpand_connection::scan_next(xpand_connection_cursor *scan, - uchar **rowdata, ulong *rowdata_length) + uchar **rowdata, ulong *rowdata_length) { *rowdata = scan->retrieve_row(rowdata_length); if (*rowdata) @@ -913,7 +909,7 @@ int xpand_connection::scan_end(xpand_connection_cursor *scan) } int xpand_connection::populate_table_list(LEX_CSTRING *db, - handlerton::discovered_list *result) + handlerton::discovered_list *result) { int error_code = 0; String stmt; @@ -944,9 +940,8 @@ error: return error_code; } -int xpand_connection::discover_table_details(LEX_CSTRING *db, - LEX_CSTRING *name, THD *thd, - TABLE_SHARE *share) +int xpand_connection::discover_table_details(LEX_CSTRING *db, LEX_CSTRING *name, + THD *thd, TABLE_SHARE *share) { DBUG_ENTER("xpand_connection::discover_table_details"); int error_code = 0; @@ -1127,7 +1122,7 @@ int xpand_connection::add_command_operand_lcb(ulonglong value) } int xpand_connection::add_command_operand_str(const uchar *str, - size_t str_length) + size_t str_length) { int error_code = add_command_operand_lcb(str_length); if (error_code) @@ -1157,7 +1152,7 @@ int xpand_connection::add_command_operand_str(const uchar *str, * str_length - size **/ int xpand_connection::add_command_operand_vlstr(const uchar *str, - size_t str_length) + size_t str_length) { int error_code = expand_command_buffer(str_length); if (error_code) -- cgit v1.2.1 From ff60d07c84b84e010f7609a9b0606a6c31ce28a5 Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Thu, 13 Feb 2020 13:42:25 -0800 Subject: Fix more spacing issues and formatting issues. --- storage/xpand/ha_xpand.cc | 97 ++++++++++++++++++-------------------- storage/xpand/ha_xpand_pushdown.cc | 69 +++++++++++++-------------- storage/xpand/ha_xpand_pushdown.h | 59 ++++++++++++----------- storage/xpand/xpand_connection.cc | 31 ++++++------ 4 files changed, 124 insertions(+), 132 deletions(-) diff --git a/storage/xpand/ha_xpand.cc b/storage/xpand/ha_xpand.cc index d19e117d1c8..3852bae1933 100644 --- a/storage/xpand/ha_xpand.cc +++ b/storage/xpand/ha_xpand.cc @@ -153,46 +153,46 @@ static MYSQL_THDVAR_UINT // Per thread select handler knob static MYSQL_THDVAR_BOOL( - select_handler, - PLUGIN_VAR_NOCMDARG, - "", - NULL, - NULL, - 1 + select_handler, + PLUGIN_VAR_NOCMDARG, + "", + NULL, + NULL, + 1 ); // Per thread derived handler knob static MYSQL_THDVAR_BOOL( - derived_handler, - PLUGIN_VAR_NOCMDARG, - "", - NULL, - NULL, - 1 + derived_handler, + PLUGIN_VAR_NOCMDARG, + "", + NULL, + NULL, + 1 ); static MYSQL_THDVAR_BOOL( - enable_direct_update, - PLUGIN_VAR_NOCMDARG, - "", - NULL, - NULL, - 1 + enable_direct_update, + PLUGIN_VAR_NOCMDARG, + "", + NULL, + NULL, + 1 ); bool select_handler_setting(THD* thd) { - return ( thd == NULL ) ? false : THDVAR(thd, select_handler); + return ( thd == NULL ) ? false : THDVAR(thd, select_handler); } bool derived_handler_setting(THD* thd) { - return ( thd == NULL ) ? false : THDVAR(thd, derived_handler); + return ( thd == NULL ) ? false : THDVAR(thd, derived_handler); } uint row_buffer_setting(THD* thd) { - return THDVAR(thd, row_buffer); + return THDVAR(thd, row_buffer); } /**************************************************************************** @@ -223,8 +223,8 @@ size_t estimate_row_size(TABLE *table) **/ static void decode_objectname(char *buf, const char *path, size_t buf_size) { - size_t new_path_len = filename_to_tablename(path, buf, buf_size); - buf[new_path_len] = '\0'; + size_t new_path_len = filename_to_tablename(path, buf, buf_size); + buf[new_path_len] = '\0'; } static void decode_file_path(const char *path, char *decoded_dbname, @@ -326,11 +326,11 @@ int ha_xpand::create(const char *name, TABLE *form, HA_CREATE_INFO *info) // To syncronize the schemas of MDB FE and XPD BE. if (form->s && form->s->db.length) { - String createdb_stmt; - createdb_stmt.append("CREATE DATABASE IF NOT EXISTS `"); - createdb_stmt.append(form->s->db.str, form->s->db.length); - createdb_stmt.append("`"); - trx->run_query(createdb_stmt); + String createdb_stmt; + createdb_stmt.append("CREATE DATABASE IF NOT EXISTS `"); + createdb_stmt.append(form->s->db.str, form->s->db.length); + createdb_stmt.append("`"); + trx->run_query(createdb_stmt); } error_code = trx->run_query(create_table_stmt); @@ -489,8 +489,7 @@ int ha_xpand::write_row(const uchar *buf) /* XXX: Xpand may needs to return HA_ERR_AUTOINC_ERANGE if we hit that error. */ ulonglong last_insert_id = 0; - if ((error_code = trx->write_row(xpand_table_oid, - packed_new_row, packed_size, + if ((error_code = trx->write_row(xpand_table_oid, packed_new_row, packed_size, &last_insert_id))) goto err; @@ -687,8 +686,7 @@ int ha_xpand::info(uint flag) if (stats.records == 0) stats.mean_rec_length = 0; else - stats.mean_rec_length = (ulong) - (stats.data_file_length / stats.records); + stats.mean_rec_length = (ulong) (stats.data_file_length / stats.records); } if (flag & HA_STATUS_CONST) @@ -780,8 +778,7 @@ int ha_xpand::index_read(uchar * buf, const uchar * key, uint key_len, table->read_set, packed_key, packed_key_len, &rowdata, &rowdata_length); if (!error_code) - error_code = unpack_row_to_buf(rgi, table, buf, rowdata, - table->read_set, + error_code = unpack_row_to_buf(rgi, table, buf, rowdata, table->read_set, rowdata + rowdata_length); } else { is_scan = true; @@ -790,7 +787,7 @@ int ha_xpand::index_read(uchar * buf, const uchar * key, uint key_len, &scan_fields, packed_key, packed_key_len, THDVAR(thd, row_buffer), &scan_cur); if (!error_code) - error_code = rnd_next(buf); + error_code = rnd_next(buf); } if (rowdata) @@ -1056,7 +1053,7 @@ int ha_xpand::external_lock(THD *thd, int lock_type) int error_code; xpand_connection *trx = get_trx(thd, &error_code); if (error_code) - DBUG_RETURN(error_code); + DBUG_RETURN(error_code); if (lock_type == F_WRLCK) xpd_lock_type = XPAND_EXCLUSIVE; @@ -1069,7 +1066,7 @@ int ha_xpand::external_lock(THD *thd, int lock_type) if (!trx->has_open_transaction()) { error_code = trx->begin_transaction_next(); if (error_code) - DBUG_RETURN(error_code); + DBUG_RETURN(error_code); } trans_register_ha(thd, FALSE, xpand_hton); @@ -1349,18 +1346,18 @@ static struct st_mysql_storage_engine xpand_storage_engine = maria_declare_plugin(xpand) { - MYSQL_STORAGE_ENGINE_PLUGIN, /* Plugin Type */ - &xpand_storage_engine, /* Plugin Descriptor */ - "XPAND", /* Plugin Name */ - "MariaDB", /* Plugin Author */ - "Xpand storage engine", /* Plugin Description */ - PLUGIN_LICENSE_GPL, /* Plugin Licence */ - xpand_init, /* Plugin Entry Point */ - xpand_deinit, /* Plugin Deinitializer */ - 0x0001, /* Hex Version Number (0.1) */ - NULL /* xpand_status_vars */, /* Status Variables */ - xpand_system_variables, /* System Variables */ - "0.1", /* String Version */ - MariaDB_PLUGIN_MATURITY_EXPERIMENTAL /* Maturity Level */ + MYSQL_STORAGE_ENGINE_PLUGIN, /* Plugin Type */ + &xpand_storage_engine, /* Plugin Descriptor */ + "XPAND", /* Plugin Name */ + "MariaDB", /* Plugin Author */ + "Xpand storage engine", /* Plugin Description */ + PLUGIN_LICENSE_GPL, /* Plugin Licence */ + xpand_init, /* Plugin Entry Point */ + xpand_deinit, /* Plugin Deinitializer */ + 0x0001, /* Hex Version Number (0.1) */ + NULL /* xpand_status_vars */, /* Status Variables */ + xpand_system_variables, /* System Variables */ + "0.1", /* String Version */ + MariaDB_PLUGIN_MATURITY_EXPERIMENTAL /* Maturity Level */ } maria_declare_plugin_end; diff --git a/storage/xpand/ha_xpand_pushdown.cc b/storage/xpand/ha_xpand_pushdown.cc index cd4291ce08e..de43d4bd75b 100644 --- a/storage/xpand/ha_xpand_pushdown.cc +++ b/storage/xpand/ha_xpand_pushdown.cc @@ -30,7 +30,8 @@ extern uint xpand_row_buffer; * metadata_size int or -1 in case of error ************************************************************/ int get_field_types(THD *thd, TABLE *table__, SELECT_LEX *sl, uchar *fieldtype, - uchar *field_metadata, uchar *null_bits, const int num_null_bytes, const uint fields_count) + uchar *field_metadata, uchar *null_bits, + const int num_null_bytes, const uint fields_count) { int field_metadata_size = 0; int metadata_index = 0; @@ -85,7 +86,6 @@ err: return field_metadata_size; } - /*@brief create_xpand_select_handler- Creates handler*/ /************************************************************ * DESCRIPTION: @@ -138,14 +138,15 @@ create_xpand_select_handler(THD* thd, SELECT_LEX* select_lex) &null_bits, num_null_bytes, &field_metadata, (items_number * 2), NULL); if (!meta_memory) { - // The only way to say something here is to raise warning - // b/c we will fallback to other access methods: derived handler or rowstore. - goto err; + // The only way to say something here is to raise warning + // b/c we will fallback to other access methods: derived handler or rowstore. + goto err; } if((field_metadata_size = - get_field_types(thd, NULL, select_lex, fieldtype, field_metadata, null_bits, num_null_bytes, items_number)) < 0) { - goto err; + get_field_types(thd, NULL, select_lex, fieldtype, field_metadata, + null_bits, num_null_bytes, items_number)) < 0) { + goto err; } trx = get_trx(thd, &error_code); @@ -199,20 +200,20 @@ ha_xpand_select_handler::ha_xpand_select_handler( **********************************************************/ ha_xpand_select_handler::~ha_xpand_select_handler() { - int error_code; - xpand_connection *trx = get_trx(thd, &error_code); - if (!trx) { - // TBD Log this - } - if (trx && scan) - trx->scan_end(scan); + int error_code; + xpand_connection *trx = get_trx(thd, &error_code); + if (!trx) { + // TBD Log this + } + if (trx && scan) + trx->scan_end(scan); - // If the ::init_scan has been executed - if (table__) - my_bitmap_free(&scan_fields); + // If the ::init_scan has been executed + if (table__) + my_bitmap_free(&scan_fields); - if (rgi) - remove_current_table_from_rpl_table_list(rgi); + if (rgi) + remove_current_table_from_rpl_table_list(rgi); } /*@brief Initiate the query for select_handler */ @@ -342,23 +343,20 @@ ha_xpand_derived_handler::ha_xpand_derived_handler( **********************************************************/ ha_xpand_derived_handler::~ha_xpand_derived_handler() { - int error_code; - - - - xpand_connection *trx = get_trx(thd, &error_code); - if (!trx) { - // TBD Log this. - } - if (trx && scan) - trx->scan_end(scan); + int error_code; + xpand_connection *trx = get_trx(thd, &error_code); + if (!trx) { + // TBD Log this. + } + if (trx && scan) + trx->scan_end(scan); - // If the ::init_scan has been executed - if (table__) - my_bitmap_free(&scan_fields); + // If the ::init_scan has been executed + if (table__) + my_bitmap_free(&scan_fields); - if (rgi) - remove_current_table_from_rpl_table_list(rgi); + if (rgi) + remove_current_table_from_rpl_table_list(rgi); } /*@brief Initiate the query for derived_handler */ @@ -395,7 +393,8 @@ int ha_xpand_derived_handler::init_scan() } if((field_metadata_size= - get_field_types(thd__, table, select, fieldtype, field_metadata, null_bits, num_null_bytes, items_number)) < 0) { + get_field_types(thd__, table, select, fieldtype, field_metadata, + null_bits, num_null_bytes, items_number)) < 0) { goto err; } diff --git a/storage/xpand/ha_xpand_pushdown.h b/storage/xpand/ha_xpand_pushdown.h index 8eb1e0dd0d8..c39d15f0b41 100644 --- a/storage/xpand/ha_xpand_pushdown.h +++ b/storage/xpand/ha_xpand_pushdown.h @@ -16,20 +16,20 @@ Copyright (c) 2019, MariaDB Corporation. class ha_xpand_base_handler { // To simulate abstract class - protected: - ha_xpand_base_handler(): thd__(0),table__(0) {} - ~ha_xpand_base_handler() {} +protected: + ha_xpand_base_handler(): thd__(0),table__(0) {} + ~ha_xpand_base_handler() {} - // Copies of pushdown handlers attributes - // to use them in shared methods. - THD *thd__; - TABLE *table__; - // The bitmap used to sent - MY_BITMAP scan_fields; - // Structures to unpack RBR rows from XPD BE - rpl_group_info *rgi; - // XPD BE scan operation reference - xpand_connection_cursor *scan; + // Copies of pushdown handlers attributes + // to use them in shared methods. + THD *thd__; + TABLE *table__; + // The bitmap used to sent + MY_BITMAP scan_fields; + // Structures to unpack RBR rows from XPD BE + rpl_group_info *rgi; + // XPD BE scan operation reference + xpand_connection_cursor *scan; }; /*@brief select_handler class*/ @@ -44,15 +44,15 @@ class ha_xpand_select_handler: private ha_xpand_base_handler, public select_handler { - public: - ha_xpand_select_handler(THD* thd_arg, SELECT_LEX* sel, - xpand_connection_cursor *scan); - ~ha_xpand_select_handler(); +public: + ha_xpand_select_handler(THD* thd_arg, SELECT_LEX* sel, + xpand_connection_cursor *scan); + ~ha_xpand_select_handler(); - int init_scan(); - int next_row(); - int end_scan(); - void print_error(int, unsigned long) {} + int init_scan(); + int next_row(); + int end_scan(); + void print_error(int, unsigned long) {} }; /*@brief derived_handler class*/ @@ -67,18 +67,17 @@ class ha_xpand_derived_handler: private ha_xpand_base_handler, public derived_handler { - public: - ha_xpand_derived_handler(THD* thd_arg, SELECT_LEX* sel, - xpand_connection_cursor *scan); - ~ha_xpand_derived_handler(); +public: + ha_xpand_derived_handler(THD* thd_arg, SELECT_LEX* sel, + xpand_connection_cursor *scan); + ~ha_xpand_derived_handler(); - int init_scan(); - int next_row(); - int end_scan(); - void print_error(int, unsigned long) {} + int init_scan(); + int next_row(); + int end_scan(); + void print_error(int, unsigned long) {} }; - select_handler *create_xpand_select_handler(THD* thd, SELECT_LEX* select_lex); derived_handler *create_xpand_derived_handler(THD* thd, TABLE_LIST *derived); diff --git a/storage/xpand/xpand_connection.cc b/storage/xpand/xpand_connection.cc index 41e0abac815..48c43237199 100644 --- a/storage/xpand/xpand_connection.cc +++ b/storage/xpand/xpand_connection.cc @@ -240,8 +240,7 @@ int xpand_connection::send_command() if (com_error) { int error_code = mysql_errno(&xpand_net); - my_printf_error(error_code, - "Xpand error: %s", MYF(0), + my_printf_error(error_code, "Xpand error: %s", MYF(0), mysql_error(&xpand_net)); return error_code; } @@ -256,8 +255,7 @@ int xpand_connection::read_query_response() if (comerr) { error_code = mysql_errno(&xpand_net); - my_printf_error(error_code, - "Xpand error: %s", MYF(0), + my_printf_error(error_code, "Xpand error: %s", MYF(0), mysql_error(&xpand_net)); } @@ -375,9 +373,8 @@ int xpand_connection::run_query(String &stmt) return error_code; } -int xpand_connection::write_row(ulonglong xpand_table_oid, - uchar *packed_row, size_t packed_size, - ulonglong *last_insert_id) +int xpand_connection::write_row(ulonglong xpand_table_oid, uchar *packed_row, + size_t packed_size, ulonglong *last_insert_id) { int error_code; command_length = 0; @@ -405,11 +402,10 @@ int xpand_connection::write_row(ulonglong xpand_table_oid, return error_code; } -int xpand_connection::key_update(ulonglong xpand_table_oid, - uchar *packed_key, size_t packed_key_length, - MY_BITMAP *update_set, - uchar *packed_new_data, - size_t packed_new_length) +int xpand_connection::key_update(ulonglong xpand_table_oid, uchar *packed_key, + size_t packed_key_length, + MY_BITMAP *update_set, uchar *packed_new_data, + size_t packed_new_length) { int error_code; command_length = 0; @@ -444,7 +440,7 @@ int xpand_connection::key_update(ulonglong xpand_table_oid, } int xpand_connection::key_delete(ulonglong xpand_table_oid, - uchar *packed_key, size_t packed_key_length) + uchar *packed_key, size_t packed_key_length) { int error_code; command_length = 0; @@ -665,8 +661,8 @@ int xpand_connection::allocate_cursor(MYSQL *xpand_net, ulong buffer_size, bool stmt_completed = FALSE; int error_code = (*scan)->initialize(&stmt_completed); if (error_code) { - delete *scan; - *scan = NULL; + delete *scan; + *scan = NULL; } if (stmt_completed) @@ -746,7 +742,8 @@ int xpand_connection::scan_query(String &stmt, uchar *fieldtype, uint fields, if ((error_code = add_command_operand_str(fieldtype, fields))) return error_code; - if ((error_code = add_command_operand_str(field_metadata, field_metadata_size))) + if ((error_code = add_command_operand_str(field_metadata, + field_metadata_size))) return error_code; // This variable length string calls for an additional store w/o lcb lenth prefix. @@ -1129,7 +1126,7 @@ int xpand_connection::add_command_operand_str(const uchar *str, return error_code; if (!str_length) - return 0; + return 0; error_code = expand_command_buffer(str_length); if (error_code) -- cgit v1.2.1 From 28e2ca38f2637d05167313db6ffd79e689a56e94 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Tue, 18 Feb 2020 11:27:17 +0000 Subject: CLX-77: INSERT ... SELECT returns rows to the client instead of inserting Make Pushdown_select write output rows into select->join->result, instead of thd->protocol. This makes - SELECT ... INTO @var - SELECT ... INTO OUTFILE - INSERT INTO myisam_table SELECT ... FROM clustrix_table work as intended. Also fixed the federatedx select pushdown handler: - Do not fail an assert if the backend no resultset. Produce an error. - For the SELECT .. INTO syntax, refuse to use Select Handler, because the impelementation doesn't support this. --- mysql-test/suite/xpand/basics.result | 22 ++++++++++++++++++++++ mysql-test/suite/xpand/basics.test | 29 +++++++++++++++++++++++++++++ storage/federatedx/federatedx_pushdown.cc | 9 +++++++++ 3 files changed, 60 insertions(+) diff --git a/mysql-test/suite/xpand/basics.result b/mysql-test/suite/xpand/basics.result index 07fb56dc072..be50e614274 100644 --- a/mysql-test/suite/xpand/basics.result +++ b/mysql-test/suite/xpand/basics.result @@ -45,5 +45,27 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL NULL NULL NULL NULL 10000 2 DERIVED intandtext ALL NULL NULL NULL NULL 10000 DROP TABLE intandtext; +set +optimizer_switch=default, +xpand_derived_handler= default, +xpand_select_handler=default; +# +# CLX-77: INSERT ... SELECT returns rows to the client instead of inserting +# +drop table if exists t1,t2; +create table t1 (a int) engine=xpand; +insert into t1 values (1); +select a into @var from t1; +select @var; +@var +1 +# This must not emit output to the client: +select a into outfile 'tmpfile1' from t1; +create table t2 (a int) engine=myisam; +insert into t2 select * from t1; +select * from t2; +a +1 +drop table t1,t2; USE test; DROP DATABASE xpd; diff --git a/mysql-test/suite/xpand/basics.test b/mysql-test/suite/xpand/basics.test index 0284086bfbd..9777ad22e51 100644 --- a/mysql-test/suite/xpand/basics.test +++ b/mysql-test/suite/xpand/basics.test @@ -34,5 +34,34 @@ EXPLAIN SELECT i,t FROM (SELECT i,t FROM intandtext) t; DROP TABLE intandtext; +set + optimizer_switch=default, + xpand_derived_handler= default, + xpand_select_handler=default; + +--echo # +--echo # CLX-77: INSERT ... SELECT returns rows to the client instead of inserting +--echo # +--disable_warnings +drop table if exists t1,t2; +--enable_warnings + +create table t1 (a int) engine=xpand; +insert into t1 values (1); + +select a into @var from t1; +select @var; + +--echo # This must not emit output to the client: +select a into outfile 'tmpfile1' from t1; +let $file=`select concat(@@datadir,'/clx/tmpfile1')`; + +--remove_file $file + +create table t2 (a int) engine=myisam; +insert into t2 select * from t1; +select * from t2; + +drop table t1,t2; USE test; DROP DATABASE xpd; diff --git a/storage/federatedx/federatedx_pushdown.cc b/storage/federatedx/federatedx_pushdown.cc index 2701436ccf5..acd90e95b1c 100644 --- a/storage/federatedx/federatedx_pushdown.cc +++ b/storage/federatedx/federatedx_pushdown.cc @@ -181,6 +181,15 @@ create_federatedx_select_handler(THD* thd, SELECT_LEX *sel) else if (ht != tbl->table->file->partition_ht()) return 0; } + + /* + Currently, ha_federatedx_select_handler::init_scan just takes the + thd->query and sends it to the backend. + This obviously won't work if the SELECT has an INTO part. + Refuse to work in this case. + */ + if (thd->lex->result) + return NULL; /* Currently, ha_federatedx_select_handler::init_scan just takes the -- cgit v1.2.1 From 2e76114cf911c3a36052da73f94d9c6e6cb4d820 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Tue, 18 Feb 2020 15:34:37 +0000 Subject: CLX-77: INSERT ... SELECT returns rows to the client... Part #2: update the testcase as the database we're using was changed. --- mysql-test/suite/xpand/basics.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/suite/xpand/basics.test b/mysql-test/suite/xpand/basics.test index 9777ad22e51..34d702d03ca 100644 --- a/mysql-test/suite/xpand/basics.test +++ b/mysql-test/suite/xpand/basics.test @@ -54,7 +54,7 @@ select @var; --echo # This must not emit output to the client: select a into outfile 'tmpfile1' from t1; -let $file=`select concat(@@datadir,'/clx/tmpfile1')`; +let $file=`select concat(@@datadir,'/xpd/tmpfile1')`; --remove_file $file -- cgit v1.2.1 From 01f3976243931273a3bceb8cc87900f63f91f1a6 Mon Sep 17 00:00:00 2001 From: Isaac Ackerman Date: Thu, 20 Feb 2020 22:04:07 +0000 Subject: Track sysvars that change pushdown execution --- storage/xpand/ha_xpand.cc | 6 ++-- storage/xpand/xpand_connection.cc | 59 ++++++++++++++++++++++++++++++++++++--- storage/xpand/xpand_connection.h | 4 ++- 3 files changed, 61 insertions(+), 8 deletions(-) diff --git a/storage/xpand/ha_xpand.cc b/storage/xpand/ha_xpand.cc index 3852bae1933..341f10acd18 100644 --- a/storage/xpand/ha_xpand.cc +++ b/storage/xpand/ha_xpand.cc @@ -253,7 +253,7 @@ xpand_connection *get_trx(THD *thd, int *error_code) xpand_connection *trx; if (!(trx = (xpand_connection *)thd_get_ha_data(thd, xpand_hton))) { - if (!(trx = new xpand_connection())) { + if (!(trx = new xpand_connection(thd))) { *error_code = HA_ERR_OUT_OF_MEM; return NULL; } @@ -1264,7 +1264,7 @@ static int xpand_discover_table_names(handlerton *hton, LEX_CSTRING *db, MY_DIR *dir, handlerton::discovered_list *result) { - xpand_connection *xpand_net = new xpand_connection(); + xpand_connection *xpand_net = new xpand_connection(NULL); int error_code = xpand_net->connect(); if (error_code) goto err; @@ -1278,7 +1278,7 @@ err: int xpand_discover_table(handlerton *hton, THD *thd, TABLE_SHARE *share) { - xpand_connection *xpand_net = new xpand_connection(); + xpand_connection *xpand_net = new xpand_connection(NULL); int error_code = xpand_net->connect(); if (error_code) goto err; diff --git a/storage/xpand/xpand_connection.cc b/storage/xpand/xpand_connection.cc index 48c43237199..9e730042a7f 100644 --- a/storage/xpand/xpand_connection.cc +++ b/storage/xpand/xpand_connection.cc @@ -6,9 +6,15 @@ Copyright (c) 2019, MariaDB Corporation. #include "xpand_connection.h" #include -#include "errmsg.h" #include "handler.h" #include "table.h" +#include "sql_class.h" +#include "tztime.h" + +//#include "errmsg.h" +//name conflicts on macro ER with sql_class.h +#define CR_CONNECTION_ERROR 2002 +#define CR_CONN_HOST_ERROR 2003 extern int xpand_connect_timeout; extern int xpand_read_timeout; @@ -82,8 +88,8 @@ enum xpand_commands { /**************************************************************************** ** Class xpand_connection ****************************************************************************/ -xpand_connection::xpand_connection() - : command_buffer(NULL), command_buffer_length(0), command_length(0), +xpand_connection::xpand_connection(THD *parent_thd) + : session(parent_thd), command_buffer(NULL), command_buffer_length(0), command_length(0), trans_state(XPAND_TRANS_NONE), trans_flags(XPAND_TRANS_NO_POST_FLAGS) { DBUG_ENTER("xpand_connection::xpand_connection"); @@ -198,6 +204,43 @@ int xpand_connection::connect() DBUG_RETURN(0); } +int xpand_connection::add_status_vars() +{ + DBUG_ENTER("xpand_connection::add_status_vars"); + assert(session); + + int error_code = 0; + system_variables vars = session->variables; + if ((error_code = add_command_operand_uchar(1))) + DBUG_RETURN(error_code); + //sql mode + if ((error_code = add_command_operand_ulonglong(vars.sql_mode))) + DBUG_RETURN(error_code); + //auto increment state + if ((error_code = add_command_operand_ushort(vars.auto_increment_increment))) + DBUG_RETURN(error_code); + if ((error_code = add_command_operand_ushort(vars.auto_increment_offset))) + DBUG_RETURN(error_code); + //character set and collation + if ((error_code = add_command_operand_ushort(vars.character_set_client->number))) + DBUG_RETURN(error_code); + if ((error_code = add_command_operand_ushort(vars.collation_connection->number))) + DBUG_RETURN(error_code); + if ((error_code = add_command_operand_ushort(vars.collation_server->number))) + DBUG_RETURN(error_code); + //timezone and time names + String tzone; //convert to utf8 + vars.time_zone->get_name()->print(&tzone, get_charset(33,0)); + if ((error_code = add_command_operand_str((const uchar*)tzone.ptr(),tzone.length()))) + DBUG_RETURN(error_code); + if ((error_code = add_command_operand_ushort(vars.lc_time_names->number))) + DBUG_RETURN(error_code); + //transaction isolation + if ((error_code = add_command_operand_uchar(vars.tx_isolation))) + DBUG_RETURN(error_code); + DBUG_RETURN(0); +} + int xpand_connection::begin_command(uchar command) { if (trans_state == XPAND_TRANS_NONE) @@ -211,6 +254,11 @@ int xpand_connection::begin_command(uchar command) if ((error_code = add_command_operand_uchar(trans_state | trans_flags))) return error_code; + if (trans_state & XPAND_TRANS_NEW_STMT || + trans_state & XPAND_TRANS_REQUESTED) + if ((error_code = add_status_vars())) + return error_code; + return error_code; } @@ -620,7 +668,10 @@ public: ulong packet_length = cli_safe_read(xpand_net); if (packet_length == packet_error) { *stmt_completed = TRUE; - DBUG_RETURN(mysql_errno(xpand_net)); + int error_code = mysql_errno(xpand_net); + my_printf_error(error_code, "Xpand error: %s", MYF(0), + mysql_error(xpand_net)); + DBUG_RETURN(error_code); } unsigned char *pos = xpand_net->net.read_pos; diff --git a/storage/xpand/xpand_connection.h b/storage/xpand/xpand_connection.h index c07d8da5f5b..41b4ddec713 100644 --- a/storage/xpand/xpand_connection.h +++ b/storage/xpand/xpand_connection.h @@ -31,6 +31,7 @@ class xpand_connection_cursor; class xpand_connection { private: + THD *session; MYSQL xpand_net; uchar *command_buffer; size_t command_buffer_length; @@ -41,7 +42,7 @@ private: int allocate_cursor(MYSQL *xpand_net, ulong buffer_size, xpand_connection_cursor **scan); public: - xpand_connection(); + xpand_connection(THD *parent_thd); ~xpand_connection(); inline bool is_connected() @@ -116,6 +117,7 @@ private: int add_command_operand_vlstr(const uchar *str, size_t length); int add_command_operand_lex_string(LEX_CSTRING str); int add_command_operand_bitmap(MY_BITMAP *bitmap); + int add_status_vars(); int begin_command(uchar command); int send_command(); int read_query_response(); -- cgit v1.2.1 From 2d9c5f1b7adf192f6e11d8939faf062aadb97bab Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Tue, 18 Feb 2020 20:20:32 +0000 Subject: CLX-55: Prepared Statements: a short term solution for UPDATEs Direct UPDATE used to print the original statement. With Prepared Statement, this could cause the statement with original parameter marks ('?') to be printed. Solve this in the same way as "Select Handler" does: print the statement back from the parse tree. The parameters would be substituted. --- mysql-test/suite/xpand/basics.result | 13 +++++++++++++ mysql-test/suite/xpand/basics.test | 12 ++++++++++++ storage/xpand/ha_xpand.cc | 3 ++- 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/xpand/basics.result b/mysql-test/suite/xpand/basics.result index be50e614274..d89fc8cf44a 100644 --- a/mysql-test/suite/xpand/basics.result +++ b/mysql-test/suite/xpand/basics.result @@ -67,5 +67,18 @@ select * from t2; a 1 drop table t1,t2; +# +# CLX-55: Prepared statement support: +# Implement "Direct Update" by printing the statement +# +create table t1 (a int primary key, b int) engine=xpand; +insert into t1 values (1,1),(2,2),(3,3); +prepare s from 'update t1 set b=b+? where a=?'; +execute s using 10000, 2; +select * from t1; +a b +1 1 +2 10002 +3 3 USE test; DROP DATABASE xpd; diff --git a/mysql-test/suite/xpand/basics.test b/mysql-test/suite/xpand/basics.test index 34d702d03ca..755c2a3fb83 100644 --- a/mysql-test/suite/xpand/basics.test +++ b/mysql-test/suite/xpand/basics.test @@ -63,5 +63,17 @@ insert into t2 select * from t1; select * from t2; drop table t1,t2; + +--echo # +--echo # CLX-55: Prepared statement support: +--echo # Implement "Direct Update" by printing the statement +--echo # +create table t1 (a int primary key, b int) engine=xpand; +insert into t1 values (1,1),(2,2),(3,3); + +prepare s from 'update t1 set b=b+? where a=?'; +execute s using 10000, 2; +--sorted_result +select * from t1; USE test; DROP DATABASE xpd; diff --git a/storage/xpand/ha_xpand.cc b/storage/xpand/ha_xpand.cc index 341f10acd18..13255107b7e 100644 --- a/storage/xpand/ha_xpand.cc +++ b/storage/xpand/ha_xpand.cc @@ -561,7 +561,8 @@ int ha_xpand::direct_update_rows(ha_rows *update_rows, ha_rows *found_rows) return error_code; String update_stmt; - update_stmt.append(thd->query_string.str()); + // Do the same as create_xpand_select_handler does: + thd->lex->print(&update_stmt, QT_ORDINARY); if (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) trx->auto_commit_next(); -- cgit v1.2.1 From 8f112cf50b426a6ee9ab939d4c609fe13a12c450 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Tue, 25 Feb 2020 17:10:40 +0000 Subject: CLX-103: xpand.update fails after for CLX-55 Fix xpand.update test It was not using the charsets correctly: UTF-8 encoded strings were passed to MariaDB as latin1. The results of SELECT statements looked correct because they were interpreted as UTF-8, too. But the data in tables was mis-encoded so UPDATE statements already didn't work correctly. --- mysql-test/suite/xpand/update.result | 33 +++++++++++++++++++++++++++++---- mysql-test/suite/xpand/update.test | 25 +++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/mysql-test/suite/xpand/update.result b/mysql-test/suite/xpand/update.result index 9b39f318ca1..9fa63f834f1 100644 --- a/mysql-test/suite/xpand/update.result +++ b/mysql-test/suite/xpand/update.result @@ -1,26 +1,51 @@ CREATE DATABASE IF NOT EXISTS `db1`; +connect con1,localhost,root,,test; +connection con1; USE `db1`; DROP TABLE IF EXISTS `t1`; -Warnings: -Note 1051 Unknown table 'db1.t1' CREATE TABLE `t1`(i BIGINT, t TEXT)ENGINE=xpand; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `i` bigint(20) DEFAULT NULL, + `t` text DEFAULT NULL +) ENGINE=XPAND DEFAULT CHARSET=utf8 +set character_set_client=utf8; +set collation_connection=utf8_bin; +set character_set_results=utf8; INSERT INTO `t1` (i, t) VALUES (42, 'один'); INSERT INTO `t1` (i, t) VALUES (42, 'ноль'); SELECT * FROM `t1` ORDER BY `i` DESC, `t` DESC; i t 42 один 42 ноль +# examine the data on the backend: +# This should show that the SELECT has been pushed to the backend: +explain +select i, hex(t) from t1; +id select_type table type possible_keys key key_len ref rows Extra +1 PUSHED SELECT NULL NULL NULL NULL NULL NULL NULL NULL +select i, hex(t) from t1; +i hex(t) +42 D0BDD0BED0BBD18C +42 D0BED0B4D0B8D0BD +# The above should match: +select hex('один') as row1, hex('ноль') as row2; +row1 row2 +D0BED0B4D0B8D0BD D0BDD0BED0BBD18C UPDATE `t1` SET i=i+1,t='два' WHERE t='один'; SELECT * FROM `t1` ORDER BY `i` DESC, `t` DESC; i t -42 один +43 два 42 ноль USE test; UPDATE `db1`.`t1` SET i=i+1,t='три' WHERE t='два'; SELECT * FROM `db1`.`t1` ORDER BY `i` DESC, `t` DESC; i t -42 один +44 три 42 ноль +disconnect con1; +connection default; DROP TABLE `db1`.`t1`; USE test; DROP DATABASE `db1`; diff --git a/mysql-test/suite/xpand/update.test b/mysql-test/suite/xpand/update.test index eb40a19d7ac..eb920fb4324 100644 --- a/mysql-test/suite/xpand/update.test +++ b/mysql-test/suite/xpand/update.test @@ -1,11 +1,33 @@ CREATE DATABASE IF NOT EXISTS `db1`; + +# Do the test in another connection so that we don't have to clean up +connect (con1,localhost,root,,test); +connection con1; + USE `db1`; +--disable_warnings DROP TABLE IF EXISTS `t1`; +--enable_warnings + CREATE TABLE `t1`(i BIGINT, t TEXT)ENGINE=xpand; +show create table t1; + +set character_set_client=utf8; +set collation_connection=utf8_bin; +set character_set_results=utf8; INSERT INTO `t1` (i, t) VALUES (42, 'один'); INSERT INTO `t1` (i, t) VALUES (42, 'ноль'); SELECT * FROM `t1` ORDER BY `i` DESC, `t` DESC; +--echo # examine the data on the backend: +--echo # This should show that the SELECT has been pushed to the backend: +explain +select i, hex(t) from t1; +--sorted_result +select i, hex(t) from t1; +--echo # The above should match: +select hex('один') as row1, hex('ноль') as row2; + UPDATE `t1` SET i=i+1,t='два' WHERE t='один'; SELECT * FROM `t1` ORDER BY `i` DESC, `t` DESC; @@ -13,6 +35,9 @@ USE test; UPDATE `db1`.`t1` SET i=i+1,t='три' WHERE t='два'; SELECT * FROM `db1`.`t1` ORDER BY `i` DESC, `t` DESC; +disconnect con1; +connection default; + DROP TABLE `db1`.`t1`; USE test; -- cgit v1.2.1 From d882f13badb2229229c4a96588ae0efe0ca45105 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Wed, 26 Feb 2020 10:10:24 +0000 Subject: CLX-103: xpand.update fails after for CLX-55, part #2 Fix the complaint from safemalloc about leaked 8 bytes. When mysql_update() uses direct update, it will still create a quick select (doesn't make much sense, does it?) Quick select will be initialized, which will call ha_xpand::index_init which will allocate ha_xpand::scan_fields. Then, ha_xpand::index_end will be called but it will fail to free scan_fields. --- storage/xpand/ha_xpand.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/storage/xpand/ha_xpand.cc b/storage/xpand/ha_xpand.cc index 13255107b7e..07905198802 100644 --- a/storage/xpand/ha_xpand.cc +++ b/storage/xpand/ha_xpand.cc @@ -875,7 +875,10 @@ int ha_xpand::index_end() if (scan_cur) DBUG_RETURN(rnd_end()); else + { + my_bitmap_free(&scan_fields); DBUG_RETURN(0); + } } int ha_xpand::rnd_init(bool scan) -- cgit v1.2.1 From 4252df833bc2d908b5eb067a3f443ef6953e81e3 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Wed, 26 Feb 2020 16:12:01 +0000 Subject: CLX-80: ALTER TABLE t ENGINE=CLUSTRIX fails with an error Fix a number of issues that were preventing row-copying ALTER TABLE from working: - ha_xpand::create() and ha_xpand::open() should take the table name from the arguments, not from TABLE_SHARE object. - ha_xpand::rename_table() should not use decode_file_path() as that fails with an error for temporary table names (#sql_nnnn) - Maintenance of clustrix_table_oid through TABLE_SHARE::tabledef_version didn't cover the temporary work tables created by ALTER TABLE code. Switch to storing it in the Xpand_share instead, and update it in ::create() and ::open. - On as-needed-basis, add quoting of table names to pieces of code that build SQL statements to be ran on the backend. This is a stop-gap measure until a real solution is implemented. --- mysql-test/suite/xpand/basics.result | 29 ++++- mysql-test/suite/xpand/basics.test | 23 +++- storage/xpand/ha_xpand.cc | 202 +++++++++++++++++++++++++---------- storage/xpand/ha_xpand.h | 12 +++ storage/xpand/xpand_connection.cc | 77 +++++++++---- storage/xpand/xpand_connection.h | 2 + 6 files changed, 266 insertions(+), 79 deletions(-) diff --git a/mysql-test/suite/xpand/basics.result b/mysql-test/suite/xpand/basics.result index d89fc8cf44a..e21ce2c574e 100644 --- a/mysql-test/suite/xpand/basics.result +++ b/mysql-test/suite/xpand/basics.result @@ -1,8 +1,6 @@ CREATE DATABASE xpd; USE xpd; -DROP TABLE IF EXISTS cx1; -Warnings: -Note 1051 Unknown table 'xpd.cx1' +DROP TABLE IF EXISTS cx1, t1, t2; CREATE TABLE cx1(i BIGINT)ENGINE=xpand; CREATE TABLE cx1(i BIGINT)ENGINE=xpand; ERROR 42S01: Table 'cx1' already exists @@ -80,5 +78,30 @@ a b 1 1 2 10002 3 3 +drop table t1; +# +# CLX-80: ALTER TABLE t ENGINE=CLUSTRIX fails with an error +# +create table t1 (a int) engine=myisam; +insert into t1 values (1),(2),(3); +alter table t1 engine=xpand; +select * from t1; +a +1 +2 +3 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL +) ENGINE=XPAND DEFAULT CHARSET=utf8 +# Try a RENAME TABLE too since the patch touches the code +alter table t1 rename t2; +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` int(11) DEFAULT NULL +) ENGINE=XPAND DEFAULT CHARSET=utf8 +drop table t2; USE test; DROP DATABASE xpd; diff --git a/mysql-test/suite/xpand/basics.test b/mysql-test/suite/xpand/basics.test index 755c2a3fb83..41f9a457da9 100644 --- a/mysql-test/suite/xpand/basics.test +++ b/mysql-test/suite/xpand/basics.test @@ -1,7 +1,10 @@ CREATE DATABASE xpd; USE xpd; -DROP TABLE IF EXISTS cx1; +--disable_warnings +DROP TABLE IF EXISTS cx1, t1, t2; +--enable_warnings + CREATE TABLE cx1(i BIGINT)ENGINE=xpand; --error ER_TABLE_EXISTS_ERROR CREATE TABLE cx1(i BIGINT)ENGINE=xpand; @@ -75,5 +78,23 @@ prepare s from 'update t1 set b=b+? where a=?'; execute s using 10000, 2; --sorted_result select * from t1; +drop table t1; + +--echo # +--echo # CLX-80: ALTER TABLE t ENGINE=CLUSTRIX fails with an error +--echo # +create table t1 (a int) engine=myisam; +insert into t1 values (1),(2),(3); +alter table t1 engine=xpand; +--sorted_result +select * from t1; +show create table t1; + +--echo # Try a RENAME TABLE too since the patch touches the code +alter table t1 rename t2; +show create table t2; + +drop table t2; + USE test; DROP DATABASE xpd; diff --git a/storage/xpand/ha_xpand.cc b/storage/xpand/ha_xpand.cc index 07905198802..90d8738e332 100644 --- a/storage/xpand/ha_xpand.cc +++ b/storage/xpand/ha_xpand.cc @@ -7,6 +7,7 @@ Copyright (c) 2019, MariaDB Corporation. #include "ha_xpand.h" #include "ha_xpand_pushdown.h" #include "key.h" +#include /* strconvert */ handlerton *xpand_hton = NULL; @@ -195,6 +196,33 @@ uint row_buffer_setting(THD* thd) return THDVAR(thd, row_buffer); } + +/* + Get an Xpand_share object for this object. If it doesn't yet exist, create + it. +*/ + +Xpand_share *ha_xpand::get_share() +{ + Xpand_share *tmp_share; + + DBUG_ENTER("ha_xpand::get_share()"); + + lock_shared_ha_data(); + if (!(tmp_share= static_cast(get_ha_share_ptr()))) + { + tmp_share= new Xpand_share; + if (!tmp_share) + goto err; + + set_ha_share_ptr(static_cast(tmp_share)); + } +err: + unlock_shared_ha_data(); + DBUG_RETURN(tmp_share); +} + + /**************************************************************************** ** Utility functions ****************************************************************************/ @@ -211,42 +239,71 @@ size_t estimate_row_size(TABLE *table) return row_size; } -/** - * @brief - * Decodes object name. - * - * @details - * Replaces the encoded object name in the path with a decoded variant, - * e.g if path contains ./test/d@0024. This f() makes it ./test/d$ - * - * Used in delete and rename DDL processing. - **/ -static void decode_objectname(char *buf, const char *path, size_t buf_size) -{ - size_t new_path_len = filename_to_tablename(path, buf, buf_size); - buf[new_path_len] = '\0'; + +/* + Try to decode a string from filename encoding, if that fails, return the + original string. + + @detail + This is used to get table (or database) name from file (or directory) + name. Names of regular tables/databases are encoded using + my_charset_filename encoding. + Names of temporary tables are not encoded, and they start with '#sql' + which is not a valid character sequence in my_charset_filename encoding. + Our way to talkle this is to + 1. Try to convert the name back + 2. If that failed, assume it's a temporary object name and just use the + name. +*/ + +static void decode_object_or_tmp_name(const char *from, uint size, + std::string *out) +{ + uint errors, new_size; + out->resize(size+1); // assume the decoded string is not longer + new_size= strconvert(&my_charset_filename, from, size, + system_charset_info, (char*)out->c_str(), size+1, + &errors); + if (errors) + out->assign(from, size); + else + out->resize(new_size); } -static void decode_file_path(const char *path, char *decoded_dbname, - char *decoded_tbname) +/* + Take a "./db_name/table_name" and extract db_name and table_name from it + + @return + 0 OK + other Error code +*/ +static int normalize_tablename(const char *db_table, + std::string *norm_db, std::string *norm_table) { - // The format cont ains './' in the beginning of a path. - char *dbname_start = (char*) path + 2; - char *dbname_end = dbname_start; - while (*dbname_end != '/') - dbname_end++; + std::string tablename(db_table); + if (tablename.size() < 2 || tablename[0] != '.' || + (tablename[1] != FN_LIBCHAR && tablename[1] != FN_LIBCHAR2)) { + DBUG_ASSERT(0); // We were not passed table name? + return HA_ERR_INTERNAL_ERROR; + } - int cnt = dbname_end - dbname_start; - char *dbname = (char *)my_alloca(cnt + 1); - memcpy(dbname, dbname_start, cnt); - dbname[cnt] = '\0'; - decode_objectname(decoded_dbname, dbname, FN_REFLEN); - my_afree(dbname); + size_t pos = tablename.find_first_of(FN_LIBCHAR, 2); + if (pos == std::string::npos) { + pos = tablename.find_first_of(FN_LIBCHAR2, 2); + } - char *tbname_start = dbname_end + 1; - decode_objectname(decoded_tbname, tbname_start, FN_REFLEN); + if (pos == std::string::npos) { + DBUG_ASSERT(0); // We were not passed table name? + return HA_ERR_INTERNAL_ERROR; + } + + decode_object_or_tmp_name(tablename.c_str() + 2, pos - 2, norm_db); + decode_object_or_tmp_name(tablename.c_str() + pos + 1, + tablename.size() - (pos + 1), norm_table); + return 0; } + xpand_connection *get_trx(THD *thd, int *error_code) { *error_code = 0; @@ -290,6 +347,7 @@ ha_xpand::~ha_xpand() remove_current_table_from_rpl_table_list(rgi); } + int ha_xpand::create(const char *name, TABLE *form, HA_CREATE_INFO *info) { int error_code; @@ -311,12 +369,16 @@ int ha_xpand::create(const char *name, TABLE *form, HA_CREATE_INFO *info) ulong old = create_info->used_fields; create_info->used_fields &= ~HA_CREATE_USED_ENGINE; + std::string norm_db, norm_table; + if ((error_code= normalize_tablename(name, &norm_db, &norm_table))) + return error_code; + TABLE_LIST table_list; memset(&table_list, 0, sizeof(table_list)); table_list.table = form; - error_code = show_create_table(thd, &table_list, &create_table_stmt, - create_info, WITH_DB_NAME); - + error_code = show_create_table_ex(thd, &table_list, + norm_db.c_str(), norm_table.c_str(), + &create_table_stmt, create_info, WITH_DB_NAME); if (!is_tmp_table) form->s->tmp_table = saved_tmp_table_type; create_info->used_fields = old; @@ -334,6 +396,13 @@ int ha_xpand::create(const char *name, TABLE *form, HA_CREATE_INFO *info) } error_code = trx->run_query(create_table_stmt); + if (error_code) + return error_code; + + // Load the oid of the created table + error_code= trx->get_table_oid(norm_db, norm_table, &xpand_table_oid, + table_share); + return error_code; } @@ -345,15 +414,17 @@ int ha_xpand::delete_table(const char *path) if (!trx) return error_code; - char decoded_dbname[FN_REFLEN]; - char decoded_tbname[FN_REFLEN]; - decode_file_path(path, decoded_dbname, decoded_tbname); + std::string decoded_dbname; + std::string decoded_tbname; + if ((error_code= normalize_tablename(path, &decoded_dbname, + &decoded_tbname))) + return error_code; String delete_cmd; delete_cmd.append("DROP TABLE `"); - delete_cmd.append(decoded_dbname); + delete_cmd.append(decoded_dbname.c_str()); delete_cmd.append("`.`"); - delete_cmd.append(decoded_tbname); + delete_cmd.append(decoded_tbname.c_str()); delete_cmd.append("`"); return trx->run_query(delete_cmd); @@ -367,23 +438,27 @@ int ha_xpand::rename_table(const char* from, const char* to) if (!trx) return error_code; - char decoded_from_dbname[FN_REFLEN]; - char decoded_from_tbname[FN_REFLEN]; - decode_file_path(from, decoded_from_dbname, decoded_from_tbname); + std::string decoded_from_dbname; + std::string decoded_from_tbname; + if ((error_code= normalize_tablename(from, &decoded_from_dbname, + &decoded_from_tbname))) + return error_code; - char decoded_to_dbname[FN_REFLEN]; - char decoded_to_tbname[FN_REFLEN]; - decode_file_path(to, decoded_to_dbname, decoded_to_tbname); + std::string decoded_to_dbname; + std::string decoded_to_tbname; + if ((error_code= normalize_tablename(to, &decoded_to_dbname, + &decoded_to_tbname))) + return error_code; String rename_cmd; rename_cmd.append("RENAME TABLE `"); - rename_cmd.append(decoded_from_dbname); + rename_cmd.append(decoded_from_dbname.c_str()); rename_cmd.append("`.`"); - rename_cmd.append(decoded_from_tbname); + rename_cmd.append(decoded_from_tbname.c_str()); rename_cmd.append("` TO `"); - rename_cmd.append(decoded_to_dbname); + rename_cmd.append(decoded_to_dbname.c_str()); rename_cmd.append("`.`"); - rename_cmd.append(decoded_to_tbname); + rename_cmd.append(decoded_to_tbname.c_str()); rename_cmd.append("`;"); return trx->run_query(rename_cmd); @@ -392,21 +467,37 @@ int ha_xpand::rename_table(const char* from, const char* to) static void xpand_mark_table_for_discovery(TABLE *table) { - table->s->tabledef_version.str = NULL; - table->s->tabledef_version.length = 0; table->m_needs_reopen = TRUE; + Xpand_share *xs; + if ((xs= (Xpand_share*)table->s->ha_share)) + xs->xpand_table_oid= 0; } int ha_xpand::open(const char *name, int mode, uint test_if_locked) { + THD *thd= ha_thd(); DBUG_ENTER("ha_xpand::open"); - DBUG_PRINT("oid", - ("%s", table->s->tabledef_version.str)); - if (!table->s->tabledef_version.str) - DBUG_RETURN(HA_ERR_TABLE_DEF_CHANGED); - if (!xpand_table_oid) - xpand_table_oid = atoll((const char *)table->s->tabledef_version.str); + if (!(share = get_share())) + DBUG_RETURN(1); + int error_code; + xpand_connection *trx = get_trx(thd, &error_code); + if (!trx) + DBUG_RETURN(error_code); + + if (!share->xpand_table_oid) { + // We may end up with two threads executing this piece concurrently but + // it's ok + std::string norm_table; + std::string norm_db; + if ((error_code= normalize_tablename(name, &norm_db, &norm_table))) + DBUG_RETURN(error_code); + + error_code= trx->get_table_oid(norm_db, norm_table, &xpand_table_oid, + table_share); + if (error_code) + DBUG_RETURN(error_code); + } // Surrogate key marker has_hidden_key = table->s->primary_key == MAX_KEY; @@ -1298,6 +1389,7 @@ err: static int xpand_init(void *p) { DBUG_ENTER("xpand_init"); + xpand_hton = (handlerton *) p; xpand_hton->flags = HTON_NO_FLAGS; xpand_hton->panic = xpand_panic; diff --git a/storage/xpand/ha_xpand.h b/storage/xpand/ha_xpand.h index 48359af6470..8e3ea059e59 100644 --- a/storage/xpand/ha_xpand.h +++ b/storage/xpand/ha_xpand.h @@ -30,9 +30,18 @@ int unpack_row_to_buf(rpl_group_info *rgi, TABLE *table, uchar *data, uchar const *const row_data, MY_BITMAP const *cols, uchar const *const row_end); + +class Xpand_share : public Handler_share { +public: + Xpand_share(): xpand_table_oid(0) {} + + std::atomic xpand_table_oid; +}; + class ha_xpand : public handler { private: + // TODO: do we need this here or one in share would be sufficient? ulonglong xpand_table_oid; rpl_group_info *rgi; @@ -56,6 +65,9 @@ private: } xpd_upsert_flags_t; int upsert_flag; + Xpand_share *share; + Xpand_share *get_share(); ///< Get the share + public: ha_xpand(handlerton *hton, TABLE_SHARE *table_arg); ~ha_xpand(); diff --git a/storage/xpand/xpand_connection.cc b/storage/xpand/xpand_connection.cc index 9e730042a7f..34ba7b7dfe1 100644 --- a/storage/xpand/xpand_connection.cc +++ b/storage/xpand/xpand_connection.cc @@ -5,6 +5,7 @@ Copyright (c) 2019, MariaDB Corporation. /** @file xpand_connection.cc */ #include "xpand_connection.h" +#include "ha_xpand.h" #include #include "handler.h" #include "table.h" @@ -988,24 +989,40 @@ error: return error_code; } -int xpand_connection::discover_table_details(LEX_CSTRING *db, LEX_CSTRING *name, - THD *thd, TABLE_SHARE *share) + +/* + Given a table name, find its OID in the Clustrix, and save it in TABLE_SHARE + + @param db Database name + @param name Table name + @param oid OUT Return the OID here + @param share INOUT If not NULL and the share has ha_share pointer, also + update Xpand_share::xpand_table_oid. + + @return + 0 - OK + error code if an error occurred +*/ + +int xpand_connection::get_table_oid(const std::string &db, + const std::string &name, + ulonglong *oid, + TABLE_SHARE *share) { - DBUG_ENTER("xpand_connection::discover_table_details"); + MYSQL_ROW row; int error_code = 0; MYSQL_RES *results_oid = NULL; - MYSQL_RES *results_create = NULL; - MYSQL_ROW row; - String get_oid, show; + String get_oid; + DBUG_ENTER("xpand_connection::get_table_oid"); /* get oid */ get_oid.append("select r.table " "from system.databases d " " inner join ""system.relations r on d.db = r.db " "where d.name = '"); - get_oid.append(db); + get_oid.append(db.c_str()); get_oid.append("' and r.name = '"); - get_oid.append(name); + get_oid.append(name.c_str()); get_oid.append("'"); if (mysql_real_query(&xpand_net, get_oid.c_ptr(), get_oid.length())) { @@ -1026,24 +1043,47 @@ int xpand_connection::discover_table_details(LEX_CSTRING *db, LEX_CSTRING *name, goto error; } - while((row = mysql_fetch_row(results_oid))) { + if ((row = mysql_fetch_row(results_oid))) { DBUG_PRINT("row", ("%s", row[0])); - uchar *to = (uchar*)alloc_root(&share->mem_root, strlen(row[0]) + 1); - if (!to) { - error_code = HA_ERR_OUT_OF_MEM; - goto error; - } - strcpy((char *)to, (char *)row[0]); - share->tabledef_version.str = to; - share->tabledef_version.length = strlen(row[0]); + *oid = strtoull((const char *)row[0], NULL, 10); + if (share->ha_share) { + Xpand_share *cs= (Xpand_share*)share->ha_share; + cs->xpand_table_oid = *oid; + } + } else { + error_code = HA_ERR_NO_SUCH_TABLE; + goto error; } +error: + if (results_oid) + mysql_free_result(results_oid); + + DBUG_RETURN(error_code); +} + + +/* + Given a table name, fetch table definition from Clustrix and fill the TABLE_SHARE + object with details about field, indexes, etc. +*/ +int xpand_connection::discover_table_details(LEX_CSTRING *db, LEX_CSTRING *name, + THD *thd, TABLE_SHARE *share) +{ + DBUG_ENTER("xpand_connection::discover_table_details"); + int error_code = 0; + MYSQL_RES *results_create = NULL; + MYSQL_ROW row; + String show; + /* get show create statement */ show.append("show simple create table "); show.append(db); show.append("."); + show.append("`"); show.append(name); + show.append("`"); if (mysql_real_query(&xpand_net, show.c_ptr(), show.length())) { if ((error_code = mysql_errno(&xpand_net))) { DBUG_PRINT("mysql_real_query returns ", ("%d", error_code)); @@ -1074,9 +1114,6 @@ int xpand_connection::discover_table_details(LEX_CSTRING *db, LEX_CSTRING *name, } error: - if (results_oid) - mysql_free_result(results_oid); - if (results_create) mysql_free_result(results_create); DBUG_RETURN(error_code); diff --git a/storage/xpand/xpand_connection.h b/storage/xpand/xpand_connection.h index 41b4ddec713..e2d4761dd68 100644 --- a/storage/xpand/xpand_connection.h +++ b/storage/xpand/xpand_connection.h @@ -103,6 +103,8 @@ public: int scan_end(xpand_connection_cursor *scan); int populate_table_list(LEX_CSTRING *db, handlerton::discovered_list *result); + int get_table_oid(const std::string& db, const std::string &name, + ulonglong *oid, TABLE_SHARE *share); int discover_table_details(LEX_CSTRING *db, LEX_CSTRING *name, THD *thd, TABLE_SHARE *share); -- cgit v1.2.1 From 1e0152b456711948a26e90e3ccbab90b5cc6f461 Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Fri, 21 Feb 2020 16:55:02 -0800 Subject: Add table synchronization for select and derived handlers. --- storage/xpand/ha_xpand.cc | 36 ++++++++++++++++++++++++++++++++++++ storage/xpand/ha_xpand.h | 3 +++ storage/xpand/ha_xpand_pushdown.cc | 16 ++++++++++++---- storage/xpand/xpand_connection.cc | 9 ++++++++- storage/xpand/xpand_connection.h | 2 +- 5 files changed, 60 insertions(+), 6 deletions(-) diff --git a/storage/xpand/ha_xpand.cc b/storage/xpand/ha_xpand.cc index 90d8738e332..577689076bb 100644 --- a/storage/xpand/ha_xpand.cc +++ b/storage/xpand/ha_xpand.cc @@ -473,6 +473,37 @@ xpand_mark_table_for_discovery(TABLE *table) xs->xpand_table_oid= 0; } +void +xpand_mark_tables_for_discovery(LEX *lex) +{ + for (TABLE_LIST *tbl= lex->query_tables; tbl; tbl= tbl->next_global) + if (tbl->table && tbl->table->file->ht == xpand_hton) + xpand_mark_table_for_discovery(tbl->table); +} + +ulonglong * +xpand_extract_table_oids(THD *thd, LEX *lex) +{ + int cnt = 1; + for (TABLE_LIST *tbl = lex->query_tables; tbl; tbl= tbl->next_global) + if (tbl->table && tbl->table->file->ht == xpand_hton) + cnt++; + + ulonglong *oids = (ulonglong*)thd_alloc(thd, cnt * sizeof(ulonglong)); + ulonglong *ptr = oids; + for (TABLE_LIST *tbl = lex->query_tables; tbl; tbl= tbl->next_global) + { + if (tbl->table && tbl->table->file->ht == xpand_hton) + { + ha_xpand *hndlr = static_cast(tbl->table->file); + *ptr++ = hndlr->get_table_oid(); + } + } + + *ptr = 0; + return oids; +} + int ha_xpand::open(const char *name, int mode, uint test_if_locked) { THD *thd= ha_thd(); @@ -1190,6 +1221,11 @@ int ha_xpand::info_push(uint info_type, void *info) return 0; } +ulonglong ha_xpand::get_table_oid() +{ + return xpand_table_oid; +} + /**************************************************************************** ** Row encoding functions ****************************************************************************/ diff --git a/storage/xpand/ha_xpand.h b/storage/xpand/ha_xpand.h index 8e3ea059e59..bc3206f2f5f 100644 --- a/storage/xpand/ha_xpand.h +++ b/storage/xpand/ha_xpand.h @@ -29,6 +29,8 @@ void remove_current_table_from_rpl_table_list(rpl_group_info *rgi); int unpack_row_to_buf(rpl_group_info *rgi, TABLE *table, uchar *data, uchar const *const row_data, MY_BITMAP const *cols, uchar const *const row_end); +void xpand_mark_tables_for_discovery(LEX *lex); +ulonglong *xpand_extract_table_oids(THD *thd, LEX *lex); class Xpand_share : public Handler_share { @@ -131,6 +133,7 @@ public: void cond_pop(); int info_push(uint info_type, void *info); + ulonglong get_table_oid(); private: void build_key_packed_row(uint index, const uchar *buf, uchar *packed_key, size_t *packed_key_len); diff --git a/storage/xpand/ha_xpand_pushdown.cc b/storage/xpand/ha_xpand_pushdown.cc index de43d4bd75b..7700d8dfa3c 100644 --- a/storage/xpand/ha_xpand_pushdown.cc +++ b/storage/xpand/ha_xpand_pushdown.cc @@ -101,6 +101,7 @@ err: select_handler* create_xpand_select_handler(THD* thd, SELECT_LEX* select_lex) { + ulonglong *oids = NULL; ha_xpand_select_handler *sh = NULL; if (!select_handler_setting(thd)) { return sh; @@ -156,20 +157,23 @@ create_xpand_select_handler(THD* thd, SELECT_LEX* select_lex) if (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) trx->auto_commit_next(); + oids = xpand_extract_table_oids(thd, select_lex->parent_lex); if ((error_code = trx->scan_query(query, fieldtype, items_number, null_bits, num_null_bytes, field_metadata, field_metadata_size, - row_buffer_setting(thd), &scan))) { + row_buffer_setting(thd), oids, &scan))) { goto err; } sh = new ha_xpand_select_handler(thd, select_lex, scan); err: - // deallocate buffers if (meta_memory) my_free(meta_memory); + if (error_code == HA_ERR_TABLE_DEF_CHANGED) + xpand_mark_tables_for_discovery(select_lex->parent_lex); + return sh; } @@ -376,6 +380,7 @@ int ha_xpand_derived_handler::init_scan() int error_code = 0; int field_metadata_size = 0; xpand_connection *trx = NULL; + ulonglong *oids = NULL; // We presume this number is equal to types.elements in get_field_types uint items_number= select->get_item_list()->elements; @@ -402,10 +407,11 @@ int ha_xpand_derived_handler::init_scan() if (!trx) goto err; + oids = xpand_extract_table_oids(thd__, select->parent_lex); if ((error_code = trx->scan_query(query, fieldtype, items_number, null_bits, num_null_bytes, field_metadata, field_metadata_size, - row_buffer_setting(thd), &scan))) { + row_buffer_setting(thd), oids, &scan))) { goto err; } @@ -420,10 +426,12 @@ int ha_xpand_derived_handler::init_scan() add_current_table_to_rpl_table_list(&rgi, thd__, table__); err: - // deallocate buffers if (meta_memory) my_free(meta_memory); + if (error_code == HA_ERR_TABLE_DEF_CHANGED) + xpand_mark_tables_for_discovery(select->parent_lex); + return error_code; } diff --git a/storage/xpand/xpand_connection.cc b/storage/xpand/xpand_connection.cc index 34ba7b7dfe1..fd3e83b1972 100644 --- a/storage/xpand/xpand_connection.cc +++ b/storage/xpand/xpand_connection.cc @@ -281,7 +281,7 @@ int xpand_connection::send_command() committed or rolled back. */ trans_state = XPAND_TRANS_STARTED; - + com_error = simple_command(&xpand_net, (enum_server_command)XPAND_SERVER_REQUEST, command_buffer, command_length, TRUE); @@ -777,6 +777,7 @@ int xpand_connection::scan_query(String &stmt, uchar *fieldtype, uint fields, uchar *null_bits, uint null_bits_size, uchar *field_metadata, uint field_metadata_size, ushort row_req, + ulonglong *oids, xpand_connection_cursor **scan) { int error_code; @@ -785,6 +786,12 @@ int xpand_connection::scan_query(String &stmt, uchar *fieldtype, uint fields, if ((error_code = begin_command(XPAND_SCAN_QUERY))) return error_code; + do { + if ((error_code = add_command_operand_ulonglong(*oids))) + return error_code; + } + while (*oids++); + if ((error_code = add_command_operand_ushort(row_req))) return error_code; diff --git a/storage/xpand/xpand_connection.h b/storage/xpand/xpand_connection.h index e2d4761dd68..a9f4df04b55 100644 --- a/storage/xpand/xpand_connection.h +++ b/storage/xpand/xpand_connection.h @@ -89,7 +89,7 @@ public: xpand_connection_cursor **scan); int scan_query(String &stmt, uchar *fieldtype, uint fields, uchar *null_bits, uint null_bits_size, uchar *field_metadata, - uint field_metadata_size, ushort row_req, + uint field_metadata_size, ushort row_req, ulonglong *oids, xpand_connection_cursor **scan); int update_query(String &stmt, LEX_CSTRING &dbname, ulonglong *affected_rows); int scan_from_key(ulonglong xpand_table_oid, uint index, -- cgit v1.2.1 From b2f56c36e9a7e0d1f1573eac71a5dcec9fc7998c Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Wed, 26 Feb 2020 15:47:05 -0800 Subject: Revert "Add table synchronization for select and derived handlers." --- storage/xpand/ha_xpand.cc | 36 ------------------------------------ storage/xpand/ha_xpand.h | 3 --- storage/xpand/ha_xpand_pushdown.cc | 16 ++++------------ storage/xpand/xpand_connection.cc | 9 +-------- storage/xpand/xpand_connection.h | 2 +- 5 files changed, 6 insertions(+), 60 deletions(-) diff --git a/storage/xpand/ha_xpand.cc b/storage/xpand/ha_xpand.cc index 577689076bb..90d8738e332 100644 --- a/storage/xpand/ha_xpand.cc +++ b/storage/xpand/ha_xpand.cc @@ -473,37 +473,6 @@ xpand_mark_table_for_discovery(TABLE *table) xs->xpand_table_oid= 0; } -void -xpand_mark_tables_for_discovery(LEX *lex) -{ - for (TABLE_LIST *tbl= lex->query_tables; tbl; tbl= tbl->next_global) - if (tbl->table && tbl->table->file->ht == xpand_hton) - xpand_mark_table_for_discovery(tbl->table); -} - -ulonglong * -xpand_extract_table_oids(THD *thd, LEX *lex) -{ - int cnt = 1; - for (TABLE_LIST *tbl = lex->query_tables; tbl; tbl= tbl->next_global) - if (tbl->table && tbl->table->file->ht == xpand_hton) - cnt++; - - ulonglong *oids = (ulonglong*)thd_alloc(thd, cnt * sizeof(ulonglong)); - ulonglong *ptr = oids; - for (TABLE_LIST *tbl = lex->query_tables; tbl; tbl= tbl->next_global) - { - if (tbl->table && tbl->table->file->ht == xpand_hton) - { - ha_xpand *hndlr = static_cast(tbl->table->file); - *ptr++ = hndlr->get_table_oid(); - } - } - - *ptr = 0; - return oids; -} - int ha_xpand::open(const char *name, int mode, uint test_if_locked) { THD *thd= ha_thd(); @@ -1221,11 +1190,6 @@ int ha_xpand::info_push(uint info_type, void *info) return 0; } -ulonglong ha_xpand::get_table_oid() -{ - return xpand_table_oid; -} - /**************************************************************************** ** Row encoding functions ****************************************************************************/ diff --git a/storage/xpand/ha_xpand.h b/storage/xpand/ha_xpand.h index bc3206f2f5f..8e3ea059e59 100644 --- a/storage/xpand/ha_xpand.h +++ b/storage/xpand/ha_xpand.h @@ -29,8 +29,6 @@ void remove_current_table_from_rpl_table_list(rpl_group_info *rgi); int unpack_row_to_buf(rpl_group_info *rgi, TABLE *table, uchar *data, uchar const *const row_data, MY_BITMAP const *cols, uchar const *const row_end); -void xpand_mark_tables_for_discovery(LEX *lex); -ulonglong *xpand_extract_table_oids(THD *thd, LEX *lex); class Xpand_share : public Handler_share { @@ -133,7 +131,6 @@ public: void cond_pop(); int info_push(uint info_type, void *info); - ulonglong get_table_oid(); private: void build_key_packed_row(uint index, const uchar *buf, uchar *packed_key, size_t *packed_key_len); diff --git a/storage/xpand/ha_xpand_pushdown.cc b/storage/xpand/ha_xpand_pushdown.cc index 7700d8dfa3c..de43d4bd75b 100644 --- a/storage/xpand/ha_xpand_pushdown.cc +++ b/storage/xpand/ha_xpand_pushdown.cc @@ -101,7 +101,6 @@ err: select_handler* create_xpand_select_handler(THD* thd, SELECT_LEX* select_lex) { - ulonglong *oids = NULL; ha_xpand_select_handler *sh = NULL; if (!select_handler_setting(thd)) { return sh; @@ -157,23 +156,20 @@ create_xpand_select_handler(THD* thd, SELECT_LEX* select_lex) if (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) trx->auto_commit_next(); - oids = xpand_extract_table_oids(thd, select_lex->parent_lex); if ((error_code = trx->scan_query(query, fieldtype, items_number, null_bits, num_null_bytes, field_metadata, field_metadata_size, - row_buffer_setting(thd), oids, &scan))) { + row_buffer_setting(thd), &scan))) { goto err; } sh = new ha_xpand_select_handler(thd, select_lex, scan); err: + // deallocate buffers if (meta_memory) my_free(meta_memory); - if (error_code == HA_ERR_TABLE_DEF_CHANGED) - xpand_mark_tables_for_discovery(select_lex->parent_lex); - return sh; } @@ -380,7 +376,6 @@ int ha_xpand_derived_handler::init_scan() int error_code = 0; int field_metadata_size = 0; xpand_connection *trx = NULL; - ulonglong *oids = NULL; // We presume this number is equal to types.elements in get_field_types uint items_number= select->get_item_list()->elements; @@ -407,11 +402,10 @@ int ha_xpand_derived_handler::init_scan() if (!trx) goto err; - oids = xpand_extract_table_oids(thd__, select->parent_lex); if ((error_code = trx->scan_query(query, fieldtype, items_number, null_bits, num_null_bytes, field_metadata, field_metadata_size, - row_buffer_setting(thd), oids, &scan))) { + row_buffer_setting(thd), &scan))) { goto err; } @@ -426,12 +420,10 @@ int ha_xpand_derived_handler::init_scan() add_current_table_to_rpl_table_list(&rgi, thd__, table__); err: + // deallocate buffers if (meta_memory) my_free(meta_memory); - if (error_code == HA_ERR_TABLE_DEF_CHANGED) - xpand_mark_tables_for_discovery(select->parent_lex); - return error_code; } diff --git a/storage/xpand/xpand_connection.cc b/storage/xpand/xpand_connection.cc index fd3e83b1972..34ba7b7dfe1 100644 --- a/storage/xpand/xpand_connection.cc +++ b/storage/xpand/xpand_connection.cc @@ -281,7 +281,7 @@ int xpand_connection::send_command() committed or rolled back. */ trans_state = XPAND_TRANS_STARTED; - + com_error = simple_command(&xpand_net, (enum_server_command)XPAND_SERVER_REQUEST, command_buffer, command_length, TRUE); @@ -777,7 +777,6 @@ int xpand_connection::scan_query(String &stmt, uchar *fieldtype, uint fields, uchar *null_bits, uint null_bits_size, uchar *field_metadata, uint field_metadata_size, ushort row_req, - ulonglong *oids, xpand_connection_cursor **scan) { int error_code; @@ -786,12 +785,6 @@ int xpand_connection::scan_query(String &stmt, uchar *fieldtype, uint fields, if ((error_code = begin_command(XPAND_SCAN_QUERY))) return error_code; - do { - if ((error_code = add_command_operand_ulonglong(*oids))) - return error_code; - } - while (*oids++); - if ((error_code = add_command_operand_ushort(row_req))) return error_code; diff --git a/storage/xpand/xpand_connection.h b/storage/xpand/xpand_connection.h index a9f4df04b55..e2d4761dd68 100644 --- a/storage/xpand/xpand_connection.h +++ b/storage/xpand/xpand_connection.h @@ -89,7 +89,7 @@ public: xpand_connection_cursor **scan); int scan_query(String &stmt, uchar *fieldtype, uint fields, uchar *null_bits, uint null_bits_size, uchar *field_metadata, - uint field_metadata_size, ushort row_req, ulonglong *oids, + uint field_metadata_size, ushort row_req, xpand_connection_cursor **scan); int update_query(String &stmt, LEX_CSTRING &dbname, ulonglong *affected_rows); int scan_from_key(ulonglong xpand_table_oid, uint index, -- cgit v1.2.1 From 5546fee6c41009daa312f72846b1f48fe32fb331 Mon Sep 17 00:00:00 2001 From: Isaac Ackerman Date: Thu, 27 Feb 2020 19:06:22 +0000 Subject: Improved connection management to clustrix supporting round robin and fail over --- storage/xpand/ha_xpand.cc | 146 ++++++++++++++++++++++++-------------- storage/xpand/xpand_connection.cc | 132 ++++++++++++++++++++++++++-------- storage/xpand/xpand_connection.h | 26 ++++++- 3 files changed, 217 insertions(+), 87 deletions(-) diff --git a/storage/xpand/ha_xpand.cc b/storage/xpand/ha_xpand.cc index 90d8738e332..ce713ac5bc0 100644 --- a/storage/xpand/ha_xpand.cc +++ b/storage/xpand/ha_xpand.cc @@ -8,6 +8,7 @@ Copyright (c) 2019, MariaDB Corporation. #include "ha_xpand_pushdown.h" #include "key.h" #include /* strconvert */ +#include "my_pthread.h" handlerton *xpand_hton = NULL; @@ -41,69 +42,100 @@ static MYSQL_SYSVAR_INT NULL, NULL, -1, -1, 2147483647, 0 ); -char *xpand_host; -static MYSQL_SYSVAR_STR +//state for load balancing +int xpand_hosts_cur; //protected by my_atomic's +ulong xpand_balance_algorithm; +const char* balance_algorithm_names[]= +{ + "first", "round_robin", NullS +}; + +TYPELIB balance_algorithms= +{ + array_elements(balance_algorithm_names) - 1, "", + balance_algorithm_names, NULL +}; + +static void update_balance_algorithm(MYSQL_THD thd, struct st_mysql_sys_var *var, + void *var_ptr, const void *save) +{ + *static_cast(var_ptr) = *static_cast(save); + my_atomic_store32(&xpand_hosts_cur, 0); +} + +static MYSQL_SYSVAR_ENUM ( - host, - xpand_host, - PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_MEMALLOC, - "Xpand host", - NULL, NULL, "127.0.0.1" + balance_algorithm, + xpand_balance_algorithm, + PLUGIN_VAR_OPCMDARG, + "Method for managing load balancing of Clustrix nodes, can take values FIRST or ROUND_ROBIN", + NULL, update_balance_algorithm, XPAND_BALANCE_ROUND_ROBIN, &balance_algorithms ); -int host_list_cnt; -char **host_list; +//current list of clx hosts +static PSI_rwlock_key key_xpand_hosts; +mysql_rwlock_t xpand_hosts_lock; +xpand_host_list *xpand_hosts; -static void free_host_list() +//only call while holding lock +static void clear_hosts() { - if (host_list) { - for (int i = 0; host_list[i]; i++) - my_free(host_list[i]); - my_free(host_list); - host_list = NULL; - } + delete xpand_hosts; + xpand_hosts = NULL; + my_atomic_store32(&xpand_hosts_cur, 0); } -static void update_host_list(char *xpand_host) +static int check_hosts(MYSQL_THD thd, struct st_mysql_sys_var *var, + void *save, struct st_mysql_value *value) { - free_host_list(); + char b; + int len = 0; + const char *val = value->val_str(value, &b, &len); - int cnt = 0; - for (char *p = xpand_host, *s = xpand_host; ; p++) { - if (*p == ',' || *p == '\0') { - if (p > s) { - cnt++; - } - if (!*p) - break; - s = p + 1; - } - } + if (!val) + return HA_ERR_OUT_OF_MEM; - DBUG_PRINT("host_cnt", ("%d", cnt)); - host_list = (char **)my_malloc(sizeof(char *) * cnt+1, MYF(MY_WME)); - host_list[cnt] = 0; - host_list_cnt = cnt; - - int i = 0; - for (char *p = xpand_host, *s = xpand_host; ; p++) { - if (*p == ',' || *p == '\0') { - if (p > s) { - char *host = (char *)my_malloc(p - s + 1, MYF(MY_WME)); - host[p-s] = '\0'; - memcpy(host, s, p-s); - DBUG_PRINT("host", ("%s", host)); - host_list[i++] = host; - } - if (!*p) - break; - s = p + 1; - } + int error_code = 0; + xpand_host_list *host_list = xpand_host_list::create(val, thd, &error_code); + if (error_code) + return error_code; + + *static_cast(save) = host_list; + return 0; +} + +static void update_hosts(MYSQL_THD thd, struct st_mysql_sys_var *var, + void *var_ptr, const void *save) +{ + mysql_rwlock_wrlock(&xpand_hosts_lock); + + xpand_host_list *from_save = *static_cast(save); + char* raw = from_save->full_list; + + int error_code = 0; + xpand_host_list *new_hosts = xpand_host_list::create(raw, &error_code); + if (error_code) { + my_printf_error(error_code, "Unhandled error setting xpand hostlist", MYF(0)); + return; } - DBUG_PRINT("xpand_host", ("%s", xpand_host)); + clear_hosts(); + xpand_hosts = new_hosts; + *static_cast(var_ptr) = new_hosts->full_list; + + mysql_rwlock_unlock(&xpand_hosts_lock); } +static char *xpand_hosts_str; +static MYSQL_SYSVAR_STR +( + hosts, + xpand_hosts_str, + PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_MEMALLOC, + "List of xpand hostnames seperated by commas, semicolons or spaces", + check_hosts, update_hosts, "localhost" +); + char *xpand_username; static MYSQL_SYSVAR_STR ( @@ -1403,15 +1435,20 @@ static int xpand_init(void *p) xpand_hton->create_select = create_xpand_select_handler; xpand_hton->create_derived = create_xpand_derived_handler; - update_host_list(xpand_host); - - DBUG_RETURN(0); + mysql_rwlock_init(key_xpand_hosts, &xpand_hosts_lock); + mysql_rwlock_wrlock(&xpand_hosts_lock); + int error_code = 0; + xpand_hosts = xpand_host_list::create(xpand_hosts_str, &error_code); + mysql_rwlock_unlock(&xpand_hosts_lock); + DBUG_RETURN(error_code); } static int xpand_deinit(void *p) { DBUG_ENTER("xpand_deinit"); - free_host_list(); + mysql_rwlock_wrlock(&xpand_hosts_lock); + delete xpand_hosts; + mysql_rwlock_destroy(&xpand_hosts_lock); DBUG_RETURN(0); } @@ -1425,7 +1462,8 @@ static struct st_mysql_sys_var* xpand_system_variables[] = MYSQL_SYSVAR(connect_timeout), MYSQL_SYSVAR(read_timeout), MYSQL_SYSVAR(write_timeout), - MYSQL_SYSVAR(host), + MYSQL_SYSVAR(balance_algorithm), + MYSQL_SYSVAR(hosts), MYSQL_SYSVAR(username), MYSQL_SYSVAR(password), MYSQL_SYSVAR(port), diff --git a/storage/xpand/xpand_connection.cc b/storage/xpand/xpand_connection.cc index 34ba7b7dfe1..73f837e6108 100644 --- a/storage/xpand/xpand_connection.cc +++ b/storage/xpand/xpand_connection.cc @@ -10,6 +10,7 @@ Copyright (c) 2019, MariaDB Corporation. #include "handler.h" #include "table.h" #include "sql_class.h" +#include "my_pthread.h" #include "tztime.h" //#include "errmsg.h" @@ -125,30 +126,42 @@ void xpand_connection::disconnect(bool is_destructor) DBUG_VOID_RETURN; } -int host_list_next; -extern int host_list_cnt; -extern char **host_list; +extern int xpand_hosts_cur; +extern ulong xpand_balance_algorithm; + +extern mysql_rwlock_t xpand_hosts_lock; +extern xpand_host_list *xpand_hosts; int xpand_connection::connect() { - int error_code = 0; - my_bool my_true = 1; DBUG_ENTER("xpand_connection::connect"); + int start = 0; + if (xpand_balance_algorithm == XPAND_BALANCE_ROUND_ROBIN) + start = my_atomic_add32(&xpand_hosts_cur, 1); - // cpu concurrency by damned! - int host_num = host_list_next; - host_num = host_num % host_list_cnt; - char *host = host_list[host_num]; - host_list_next = host_num + 1; - DBUG_PRINT("host", ("%s", host)); + mysql_rwlock_rdlock(&xpand_hosts_lock); - /* Validate the connection parameters */ - if (!strcmp(xpand_socket, "")) - if (!strcmp(host, "127.0.0.1")) - if (xpand_port == MYSQL_PORT_DEFAULT) - DBUG_RETURN(ER_CONNECT_TO_FOREIGN_DATA_SOURCE); + //search for available host + int error_code = 0; + for (int i = 0; i < xpand_hosts->hosts_len; i++) { + char *host = xpand_hosts->hosts[(start + i) % xpand_hosts->hosts_len]; + error_code = connect_direct(host); + if (!error_code) + break; + } + mysql_rwlock_unlock(&xpand_hosts_lock); + if (error_code) + my_error(error_code, MYF(0), "clustrix"); + + DBUG_RETURN(error_code); +} - //xpand_net.methods = &connection_methods; + +int xpand_connection::connect_direct(char *host) +{ + DBUG_ENTER("xpand_connection::connect_direct"); + my_bool my_true = true; + DBUG_PRINT("host", ("%s", host)); if (!mysql_init(&xpand_net)) DBUG_RETURN(HA_ERR_OUT_OF_MEM); @@ -180,29 +193,20 @@ int xpand_connection::connect() } #endif + int error_code = 0; if (!mysql_real_connect(&xpand_net, host, xpand_username, xpand_password, NULL, xpand_port, xpand_socket, CLIENT_MULTI_STATEMENTS)) { error_code = mysql_errno(&xpand_net); disconnect(); - - if (error_code != CR_CONN_HOST_ERROR && - error_code != CR_CONNECTION_ERROR) - { - if (error_code == ER_CON_COUNT_ERROR) - { - my_error(ER_CON_COUNT_ERROR, MYF(0)); - DBUG_RETURN(ER_CON_COUNT_ERROR); - } - my_error(ER_CONNECT_TO_FOREIGN_DATA_SOURCE, MYF(0), host); - DBUG_RETURN(ER_CONNECT_TO_FOREIGN_DATA_SOURCE); - } } - xpand_net.reconnect = 1; + if (error_code && error_code != ER_CON_COUNT_ERROR) { + error_code = ER_CONNECT_TO_FOREIGN_DATA_SOURCE; + } - DBUG_RETURN(0); + DBUG_RETURN(error_code); } int xpand_connection::add_status_vars() @@ -1268,3 +1272,69 @@ int xpand_connection::add_command_operand_bitmap(MY_BITMAP *bitmap) command_length += no_bytes; return 0; } + +/**************************************************************************** +** Class xpand_host_list +****************************************************************************/ + +xpand_host_list *xpand_host_list::create(const char *hosts, int *error_code) +{ + return xpand_host_list::create(hosts, NULL, error_code); +} + +xpand_host_list *xpand_host_list::create(const char *hosts, THD *thd, int *error_code) +{ + xpand_host_list *list = static_cast( + thd ? + thd_calloc(thd, sizeof(xpand_host_list)) : + my_malloc(sizeof(xpand_host_list), MYF(MY_WME | MY_ZEROFILL))); + if (!list) { + *error_code = HA_ERR_OUT_OF_MEM; + return NULL; + } + + list->full_list = thd ? + thd_strdup(thd, hosts) : + my_strdup(hosts, MYF(MY_WME)); + list->strtok_buf = thd ? + thd_strdup(thd, hosts) : + my_strdup(hosts, MYF(MY_WME)); + if (!list->full_list || !list->strtok_buf) { + *error_code = HA_ERR_OUT_OF_MEM; + return NULL; + } + + const char *sep = ",; "; + //parse into array + int i = 0; + char *cursor = NULL; + char *token = NULL; + for (token = strtok_r(list->strtok_buf, sep, &cursor); + token && i < max_host_count; + token = strtok_r(NULL, sep, &cursor)) { + list->hosts[i] = token; + i++; + } + + //host count out of range + if (i == 0 || token) { + my_free(list->full_list); + my_free(list->strtok_buf); + my_free(list); + *error_code = ER_BAD_HOST_ERROR; + return NULL; + } + list->hosts_len = i; + + return list; +} + +void xpand_host_list::operator delete(void *p) +{ + xpand_host_list *list = static_cast(p); + if (list) { + my_free(list->full_list); + my_free(list->strtok_buf); + } + my_free(list); +} diff --git a/storage/xpand/xpand_connection.h b/storage/xpand/xpand_connection.h index e2d4761dd68..f641a105e89 100644 --- a/storage/xpand/xpand_connection.h +++ b/storage/xpand/xpand_connection.h @@ -21,11 +21,32 @@ Copyright (c) 2019, MariaDB Corporation. #define XPAND_SERVER_REQUEST 30 -typedef enum xpand_lock_mode { +enum xpand_lock_mode_t { XPAND_NO_LOCKS, XPAND_SHARED, XPAND_EXCLUSIVE, -} xpand_lock_mode_t; +}; + +enum xpand_balance_algorithm_enum { + XPAND_BALANCE_FIRST, + XPAND_BALANCE_ROUND_ROBIN +}; + +static const int max_host_count = 128; +class xpand_host_list { +private: + char *strtok_buf; +public: + char *full_list; + int hosts_len; + char *hosts[max_host_count]; + + static xpand_host_list *create(const char *hosts, int *error_code); + static xpand_host_list *create(const char *hosts, THD *thd, int *error_code); + xpand_host_list() = delete; + static void operator delete(void *p); +}; + class xpand_connection_cursor; class xpand_connection @@ -50,6 +71,7 @@ public: return xpand_net.net.vio; } int connect(); + int connect_direct(char *host); void disconnect(bool is_destructor = FALSE); bool has_open_transaction(); -- cgit v1.2.1 From d4ae797bd20b3e752b86633e8ff4e7aba2b7b352 Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Thu, 27 Feb 2020 15:42:21 -0800 Subject: Revert "Revert "Add table synchronization for select and derived handlers."" --- storage/xpand/ha_xpand.cc | 36 ++++++++++++++++++++++++++++++++++++ storage/xpand/ha_xpand.h | 3 +++ storage/xpand/ha_xpand_pushdown.cc | 16 ++++++++++++---- storage/xpand/xpand_connection.cc | 9 ++++++++- storage/xpand/xpand_connection.h | 2 +- 5 files changed, 60 insertions(+), 6 deletions(-) diff --git a/storage/xpand/ha_xpand.cc b/storage/xpand/ha_xpand.cc index ce713ac5bc0..49a6d44a4bf 100644 --- a/storage/xpand/ha_xpand.cc +++ b/storage/xpand/ha_xpand.cc @@ -505,6 +505,37 @@ xpand_mark_table_for_discovery(TABLE *table) xs->xpand_table_oid= 0; } +void +xpand_mark_tables_for_discovery(LEX *lex) +{ + for (TABLE_LIST *tbl= lex->query_tables; tbl; tbl= tbl->next_global) + if (tbl->table && tbl->table->file->ht == xpand_hton) + xpand_mark_table_for_discovery(tbl->table); +} + +ulonglong * +xpand_extract_table_oids(THD *thd, LEX *lex) +{ + int cnt = 1; + for (TABLE_LIST *tbl = lex->query_tables; tbl; tbl= tbl->next_global) + if (tbl->table && tbl->table->file->ht == xpand_hton) + cnt++; + + ulonglong *oids = (ulonglong*)thd_alloc(thd, cnt * sizeof(ulonglong)); + ulonglong *ptr = oids; + for (TABLE_LIST *tbl = lex->query_tables; tbl; tbl= tbl->next_global) + { + if (tbl->table && tbl->table->file->ht == xpand_hton) + { + ha_xpand *hndlr = static_cast(tbl->table->file); + *ptr++ = hndlr->get_table_oid(); + } + } + + *ptr = 0; + return oids; +} + int ha_xpand::open(const char *name, int mode, uint test_if_locked) { THD *thd= ha_thd(); @@ -1222,6 +1253,11 @@ int ha_xpand::info_push(uint info_type, void *info) return 0; } +ulonglong ha_xpand::get_table_oid() +{ + return xpand_table_oid; +} + /**************************************************************************** ** Row encoding functions ****************************************************************************/ diff --git a/storage/xpand/ha_xpand.h b/storage/xpand/ha_xpand.h index 8e3ea059e59..bc3206f2f5f 100644 --- a/storage/xpand/ha_xpand.h +++ b/storage/xpand/ha_xpand.h @@ -29,6 +29,8 @@ void remove_current_table_from_rpl_table_list(rpl_group_info *rgi); int unpack_row_to_buf(rpl_group_info *rgi, TABLE *table, uchar *data, uchar const *const row_data, MY_BITMAP const *cols, uchar const *const row_end); +void xpand_mark_tables_for_discovery(LEX *lex); +ulonglong *xpand_extract_table_oids(THD *thd, LEX *lex); class Xpand_share : public Handler_share { @@ -131,6 +133,7 @@ public: void cond_pop(); int info_push(uint info_type, void *info); + ulonglong get_table_oid(); private: void build_key_packed_row(uint index, const uchar *buf, uchar *packed_key, size_t *packed_key_len); diff --git a/storage/xpand/ha_xpand_pushdown.cc b/storage/xpand/ha_xpand_pushdown.cc index de43d4bd75b..7700d8dfa3c 100644 --- a/storage/xpand/ha_xpand_pushdown.cc +++ b/storage/xpand/ha_xpand_pushdown.cc @@ -101,6 +101,7 @@ err: select_handler* create_xpand_select_handler(THD* thd, SELECT_LEX* select_lex) { + ulonglong *oids = NULL; ha_xpand_select_handler *sh = NULL; if (!select_handler_setting(thd)) { return sh; @@ -156,20 +157,23 @@ create_xpand_select_handler(THD* thd, SELECT_LEX* select_lex) if (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) trx->auto_commit_next(); + oids = xpand_extract_table_oids(thd, select_lex->parent_lex); if ((error_code = trx->scan_query(query, fieldtype, items_number, null_bits, num_null_bytes, field_metadata, field_metadata_size, - row_buffer_setting(thd), &scan))) { + row_buffer_setting(thd), oids, &scan))) { goto err; } sh = new ha_xpand_select_handler(thd, select_lex, scan); err: - // deallocate buffers if (meta_memory) my_free(meta_memory); + if (error_code == HA_ERR_TABLE_DEF_CHANGED) + xpand_mark_tables_for_discovery(select_lex->parent_lex); + return sh; } @@ -376,6 +380,7 @@ int ha_xpand_derived_handler::init_scan() int error_code = 0; int field_metadata_size = 0; xpand_connection *trx = NULL; + ulonglong *oids = NULL; // We presume this number is equal to types.elements in get_field_types uint items_number= select->get_item_list()->elements; @@ -402,10 +407,11 @@ int ha_xpand_derived_handler::init_scan() if (!trx) goto err; + oids = xpand_extract_table_oids(thd__, select->parent_lex); if ((error_code = trx->scan_query(query, fieldtype, items_number, null_bits, num_null_bytes, field_metadata, field_metadata_size, - row_buffer_setting(thd), &scan))) { + row_buffer_setting(thd), oids, &scan))) { goto err; } @@ -420,10 +426,12 @@ int ha_xpand_derived_handler::init_scan() add_current_table_to_rpl_table_list(&rgi, thd__, table__); err: - // deallocate buffers if (meta_memory) my_free(meta_memory); + if (error_code == HA_ERR_TABLE_DEF_CHANGED) + xpand_mark_tables_for_discovery(select->parent_lex); + return error_code; } diff --git a/storage/xpand/xpand_connection.cc b/storage/xpand/xpand_connection.cc index 73f837e6108..93f7c2fe4df 100644 --- a/storage/xpand/xpand_connection.cc +++ b/storage/xpand/xpand_connection.cc @@ -285,7 +285,7 @@ int xpand_connection::send_command() committed or rolled back. */ trans_state = XPAND_TRANS_STARTED; - + com_error = simple_command(&xpand_net, (enum_server_command)XPAND_SERVER_REQUEST, command_buffer, command_length, TRUE); @@ -781,6 +781,7 @@ int xpand_connection::scan_query(String &stmt, uchar *fieldtype, uint fields, uchar *null_bits, uint null_bits_size, uchar *field_metadata, uint field_metadata_size, ushort row_req, + ulonglong *oids, xpand_connection_cursor **scan) { int error_code; @@ -789,6 +790,12 @@ int xpand_connection::scan_query(String &stmt, uchar *fieldtype, uint fields, if ((error_code = begin_command(XPAND_SCAN_QUERY))) return error_code; + do { + if ((error_code = add_command_operand_ulonglong(*oids))) + return error_code; + } + while (*oids++); + if ((error_code = add_command_operand_ushort(row_req))) return error_code; diff --git a/storage/xpand/xpand_connection.h b/storage/xpand/xpand_connection.h index f641a105e89..df04fc12738 100644 --- a/storage/xpand/xpand_connection.h +++ b/storage/xpand/xpand_connection.h @@ -111,7 +111,7 @@ public: xpand_connection_cursor **scan); int scan_query(String &stmt, uchar *fieldtype, uint fields, uchar *null_bits, uint null_bits_size, uchar *field_metadata, - uint field_metadata_size, ushort row_req, + uint field_metadata_size, ushort row_req, ulonglong *oids, xpand_connection_cursor **scan); int update_query(String &stmt, LEX_CSTRING &dbname, ulonglong *affected_rows); int scan_from_key(ulonglong xpand_table_oid, uint index, -- cgit v1.2.1 From 37a5b125fb0b29959670d8540dfec0db186e7afd Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Fri, 21 Feb 2020 18:36:39 -0800 Subject: Add table synchronization for direct update. --- storage/xpand/ha_xpand.cc | 12 ++++++++++-- storage/xpand/xpand_connection.cc | 8 +++++++- storage/xpand/xpand_connection.h | 3 ++- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/storage/xpand/ha_xpand.cc b/storage/xpand/ha_xpand.cc index 49a6d44a4bf..cb801f1e368 100644 --- a/storage/xpand/ha_xpand.cc +++ b/storage/xpand/ha_xpand.cc @@ -626,13 +626,17 @@ int ha_xpand::write_row(const uchar *buf) if (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) trx->auto_commit_next(); - error_code= trx->update_query(update_stmt, table->s->db, &update_rows); + ulonglong *oids = xpand_extract_table_oids(thd, thd->lex); + error_code= trx->update_query(update_stmt, table->s->db, oids, + &update_rows); if (upsert_flag & XPAND_BULK_UPSERT) upsert_flag |= XPAND_UPSERT_SENT; else upsert_flag &= ~XPAND_HAS_UPSERT; } + if (error_code == HA_ERR_TABLE_DEF_CHANGED) + xpand_mark_tables_for_discovery(thd->lex); return error_code; } @@ -721,8 +725,12 @@ int ha_xpand::direct_update_rows(ha_rows *update_rows, ha_rows *found_rows) if (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) trx->auto_commit_next(); - error_code = trx->update_query(update_stmt, table->s->db, update_rows); + ulonglong *oids = xpand_extract_table_oids(thd, thd->lex); + error_code = trx->update_query(update_stmt, table->s->db, oids, update_rows); *found_rows = *update_rows; + + if (error_code == HA_ERR_TABLE_DEF_CHANGED) + xpand_mark_tables_for_discovery(thd->lex); DBUG_RETURN(error_code); } diff --git a/storage/xpand/xpand_connection.cc b/storage/xpand/xpand_connection.cc index 93f7c2fe4df..08688ee8d31 100644 --- a/storage/xpand/xpand_connection.cc +++ b/storage/xpand/xpand_connection.cc @@ -831,7 +831,7 @@ int xpand_connection::scan_query(String &stmt, uchar *fieldtype, uint fields, * dbname ¤t database name **/ int xpand_connection::update_query(String &stmt, LEX_CSTRING &dbname, - ulonglong *affected_rows) + ulonglong *oids, ulonglong *affected_rows) { int error_code; command_length = 0; @@ -839,6 +839,12 @@ int xpand_connection::update_query(String &stmt, LEX_CSTRING &dbname, if ((error_code = begin_command(XPAND_UPDATE_QUERY))) return error_code; + do { + if ((error_code = add_command_operand_ulonglong(*oids))) + return error_code; + } + while (*oids++); + if ((error_code = add_command_operand_str((uchar*)dbname.str, dbname.length))) return error_code; diff --git a/storage/xpand/xpand_connection.h b/storage/xpand/xpand_connection.h index df04fc12738..04e2b44bf5b 100644 --- a/storage/xpand/xpand_connection.h +++ b/storage/xpand/xpand_connection.h @@ -113,7 +113,8 @@ public: uint null_bits_size, uchar *field_metadata, uint field_metadata_size, ushort row_req, ulonglong *oids, xpand_connection_cursor **scan); - int update_query(String &stmt, LEX_CSTRING &dbname, ulonglong *affected_rows); + int update_query(String &stmt, LEX_CSTRING &dbname, ulonglong *oids, + ulonglong *affected_rows); int scan_from_key(ulonglong xpand_table_oid, uint index, xpand_lock_mode_t lock_mode, enum scan_type scan_dir, int no_key_cols, bool sorted_scan, -- cgit v1.2.1 From 8eeaebc612d9c7d3cdb99f5d06d8120d4bcd5362 Mon Sep 17 00:00:00 2001 From: Isaac Ackerman Date: Fri, 28 Feb 2020 21:59:22 +0000 Subject: Cleanup of allocation strategy --- storage/xpand/ha_xpand.cc | 40 ++++++++++--------------- storage/xpand/xpand_connection.cc | 63 +++++++++++---------------------------- storage/xpand/xpand_connection.h | 29 ++++++++---------- 3 files changed, 47 insertions(+), 85 deletions(-) diff --git a/storage/xpand/ha_xpand.cc b/storage/xpand/ha_xpand.cc index cb801f1e368..73797d07a1c 100644 --- a/storage/xpand/ha_xpand.cc +++ b/storage/xpand/ha_xpand.cc @@ -75,15 +75,7 @@ static MYSQL_SYSVAR_ENUM //current list of clx hosts static PSI_rwlock_key key_xpand_hosts; mysql_rwlock_t xpand_hosts_lock; -xpand_host_list *xpand_hosts; - -//only call while holding lock -static void clear_hosts() -{ - delete xpand_hosts; - xpand_hosts = NULL; - my_atomic_store32(&xpand_hosts_cur, 0); -} +xpand_host_list xpand_hosts; static int check_hosts(MYSQL_THD thd, struct st_mysql_sys_var *var, void *save, struct st_mysql_value *value) @@ -91,37 +83,38 @@ static int check_hosts(MYSQL_THD thd, struct st_mysql_sys_var *var, char b; int len = 0; const char *val = value->val_str(value, &b, &len); - if (!val) return HA_ERR_OUT_OF_MEM; + xpand_host_list *list = static_cast( + thd_calloc(thd, sizeof(xpand_host_list))); + if (!list) + return HA_ERR_OUT_OF_MEM; + int error_code = 0; - xpand_host_list *host_list = xpand_host_list::create(val, thd, &error_code); - if (error_code) + if ((error_code = list->fill(val))) return error_code; + list->empty(); - *static_cast(save) = host_list; + *static_cast(save) = thd_strdup(thd, val); return 0; } static void update_hosts(MYSQL_THD thd, struct st_mysql_sys_var *var, void *var_ptr, const void *save) { - mysql_rwlock_wrlock(&xpand_hosts_lock); + char *from_save = *static_cast(save); - xpand_host_list *from_save = *static_cast(save); - char* raw = from_save->full_list; + mysql_rwlock_wrlock(&xpand_hosts_lock); - int error_code = 0; - xpand_host_list *new_hosts = xpand_host_list::create(raw, &error_code); + xpand_hosts.empty(); + int error_code = xpand_hosts.fill(from_save); if (error_code) { my_printf_error(error_code, "Unhandled error setting xpand hostlist", MYF(0)); return; } - clear_hosts(); - xpand_hosts = new_hosts; - *static_cast(var_ptr) = new_hosts->full_list; + *static_cast(var_ptr) = my_strdup(from_save, MYF(MY_WME)); mysql_rwlock_unlock(&xpand_hosts_lock); } @@ -1481,8 +1474,7 @@ static int xpand_init(void *p) mysql_rwlock_init(key_xpand_hosts, &xpand_hosts_lock); mysql_rwlock_wrlock(&xpand_hosts_lock); - int error_code = 0; - xpand_hosts = xpand_host_list::create(xpand_hosts_str, &error_code); + int error_code = xpand_hosts.fill(xpand_hosts_str); mysql_rwlock_unlock(&xpand_hosts_lock); DBUG_RETURN(error_code); } @@ -1491,7 +1483,7 @@ static int xpand_deinit(void *p) { DBUG_ENTER("xpand_deinit"); mysql_rwlock_wrlock(&xpand_hosts_lock); - delete xpand_hosts; + xpand_hosts.empty(); mysql_rwlock_destroy(&xpand_hosts_lock); DBUG_RETURN(0); } diff --git a/storage/xpand/xpand_connection.cc b/storage/xpand/xpand_connection.cc index 08688ee8d31..d3e3357ed06 100644 --- a/storage/xpand/xpand_connection.cc +++ b/storage/xpand/xpand_connection.cc @@ -21,7 +21,6 @@ Copyright (c) 2019, MariaDB Corporation. extern int xpand_connect_timeout; extern int xpand_read_timeout; extern int xpand_write_timeout; -extern char *xpand_host; extern char *xpand_username; extern char *xpand_password; extern uint xpand_port; @@ -130,7 +129,7 @@ extern int xpand_hosts_cur; extern ulong xpand_balance_algorithm; extern mysql_rwlock_t xpand_hosts_lock; -extern xpand_host_list *xpand_hosts; +extern xpand_host_list xpand_hosts; int xpand_connection::connect() { @@ -142,9 +141,9 @@ int xpand_connection::connect() mysql_rwlock_rdlock(&xpand_hosts_lock); //search for available host - int error_code = 0; - for (int i = 0; i < xpand_hosts->hosts_len; i++) { - char *host = xpand_hosts->hosts[(start + i) % xpand_hosts->hosts_len]; + int error_code = ER_BAD_HOST_ERROR; + for (int i = 0; i < xpand_hosts.hosts_len; i++) { + char *host = xpand_hosts.hosts[(start + i) % xpand_hosts.hosts_len]; error_code = connect_direct(host); if (!error_code) break; @@ -1290,31 +1289,11 @@ int xpand_connection::add_command_operand_bitmap(MY_BITMAP *bitmap) ** Class xpand_host_list ****************************************************************************/ -xpand_host_list *xpand_host_list::create(const char *hosts, int *error_code) +int xpand_host_list::fill(const char *hosts) { - return xpand_host_list::create(hosts, NULL, error_code); -} - -xpand_host_list *xpand_host_list::create(const char *hosts, THD *thd, int *error_code) -{ - xpand_host_list *list = static_cast( - thd ? - thd_calloc(thd, sizeof(xpand_host_list)) : - my_malloc(sizeof(xpand_host_list), MYF(MY_WME | MY_ZEROFILL))); - if (!list) { - *error_code = HA_ERR_OUT_OF_MEM; - return NULL; - } - - list->full_list = thd ? - thd_strdup(thd, hosts) : - my_strdup(hosts, MYF(MY_WME)); - list->strtok_buf = thd ? - thd_strdup(thd, hosts) : - my_strdup(hosts, MYF(MY_WME)); - if (!list->full_list || !list->strtok_buf) { - *error_code = HA_ERR_OUT_OF_MEM; - return NULL; + strtok_buf = my_strdup(hosts, MYF(MY_WME)); + if (!strtok_buf) { + return HA_ERR_OUT_OF_MEM; } const char *sep = ",; "; @@ -1322,32 +1301,26 @@ xpand_host_list *xpand_host_list::create(const char *hosts, THD *thd, int *error int i = 0; char *cursor = NULL; char *token = NULL; - for (token = strtok_r(list->strtok_buf, sep, &cursor); + for (token = strtok_r(strtok_buf, sep, &cursor); token && i < max_host_count; token = strtok_r(NULL, sep, &cursor)) { - list->hosts[i] = token; + this->hosts[i] = token; i++; } //host count out of range if (i == 0 || token) { - my_free(list->full_list); - my_free(list->strtok_buf); - my_free(list); - *error_code = ER_BAD_HOST_ERROR; - return NULL; + my_free(strtok_buf); + return ER_BAD_HOST_ERROR; } - list->hosts_len = i; + hosts_len = i; - return list; + return 0; } -void xpand_host_list::operator delete(void *p) +void xpand_host_list::empty() { - xpand_host_list *list = static_cast(p); - if (list) { - my_free(list->full_list); - my_free(list->strtok_buf); - } - my_free(list); + my_free(strtok_buf); + strtok_buf = NULL; + hosts_len = 0; } diff --git a/storage/xpand/xpand_connection.h b/storage/xpand/xpand_connection.h index 04e2b44bf5b..bc56112377f 100644 --- a/storage/xpand/xpand_connection.h +++ b/storage/xpand/xpand_connection.h @@ -32,22 +32,6 @@ enum xpand_balance_algorithm_enum { XPAND_BALANCE_ROUND_ROBIN }; -static const int max_host_count = 128; -class xpand_host_list { -private: - char *strtok_buf; -public: - char *full_list; - int hosts_len; - char *hosts[max_host_count]; - - static xpand_host_list *create(const char *hosts, int *error_code); - static xpand_host_list *create(const char *hosts, THD *thd, int *error_code); - xpand_host_list() = delete; - static void operator delete(void *p); -}; - - class xpand_connection_cursor; class xpand_connection { @@ -147,4 +131,17 @@ private: int send_command(); int read_query_response(); }; + +static const int max_host_count = 128; +class xpand_host_list { +private: + char *strtok_buf; +public: + int hosts_len; + char *hosts[max_host_count]; + + int fill(const char *hosts); + void empty(); +}; + #endif // _xpand_connection_h -- cgit v1.2.1 From bcc0148b361c6bf5b5442dafe9ad21b52b4dd848 Mon Sep 17 00:00:00 2001 From: Isaac Ackerman Date: Sat, 29 Feb 2020 00:32:53 +0000 Subject: Moved xpand_hosts back to heap, Fixed malformed data on out of memory --- storage/xpand/ha_xpand.cc | 41 ++++++++++++++++++++++++++------------- storage/xpand/xpand_connection.cc | 6 +++--- 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/storage/xpand/ha_xpand.cc b/storage/xpand/ha_xpand.cc index 73797d07a1c..880fc12b6bf 100644 --- a/storage/xpand/ha_xpand.cc +++ b/storage/xpand/ha_xpand.cc @@ -75,7 +75,7 @@ static MYSQL_SYSVAR_ENUM //current list of clx hosts static PSI_rwlock_key key_xpand_hosts; mysql_rwlock_t xpand_hosts_lock; -xpand_host_list xpand_hosts; +xpand_host_list *xpand_hosts; static int check_hosts(MYSQL_THD thd, struct st_mysql_sys_var *var, void *save, struct st_mysql_value *value) @@ -86,35 +86,41 @@ static int check_hosts(MYSQL_THD thd, struct st_mysql_sys_var *var, if (!val) return HA_ERR_OUT_OF_MEM; - xpand_host_list *list = static_cast( - thd_calloc(thd, sizeof(xpand_host_list))); - if (!list) - return HA_ERR_OUT_OF_MEM; + xpand_host_list list; + memset(&list, 0, sizeof(list)); int error_code = 0; - if ((error_code = list->fill(val))) + if ((error_code = list.fill(val))) return error_code; - list->empty(); + list.empty(); - *static_cast(save) = thd_strdup(thd, val); + *static_cast(save) = val; return 0; } static void update_hosts(MYSQL_THD thd, struct st_mysql_sys_var *var, void *var_ptr, const void *save) { - char *from_save = *static_cast(save); + const char *from_save = *static_cast(save); mysql_rwlock_wrlock(&xpand_hosts_lock); - xpand_hosts.empty(); - int error_code = xpand_hosts.fill(from_save); + xpand_host_list *list = static_cast( + my_malloc(sizeof(xpand_host_list), MYF(MY_WME | MY_ZEROFILL))); + int error_code = list->fill(from_save); if (error_code) { + my_free(list); my_printf_error(error_code, "Unhandled error setting xpand hostlist", MYF(0)); return; } - *static_cast(var_ptr) = my_strdup(from_save, MYF(MY_WME)); + xpand_hosts->empty(); + my_free(xpand_hosts); + xpand_hosts = list; + + char **display_var = static_cast(var_ptr); + my_free(*display_var); + *display_var = my_strdup(from_save, MYF(MY_WME)); mysql_rwlock_unlock(&xpand_hosts_lock); } @@ -1474,7 +1480,13 @@ static int xpand_init(void *p) mysql_rwlock_init(key_xpand_hosts, &xpand_hosts_lock); mysql_rwlock_wrlock(&xpand_hosts_lock); - int error_code = xpand_hosts.fill(xpand_hosts_str); + xpand_hosts = static_cast( + my_malloc(sizeof(xpand_host_list), MYF(MY_WME | MY_ZEROFILL))); + int error_code = xpand_hosts->fill(xpand_hosts_str); + if (error_code) { + my_free(xpand_hosts); + xpand_hosts = NULL; + } mysql_rwlock_unlock(&xpand_hosts_lock); DBUG_RETURN(error_code); } @@ -1483,7 +1495,8 @@ static int xpand_deinit(void *p) { DBUG_ENTER("xpand_deinit"); mysql_rwlock_wrlock(&xpand_hosts_lock); - xpand_hosts.empty(); + xpand_hosts->empty(); + xpand_hosts = NULL; mysql_rwlock_destroy(&xpand_hosts_lock); DBUG_RETURN(0); } diff --git a/storage/xpand/xpand_connection.cc b/storage/xpand/xpand_connection.cc index d3e3357ed06..f9a38432db4 100644 --- a/storage/xpand/xpand_connection.cc +++ b/storage/xpand/xpand_connection.cc @@ -129,7 +129,7 @@ extern int xpand_hosts_cur; extern ulong xpand_balance_algorithm; extern mysql_rwlock_t xpand_hosts_lock; -extern xpand_host_list xpand_hosts; +extern xpand_host_list *xpand_hosts; int xpand_connection::connect() { @@ -142,8 +142,8 @@ int xpand_connection::connect() //search for available host int error_code = ER_BAD_HOST_ERROR; - for (int i = 0; i < xpand_hosts.hosts_len; i++) { - char *host = xpand_hosts.hosts[(start + i) % xpand_hosts.hosts_len]; + for (int i = 0; i < xpand_hosts->hosts_len; i++) { + char *host = xpand_hosts->hosts[(start + i) % xpand_hosts->hosts_len]; error_code = connect_direct(host); if (!error_code) break; -- cgit v1.2.1 From e5e812698d773a038ebb87b7dbd30dc6b6745a65 Mon Sep 17 00:00:00 2001 From: Michael Erickson Date: Mon, 2 Mar 2020 11:50:18 -0800 Subject: hardcode xpand protocol to tcp Hardcode MYSQL_OPT_PROTOCOL to TCP in the Xpand connection. We can add support for sockets later. Also fix a memory leak in xpand_hosts global variable. --- storage/xpand/ha_xpand.cc | 14 +++++++++----- storage/xpand/xpand_connection.cc | 2 ++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/storage/xpand/ha_xpand.cc b/storage/xpand/ha_xpand.cc index 880fc12b6bf..58b13a50314 100644 --- a/storage/xpand/ha_xpand.cc +++ b/storage/xpand/ha_xpand.cc @@ -80,27 +80,29 @@ xpand_host_list *xpand_hosts; static int check_hosts(MYSQL_THD thd, struct st_mysql_sys_var *var, void *save, struct st_mysql_value *value) { + DBUG_ENTER("check_hosts"); char b; int len = 0; const char *val = value->val_str(value, &b, &len); if (!val) - return HA_ERR_OUT_OF_MEM; + DBUG_RETURN(HA_ERR_OUT_OF_MEM); xpand_host_list list; memset(&list, 0, sizeof(list)); int error_code = 0; if ((error_code = list.fill(val))) - return error_code; + DBUG_RETURN(error_code); list.empty(); *static_cast(save) = val; - return 0; + DBUG_RETURN(0); } static void update_hosts(MYSQL_THD thd, struct st_mysql_sys_var *var, void *var_ptr, const void *save) { + DBUG_ENTER("update_hosts"); const char *from_save = *static_cast(save); mysql_rwlock_wrlock(&xpand_hosts_lock); @@ -111,7 +113,7 @@ static void update_hosts(MYSQL_THD thd, struct st_mysql_sys_var *var, if (error_code) { my_free(list); my_printf_error(error_code, "Unhandled error setting xpand hostlist", MYF(0)); - return; + DBUG_VOID_RETURN; } xpand_hosts->empty(); @@ -123,6 +125,7 @@ static void update_hosts(MYSQL_THD thd, struct st_mysql_sys_var *var, *display_var = my_strdup(from_save, MYF(MY_WME)); mysql_rwlock_unlock(&xpand_hosts_lock); + DBUG_VOID_RETURN; } static char *xpand_hosts_str; @@ -132,7 +135,7 @@ static MYSQL_SYSVAR_STR xpand_hosts_str, PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_MEMALLOC, "List of xpand hostnames seperated by commas, semicolons or spaces", - check_hosts, update_hosts, "localhost" + check_hosts, update_hosts, "127.0.0.1" ); char *xpand_username; @@ -1496,6 +1499,7 @@ static int xpand_deinit(void *p) DBUG_ENTER("xpand_deinit"); mysql_rwlock_wrlock(&xpand_hosts_lock); xpand_hosts->empty(); + my_free(xpand_hosts); xpand_hosts = NULL; mysql_rwlock_destroy(&xpand_hosts_lock); DBUG_RETURN(0); diff --git a/storage/xpand/xpand_connection.cc b/storage/xpand/xpand_connection.cc index f9a38432db4..c06bdd0773e 100644 --- a/storage/xpand/xpand_connection.cc +++ b/storage/xpand/xpand_connection.cc @@ -165,6 +165,8 @@ int xpand_connection::connect_direct(char *host) if (!mysql_init(&xpand_net)) DBUG_RETURN(HA_ERR_OUT_OF_MEM); + uint protocol_tcp = MYSQL_PROTOCOL_TCP; + mysql_options(&xpand_net, MYSQL_OPT_PROTOCOL, &protocol_tcp); mysql_options(&xpand_net, MYSQL_OPT_READ_TIMEOUT, &xpand_read_timeout); mysql_options(&xpand_net, MYSQL_OPT_WRITE_TIMEOUT, -- cgit v1.2.1 From 7d6af8f5e038a7ad1e65d6d9c38b240ac4f22849 Mon Sep 17 00:00:00 2001 From: Michael Erickson Date: Mon, 2 Mar 2020 11:55:21 -0800 Subject: set xpand_hosts default back to localhost Whoops, I did not mean to change the default of xpand_hosts. --- storage/xpand/ha_xpand.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/xpand/ha_xpand.cc b/storage/xpand/ha_xpand.cc index 58b13a50314..3f33b42aa5d 100644 --- a/storage/xpand/ha_xpand.cc +++ b/storage/xpand/ha_xpand.cc @@ -135,7 +135,7 @@ static MYSQL_SYSVAR_STR xpand_hosts_str, PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_MEMALLOC, "List of xpand hostnames seperated by commas, semicolons or spaces", - check_hosts, update_hosts, "127.0.0.1" + check_hosts, update_hosts, "localhost" ); char *xpand_username; -- cgit v1.2.1 From 9d2d40362c1990f7b99affe75cd9ce0baf3b7abf Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Thu, 27 Feb 2020 13:11:27 -0800 Subject: Remove spaces from the ends of lines. --- storage/xpand/ha_xpand.cc | 34 +++++++++++++++++----------------- storage/xpand/ha_xpand_pushdown.h | 4 ++-- storage/xpand/xpand_connection.cc | 8 ++++---- storage/xpand/xpand_connection.h | 2 +- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/storage/xpand/ha_xpand.cc b/storage/xpand/ha_xpand.cc index 3f33b42aa5d..234754c9f6e 100644 --- a/storage/xpand/ha_xpand.cc +++ b/storage/xpand/ha_xpand.cc @@ -232,7 +232,7 @@ uint row_buffer_setting(THD* thd) /* - Get an Xpand_share object for this object. If it doesn't yet exist, create + Get an Xpand_share object for this object. If it doesn't yet exist, create it. */ @@ -275,28 +275,28 @@ size_t estimate_row_size(TABLE *table) /* - Try to decode a string from filename encoding, if that fails, return the + Try to decode a string from filename encoding, if that fails, return the original string. @detail - This is used to get table (or database) name from file (or directory) - name. Names of regular tables/databases are encoded using + This is used to get table (or database) name from file (or directory) + name. Names of regular tables/databases are encoded using my_charset_filename encoding. - Names of temporary tables are not encoded, and they start with '#sql' + Names of temporary tables are not encoded, and they start with '#sql' which is not a valid character sequence in my_charset_filename encoding. Our way to talkle this is to 1. Try to convert the name back - 2. If that failed, assume it's a temporary object name and just use the + 2. If that failed, assume it's a temporary object name and just use the name. */ -static void decode_object_or_tmp_name(const char *from, uint size, +static void decode_object_or_tmp_name(const char *from, uint size, std::string *out) { uint errors, new_size; out->resize(size+1); // assume the decoded string is not longer new_size= strconvert(&my_charset_filename, from, size, - system_charset_info, (char*)out->c_str(), size+1, + system_charset_info, (char*)out->c_str(), size+1, &errors); if (errors) out->assign(from, size); @@ -307,7 +307,7 @@ static void decode_object_or_tmp_name(const char *from, uint size, /* Take a "./db_name/table_name" and extract db_name and table_name from it - @return + @return 0 OK other Error code */ @@ -330,9 +330,9 @@ static int normalize_tablename(const char *db_table, DBUG_ASSERT(0); // We were not passed table name? return HA_ERR_INTERNAL_ERROR; } - + decode_object_or_tmp_name(tablename.c_str() + 2, pos - 2, norm_db); - decode_object_or_tmp_name(tablename.c_str() + pos + 1, + decode_object_or_tmp_name(tablename.c_str() + pos + 1, tablename.size() - (pos + 1), norm_table); return 0; } @@ -410,7 +410,7 @@ int ha_xpand::create(const char *name, TABLE *form, HA_CREATE_INFO *info) TABLE_LIST table_list; memset(&table_list, 0, sizeof(table_list)); table_list.table = form; - error_code = show_create_table_ex(thd, &table_list, + error_code = show_create_table_ex(thd, &table_list, norm_db.c_str(), norm_table.c_str(), &create_table_stmt, create_info, WITH_DB_NAME); if (!is_tmp_table) @@ -432,9 +432,9 @@ int ha_xpand::create(const char *name, TABLE *form, HA_CREATE_INFO *info) error_code = trx->run_query(create_table_stmt); if (error_code) return error_code; - + // Load the oid of the created table - error_code= trx->get_table_oid(norm_db, norm_table, &xpand_table_oid, + error_code= trx->get_table_oid(norm_db, norm_table, &xpand_table_oid, table_share); return error_code; @@ -480,7 +480,7 @@ int ha_xpand::rename_table(const char* from, const char* to) std::string decoded_to_dbname; std::string decoded_to_tbname; - if ((error_code= normalize_tablename(to, &decoded_to_dbname, + if ((error_code= normalize_tablename(to, &decoded_to_dbname, &decoded_to_tbname))) return error_code; @@ -557,8 +557,8 @@ int ha_xpand::open(const char *name, int mode, uint test_if_locked) std::string norm_db; if ((error_code= normalize_tablename(name, &norm_db, &norm_table))) DBUG_RETURN(error_code); - - error_code= trx->get_table_oid(norm_db, norm_table, &xpand_table_oid, + + error_code= trx->get_table_oid(norm_db, norm_table, &xpand_table_oid, table_share); if (error_code) DBUG_RETURN(error_code); diff --git a/storage/xpand/ha_xpand_pushdown.h b/storage/xpand/ha_xpand_pushdown.h index c39d15f0b41..494283f1ebd 100644 --- a/storage/xpand/ha_xpand_pushdown.h +++ b/storage/xpand/ha_xpand_pushdown.h @@ -40,8 +40,8 @@ protected: * More details in server/sql/select_handler.h * sel semantic tree for the query in SELECT_LEX. ************************************************************/ -class ha_xpand_select_handler: - private ha_xpand_base_handler, +class ha_xpand_select_handler: + private ha_xpand_base_handler, public select_handler { public: diff --git a/storage/xpand/xpand_connection.cc b/storage/xpand/xpand_connection.cc index c06bdd0773e..ad3aecb2c1b 100644 --- a/storage/xpand/xpand_connection.cc +++ b/storage/xpand/xpand_connection.cc @@ -1018,13 +1018,13 @@ error: update Xpand_share::xpand_table_oid. @return - 0 - OK + 0 - OK error code if an error occurred */ -int xpand_connection::get_table_oid(const std::string &db, - const std::string &name, - ulonglong *oid, +int xpand_connection::get_table_oid(const std::string &db, + const std::string &name, + ulonglong *oid, TABLE_SHARE *share) { MYSQL_ROW row; diff --git a/storage/xpand/xpand_connection.h b/storage/xpand/xpand_connection.h index bc56112377f..65f6a4a3e81 100644 --- a/storage/xpand/xpand_connection.h +++ b/storage/xpand/xpand_connection.h @@ -110,7 +110,7 @@ public: int scan_end(xpand_connection_cursor *scan); int populate_table_list(LEX_CSTRING *db, handlerton::discovered_list *result); - int get_table_oid(const std::string& db, const std::string &name, + int get_table_oid(const std::string& db, const std::string &name, ulonglong *oid, TABLE_SHARE *share); int discover_table_details(LEX_CSTRING *db, LEX_CSTRING *name, THD *thd, TABLE_SHARE *share); -- cgit v1.2.1 From b79a921f8634ab3ae4aa5c0f2ca22c9ce98c150e Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Thu, 27 Feb 2020 18:33:37 -0800 Subject: Pass C strings to get_table_oid. --- storage/xpand/ha_xpand.cc | 9 ++++++--- storage/xpand/xpand_connection.cc | 14 ++++++++++---- storage/xpand/xpand_connection.h | 4 ++-- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/storage/xpand/ha_xpand.cc b/storage/xpand/ha_xpand.cc index 234754c9f6e..8ee01467124 100644 --- a/storage/xpand/ha_xpand.cc +++ b/storage/xpand/ha_xpand.cc @@ -434,8 +434,9 @@ int ha_xpand::create(const char *name, TABLE *form, HA_CREATE_INFO *info) return error_code; // Load the oid of the created table - error_code= trx->get_table_oid(norm_db, norm_table, &xpand_table_oid, - table_share); + error_code= trx->get_table_oid(norm_db.c_str(), strlen(norm_db.c_str()), + norm_table.c_str(), strlen(norm_table.c_str()), + &xpand_table_oid, table_share); return error_code; } @@ -558,7 +559,9 @@ int ha_xpand::open(const char *name, int mode, uint test_if_locked) if ((error_code= normalize_tablename(name, &norm_db, &norm_table))) DBUG_RETURN(error_code); - error_code= trx->get_table_oid(norm_db, norm_table, &xpand_table_oid, + error_code= trx->get_table_oid(norm_db.c_str(), strlen(norm_db.c_str()), + norm_table.c_str(), + strlen(norm_table.c_str()), &xpand_table_oid, table_share); if (error_code) DBUG_RETURN(error_code); diff --git a/storage/xpand/xpand_connection.cc b/storage/xpand/xpand_connection.cc index ad3aecb2c1b..ed251ba1da3 100644 --- a/storage/xpand/xpand_connection.cc +++ b/storage/xpand/xpand_connection.cc @@ -1022,8 +1022,8 @@ error: error code if an error occurred */ -int xpand_connection::get_table_oid(const std::string &db, - const std::string &name, +int xpand_connection::get_table_oid(const char *db, size_t db_len, + const char *name, size_t name_len, ulonglong *oid, TABLE_SHARE *share) { @@ -1038,9 +1038,9 @@ int xpand_connection::get_table_oid(const std::string &db, "from system.databases d " " inner join ""system.relations r on d.db = r.db " "where d.name = '"); - get_oid.append(db.c_str()); + get_oid.append(db, db_len); get_oid.append("' and r.name = '"); - get_oid.append(name.c_str()); + get_oid.append(name, name_len); get_oid.append("'"); if (mysql_real_query(&xpand_net, get_oid.c_ptr(), get_oid.length())) { @@ -1094,6 +1094,12 @@ int xpand_connection::discover_table_details(LEX_CSTRING *db, LEX_CSTRING *name, MYSQL_RES *results_create = NULL; MYSQL_ROW row; String show; + ulonglong oid; + + if ((error_code = xpand_connection::get_table_oid(db->str, db->length, + name->str, name->length, + &oid, share))) + goto error; /* get show create statement */ show.append("show simple create table "); diff --git a/storage/xpand/xpand_connection.h b/storage/xpand/xpand_connection.h index 65f6a4a3e81..9c78d37facc 100644 --- a/storage/xpand/xpand_connection.h +++ b/storage/xpand/xpand_connection.h @@ -110,8 +110,8 @@ public: int scan_end(xpand_connection_cursor *scan); int populate_table_list(LEX_CSTRING *db, handlerton::discovered_list *result); - int get_table_oid(const std::string& db, const std::string &name, - ulonglong *oid, TABLE_SHARE *share); + int get_table_oid(const char *db, size_t db_len, const char *name, + size_t name_len, ulonglong *oid, TABLE_SHARE *share); int discover_table_details(LEX_CSTRING *db, LEX_CSTRING *name, THD *thd, TABLE_SHARE *share); -- cgit v1.2.1 From 366fd6523d9cf250584e401bd45baf84aabe7556 Mon Sep 17 00:00:00 2001 From: Michael Erickson Date: Wed, 4 Mar 2020 10:56:56 -0800 Subject: Simplify xpand CMakeLists.txt We don't need the MSVC hacks used by Spider. --- storage/xpand/CMakeLists.txt | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/storage/xpand/CMakeLists.txt b/storage/xpand/CMakeLists.txt index 78fe16c0525..a3d1b9f3c86 100644 --- a/storage/xpand/CMakeLists.txt +++ b/storage/xpand/CMakeLists.txt @@ -1,24 +1,6 @@ #***************************************************************************** -# Copyright (c) 2019, MariaDB Corporation. +# Copyright (c) 2020, MariaDB Corporation. #****************************************************************************/ -IF(MSVC) - # Temporarily disable "conversion from size_t .." - IF(CMAKE_SIZEOF_VOID_P EQUAL 8) - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4267") - ENDIF() -ENDIF() - -SET(XPAND_PLUGIN_STATIC "xpand") -SET(XPAND_PLUGIN_DYNAMIC "ha_xpand") SET(XPAND_SOURCES ha_xpand.cc xpand_connection.cc ha_xpand_pushdown.cc) MYSQL_ADD_PLUGIN(xpand ${XPAND_SOURCES} STORAGE_ENGINE) - -IF(MSVC) - IF (CMAKE_BUILD_TYPE STREQUAL "Debug") - ADD_CUSTOM_COMMAND(TARGET xpand - POST_BUILD - COMMAND if not exist ..\\..\\sql\\lib mkdir ..\\..\\sql\\lib\\plugin - COMMAND copy Debug\\ha_xpand.dll ..\\..\\sql\\lib\\plugin\\ha_xpand.dll) - ENDIF() -ENDIF() -- cgit v1.2.1 From 9062b02365c4b5cee5ce21b97a9161691934609c Mon Sep 17 00:00:00 2001 From: Will DeVries Date: Fri, 28 Feb 2020 00:58:16 -0800 Subject: Fix table discovery. --- storage/xpand/ha_xpand.cc | 29 +++++++++++++++-------------- storage/xpand/ha_xpand.h | 4 ++-- storage/xpand/xpand_connection.cc | 17 +++++++++-------- 3 files changed, 26 insertions(+), 24 deletions(-) diff --git a/storage/xpand/ha_xpand.cc b/storage/xpand/ha_xpand.cc index 8ee01467124..bf8119ed464 100644 --- a/storage/xpand/ha_xpand.cc +++ b/storage/xpand/ha_xpand.cc @@ -429,16 +429,7 @@ int ha_xpand::create(const char *name, TABLE *form, HA_CREATE_INFO *info) trx->run_query(createdb_stmt); } - error_code = trx->run_query(create_table_stmt); - if (error_code) - return error_code; - - // Load the oid of the created table - error_code= trx->get_table_oid(norm_db.c_str(), strlen(norm_db.c_str()), - norm_table.c_str(), strlen(norm_table.c_str()), - &xpand_table_oid, table_share); - - return error_code; + return trx->run_query(create_table_stmt); } int ha_xpand::delete_table(const char *path) @@ -502,10 +493,10 @@ int ha_xpand::rename_table(const char* from, const char* to) static void xpand_mark_table_for_discovery(TABLE *table) { - table->m_needs_reopen = TRUE; + table->m_needs_reopen = true; Xpand_share *xs; - if ((xs= (Xpand_share*)table->s->ha_share)) - xs->xpand_table_oid= 0; + if ((xs= static_cast(table->s->ha_share))) + xs->rediscover_table = true; } void @@ -544,13 +535,18 @@ int ha_xpand::open(const char *name, int mode, uint test_if_locked) THD *thd= ha_thd(); DBUG_ENTER("ha_xpand::open"); + Xpand_share *share; if (!(share = get_share())) DBUG_RETURN(1); + int error_code; xpand_connection *trx = get_trx(thd, &error_code); if (!trx) DBUG_RETURN(error_code); + if (share->rediscover_table) + DBUG_RETURN(HA_ERR_TABLE_DEF_CHANGED); + if (!share->xpand_table_oid) { // We may end up with two threads executing this piece concurrently but // it's ok @@ -559,14 +555,19 @@ int ha_xpand::open(const char *name, int mode, uint test_if_locked) if ((error_code= normalize_tablename(name, &norm_db, &norm_table))) DBUG_RETURN(error_code); + ulonglong oid = 0; error_code= trx->get_table_oid(norm_db.c_str(), strlen(norm_db.c_str()), norm_table.c_str(), - strlen(norm_table.c_str()), &xpand_table_oid, + strlen(norm_table.c_str()), &oid, table_share); if (error_code) DBUG_RETURN(error_code); + + share->xpand_table_oid = oid; } + xpand_table_oid = share->xpand_table_oid; + // Surrogate key marker has_hidden_key = table->s->primary_key == MAX_KEY; if (has_hidden_key) { diff --git a/storage/xpand/ha_xpand.h b/storage/xpand/ha_xpand.h index bc3206f2f5f..06dca73f15b 100644 --- a/storage/xpand/ha_xpand.h +++ b/storage/xpand/ha_xpand.h @@ -35,9 +35,10 @@ ulonglong *xpand_extract_table_oids(THD *thd, LEX *lex); class Xpand_share : public Handler_share { public: - Xpand_share(): xpand_table_oid(0) {} + Xpand_share(): xpand_table_oid(0), rediscover_table(false) {} std::atomic xpand_table_oid; + std::atomic rediscover_table; }; class ha_xpand : public handler @@ -67,7 +68,6 @@ private: } xpd_upsert_flags_t; int upsert_flag; - Xpand_share *share; Xpand_share *get_share(); ///< Get the share public: diff --git a/storage/xpand/xpand_connection.cc b/storage/xpand/xpand_connection.cc index ed251ba1da3..299679f989b 100644 --- a/storage/xpand/xpand_connection.cc +++ b/storage/xpand/xpand_connection.cc @@ -1024,8 +1024,7 @@ error: int xpand_connection::get_table_oid(const char *db, size_t db_len, const char *name, size_t name_len, - ulonglong *oid, - TABLE_SHARE *share) + ulonglong *oid, TABLE_SHARE *share) { MYSQL_ROW row; int error_code = 0; @@ -1063,12 +1062,7 @@ int xpand_connection::get_table_oid(const char *db, size_t db_len, if ((row = mysql_fetch_row(results_oid))) { DBUG_PRINT("row", ("%s", row[0])); - *oid = strtoull((const char *)row[0], NULL, 10); - if (share->ha_share) { - Xpand_share *cs= (Xpand_share*)share->ha_share; - cs->xpand_table_oid = *oid; - } } else { error_code = HA_ERR_NO_SUCH_TABLE; goto error; @@ -1094,13 +1088,19 @@ int xpand_connection::discover_table_details(LEX_CSTRING *db, LEX_CSTRING *name, MYSQL_RES *results_create = NULL; MYSQL_ROW row; String show; - ulonglong oid; + ulonglong oid = 0; + Xpand_share *cs; if ((error_code = xpand_connection::get_table_oid(db->str, db->length, name->str, name->length, &oid, share))) goto error; + if (!share->ha_share) + share->ha_share= new Xpand_share; + cs= static_cast(share->ha_share); + cs->xpand_table_oid = oid; + /* get show create statement */ show.append("show simple create table "); show.append(db); @@ -1137,6 +1137,7 @@ int xpand_connection::discover_table_details(LEX_CSTRING *db, LEX_CSTRING *name, strlen(row[1])); } + cs->rediscover_table = false; error: if (results_create) mysql_free_result(results_create); -- cgit v1.2.1 From 4e9bc0dc0d7f1fa2d81eda1a31a6eb1bdea817dd Mon Sep 17 00:00:00 2001 From: Michael Erickson Date: Wed, 4 Mar 2020 16:00:27 -0800 Subject: add override specifier to handler functions --- storage/xpand/ha_xpand.h | 84 +++++++++++++++++++-------------------- storage/xpand/ha_xpand_pushdown.h | 16 ++++---- 2 files changed, 50 insertions(+), 50 deletions(-) diff --git a/storage/xpand/ha_xpand.h b/storage/xpand/ha_xpand.h index 06dca73f15b..65808ecc72f 100644 --- a/storage/xpand/ha_xpand.h +++ b/storage/xpand/ha_xpand.h @@ -73,65 +73,65 @@ private: public: ha_xpand(handlerton *hton, TABLE_SHARE *table_arg); ~ha_xpand(); - int create(const char *name, TABLE *form, HA_CREATE_INFO *info); - int delete_table(const char *name); - int rename_table(const char* from, const char* to); - int open(const char *name, int mode, uint test_if_locked); - int close(void); - int reset(); - int extra(enum ha_extra_function operation); - int write_row(const uchar *buf); + int create(const char *name, TABLE *form, HA_CREATE_INFO *info) override; + int delete_table(const char *name) override; + int rename_table(const char* from, const char* to) override; + int open(const char *name, int mode, uint test_if_locked) override; + int close(void) override; + int reset() override; + int extra(enum ha_extra_function operation) override; + int write_row(const uchar *buf) override; // start_bulk_update exec_bulk_update - int update_row(const uchar *old_data, const uchar *new_data); + int update_row(const uchar *old_data, const uchar *new_data) override; // start_bulk_delete exec_bulk_delete - int delete_row(const uchar *buf); - int direct_update_rows_init(List *update_fields); - int direct_update_rows(ha_rows *update_rows, ha_rows *found_rows); - void start_bulk_insert(ha_rows rows, uint flags = 0); - int end_bulk_insert(); + int delete_row(const uchar *buf) override; + int direct_update_rows_init(List *update_fields) override; + int direct_update_rows(ha_rows *update_rows, ha_rows *found_rows) override; + void start_bulk_insert(ha_rows rows, uint flags = 0) override; + int end_bulk_insert() override; - Table_flags table_flags(void) const; - ulong index_flags(uint idx, uint part, bool all_parts) const; - uint max_supported_keys() const { return MAX_KEY; } + Table_flags table_flags(void) const override; + ulong index_flags(uint idx, uint part, bool all_parts) const override; + uint max_supported_keys() const override { return MAX_KEY; } - ha_rows records(); + ha_rows records() override; ha_rows records_in_range(uint inx, key_range *min_key, - key_range *max_key); + key_range *max_key) override; - int info(uint flag); // see my_base.h for full description + int info(uint flag) override; // see my_base.h for full description // multi_read_range // read_range - int index_init(uint idx, bool sorted); + int index_init(uint idx, bool sorted) override; int index_read(uchar * buf, const uchar * key, uint key_len, - enum ha_rkey_function find_flag); - int index_first(uchar *buf); - int index_prev(uchar *buf); - int index_last(uchar *buf); - int index_next(uchar *buf); - //int index_next_same(uchar *buf, const uchar *key, uint keylen); - int index_end(); - - int rnd_init(bool scan); - int rnd_next(uchar *buf); - int rnd_pos(uchar * buf, uchar *pos); - int rnd_end(); - - void position(const uchar *record); - uint lock_count(void) const; + enum ha_rkey_function find_flag) override; + int index_first(uchar *buf) override; + int index_prev(uchar *buf) override; + int index_last(uchar *buf) override; + int index_next(uchar *buf) override; + //int index_next_same(uchar *buf, const uchar *key, uint keylen) override; + int index_end() override; + + int rnd_init(bool scan) override; + int rnd_next(uchar *buf) override; + int rnd_pos(uchar * buf, uchar *pos) override; + int rnd_end() override; + + void position(const uchar *record) override; + uint lock_count(void) const override; THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, - enum thr_lock_type lock_type); - int external_lock(THD *thd, int lock_type); + enum thr_lock_type lock_type) override; + int external_lock(THD *thd, int lock_type) override; - uint8 table_cache_type() + uint8 table_cache_type() override { return(HA_CACHE_TBL_NOCACHE); } - const COND *cond_push(const COND *cond); - void cond_pop(); - int info_push(uint info_type, void *info); + const COND *cond_push(const COND *cond) override; + void cond_pop() override; + int info_push(uint info_type, void *info) override; ulonglong get_table_oid(); private: diff --git a/storage/xpand/ha_xpand_pushdown.h b/storage/xpand/ha_xpand_pushdown.h index 494283f1ebd..b98d73b838d 100644 --- a/storage/xpand/ha_xpand_pushdown.h +++ b/storage/xpand/ha_xpand_pushdown.h @@ -49,10 +49,10 @@ public: xpand_connection_cursor *scan); ~ha_xpand_select_handler(); - int init_scan(); - int next_row(); - int end_scan(); - void print_error(int, unsigned long) {} + int init_scan() override; + int next_row() override; + int end_scan() override; + void print_error(int, unsigned long) override {} }; /*@brief derived_handler class*/ @@ -72,10 +72,10 @@ public: xpand_connection_cursor *scan); ~ha_xpand_derived_handler(); - int init_scan(); - int next_row(); - int end_scan(); - void print_error(int, unsigned long) {} + int init_scan() override; + int next_row() override; + int end_scan() override; + void print_error(int, unsigned long) override {} }; select_handler *create_xpand_select_handler(THD* thd, SELECT_LEX* select_lex); -- cgit v1.2.1 From 8587915744aa6dde28619e402cd4321e30a12203 Mon Sep 17 00:00:00 2001 From: Michael Erickson Date: Wed, 4 Mar 2020 16:17:47 -0800 Subject: bump copyright on all xpand source files --- storage/xpand/CMakeLists.txt | 2 +- storage/xpand/ha_xpand.cc | 2 +- storage/xpand/ha_xpand.h | 2 +- storage/xpand/ha_xpand_pushdown.cc | 2 +- storage/xpand/ha_xpand_pushdown.h | 2 +- storage/xpand/xpand_connection.cc | 2 +- storage/xpand/xpand_connection.h | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/storage/xpand/CMakeLists.txt b/storage/xpand/CMakeLists.txt index a3d1b9f3c86..4047653dca2 100644 --- a/storage/xpand/CMakeLists.txt +++ b/storage/xpand/CMakeLists.txt @@ -1,5 +1,5 @@ #***************************************************************************** -# Copyright (c) 2020, MariaDB Corporation. +# Copyright (c) 2019, 2020, MariaDB Corporation. #****************************************************************************/ SET(XPAND_SOURCES ha_xpand.cc xpand_connection.cc ha_xpand_pushdown.cc) diff --git a/storage/xpand/ha_xpand.cc b/storage/xpand/ha_xpand.cc index bf8119ed464..e9d38c123fc 100644 --- a/storage/xpand/ha_xpand.cc +++ b/storage/xpand/ha_xpand.cc @@ -1,5 +1,5 @@ /***************************************************************************** -Copyright (c) 2019, MariaDB Corporation. +Copyright (c) 2019, 2020, MariaDB Corporation. *****************************************************************************/ /** @file ha_xpand.cc */ diff --git a/storage/xpand/ha_xpand.h b/storage/xpand/ha_xpand.h index 65808ecc72f..afc4896e9f1 100644 --- a/storage/xpand/ha_xpand.h +++ b/storage/xpand/ha_xpand.h @@ -1,5 +1,5 @@ /***************************************************************************** -Copyright (c) 2019, MariaDB Corporation. +Copyright (c) 2019, 2020, MariaDB Corporation. *****************************************************************************/ #ifndef _ha_xpand_h diff --git a/storage/xpand/ha_xpand_pushdown.cc b/storage/xpand/ha_xpand_pushdown.cc index 7700d8dfa3c..e51bc162236 100644 --- a/storage/xpand/ha_xpand_pushdown.cc +++ b/storage/xpand/ha_xpand_pushdown.cc @@ -1,5 +1,5 @@ /***************************************************************************** -Copyright (c) 2019, MariaDB Corporation. +Copyright (c) 2019, 2020, MariaDB Corporation. *****************************************************************************/ #include "ha_xpand.h" diff --git a/storage/xpand/ha_xpand_pushdown.h b/storage/xpand/ha_xpand_pushdown.h index b98d73b838d..16284b8e076 100644 --- a/storage/xpand/ha_xpand_pushdown.h +++ b/storage/xpand/ha_xpand_pushdown.h @@ -1,5 +1,5 @@ /***************************************************************************** -Copyright (c) 2019, MariaDB Corporation. +Copyright (c) 2019, 2020, MariaDB Corporation. *****************************************************************************/ #ifndef _ha_xpand_pushdown_h #define _ha_xpand_pushdown_h diff --git a/storage/xpand/xpand_connection.cc b/storage/xpand/xpand_connection.cc index 299679f989b..95ec565f306 100644 --- a/storage/xpand/xpand_connection.cc +++ b/storage/xpand/xpand_connection.cc @@ -1,5 +1,5 @@ /***************************************************************************** -Copyright (c) 2019, MariaDB Corporation. +Copyright (c) 2019, 2020, MariaDB Corporation. *****************************************************************************/ /** @file xpand_connection.cc */ diff --git a/storage/xpand/xpand_connection.h b/storage/xpand/xpand_connection.h index 9c78d37facc..df725e1c361 100644 --- a/storage/xpand/xpand_connection.h +++ b/storage/xpand/xpand_connection.h @@ -1,5 +1,5 @@ /***************************************************************************** -Copyright (c) 2019, MariaDB Corporation. +Copyright (c) 2019, 2020, MariaDB Corporation. *****************************************************************************/ #ifndef _xpand_connection_h -- cgit v1.2.1 From f2994aafca770f6efbd5aa6a524d426dfdbeab98 Mon Sep 17 00:00:00 2001 From: Isaac Ackerman Date: Thu, 5 Mar 2020 01:09:50 +0000 Subject: Added character set results, minor cleanup --- storage/xpand/ha_xpand.cc | 6 +++--- storage/xpand/xpand_connection.cc | 33 +++++++++++++++++---------------- storage/xpand/xpand_connection.h | 3 +-- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/storage/xpand/ha_xpand.cc b/storage/xpand/ha_xpand.cc index e9d38c123fc..9b09ec7af95 100644 --- a/storage/xpand/ha_xpand.cc +++ b/storage/xpand/ha_xpand.cc @@ -344,7 +344,7 @@ xpand_connection *get_trx(THD *thd, int *error_code) xpand_connection *trx; if (!(trx = (xpand_connection *)thd_get_ha_data(thd, xpand_hton))) { - if (!(trx = new xpand_connection(thd))) { + if (!(trx = new xpand_connection())) { *error_code = HA_ERR_OUT_OF_MEM; return NULL; } @@ -1441,7 +1441,7 @@ static int xpand_discover_table_names(handlerton *hton, LEX_CSTRING *db, MY_DIR *dir, handlerton::discovered_list *result) { - xpand_connection *xpand_net = new xpand_connection(NULL); + xpand_connection *xpand_net = new xpand_connection(); int error_code = xpand_net->connect(); if (error_code) goto err; @@ -1455,7 +1455,7 @@ err: int xpand_discover_table(handlerton *hton, THD *thd, TABLE_SHARE *share) { - xpand_connection *xpand_net = new xpand_connection(NULL); + xpand_connection *xpand_net = new xpand_connection(); int error_code = xpand_net->connect(); if (error_code) goto err; diff --git a/storage/xpand/xpand_connection.cc b/storage/xpand/xpand_connection.cc index 95ec565f306..4c7b5582362 100644 --- a/storage/xpand/xpand_connection.cc +++ b/storage/xpand/xpand_connection.cc @@ -12,11 +12,7 @@ Copyright (c) 2019, 2020, MariaDB Corporation. #include "sql_class.h" #include "my_pthread.h" #include "tztime.h" - -//#include "errmsg.h" -//name conflicts on macro ER with sql_class.h -#define CR_CONNECTION_ERROR 2002 -#define CR_CONN_HOST_ERROR 2003 +#include "errmsg.h" extern int xpand_connect_timeout; extern int xpand_read_timeout; @@ -65,6 +61,9 @@ enum xpand_trans_state { XPAND_TRANS_ROLLBACK_STMT = 4, XPAND_TRANS_NONE = 32, }; +const int XPAND_TRANS_STARTS_STMT = (XPAND_TRANS_NEW_STMT | + XPAND_TRANS_REQUESTED | + XPAND_TRANS_ROLLBACK_STMT); enum xpand_trans_post_flags { XPAND_TRANS_AUTOCOMMIT = 8, @@ -89,8 +88,8 @@ enum xpand_commands { /**************************************************************************** ** Class xpand_connection ****************************************************************************/ -xpand_connection::xpand_connection(THD *parent_thd) - : session(parent_thd), command_buffer(NULL), command_buffer_length(0), command_length(0), +xpand_connection::xpand_connection() + : command_buffer(NULL), command_buffer_length(0), command_length(0), trans_state(XPAND_TRANS_NONE), trans_flags(XPAND_TRANS_NO_POST_FLAGS) { DBUG_ENTER("xpand_connection::xpand_connection"); @@ -213,10 +212,12 @@ int xpand_connection::connect_direct(char *host) int xpand_connection::add_status_vars() { DBUG_ENTER("xpand_connection::add_status_vars"); - assert(session); + + if (!(trans_state & XPAND_TRANS_STARTS_STMT)) + DBUG_RETURN(add_command_operand_uchar(0)); int error_code = 0; - system_variables vars = session->variables; + system_variables vars = current_thd->variables; if ((error_code = add_command_operand_uchar(1))) DBUG_RETURN(error_code); //sql mode @@ -227,7 +228,9 @@ int xpand_connection::add_status_vars() DBUG_RETURN(error_code); if ((error_code = add_command_operand_ushort(vars.auto_increment_offset))) DBUG_RETURN(error_code); - //character set and collation + //character sets and collations + if ((error_code = add_command_operand_ushort(vars.character_set_results->number))) + DBUG_RETURN(error_code); if ((error_code = add_command_operand_ushort(vars.character_set_client->number))) DBUG_RETURN(error_code); if ((error_code = add_command_operand_ushort(vars.collation_connection->number))) @@ -235,8 +238,8 @@ int xpand_connection::add_status_vars() if ((error_code = add_command_operand_ushort(vars.collation_server->number))) DBUG_RETURN(error_code); //timezone and time names - String tzone; //convert to utf8 - vars.time_zone->get_name()->print(&tzone, get_charset(33,0)); + String tzone; + vars.time_zone->get_name()->print(&tzone, system_charset_info); if ((error_code = add_command_operand_str((const uchar*)tzone.ptr(),tzone.length()))) DBUG_RETURN(error_code); if ((error_code = add_command_operand_ushort(vars.lc_time_names->number))) @@ -260,10 +263,8 @@ int xpand_connection::begin_command(uchar command) if ((error_code = add_command_operand_uchar(trans_state | trans_flags))) return error_code; - if (trans_state & XPAND_TRANS_NEW_STMT || - trans_state & XPAND_TRANS_REQUESTED) - if ((error_code = add_status_vars())) - return error_code; + if ((error_code = add_status_vars())) + return error_code; return error_code; } diff --git a/storage/xpand/xpand_connection.h b/storage/xpand/xpand_connection.h index df725e1c361..523cab0df97 100644 --- a/storage/xpand/xpand_connection.h +++ b/storage/xpand/xpand_connection.h @@ -36,7 +36,6 @@ class xpand_connection_cursor; class xpand_connection { private: - THD *session; MYSQL xpand_net; uchar *command_buffer; size_t command_buffer_length; @@ -47,7 +46,7 @@ private: int allocate_cursor(MYSQL *xpand_net, ulong buffer_size, xpand_connection_cursor **scan); public: - xpand_connection(THD *parent_thd); + xpand_connection(); ~xpand_connection(); inline bool is_connected() -- cgit v1.2.1 From 4c308dd2b736f3ada2a7124834d191deea306b1b Mon Sep 17 00:00:00 2001 From: Roman Nozdrin Date: Wed, 4 Mar 2020 15:34:50 +0000 Subject: CLX-14 This commit adds support for pushed conditions for table API. --- mysql-test/suite/xpand/pushdown_conditions.result | 47 +++++++++++++++++++++++ mysql-test/suite/xpand/pushdown_conditions.test | 34 ++++++++++++++++ storage/xpand/ha_xpand.cc | 28 +++++++++++++- storage/xpand/ha_xpand.h | 2 + storage/xpand/xpand_connection.cc | 21 ++++++++-- storage/xpand/xpand_connection.h | 2 +- 6 files changed, 128 insertions(+), 6 deletions(-) create mode 100644 mysql-test/suite/xpand/pushdown_conditions.result create mode 100644 mysql-test/suite/xpand/pushdown_conditions.test diff --git a/mysql-test/suite/xpand/pushdown_conditions.result b/mysql-test/suite/xpand/pushdown_conditions.result new file mode 100644 index 00000000000..3120000e56a --- /dev/null +++ b/mysql-test/suite/xpand/pushdown_conditions.result @@ -0,0 +1,47 @@ +CREATE DATABASE xpd; +USE xpd; +DROP TABLE IF EXISTS cx1; +CREATE TABLE cx1(i BIGINT, i2 BIGINT, t TEXT)ENGINE=xpand; +INSERT INTO cx1 VALUES (41, 43, 'some1'), (42, 42, 'some2'), (43, 41, 'some3'); +SELECT * FROM cx1 ORDER BY i; +i i2 t +41 43 some1 +42 42 some2 +43 41 some3 +SET xpand_select_handler=OFF; +SELECT * FROM cx1 WHERE i>41 AND i2>41; +i i2 t +42 42 some2 +EXPLAIN SELECT * FROM cx1 WHERE i>41 AND i2>41; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE cx1 ALL NULL NULL NULL NULL 10000 Using where with pushed condition +SELECT * FROM cx1 WHERE i>41 AND i2>41 AND t='some2'; +i i2 t +42 42 some2 +EXPLAIN SELECT * FROM cx1 WHERE i>41 AND i2>41 AND t='some2'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE cx1 ALL NULL NULL NULL NULL 10000 Using where with pushed condition +SELECT * FROM cx1 WHERE i>i2+1; +i i2 t +43 41 some3 +EXPLAIN SELECT * FROM cx1 WHERE i>i2+1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE cx1 ALL NULL NULL NULL NULL 10000 Using where with pushed condition +SET @@optimizer_switch='derived_merge=OFF'; +SELECT * FROM (SELECT * FROM cx1 WHERE i>i2+1) a1 ORDER BY i; +i i2 t +43 41 some3 +EXPLAIN SELECT * FROM (SELECT * FROM cx1 WHERE i>i2+1) a1 ORDER BY i; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ALL NULL NULL NULL NULL 10000 Using filesort +2 PUSHED DERIVED NULL NULL NULL NULL NULL NULL NULL NULL +SET xpand_derived_handler=OFF; +SELECT * FROM (SELECT * FROM cx1 WHERE i>i2+1) a1 ORDER BY i; +i i2 t +43 41 some3 +EXPLAIN SELECT * FROM (SELECT * FROM cx1 WHERE i>i2+1) a1 ORDER BY i; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ALL NULL NULL NULL NULL 10000 Using filesort +2 DERIVED cx1 ALL NULL NULL NULL NULL 10000 Using where with pushed condition +USE test; +DROP DATABASE xpd; diff --git a/mysql-test/suite/xpand/pushdown_conditions.test b/mysql-test/suite/xpand/pushdown_conditions.test new file mode 100644 index 00000000000..9d8eb1f3bf5 --- /dev/null +++ b/mysql-test/suite/xpand/pushdown_conditions.test @@ -0,0 +1,34 @@ +CREATE DATABASE xpd; +USE xpd; + +--disable_warnings +DROP TABLE IF EXISTS cx1; +--enable_warnings +CREATE TABLE cx1(i BIGINT, i2 BIGINT, t TEXT)ENGINE=xpand; + +INSERT INTO cx1 VALUES (41, 43, 'some1'), (42, 42, 'some2'), (43, 41, 'some3'); + +SELECT * FROM cx1 ORDER BY i; +SET xpand_select_handler=OFF; + +SELECT * FROM cx1 WHERE i>41 AND i2>41; +EXPLAIN SELECT * FROM cx1 WHERE i>41 AND i2>41; +SELECT * FROM cx1 WHERE i>41 AND i2>41 AND t='some2'; +EXPLAIN SELECT * FROM cx1 WHERE i>41 AND i2>41 AND t='some2'; +SELECT * FROM cx1 WHERE i>i2+1; +EXPLAIN SELECT * FROM cx1 WHERE i>i2+1; + +# The plugin doesn't use pushdown conditions for DH as of 10.5.1 +# but it is worth to test memory leaks. +SET @@optimizer_switch='derived_merge=OFF'; +SELECT * FROM (SELECT * FROM cx1 WHERE i>i2+1) a1 ORDER BY i; +EXPLAIN SELECT * FROM (SELECT * FROM cx1 WHERE i>i2+1) a1 ORDER BY i; +SET xpand_derived_handler=OFF; +SELECT * FROM (SELECT * FROM cx1 WHERE i>i2+1) a1 ORDER BY i; +EXPLAIN SELECT * FROM (SELECT * FROM cx1 WHERE i>i2+1) a1 ORDER BY i; + +# SELECT * FROM (SELECT i FROM cx1 WHERE i=42)a1,(SELECT i FROM cx1 WHERE i =42)a2 WHERE a1.i=a2.i; +# EXPLAIN SELECT * FROM (SELECT i FROM cx1 WHERE i=42)a1,(SELECT i FROM cx1 WHERE i =42)a2 WHERE a1.i=a2.i; + +USE test; +DROP DATABASE xpd; diff --git a/storage/xpand/ha_xpand.cc b/storage/xpand/ha_xpand.cc index 9b09ec7af95..d5702fcab50 100644 --- a/storage/xpand/ha_xpand.cc +++ b/storage/xpand/ha_xpand.cc @@ -593,6 +593,7 @@ int ha_xpand::reset() upsert_flag &= ~XPAND_HAS_UPSERT; upsert_flag &= ~XPAND_UPSERT_SENT; xpd_lock_type = XPAND_NO_LOCKS; + pushdown_cond_list.empty(); return 0; } @@ -1079,8 +1080,25 @@ int ha_xpand::rnd_init(bool scan) bitmap_set_all(&scan_fields); #endif + String* pushdown_cond_sql = nullptr; + if (pushdown_cond_list.elements) { + pushdown_cond_sql = new String(); + while (pushdown_cond_list.elements > 0) { + COND* cond = pushdown_cond_list.pop(); + String sql_predicate; + cond->print_for_table_def(&sql_predicate); + pushdown_cond_sql->append(sql_predicate); + if ( pushdown_cond_list.elements > 0) + pushdown_cond_sql->append(" AND "); + } + } + error_code = trx->scan_table(xpand_table_oid, xpd_lock_type, &scan_fields, - THDVAR(thd, row_buffer), &scan_cur); + THDVAR(thd, row_buffer), &scan_cur, + pushdown_cond_sql); + + if (pushdown_cond_sql != nullptr) + delete pushdown_cond_sql; if (error_code == HA_ERR_TABLE_DEF_CHANGED) xpand_mark_table_for_discovery(table); @@ -1255,11 +1273,17 @@ int ha_xpand::external_lock(THD *thd, int lock_type) const COND *ha_xpand::cond_push(const COND *cond) { - return cond; + THD *thd= ha_thd(); + if (!thd->lex->describe) { + pushdown_cond_list.push_front(const_cast(cond)); + } + + return NULL; } void ha_xpand::cond_pop() { + pushdown_cond_list.pop(); } int ha_xpand::info_push(uint info_type, void *info) diff --git a/storage/xpand/ha_xpand.h b/storage/xpand/ha_xpand.h index afc4896e9f1..808e516edd3 100644 --- a/storage/xpand/ha_xpand.h +++ b/storage/xpand/ha_xpand.h @@ -68,6 +68,8 @@ private: } xpd_upsert_flags_t; int upsert_flag; + List pushdown_cond_list; + Xpand_share *get_share(); ///< Get the share public: diff --git a/storage/xpand/xpand_connection.cc b/storage/xpand/xpand_connection.cc index 4c7b5582362..cc99ebc0476 100644 --- a/storage/xpand/xpand_connection.cc +++ b/storage/xpand/xpand_connection.cc @@ -83,6 +83,7 @@ enum xpand_commands { XPAND_UPDATE_QUERY, XPAND_COMMIT, XPAND_ROLLBACK, + XPAND_SCAN_TABLE_COND, }; /**************************************************************************** @@ -732,7 +733,8 @@ int xpand_connection::allocate_cursor(MYSQL *xpand_net, ulong buffer_size, int xpand_connection::scan_table(ulonglong xpand_table_oid, xpand_lock_mode_t lock_mode, MY_BITMAP *read_set, ushort row_req, - xpand_connection_cursor **scan) + xpand_connection_cursor **scan, + String* pushdown_cond_sql) { int error_code; command_length = 0; @@ -741,8 +743,13 @@ int xpand_connection::scan_table(ulonglong xpand_table_oid, if (trans_flags & XPAND_TRANS_AUTOCOMMIT) return HA_ERR_INTERNAL_ERROR; - if ((error_code = begin_command(XPAND_SCAN_TABLE))) - return error_code; + if (pushdown_cond_sql != nullptr) { + if ((error_code= begin_command(XPAND_SCAN_TABLE_COND))) + return error_code; + } else { + if ((error_code= begin_command(XPAND_SCAN_TABLE))) + return error_code; + } if ((error_code = add_command_operand_ushort(row_req))) return error_code; @@ -756,6 +763,14 @@ int xpand_connection::scan_table(ulonglong xpand_table_oid, if ((error_code = add_command_operand_bitmap(read_set))) return error_code; + if (pushdown_cond_sql != nullptr) { + if ((error_code= add_command_operand_str( + reinterpret_cast(pushdown_cond_sql->ptr()), + pushdown_cond_sql->length()))) { + return error_code; + } + } + if ((error_code = send_command())) return error_code; diff --git a/storage/xpand/xpand_connection.h b/storage/xpand/xpand_connection.h index 523cab0df97..c5b558857d6 100644 --- a/storage/xpand/xpand_connection.h +++ b/storage/xpand/xpand_connection.h @@ -91,7 +91,7 @@ public: int scan_table(ulonglong xpand_table_oid, xpand_lock_mode_t lock_mode, MY_BITMAP *read_set, ushort row_req, - xpand_connection_cursor **scan); + xpand_connection_cursor **scan, String* pushdown_cond_sql); int scan_query(String &stmt, uchar *fieldtype, uint fields, uchar *null_bits, uint null_bits_size, uchar *field_metadata, uint field_metadata_size, ushort row_req, ulonglong *oids, -- cgit v1.2.1 From cd2da606414e5d336cdb6b3911e78a649533f3c2 Mon Sep 17 00:00:00 2001 From: Michael Erickson Date: Fri, 6 Mar 2020 15:30:03 -0800 Subject: remove my_error and my_printf_error --- storage/xpand/ha_xpand.cc | 2 +- storage/xpand/xpand_connection.cc | 29 +++++------------------------ 2 files changed, 6 insertions(+), 25 deletions(-) diff --git a/storage/xpand/ha_xpand.cc b/storage/xpand/ha_xpand.cc index d5702fcab50..6bc516d05f0 100644 --- a/storage/xpand/ha_xpand.cc +++ b/storage/xpand/ha_xpand.cc @@ -112,7 +112,7 @@ static void update_hosts(MYSQL_THD thd, struct st_mysql_sys_var *var, int error_code = list->fill(from_save); if (error_code) { my_free(list); - my_printf_error(error_code, "Unhandled error setting xpand hostlist", MYF(0)); + sql_print_error("Unhandled error %d setting xpand hostlist", error_code); DBUG_VOID_RETURN; } diff --git a/storage/xpand/xpand_connection.cc b/storage/xpand/xpand_connection.cc index cc99ebc0476..eb3cfb20d26 100644 --- a/storage/xpand/xpand_connection.cc +++ b/storage/xpand/xpand_connection.cc @@ -149,9 +149,6 @@ int xpand_connection::connect() break; } mysql_rwlock_unlock(&xpand_hosts_lock); - if (error_code) - my_error(error_code, MYF(0), "clustrix"); - DBUG_RETURN(error_code); } @@ -272,8 +269,6 @@ int xpand_connection::begin_command(uchar command) int xpand_connection::send_command() { - my_bool com_error; - /* Please note: * The transaction state is set before the command is sent because rolling @@ -289,32 +284,18 @@ int xpand_connection::send_command() */ trans_state = XPAND_TRANS_STARTED; - com_error = simple_command(&xpand_net, - (enum_server_command)XPAND_SERVER_REQUEST, - command_buffer, command_length, TRUE); - - if (com_error) - { - int error_code = mysql_errno(&xpand_net); - my_printf_error(error_code, "Xpand error: %s", MYF(0), - mysql_error(&xpand_net)); - return error_code; - } - + if (simple_command(&xpand_net, + (enum_server_command)XPAND_SERVER_REQUEST, + command_buffer, command_length, TRUE)) + return mysql_errno(&xpand_net); return 0; } int xpand_connection::read_query_response() { - my_bool comerr = xpand_net.methods->read_query_result(&xpand_net); int error_code = 0; - if (comerr) - { + if (xpand_net.methods->read_query_result(&xpand_net)) error_code = mysql_errno(&xpand_net); - my_printf_error(error_code, "Xpand error: %s", MYF(0), - mysql_error(&xpand_net)); - } - auto_commit_closed(); return error_code; } -- cgit v1.2.1 From 76b4f4d3593ce31e9ee205ce8dfcc61fc53d7b4c Mon Sep 17 00:00:00 2001 From: Michael Erickson Date: Fri, 6 Mar 2020 16:10:36 -0800 Subject: make table discovery work --- storage/xpand/ha_xpand.cc | 12 +++++++++--- storage/xpand/xpand_connection.cc | 9 +++------ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/storage/xpand/ha_xpand.cc b/storage/xpand/ha_xpand.cc index 6bc516d05f0..42596b7af53 100644 --- a/storage/xpand/ha_xpand.cc +++ b/storage/xpand/ha_xpand.cc @@ -1467,10 +1467,13 @@ static int xpand_discover_table_names(handlerton *hton, LEX_CSTRING *db, { xpand_connection *xpand_net = new xpand_connection(); int error_code = xpand_net->connect(); - if (error_code) + if (error_code) { + if (error_code == HA_ERR_NO_CONNECTION) + error_code = 0; goto err; + } - xpand_net->populate_table_list(db, result); + error_code = xpand_net->populate_table_list(db, result); err: delete xpand_net; @@ -1481,8 +1484,11 @@ int xpand_discover_table(handlerton *hton, THD *thd, TABLE_SHARE *share) { xpand_connection *xpand_net = new xpand_connection(); int error_code = xpand_net->connect(); - if (error_code) + if (error_code) { + if (error_code == HA_ERR_NO_CONNECTION) + error_code = HA_ERR_NO_SUCH_TABLE; goto err; + } error_code = xpand_net->discover_table_details(&share->db, &share->table_name, thd, share); diff --git a/storage/xpand/xpand_connection.cc b/storage/xpand/xpand_connection.cc index eb3cfb20d26..21f2e0b40ed 100644 --- a/storage/xpand/xpand_connection.cc +++ b/storage/xpand/xpand_connection.cc @@ -141,7 +141,7 @@ int xpand_connection::connect() mysql_rwlock_rdlock(&xpand_hosts_lock); //search for available host - int error_code = ER_BAD_HOST_ERROR; + int error_code = HA_ERR_NO_CONNECTION; for (int i = 0; i < xpand_hosts->hosts_len; i++) { char *host = xpand_hosts->hosts[(start + i) % xpand_hosts->hosts_len]; error_code = connect_direct(host); @@ -196,12 +196,9 @@ int xpand_connection::connect_direct(char *host) NULL, xpand_port, xpand_socket, CLIENT_MULTI_STATEMENTS)) { - error_code = mysql_errno(&xpand_net); + sql_print_error("Error connecting to xpand: %s", mysql_error(&xpand_net)); disconnect(); - } - - if (error_code && error_code != ER_CON_COUNT_ERROR) { - error_code = ER_CONNECT_TO_FOREIGN_DATA_SOURCE; + error_code = HA_ERR_NO_CONNECTION; } DBUG_RETURN(error_code); -- cgit v1.2.1 From 0de7eb5a38b85f3fd6c9cacf65ef6ea532016ee7 Mon Sep 17 00:00:00 2001 From: Michael Erickson Date: Fri, 6 Mar 2020 16:19:59 -0800 Subject: add more debug --- storage/xpand/ha_xpand.cc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/storage/xpand/ha_xpand.cc b/storage/xpand/ha_xpand.cc index 42596b7af53..bd16a6e2722 100644 --- a/storage/xpand/ha_xpand.cc +++ b/storage/xpand/ha_xpand.cc @@ -1193,7 +1193,7 @@ err: int ha_xpand::rnd_end() { - DBUG_ENTER("ha_xpand::rnd_end()"); + DBUG_ENTER("ha_xpand::rnd_end"); int error_code = 0; THD *thd = ha_thd(); if (thd->lex->sql_command == SQLCOM_UPDATE) @@ -1465,6 +1465,7 @@ static int xpand_discover_table_names(handlerton *hton, LEX_CSTRING *db, MY_DIR *dir, handlerton::discovered_list *result) { + DBUG_ENTER("xpand_discover_table_names"); xpand_connection *xpand_net = new xpand_connection(); int error_code = xpand_net->connect(); if (error_code) { @@ -1477,11 +1478,12 @@ static int xpand_discover_table_names(handlerton *hton, LEX_CSTRING *db, err: delete xpand_net; - return error_code; + DBUG_RETURN(error_code); } int xpand_discover_table(handlerton *hton, THD *thd, TABLE_SHARE *share) { + DBUG_ENTER("xpand_discover_table"); xpand_connection *xpand_net = new xpand_connection(); int error_code = xpand_net->connect(); if (error_code) { @@ -1495,7 +1497,7 @@ int xpand_discover_table(handlerton *hton, THD *thd, TABLE_SHARE *share) err: delete xpand_net; - return error_code; + DBUG_RETURN(error_code); } static int xpand_init(void *p) -- cgit v1.2.1 From fca2a06c4b053ee07f5a4c74e0fb078b251e3fb2 Mon Sep 17 00:00:00 2001 From: Michael Erickson Date: Fri, 6 Mar 2020 16:51:58 -0800 Subject: attempt to fix dup key error --- storage/xpand/xpand_connection.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/storage/xpand/xpand_connection.cc b/storage/xpand/xpand_connection.cc index 21f2e0b40ed..fc7bf000661 100644 --- a/storage/xpand/xpand_connection.cc +++ b/storage/xpand/xpand_connection.cc @@ -429,8 +429,11 @@ int xpand_connection::write_row(ulonglong xpand_table_oid, uchar *packed_row, if ((error_code = send_command())) return error_code; - if ((error_code = read_query_response())) + if ((error_code = read_query_response())) { + if (error_code == ER_DUP_ENTRY) + return HA_ERR_FOUND_DUPP_KEY; return error_code; + } *last_insert_id = xpand_net.insert_id; return error_code; -- cgit v1.2.1 From 46bfebbb978de57a92d480c79cc627cb4a0e5129 Mon Sep 17 00:00:00 2001 From: Michael Erickson Date: Mon, 9 Mar 2020 13:08:48 -0700 Subject: change upsert test to expect new error --- mysql-test/suite/xpand/upsert.result | 12 ++++++------ mysql-test/suite/xpand/upsert.test | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/mysql-test/suite/xpand/upsert.result b/mysql-test/suite/xpand/upsert.result index 13c948c0a60..9cbad652dd4 100644 --- a/mysql-test/suite/xpand/upsert.result +++ b/mysql-test/suite/xpand/upsert.result @@ -11,7 +11,7 @@ id animal 2 Cheetah 3 Zebra INSERT INTO ins_duplicate VALUES (1,'Antelope'); -ERROR 23000: Xpand error: [5120] Duplicate key in container: `db1`.`ins_duplicate` Primary key: (1) +ERROR 23000: Can't write; duplicate key in table 'ins_duplicate' INSERT INTO ins_duplicate VALUES (1,'Antelope') ON DUPLICATE KEY UPDATE animal='Banana'; SELECT * FROM `ins_duplicate` ORDER BY `id`; id animal @@ -19,7 +19,7 @@ id animal 2 Cheetah 3 Zebra INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah'); -ERROR 23000: Xpand error: [5120] Duplicate key in container: `db1`.`ins_duplicate` Primary key: (1) +ERROR 23000: Can't write; duplicate key in table 'ins_duplicate' INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah') ON DUPLICATE KEY UPDATE animal='hybrid'; SELECT * FROM `ins_duplicate` ORDER BY `id`; id animal @@ -33,7 +33,7 @@ id animal 2 hybrid 3 Zebra INSERT INTO ins_duplicate VALUES (1,'Antelope'); -ERROR 23000: Xpand error: [5120] Duplicate key in container: `db1`.`ins_duplicate` Primary key: (1) +ERROR 23000: Can't write; duplicate key in table 'ins_duplicate' INSERT INTO ins_duplicate VALUES (1,'Antelope') ON DUPLICATE KEY UPDATE animal='Vegetable'; SELECT * FROM `ins_duplicate` ORDER BY `id`; id animal @@ -41,7 +41,7 @@ id animal 2 hybrid 3 Zebra INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah'); -ERROR 23000: Xpand error: [5120] Duplicate key in container: `db1`.`ins_duplicate` Primary key: (1) +ERROR 23000: Can't write; duplicate key in table 'ins_duplicate' INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah') ON DUPLICATE KEY UPDATE animal='hybrid2'; COMMIT; BEGIN; @@ -51,7 +51,7 @@ id animal 2 hybrid2 3 Zebra INSERT INTO ins_duplicate VALUES (1,'Antelope'); -ERROR 23000: Xpand error: [5120] Duplicate key in container: `db1`.`ins_duplicate` Primary key: (1) +ERROR 23000: Can't write; duplicate key in table 'ins_duplicate' INSERT INTO ins_duplicate VALUES (1,'Antelope') ON DUPLICATE KEY UPDATE animal='Vegetable'; SELECT * FROM `ins_duplicate` ORDER BY `id`; id animal @@ -59,7 +59,7 @@ id animal 2 hybrid2 3 Zebra INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah'); -ERROR 23000: Xpand error: [5120] Duplicate key in container: `db1`.`ins_duplicate` Primary key: (1) +ERROR 23000: Can't write; duplicate key in table 'ins_duplicate' INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah') ON DUPLICATE KEY UPDATE animal='hybrid3'; ROLLBACK; SELECT * FROM `ins_duplicate` ORDER BY `id`; diff --git a/mysql-test/suite/xpand/upsert.test b/mysql-test/suite/xpand/upsert.test index 7763cb27d61..ab46b1a01b8 100644 --- a/mysql-test/suite/xpand/upsert.test +++ b/mysql-test/suite/xpand/upsert.test @@ -5,12 +5,12 @@ CREATE TABLE `ins_duplicate`(`id` INT PRIMARY KEY, `animal` VARCHAR(30)) ENGINE= INSERT INTO `ins_duplicate` VALUES (1,'Aardvark'), (2,'Cheetah'), (3,'Zebra'); SELECT * FROM `ins_duplicate` ORDER BY `id`; ---error ER_DUP_ENTRY +--error ER_DUP_KEY INSERT INTO ins_duplicate VALUES (1,'Antelope'); INSERT INTO ins_duplicate VALUES (1,'Antelope') ON DUPLICATE KEY UPDATE animal='Banana'; SELECT * FROM `ins_duplicate` ORDER BY `id`; ---error ER_DUP_ENTRY +--error ER_DUP_KEY INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah'); INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah') ON DUPLICATE KEY UPDATE animal='hybrid'; SELECT * FROM `ins_duplicate` ORDER BY `id`; @@ -18,12 +18,12 @@ SELECT * FROM `ins_duplicate` ORDER BY `id`; BEGIN; SELECT * FROM `ins_duplicate` ORDER BY `id`; ---error ER_DUP_ENTRY +--error ER_DUP_KEY INSERT INTO ins_duplicate VALUES (1,'Antelope'); INSERT INTO ins_duplicate VALUES (1,'Antelope') ON DUPLICATE KEY UPDATE animal='Vegetable'; SELECT * FROM `ins_duplicate` ORDER BY `id`; ---error ER_DUP_ENTRY +--error ER_DUP_KEY INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah'); INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah') ON DUPLICATE KEY UPDATE animal='hybrid2'; COMMIT; @@ -31,12 +31,12 @@ COMMIT; BEGIN; SELECT * FROM `ins_duplicate` ORDER BY `id`; ---error ER_DUP_ENTRY +--error ER_DUP_KEY INSERT INTO ins_duplicate VALUES (1,'Antelope'); INSERT INTO ins_duplicate VALUES (1,'Antelope') ON DUPLICATE KEY UPDATE animal='Vegetable'; SELECT * FROM `ins_duplicate` ORDER BY `id`; ---error ER_DUP_ENTRY +--error ER_DUP_KEY INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah'); INSERT INTO ins_duplicate VALUES (1,'Antelope'),(2,'Cheetah') ON DUPLICATE KEY UPDATE animal='hybrid3'; ROLLBACK; -- cgit v1.2.1 From 26cf4e69882ff7de2c2b7b5d40eefcf8744024f0 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Tue, 10 Mar 2020 01:22:21 +0300 Subject: Fix compile failure: P_S-related code should be inside #ifdef --- storage/xpand/ha_xpand.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/storage/xpand/ha_xpand.cc b/storage/xpand/ha_xpand.cc index bd16a6e2722..3c8c891f51d 100644 --- a/storage/xpand/ha_xpand.cc +++ b/storage/xpand/ha_xpand.cc @@ -73,7 +73,9 @@ static MYSQL_SYSVAR_ENUM ); //current list of clx hosts +#ifdef HAVE_PSI_INTERFACE static PSI_rwlock_key key_xpand_hosts; +#endif mysql_rwlock_t xpand_hosts_lock; xpand_host_list *xpand_hosts; -- cgit v1.2.1 From d414f8a9824262212ab5a0416da816f6377179ea Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Tue, 10 Mar 2020 01:24:33 +0300 Subject: Fix compile error on windows: htobe{16,32,64} are not defined Use the same solution as we used for MyRocks. --- storage/xpand/xpand_connection.cc | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/storage/xpand/xpand_connection.cc b/storage/xpand/xpand_connection.cc index fc7bf000661..7bbec588d2c 100644 --- a/storage/xpand/xpand_connection.cc +++ b/storage/xpand/xpand_connection.cc @@ -14,6 +14,27 @@ Copyright (c) 2019, 2020, MariaDB Corporation. #include "tztime.h" #include "errmsg.h" +#ifdef _WIN32 +#include +#define htobe64 _byteswap_uint64 +#define be64toh _byteswap_uint64 +#define htobe32 _byteswap_ulong +#define be32toh _byteswap_ulong +#define htobe16 _byteswap_ushort +#define be16toh _byteswap_ushort +#endif + +#if defined(__APPLE__) +#include +#define htobe64(x) OSSwapHostToBigInt64(x) +#define be64toh(x) OSSwapBigToHostInt64(x) +#define htobe32(x) OSSwapHostToBigInt32(x) +#define be32toh(x) OSSwapBigToHostInt32(x) +#define htobe16(x) OSSwapHostToBigInt16(x) +#define be16toh(x) OSSwapBigToHostInt16(x) +#endif + + extern int xpand_connect_timeout; extern int xpand_read_timeout; extern int xpand_write_timeout; -- cgit v1.2.1 From 3fcb770f1c0be6e89644583494990baffeedcba9 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Tue, 10 Mar 2020 01:25:40 +0300 Subject: Fix federated.federatedx_create_handler with --ps-protocol, for CLX-77 CLX-77 code used "thd->lex->result!=NULL" to check if the SELECT has an INTO part. This is not correct, as the condition also holds when we're using the PS protocol. Use a more generic check: check whether the SELECT has any side effect. --- storage/federatedx/federatedx_pushdown.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/storage/federatedx/federatedx_pushdown.cc b/storage/federatedx/federatedx_pushdown.cc index acd90e95b1c..baaf8245aea 100644 --- a/storage/federatedx/federatedx_pushdown.cc +++ b/storage/federatedx/federatedx_pushdown.cc @@ -185,10 +185,11 @@ create_federatedx_select_handler(THD* thd, SELECT_LEX *sel) /* Currently, ha_federatedx_select_handler::init_scan just takes the thd->query and sends it to the backend. - This obviously won't work if the SELECT has an INTO part. - Refuse to work in this case. + This obviously won't work if the SELECT uses an "INTO @var" or + "INTO OUTFILE". It is also unlikely to work if the select has some + other kind of side effect. */ - if (thd->lex->result) + if (sel->uncacheable & UNCACHEABLE_SIDEEFFECT) return NULL; /* -- cgit v1.2.1 From b6992df1115406a3b356f0c1c5a085b549ec9ff7 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Tue, 10 Mar 2020 01:27:03 +0300 Subject: Fix compile warnings on windows The fix needs a followup: "ulong" is 32-bit on 64-bit Windows, so xpand_connection_cursor::rowdata::length needs to be 64-bit but this causes a cascade of datatype changes all over the code. --- storage/xpand/ha_xpand.cc | 4 ++-- storage/xpand/xpand_connection.cc | 4 ++-- storage/xpand/xpand_connection.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/storage/xpand/ha_xpand.cc b/storage/xpand/ha_xpand.cc index 3c8c891f51d..04369c35fe8 100644 --- a/storage/xpand/ha_xpand.cc +++ b/storage/xpand/ha_xpand.cc @@ -945,7 +945,7 @@ int ha_xpand::index_read(uchar * buf, const uchar * key, uint key_len, uchar *rowdata = NULL; if (exact) { is_scan = false; - ulong rowdata_length; + ulonglong rowdata_length; error_code = trx->key_read(xpand_table_oid, 0, xpd_lock_type, table->read_set, packed_key, packed_key_len, &rowdata, &rowdata_length); @@ -1170,7 +1170,7 @@ int ha_xpand::rnd_pos(uchar * buf, uchar *pos) build_key_packed_row(table->s->primary_key, buf, packed_key, &packed_key_len); uchar *rowdata = NULL; - ulong rowdata_length; + ulonglong rowdata_length; if ((error_code = trx->key_read(xpand_table_oid, 0, xpd_lock_type, table->read_set, packed_key, packed_key_len, &rowdata, &rowdata_length))) diff --git a/storage/xpand/xpand_connection.cc b/storage/xpand/xpand_connection.cc index 7bbec588d2c..a9c1ca0d338 100644 --- a/storage/xpand/xpand_connection.cc +++ b/storage/xpand/xpand_connection.cc @@ -528,7 +528,7 @@ int xpand_connection::key_delete(ulonglong xpand_table_oid, int xpand_connection::key_read(ulonglong xpand_table_oid, uint index, xpand_lock_mode_t lock_mode, MY_BITMAP *read_set, uchar *packed_key, ulong packed_key_length, - uchar **rowdata, ulong *rowdata_length) + uchar **rowdata, ulonglong *rowdata_length) { int error_code; command_length = 0; @@ -625,7 +625,7 @@ private: } uchar *rowdata = xpand_net->net.read_pos; - ulong rowdata_length = safe_net_field_length_ll(&rowdata, packet_length); + ulong rowdata_length = (ulong) safe_net_field_length_ll(&rowdata, packet_length); if (!rowdata_length) { // We have read all rows in this batch. DBUG_RETURN(0); diff --git a/storage/xpand/xpand_connection.h b/storage/xpand/xpand_connection.h index c5b558857d6..beeaf8a95f4 100644 --- a/storage/xpand/xpand_connection.h +++ b/storage/xpand/xpand_connection.h @@ -78,7 +78,7 @@ public: int key_read(ulonglong xpand_table_oid, uint index, xpand_lock_mode_t lock_mode, MY_BITMAP *read_set, uchar *packed_key, ulong packed_key_length, uchar **rowdata, - ulong *rowdata_length); + ulonglong *rowdata_length); enum sort_order {SORT_NONE = 0, SORT_ASC = 1, SORT_DESC = 2}; enum scan_type { READ_KEY_OR_NEXT, /* rows with key and greater */ -- cgit v1.2.1 From 3393815668999a3233afef3ca536f984a5cbd9b3 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Tue, 10 Mar 2020 01:28:13 +0300 Subject: XPand: fix compile error on Winx64: pass ushort to add_command_operand_ushort Also add a safety check --- storage/xpand/xpand_connection.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/storage/xpand/xpand_connection.cc b/storage/xpand/xpand_connection.cc index a9c1ca0d338..e6b5059322b 100644 --- a/storage/xpand/xpand_connection.cc +++ b/storage/xpand/xpand_connection.cc @@ -947,7 +947,11 @@ int xpand_connection::scan_next(xpand_connection_cursor *scan, if ((error_code = begin_command(XPAND_SCAN_NEXT))) return error_code; - if ((error_code = add_command_operand_ushort(scan->buffer_size))) + // This should not happen as @@xpand_row_buffer has this limit. + if (scan->buffer_size > 65535) + return HA_ERR_INTERNAL_ERROR; + + if ((error_code = add_command_operand_ushort((ushort)scan->buffer_size))) return error_code; if ((error_code = add_command_operand_lcb(scan->scan_refid))) -- cgit v1.2.1 From cc5f54819da673cce2f56fa7b592512d0897c825 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Tue, 10 Mar 2020 01:29:30 +0300 Subject: XPand SE: Attempt to get packages built --- storage/xpand/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/xpand/CMakeLists.txt b/storage/xpand/CMakeLists.txt index 4047653dca2..7b4727c09da 100644 --- a/storage/xpand/CMakeLists.txt +++ b/storage/xpand/CMakeLists.txt @@ -3,4 +3,4 @@ #****************************************************************************/ SET(XPAND_SOURCES ha_xpand.cc xpand_connection.cc ha_xpand_pushdown.cc) -MYSQL_ADD_PLUGIN(xpand ${XPAND_SOURCES} STORAGE_ENGINE) +MYSQL_ADD_PLUGIN(xpand ${XPAND_SOURCES} STORAGE_ENGINE COMPONENT xpand-engine) -- cgit v1.2.1