Permalink
Fetching contributors…
Cannot retrieve contributors at this time
18468 lines (16887 sloc) 553 KB
/* -*- c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Copyright(C) 2010 Tetsuro IKEDA
Copyright(C) 2010-2013 Kentoku SHIBA
Copyright(C) 2011-2018 Kouhei Sutou <kou@clear-code.com>
Copyright(C) 2013 Kenji Maruyama <mmmaru777@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "mrn_mysql.h"
#include "mrn_mysql_compat.h"
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation
#endif
#include <sql_show.h>
#include <key.h>
#include <tztime.h>
#include <sql_base.h>
#include <sql_select.h>
#include <item_sum.h>
#ifdef MRN_HAVE_BINLOG_H
# include <binlog.h>
#endif
#ifdef MRN_HAVE_SQL_OPTIMIZER_H
# include <sql_optimizer.h>
#endif
#include <ft_global.h>
#include <spatial.h>
#include <mysql.h>
#include <mysql/plugin.h>
#ifdef MRN_HAVE_MYSQL_PSI_MYSQL_MEMORY_H
# include <mysql/psi/mysql_memory.h>
#endif
#ifdef MRN_HAVE_SQL_DERROR_H
# include <sql/derror.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#ifdef WIN32
# include <math.h>
# include <direct.h>
# define MRN_TABLE_SHARE_LOCK_SHARE_PROC "?key_TABLE_SHARE_LOCK_share@@3IA"
# define MRN_TABLE_SHARE_LOCK_HA_DATA_PROC "?key_TABLE_SHARE_LOCK_ha_data@@3IA"
# ifdef _WIN64
# define MRN_BINLOG_FILTER_PROC "?binlog_filter@@3PEAVRpl_filter@@EA"
# define MRN_MY_TZ_UTC_PROC "?my_tz_UTC@@3PEAVTime_zone@@EA"
# else
# define MRN_BINLOG_FILTER_PROC "?binlog_filter@@3PAVRpl_filter@@A"
# define MRN_MY_TZ_UTC_PROC "?my_tz_UTC@@3PAVTime_zone@@A"
# endif
#else
# include <dirent.h>
# include <unistd.h>
#endif
#include <cstring>
#include "mrn_err.h"
#include "mrn_table.hpp"
#include <groonga/plugin.h>
#include "ha_mroonga.hpp"
#include <mrn_path_mapper.hpp>
#include <mrn_index_table_name.hpp>
#include <mrn_index_column_name.hpp>
#include <mrn_debug_column_access.hpp>
#include <mrn_auto_increment_value_lock.hpp>
#include <mrn_external_lock.hpp>
#include <mrn_match_escalation_threshold_scope.hpp>
#include <mrn_multiple_column_key_codec.hpp>
#include <mrn_field_normalizer.hpp>
#include <mrn_encoding.hpp>
#include <mrn_parameters_parser.hpp>
#include <mrn_lock.hpp>
#include <mrn_condition_converter.hpp>
#include <mrn_time_converter.hpp>
#include <mrn_smart_grn_obj.hpp>
#include <mrn_database_manager.hpp>
#include <mrn_context_pool.hpp>
#include <mrn_grn.hpp>
#include <mrn_value_decoder.hpp>
#include <mrn_database_repairer.hpp>
#include <mrn_operation.hpp>
#include <mrn_column_name.hpp>
#include <mrn_count_skip_checker.hpp>
#include <mrn_variables.hpp>
#include <mrn_query_parser.hpp>
#include <mrn_smart_bitmap.hpp>
#include <mrn_table_fields_offset_mover.hpp>
#ifdef MRN_SUPPORT_FOREIGN_KEYS
# include <sql_table.h>
#endif
#ifdef MRN_SUPPORT_CUSTOM_OPTIONS
# include <create_options.h>
#endif
#ifdef MRN_HAVE_DB_TYPE_ROCKSDB
# include <mysql/psi/mysql_file.h>
#endif
#ifdef MRN_HANDLER_DELETE_TABLE_HAVE_TABLE_DEFINITION
# include <sql/dd/types/table.h>
#endif
// for debug
#define MRN_CLASS_NAME "ha_mroonga"
#define MRN_SHORT_TEXT_SIZE (1 << 12) // 4Kbytes
#define MRN_TEXT_SIZE (1 << 16) // 64Kbytes
#define MRN_LONG_TEXT_SIZE (1 << 31) // 2Gbytes
#ifdef MRN_HAVE_TDC_LOCK_TABLE_SHARE
# ifdef MRN_TABLE_SHARE_TDC_IS_POINTER
# define mrn_open_mutex(share) &((share)->tdc->LOCK_table_share)
# else
# define mrn_open_mutex(share) &((share)->tdc.LOCK_table_share)
# endif
# define mrn_open_mutex_lock(share) do { \
TABLE_SHARE *share_ = share; \
if (share_ && share_->tmp_table == NO_TMP_TABLE) { \
mysql_mutex_lock(mrn_open_mutex(share_)); \
} \
} while (0)
# define mrn_open_mutex_unlock(share) do { \
TABLE_SHARE *share_ = share; \
if (share_ && share_->tmp_table == NO_TMP_TABLE) { \
mysql_mutex_unlock(mrn_open_mutex(share_)); \
} \
} while (0)
#else
# ifdef DBUG_OFF
# ifndef _WIN32
extern mysql_mutex_t LOCK_open;
# endif
# endif
static mysql_mutex_t *mrn_LOCK_open;
# define mrn_open_mutex_lock(share) mysql_mutex_lock(mrn_LOCK_open)
# define mrn_open_mutex_unlock(share) mysql_mutex_unlock(mrn_LOCK_open)
#endif
#if MYSQL_VERSION_ID >= 50600
# define MRN_NEED_M_LOCK_TYPE_CHECK_FOR_WRAPPER_EXTERNAL_LOCK
#endif
#ifdef MRN_MARIADB_P
# if MYSQL_VERSION_ID >= 100200
# define MRN_ORDER_IS_ASC(order) ((order)->direction == ORDER::ORDER_ASC)
# else
# define MRN_ORDER_IS_ASC(order) ((order)->asc)
# endif
#else
# if MYSQL_VERSION_ID >= 80011
# define MRN_ORDER_IS_ASC(order) ((order)->direction == ORDER_ASC)
# elif MYSQL_VERSION_ID >= 50603
# define MRN_ORDER_IS_ASC(order) ((order)->direction == ORDER::ORDER_ASC)
# else
# define MRN_ORDER_IS_ASC(order) ((order)->asc)
# endif
#endif
#define MRN_STRINGIFY(macro_or_string) MRN_STRINGIFY_ARG(macro_or_string)
#define MRN_STRINGIFY_ARG(contents) #contents
#define MRN_PLUGIN_NAME mroonga
#define MRN_PLUGIN_NAME_STRING "Mroonga"
#define MRN_STATUS_VARIABLE_NAME_PREFIX_STRING "Mroonga"
#ifdef MRN_MARIADB_P
# define st_mysql_plugin st_maria_plugin
# define mrn_declare_plugin(NAME) maria_declare_plugin(NAME)
# define mrn_declare_plugin_end maria_declare_plugin_end
# define MRN_PLUGIN_LAST_VALUES MRN_VERSION, MariaDB_PLUGIN_MATURITY_STABLE
#else
# define mrn_declare_plugin(NAME) mysql_declare_plugin(NAME)
# define mrn_declare_plugin_end mysql_declare_plugin_end
# define MRN_PLUGIN_LAST_VALUES NULL, 0
#endif
#if MYSQL_VERSION_ID >= 100007 && defined(MRN_MARIADB_P)
# define MRN_THD_GET_AUTOINC(thd, off, inc) thd_get_autoinc(thd, off, inc)
#else
# define MRN_THD_GET_AUTOINC(thd, off, inc) \
{ \
*(off) = thd->variables.auto_increment_offset; \
*(inc) = thd->variables.auto_increment_increment; \
}
#endif
#if MYSQL_VERSION_ID >= 50706 && !defined(MRN_MARIADB_P)
# define MRN_LEX_GET_TABLE_LIST(lex) (lex)->select_lex->table_list.first
#else
# define MRN_LEX_GET_TABLE_LIST(lex) (lex)->select_lex.table_list.first
#endif
#if MYSQL_VERSION_ID >= 80011 && !defined(MRN_MARIADB_P)
# define MRN_LEX_GET_CREATE_INFO(lex) ((lex)->create_info)
# define MRN_LEX_GET_ALTER_INFO(lex) ((lex)->alter_info)
#else
# define MRN_LEX_GET_CREATE_INFO(lex) &((lex)->create_info)
# define MRN_LEX_GET_ALTER_INFO(lex) &((lex)->alter_info)
#endif
#if MYSQL_VERSION_ID >= 50706 && !defined(MRN_MARIADB_P)
# define MRN_KEYTYPE_FOREIGN KEYTYPE_FOREIGN
#else
# define MRN_KEYTYPE_FOREIGN Key::FOREIGN_KEY
#endif
#if MYSQL_VERSION_ID >= 50706 && !defined(MRN_MARIADB_P)
# define mrn_calculate_key_len(table, key_index, buffer, keypart_map) \
calculate_key_len(table, key_index, keypart_map)
#else
# define mrn_calculate_key_len(table, key_index, buffer, keypart_map) \
calculate_key_len(table, key_index, buffer, keypart_map)
#endif
#if MYSQL_VERSION_ID >= 50706 && !defined(MRN_MARIADB_P)
# define MRN_TABLE_LIST_GET_DERIVED(table_list) NULL
#else
# define MRN_TABLE_LIST_GET_DERIVED(table_list) (table_list)->derived
#endif
#if MYSQL_VERSION_ID >= 80011 && !defined(MRN_MARIADB_P)
# define MRN_TABLE_SET_FOUND_ROW(table) table->set_found_row();
# define MRN_TABLE_SET_NO_ROW(table) table->set_no_row();
#else
# define MRN_TABLE_SET_FOUND_ROW(table) table->status = 0;
# define MRN_TABLE_SET_NO_ROW(table) table->status = STATUS_NOT_FOUND;
#endif
#if MYSQL_VERSION_ID >= 50706 && !defined(MRN_MARIADB_P)
# define MRN_GEOMETRY_FREE(geometry)
#else
# define MRN_GEOMETRY_FREE(geometry) delete (geometry)
#endif
#if MYSQL_VERSION_ID >= 80011 && !defined(MRN_MARIADB_P)
# include <sql/thd_raii.h>
# define MRN_DISABLE_BINLOG_BEGIN(thd) \
do { \
Disable_binlog_guard guard(thd);
# define MRN_DISABLE_BINLOG_END(thd) \
} while (false)
#else
# define MRN_DISABLE_BINLOG_BEGIN(thd) \
do { \
tmp_disable_binlog(thd);
# define MRN_DISABLE_BINLOG_END(thd) \
reenable_binlog(thd); \
} while (false)
#endif
Rpl_filter *mrn_binlog_filter;
Time_zone *mrn_my_tz_UTC;
#ifdef MRN_HAVE_TABLE_DEF_CACHE
mrn_table_def_cache_type *mrn_table_def_cache;
#endif
#if MYSQL_VERSION_ID >= 80011 && !defined(MRN_MARIADB_P)
# define PSI_INFO_ENTRY(key, name, flags, volatility, documentation) \
{key, name, flags, volatility, documentation}
#else
# define PSI_INFO_ENTRY(key, name, flags, volatility, documentation) \
{key, name, flags}
# define PSI_FLAG_SINGLETON PSI_FLAG_GLOBAL
#endif
#ifdef MRN_HAVE_PSI_MEMORY_KEY
PSI_memory_key mrn_memory_key;
static PSI_memory_info mrn_all_memory_keys[]=
{
PSI_INFO_ENTRY(&mrn_memory_key,
"Mroonga",
0,
PSI_VOLATILITY_UNKNOWN,
PSI_DOCUMENT_ME),
};
#endif
#ifdef MRN_HAVE_PSI_FILE_KEY
static PSI_file_key mrn_key_file_frm;
static PSI_file_info mrn_all_file_keys[] = {
PSI_INFO_ENTRY(&mrn_key_file_frm,
"Mroonga: FRM",
0,
PSI_VOLATILITY_UNKNOWN,
PSI_DOCUMENT_ME),
};
#endif
static const char *INDEX_COLUMN_NAME = "index";
static const char *MRN_PLUGIN_AUTHOR = "The Mroonga project";
#ifdef __cplusplus
extern "C" {
#endif
#ifdef HAVE_PSI_INTERFACE
# ifdef WIN32
# ifdef MRN_TABLE_SHARE_HAVE_LOCK_SHARE
PSI_mutex_key *mrn_table_share_lock_share;
# endif
PSI_mutex_key *mrn_table_share_lock_ha_data;
# endif
static PSI_mutex_key mrn_open_tables_mutex_key;
static PSI_mutex_key mrn_long_term_shares_mutex_key;
static PSI_mutex_key mrn_allocated_thds_mutex_key;
PSI_mutex_key mrn_share_mutex_key;
PSI_mutex_key mrn_long_term_share_auto_inc_mutex_key;
static PSI_mutex_key mrn_db_manager_mutex_key;
static PSI_mutex_key mrn_context_pool_mutex_key;
static PSI_mutex_key mrn_operations_mutex_key;
# if (!defined(MRN_MARIADB_P) && MYSQL_VERSION_ID >= 80011)
# define MRN_MUTEXT_INFO_ENTRY(key, name, flags, volatility, document) \
{key, name, flags, volatility, document}
# else
# define MRN_MUTEXT_INFO_ENTRY(key, name, flags, volatility, document) \
{key, name, flags}
# endif
static PSI_mutex_info mrn_mutexes[] =
{
MRN_MUTEXT_INFO_ENTRY(&mrn_open_tables_mutex_key,
"mrn::open_tables",
PSI_FLAG_SINGLETON,
PSI_VOLATILITY_UNKNOWN,
PSI_DOCUMENT_ME),
MRN_MUTEXT_INFO_ENTRY(&mrn_long_term_shares_mutex_key,
"mrn::long_term_shares",
PSI_FLAG_SINGLETON,
PSI_VOLATILITY_UNKNOWN,
PSI_DOCUMENT_ME),
MRN_MUTEXT_INFO_ENTRY(&mrn_allocated_thds_mutex_key,
"mrn::allocated_thds",
PSI_FLAG_SINGLETON,
PSI_VOLATILITY_UNKNOWN,
PSI_DOCUMENT_ME),
MRN_MUTEXT_INFO_ENTRY(&mrn_share_mutex_key,
"mrn::share",
0,
PSI_VOLATILITY_UNKNOWN,
PSI_DOCUMENT_ME),
MRN_MUTEXT_INFO_ENTRY(&mrn_long_term_share_auto_inc_mutex_key,
"mrn::long_term_share::auto_inc",
0,
PSI_VOLATILITY_UNKNOWN,
PSI_DOCUMENT_ME),
MRN_MUTEXT_INFO_ENTRY(&mrn_db_manager_mutex_key,
"mrn::DatabaseManager",
PSI_FLAG_SINGLETON,
PSI_VOLATILITY_UNKNOWN,
PSI_DOCUMENT_ME),
MRN_MUTEXT_INFO_ENTRY(&mrn_context_pool_mutex_key,
"mrn::ContextPool",
PSI_FLAG_SINGLETON,
PSI_VOLATILITY_UNKNOWN,
PSI_DOCUMENT_ME),
MRN_MUTEXT_INFO_ENTRY(&mrn_operations_mutex_key,
"mrn::Operations",
PSI_FLAG_SINGLETON,
PSI_VOLATILITY_UNKNOWN,
PSI_DOCUMENT_ME)
};
# if MYSQL_VERSION_ID >= 50720 && !defined(MRN_MARIADB_P)
# define MRN_REGISTER_MUTEXES(category, mutexes) \
do { \
int n_mutexes = array_elements(mutexes); \
mysql_mutex_register(category, mutexes, n_mutexes); \
} while (false)
# elif defined(MRN_HAVE_PSI_SERVER)
# define MRN_REGISTER_MUTEXES(category, mutexes) \
do { \
if (PSI_server) { \
int n_mutexes = array_elements(mutexes); \
PSI_server->register_mutex(category, mutexes, n_mutexes); \
} \
} while (false)
# endif
#else
# define MRN_REGISTER_MUTEXES(category, mutexes)
#endif
/* global variables */
grn_ctx mrn_ctx;
handlerton *mrn_hton_ptr;
grn_hash *mrn_open_tables;
mysql_mutex_t mrn_open_tables_mutex;
grn_hash *mrn_long_term_shares;
mysql_mutex_t mrn_long_term_shares_mutex;
grn_hash *mrn_allocated_thds;
mysql_mutex_t mrn_allocated_thds_mutex;
/* internal variables */
static grn_obj *mrn_db;
static grn_ctx mrn_db_manager_ctx;
static mysql_mutex_t mrn_db_manager_mutex;
mrn::DatabaseManager *mrn_db_manager = NULL;
static mysql_mutex_t mrn_context_pool_mutex;
mrn::ContextPool *mrn_context_pool = NULL;
static mysql_mutex_t mrn_operations_mutex;
#ifdef WIN32
static inline double round(double x)
{
return (floor(x + 0.5));
}
#endif
static void mrn_init_encoding_map()
{
mrn::encoding::init();
}
static int mrn_change_encoding(grn_ctx *ctx, const CHARSET_INFO *charset)
{
return mrn::encoding::set(ctx, charset);
}
#if !defined(DBUG_OFF) && !defined(_lint)
static const char *mrn_inspect_thr_lock_type(enum thr_lock_type lock_type)
{
const char *inspected = "<unknown>";
switch (lock_type) {
case TL_IGNORE:
inspected = "TL_IGNORE";
break;
case TL_UNLOCK:
inspected = "TL_UNLOCK";
break;
case TL_READ_DEFAULT:
inspected = "TL_READ_DEFAULT";
break;
case TL_READ:
inspected = "TL_READ";
break;
case TL_READ_WITH_SHARED_LOCKS:
inspected = "TL_READ_WITH_SHARED_LOCKS";
break;
case TL_READ_HIGH_PRIORITY:
inspected = "TL_READ_HIGH_PRIORITY";
break;
case TL_READ_NO_INSERT:
inspected = "TL_READ_NO_INSERT";
break;
case TL_WRITE_ALLOW_WRITE:
inspected = "TL_WRITE_ALLOW_WRITE";
break;
#ifdef MRN_HAVE_TL_WRITE_CONCURRENT_DEFAULT
case TL_WRITE_CONCURRENT_DEFAULT:
inspected = "TL_WRITE_CONCURRENT_DEFAULT";
break;
#endif
case TL_WRITE_CONCURRENT_INSERT:
inspected = "TL_WRITE_CONCURRENT_INSERT";
break;
#ifdef MRN_HAVE_TL_WRITE_DELAYED
case TL_WRITE_DELAYED:
inspected = "TL_WRITE_DELAYED";
break;
#endif
case TL_WRITE_DEFAULT:
inspected = "TL_WRITE_DEFAULT";
break;
case TL_WRITE_LOW_PRIORITY:
inspected = "TL_WRITE_LOW_PRIORITY";
break;
case TL_WRITE:
inspected = "TL_WRITE";
break;
case TL_WRITE_ONLY:
inspected = "TL_WRITE_ONLY";
break;
}
return inspected;
}
static const char *mrn_inspect_extra_function(enum ha_extra_function operation)
{
const char *inspected = "<unknown>";
switch (operation) {
case HA_EXTRA_NORMAL:
inspected = "HA_EXTRA_NORMAL";
break;
case HA_EXTRA_QUICK:
inspected = "HA_EXTRA_QUICK";
break;
case HA_EXTRA_NOT_USED:
inspected = "HA_EXTRA_NOT_USED";
break;
#ifdef MRN_HAVE_HA_EXTRA_CACHE
case HA_EXTRA_CACHE:
inspected = "HA_EXTRA_CACHE";
break;
#endif
#ifdef MRN_HAVE_HA_EXTRA_NO_CACHE
case HA_EXTRA_NO_CACHE:
inspected = "HA_EXTRA_NO_CACHE";
break;
#endif
case HA_EXTRA_NO_READCHECK:
inspected = "HA_EXTRA_NO_READCHECK";
break;
case HA_EXTRA_READCHECK:
inspected = "HA_EXTRA_READCHECK";
break;
case HA_EXTRA_KEYREAD:
inspected = "HA_EXTRA_KEYREAD";
break;
case HA_EXTRA_NO_KEYREAD:
inspected = "HA_EXTRA_NO_KEYREAD";
break;
case HA_EXTRA_NO_USER_CHANGE:
inspected = "HA_EXTRA_NO_USER_CHANGE";
break;
#ifdef MRN_HAVE_HA_EXTRA_KEY_CACHE
case HA_EXTRA_KEY_CACHE:
inspected = "HA_EXTRA_KEY_CACHE";
break;
#endif
#ifdef MRN_HAVE_HA_EXTRA_NO_KEY_CACHE
case HA_EXTRA_NO_KEY_CACHE:
inspected = "HA_EXTRA_NO_KEY_CACHE";
break;
#endif
case HA_EXTRA_WAIT_LOCK:
inspected = "HA_EXTRA_WAIT_LOCK";
break;
case HA_EXTRA_NO_WAIT_LOCK:
inspected = "HA_EXTRA_NO_WAIT_LOCK";
break;
#ifdef MRN_HAVE_HA_EXTRA_WRITE_CACHE
case HA_EXTRA_WRITE_CACHE:
inspected = "HA_EXTRA_WRITE_CACHE";
break;
#endif
#ifdef MRN_HAVE_HA_EXTRA_FLUSH_CACHE
case HA_EXTRA_FLUSH_CACHE:
inspected = "HA_EXTRA_FLUSH_CACHE";
break;
#endif
case HA_EXTRA_NO_KEYS:
inspected = "HA_EXTRA_NO_KEYS";
break;
case HA_EXTRA_KEYREAD_CHANGE_POS:
inspected = "HA_EXTRA_KEYREAD_CHANGE_POS";
break;
case HA_EXTRA_REMEMBER_POS:
inspected = "HA_EXTRA_REMEMBER_POS";
break;
case HA_EXTRA_RESTORE_POS:
inspected = "HA_EXTRA_RESTORE_POS";
break;
#ifdef MRN_HAVE_HA_EXTRA_REINIT_CACHE
case HA_EXTRA_REINIT_CACHE:
inspected = "HA_EXTRA_REINIT_CACHE";
break;
#endif
case HA_EXTRA_FORCE_REOPEN:
inspected = "HA_EXTRA_FORCE_REOPEN";
break;
case HA_EXTRA_FLUSH:
inspected = "HA_EXTRA_FLUSH";
break;
case HA_EXTRA_NO_ROWS:
inspected = "HA_EXTRA_NO_ROWS";
break;
case HA_EXTRA_RESET_STATE:
inspected = "HA_EXTRA_RESET_STATE";
break;
case HA_EXTRA_IGNORE_DUP_KEY:
inspected = "HA_EXTRA_IGNORE_DUP_KEY";
break;
case HA_EXTRA_NO_IGNORE_DUP_KEY:
inspected = "HA_EXTRA_NO_IGNORE_DUP_KEY";
break;
case HA_EXTRA_PREPARE_FOR_DROP:
inspected = "HA_EXTRA_PREPARE_FOR_DROP";
break;
case HA_EXTRA_PREPARE_FOR_UPDATE:
inspected = "HA_EXTRA_PREPARE_FOR_UPDATE";
break;
case HA_EXTRA_PRELOAD_BUFFER_SIZE:
inspected = "HA_EXTRA_PRELOAD_BUFFER_SIZE";
break;
case HA_EXTRA_CHANGE_KEY_TO_UNIQUE:
inspected = "HA_EXTRA_CHANGE_KEY_TO_UNIQUE";
break;
case HA_EXTRA_CHANGE_KEY_TO_DUP:
inspected = "HA_EXTRA_CHANGE_KEY_TO_DUP";
break;
case HA_EXTRA_KEYREAD_PRESERVE_FIELDS:
inspected = "HA_EXTRA_KEYREAD_PRESERVE_FIELDS";
break;
#ifdef MRN_HAVE_HA_EXTRA_MMAP
case HA_EXTRA_MMAP:
inspected = "HA_EXTRA_MMAP";
break;
#endif
case HA_EXTRA_IGNORE_NO_KEY:
inspected = "HA_EXTRA_IGNORE_NO_KEY";
break;
case HA_EXTRA_NO_IGNORE_NO_KEY:
inspected = "HA_EXTRA_NO_IGNORE_NO_KEY";
break;
case HA_EXTRA_MARK_AS_LOG_TABLE:
inspected = "HA_EXTRA_MARK_AS_LOG_TABLE";
break;
case HA_EXTRA_WRITE_CAN_REPLACE:
inspected = "HA_EXTRA_WRITE_CAN_REPLACE";
break;
case HA_EXTRA_WRITE_CANNOT_REPLACE:
inspected = "HA_EXTRA_WRITE_CANNOT_REPLACE";
break;
case HA_EXTRA_DELETE_CANNOT_BATCH:
inspected = "HA_EXTRA_DELETE_CANNOT_BATCH";
break;
case HA_EXTRA_UPDATE_CANNOT_BATCH:
inspected = "HA_EXTRA_UPDATE_CANNOT_BATCH";
break;
case HA_EXTRA_INSERT_WITH_UPDATE:
inspected = "HA_EXTRA_INSERT_WITH_UPDATE";
break;
case HA_EXTRA_PREPARE_FOR_RENAME:
inspected = "HA_EXTRA_PREPARE_FOR_RENAME";
break;
case HA_EXTRA_ADD_CHILDREN_LIST:
inspected = "HA_EXTRA_ADD_CHILDREN_LIST";
break;
case HA_EXTRA_ATTACH_CHILDREN:
inspected = "HA_EXTRA_ATTACH_CHILDREN";
break;
case HA_EXTRA_IS_ATTACHED_CHILDREN:
inspected = "HA_EXTRA_IS_ATTACHED_CHILDREN";
break;
case HA_EXTRA_DETACH_CHILDREN:
inspected = "HA_EXTRA_DETACH_CHILDREN";
break;
#ifdef MRN_HAVE_HA_EXTRA_EXPORT
case HA_EXTRA_EXPORT:
inspected = "HA_EXTRA_EXPORT";
break;
#endif
#ifdef MRN_HAVE_HA_EXTRA_SECONDARY_SORT_ROWID
case HA_EXTRA_SECONDARY_SORT_ROWID:
inspected = "HA_EXTRA_SECONDARY_SORT_ROWID";
break;
#endif
#ifdef MRN_HAVE_HA_EXTRA_DETACH_CHILD
case HA_EXTRA_DETACH_CHILD:
inspected = "HA_EXTRA_DETACH_CHILD";
break;
#endif
#ifdef MRN_HAVE_HA_EXTRA_PREPARE_FOR_FORCED_CLOSE
case HA_EXTRA_PREPARE_FOR_FORCED_CLOSE:
inspected = "HA_EXTRA_PREPARE_FOR_FORCED_CLOSE";
break;
#endif
#ifdef MRN_HAVE_HA_EXTRA_SKIP_SERIALIZABLE_DD_VIEW
case HA_EXTRA_SKIP_SERIALIZABLE_DD_VIEW:
inspected = "HA_EXTRA_SKIP_SERIALIZABLE_DD_VIEW";
break;
#endif
#ifdef MRN_HAVE_HA_EXTRA_BEGIN_ALTER_COPY
case HA_EXTRA_BEGIN_ALTER_COPY:
inspected = "HA_EXTRA_BEGIN_ALTER_COPY";
break;
#endif
#ifdef MRN_HAVE_HA_EXTRA_END_ALTER_COPY
case HA_EXTRA_END_ALTER_COPY:
inspected = "HA_EXTRA_END_ALTER_COPY";
break;
#endif
#ifdef MRN_HAVE_HA_EXTRA_NO_AUTOINC_LOCKING
case HA_EXTRA_NO_AUTOINC_LOCKING:
inspected = "HA_EXTRA_NO_AUTOINC_LOCKING";
break;
#endif
#ifdef MRN_HAVE_HA_EXTRA_PREPARE_FOR_ALTER_TABLE
case HA_EXTRA_PREPARE_FOR_ALTER_TABLE:
inspected = "HA_EXTRA_PREPARE_FOR_ALTER_TABLE";
break;
#endif
#ifdef MRN_HAVE_HA_EXTRA_STARTING_ORDERED_INDEX_SCAN
case HA_EXTRA_STARTING_ORDERED_INDEX_SCAN:
inspected = "HA_EXTRA_STARTING_ORDERED_INDEX_SCAN";
break;
#endif
#ifdef MRN_HAVE_HA_EXTRA_FAKE_START_STMT
case HA_EXTRA_FAKE_START_STMT:
inspected = "HA_EXTRA_FAKE_START_STMT";
break;
#endif
}
return inspected;
}
#endif
/* status */
static long mrn_count_skip = 0;
static long mrn_fast_order_limit = 0;
static long mrn_condition_push_down = 0;
static long mrn_n_pooling_contexts = 0;
/* logging */
static char *mrn_log_file_path = NULL;
static grn_log_level mrn_log_level_default = GRN_LOG_DEFAULT_LEVEL;
static ulong mrn_log_level = mrn_log_level_default;
static char *mrn_query_log_file_path = NULL;
char *mrn_default_tokenizer = NULL;
char *mrn_default_wrapper_engine = NULL;
static int mrn_lock_timeout = grn_get_lock_timeout();
static char *mrn_libgroonga_version = const_cast<char *>(grn_get_version());
static char *mrn_version = const_cast<char *>(MRN_VERSION);
static char *mrn_vector_column_delimiter = NULL;
static mrn_bool mrn_libgroonga_support_zlib = false;
static mrn_bool mrn_libgroonga_support_lz4 = false;
static mrn_bool mrn_libgroonga_support_zstd = false;
static mrn_bool mrn_enable_operations_recording = true;
#ifdef MRN_SUPPORT_THDVAR_SET
static const char *mrn_boolean_mode_sytnax_flag_names[] = {
"DEFAULT",
"SYNTAX_QUERY",
"SYNTAX_SCRIPT",
"ALLOW_COLUMN",
"ALLOW_UPDATE",
"ALLOW_LEADING_NOT",
NullS
};
static TYPELIB mrn_boolean_mode_syntax_flags_typelib = {
array_elements(mrn_boolean_mode_sytnax_flag_names) - 1,
"",
mrn_boolean_mode_sytnax_flag_names,
NULL
};
#endif
#ifdef MRN_GROONGA_EMBEDDED
static mrn_bool mrn_libgroonga_embedded = true;
#else
static mrn_bool mrn_libgroonga_embedded = false;
#endif
static mrn::variables::ActionOnError mrn_action_on_fulltext_query_error_default =
mrn::variables::ACTION_ON_ERROR_ERROR_AND_LOG;
/* system functions */
static struct st_mysql_storage_engine storage_engine_structure =
{ MYSQL_HANDLERTON_INTERFACE_VERSION };
#if MYSQL_VERSION_ID >= 80011 && !defined(MRN_MARIADB_P)
typedef SHOW_VAR mrn_show_var;
#else
typedef struct st_mysql_show_var mrn_show_var;
#endif
#if MYSQL_VERSION_ID >= 50706 && !defined(MRN_MARIADB_P)
# define MRN_STATUS_VARIABLE_ENTRY(name, value, type, scope) \
{name, value, type, scope}
#else
# define MRN_STATUS_VARIABLE_ENTRY(name, value, type, scope) \
{name, value, type}
#endif
static mrn_show_var mrn_status_variables[] =
{
MRN_STATUS_VARIABLE_ENTRY(MRN_STATUS_VARIABLE_NAME_PREFIX_STRING "_count_skip",
(char *)&mrn_count_skip,
SHOW_LONG,
SHOW_SCOPE_GLOBAL),
MRN_STATUS_VARIABLE_ENTRY(MRN_STATUS_VARIABLE_NAME_PREFIX_STRING "_fast_order_limit",
(char *)&mrn_fast_order_limit,
SHOW_LONG,
SHOW_SCOPE_GLOBAL),
MRN_STATUS_VARIABLE_ENTRY(MRN_STATUS_VARIABLE_NAME_PREFIX_STRING "_condition_push_down",
(char *)&mrn_condition_push_down,
SHOW_LONG,
SHOW_SCOPE_GLOBAL),
MRN_STATUS_VARIABLE_ENTRY(MRN_STATUS_VARIABLE_NAME_PREFIX_STRING "_n_pooling_contexts",
(char *)&mrn_n_pooling_contexts,
SHOW_LONG_NOFLUSH,
SHOW_SCOPE_GLOBAL),
MRN_STATUS_VARIABLE_ENTRY(NullS, NullS, SHOW_LONG, SHOW_SCOPE_GLOBAL)
};
static const char *mrn_log_level_type_names[] = {
"NONE",
"EMERG",
"ALERT",
"CRIT",
"ERROR",
"WARNING",
"NOTICE",
"INFO",
"DEBUG",
"DUMP",
NullS
};
static TYPELIB mrn_log_level_typelib = {
array_elements(mrn_log_level_type_names) - 1,
"mrn_log_level_typelib",
mrn_log_level_type_names,
NULL
};
#if MYSQL_VERSION_ID >= 80011 && !defined(MRN_MARIADB_P)
typedef SYS_VAR mrn_sys_var;
#else
typedef struct st_mysql_sys_var mrn_sys_var;
#endif
static void mrn_log_level_update(THD *thd,
mrn_sys_var *var,
void *var_ptr,
const void *save)
{
MRN_DBUG_ENTER_FUNCTION();
ulong new_value = *static_cast<const ulong *>(save);
ulong old_value = mrn_log_level;
mrn_log_level = new_value;
grn_default_logger_set_max_level(static_cast<grn_log_level>(mrn_log_level));
grn_ctx *ctx = grn_ctx_open(0);
mrn_change_encoding(ctx, system_charset_info);
GRN_LOG(ctx, GRN_LOG_NOTICE, "log level changed from '%s' to '%s'",
mrn_log_level_type_names[old_value],
mrn_log_level_type_names[new_value]);
grn_ctx_fin(ctx);
DBUG_VOID_RETURN;
}
static MYSQL_SYSVAR_ENUM(log_level, mrn_log_level,
PLUGIN_VAR_RQCMDARG,
"logging level",
NULL,
mrn_log_level_update,
static_cast<ulong>(mrn_log_level),
&mrn_log_level_typelib);
static void mrn_log_file_update(THD *thd,
mrn_sys_var *var,
void *var_ptr,
const void *save)
{
MRN_DBUG_ENTER_FUNCTION();
const char *new_value = *((const char **)save);
char **old_value_ptr = (char **)var_ptr;
grn_ctx *ctx = &mrn_ctx;
mrn_change_encoding(ctx, system_charset_info);
const char *new_log_file_name;
new_log_file_name = *old_value_ptr;
if (strcmp(*old_value_ptr, new_value) == 0) {
GRN_LOG(ctx, GRN_LOG_NOTICE,
"log file isn't changed "
"because the requested path isn't different: <%s>",
new_value);
} else {
GRN_LOG(ctx, GRN_LOG_NOTICE,
"log file is changed: <%s> -> <%s>",
*old_value_ptr, new_value);
grn_default_logger_set_path(new_value);
grn_logger_reopen(ctx);
GRN_LOG(ctx, GRN_LOG_NOTICE,
"log file is changed: <%s> -> <%s>",
*old_value_ptr, new_value);
new_log_file_name = new_value;
}
#ifdef MRN_NEED_FREE_STRING_MEMALLOC_PLUGIN_VAR
char *old_log_file_name = *old_value_ptr;
*old_value_ptr = mrn_my_strdup(new_log_file_name, MYF(MY_WME));
my_free(old_log_file_name);
#else
*old_value_ptr = mrn_my_strdup(new_log_file_name, MYF(MY_WME));
#endif
DBUG_VOID_RETURN;
}
static MYSQL_SYSVAR_STR(log_file, mrn_log_file_path,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
"log file for " MRN_PLUGIN_NAME_STRING,
NULL,
mrn_log_file_update,
MRN_LOG_FILE_PATH);
static void mrn_query_log_file_update(THD *thd,
mrn_sys_var *var,
void *var_ptr,
const void *save)
{
MRN_DBUG_ENTER_FUNCTION();
const char *new_value = *((const char **)save);
char **old_value_ptr = (char **)var_ptr;
const char *normalized_new_value = NULL;
grn_ctx *ctx = &mrn_ctx;
mrn_change_encoding(ctx, system_charset_info);
const char *new_query_log_file_name;
new_query_log_file_name = *old_value_ptr;
bool need_update = false;
if (!*old_value_ptr) {
if (new_value && new_value[0] != '\0') {
GRN_LOG(ctx, GRN_LOG_NOTICE,
"query log is enabled: <%s>",
new_value);
need_update = true;
normalized_new_value = new_value;
} else {
GRN_LOG(ctx, GRN_LOG_NOTICE,
"query log file is still disabled");
}
} else {
if (!new_value || new_value[0] == '\0') {
GRN_LOG(ctx, GRN_LOG_NOTICE,
"query log file is disabled: <%s>",
*old_value_ptr);
need_update = true;
normalized_new_value = NULL;
} else if (strcmp(*old_value_ptr, new_value) == 0) {
GRN_LOG(ctx, GRN_LOG_NOTICE,
"query log file isn't changed "
"because the requested path isn't different: <%s>",
new_value);
} else {
GRN_LOG(ctx, GRN_LOG_NOTICE,
"query log file is changed: <%s> -> <%s>",
*old_value_ptr, new_value);
need_update = true;
normalized_new_value = new_value;
}
}
if (need_update) {
grn_default_query_logger_set_path(normalized_new_value);
grn_query_logger_reopen(ctx);
new_query_log_file_name = normalized_new_value;
}
#ifdef MRN_NEED_FREE_STRING_MEMALLOC_PLUGIN_VAR
char *old_query_log_file_name = *old_value_ptr;
#endif
if (new_query_log_file_name) {
*old_value_ptr = mrn_my_strdup(new_query_log_file_name, MYF(0));
} else {
*old_value_ptr = NULL;
}
#ifdef MRN_NEED_FREE_STRING_MEMALLOC_PLUGIN_VAR
my_free(old_query_log_file_name);
#endif
DBUG_VOID_RETURN;
}
static MYSQL_SYSVAR_STR(query_log_file, mrn_query_log_file_path,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
"query log file for " MRN_PLUGIN_NAME_STRING,
NULL,
mrn_query_log_file_update,
NULL);
static void mrn_default_tokenizer_update(THD *thd,
mrn_sys_var *var,
void *var_ptr,
const void *save)
{
MRN_DBUG_ENTER_FUNCTION();
const char *new_value = *((const char **)save);
char **old_value_ptr = (char **)var_ptr;
grn_ctx *ctx = &mrn_ctx;
mrn_change_encoding(ctx, system_charset_info);
if (strcmp(*old_value_ptr, new_value) == 0) {
GRN_LOG(ctx, GRN_LOG_NOTICE,
"default tokenizer for fulltext index isn't changed "
"because the requested default tokenizer isn't different: <%s>",
new_value);
} else {
GRN_LOG(ctx, GRN_LOG_NOTICE,
"default tokenizer for fulltext index is changed: <%s> -> <%s>",
*old_value_ptr, new_value);
}
#ifdef MRN_NEED_FREE_STRING_MEMALLOC_PLUGIN_VAR
my_free(*old_value_ptr);
*old_value_ptr = mrn_my_strdup(new_value, MYF(MY_WME));
#else
*old_value_ptr = (char *)new_value;
#endif
DBUG_VOID_RETURN;
}
static MYSQL_SYSVAR_STR(default_parser, mrn_default_tokenizer,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
"default fulltext parser "
"(Deprecated. Use mroonga_default_tokenizer instead.)",
NULL,
mrn_default_tokenizer_update,
MRN_DEFAULT_TOKENIZER);
static MYSQL_SYSVAR_STR(default_tokenizer, mrn_default_tokenizer,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
"default tokenizer for fulltext index",
NULL,
mrn_default_tokenizer_update,
MRN_DEFAULT_TOKENIZER);
static MYSQL_THDVAR_BOOL(
dry_write, /* name */
PLUGIN_VAR_OPCMDARG, /* options */
"If dry_write is true, any write operations are ignored.", /* comment */
NULL, /* check */
NULL, /* update */
false /* default */
);
static MYSQL_THDVAR_BOOL(
enable_optimization, /* name */
PLUGIN_VAR_OPCMDARG, /* options */
"If enable_optimization is true, some optimizations will be applied.", /* comment */
NULL, /* check */
NULL, /* update */
true /* default */
);
static MYSQL_THDVAR_LONGLONG(match_escalation_threshold,
PLUGIN_VAR_RQCMDARG,
"The threshold to determin whether search method is escalated",
NULL,
NULL,
grn_get_default_match_escalation_threshold(),
-1,
INT_MAX64,
0);
static void mrn_vector_column_delimiter_update(THD *thd,
mrn_sys_var *var,
void *var_ptr,
const void *save)
{
MRN_DBUG_ENTER_FUNCTION();
const char *new_value = *((const char **)save);
char **old_value_ptr = (char **)var_ptr;
#ifdef MRN_NEED_FREE_STRING_MEMALLOC_PLUGIN_VAR
my_free(*old_value_ptr);
*old_value_ptr = mrn_my_strdup(new_value, MYF(MY_WME));
#else
*old_value_ptr = (char *)new_value;
#endif
DBUG_VOID_RETURN;
}
static MYSQL_SYSVAR_STR(vector_column_delimiter, mrn_vector_column_delimiter,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
"The vector column delimiter",
NULL,
&mrn_vector_column_delimiter_update,
" ");
static void mrn_database_path_prefix_update(THD *thd,
mrn_sys_var *var,
void *var_ptr,
const void *save)
{
MRN_DBUG_ENTER_FUNCTION();
const char *new_value = *((const char **)save);
char **old_value_ptr = (char **)var_ptr;
#ifdef MRN_NEED_FREE_STRING_MEMALLOC_PLUGIN_VAR
if (*old_value_ptr)
my_free(*old_value_ptr);
if (new_value)
*old_value_ptr = mrn_my_strdup(new_value, MYF(MY_WME));
else
*old_value_ptr = NULL;
#else
*old_value_ptr = (char *)new_value;
#endif
DBUG_VOID_RETURN;
}
static MYSQL_SYSVAR_STR(database_path_prefix,
mrn::PathMapper::default_path_prefix,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
"The database path prefix",
NULL,
&mrn_database_path_prefix_update,
NULL);
static MYSQL_SYSVAR_STR(default_wrapper_engine, mrn_default_wrapper_engine,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
"The default engine for wrapper mode",
NULL,
NULL,
NULL);
static const char *mrn_action_on_error_names[] = {
"ERROR",
"ERROR_AND_LOG",
"IGNORE",
"IGNORE_AND_LOG",
NullS,
};
static TYPELIB mrn_action_on_error_typelib =
{
array_elements(mrn_action_on_error_names) - 1,
"mrn_action_on_error_typelib",
mrn_action_on_error_names,
NULL
};
static MYSQL_THDVAR_ENUM(action_on_fulltext_query_error,
PLUGIN_VAR_RQCMDARG,
"action on fulltext query error",
NULL,
NULL,
mrn_action_on_fulltext_query_error_default,
&mrn_action_on_error_typelib);
static void mrn_lock_timeout_update(THD *thd,
mrn_sys_var *var,
void *var_ptr,
const void *save)
{
MRN_DBUG_ENTER_FUNCTION();
const int new_value = *static_cast<const int *>(save);
int *old_value_ptr = static_cast<int *>(var_ptr);
*old_value_ptr = new_value;
grn_set_lock_timeout(new_value);
DBUG_VOID_RETURN;
}
static MYSQL_SYSVAR_INT(lock_timeout,
mrn_lock_timeout,
PLUGIN_VAR_RQCMDARG,
"lock timeout used in Groonga",
NULL,
mrn_lock_timeout_update,
grn_get_lock_timeout(),
-1,
INT_MAX,
1);
static MYSQL_SYSVAR_STR(libgroonga_version, mrn_libgroonga_version,
PLUGIN_VAR_NOCMDOPT | PLUGIN_VAR_READONLY,
"The version of libgroonga",
NULL,
NULL,
grn_get_version());
static MYSQL_SYSVAR_STR(version, mrn_version,
PLUGIN_VAR_NOCMDOPT | PLUGIN_VAR_READONLY,
"The version of mroonga",
NULL,
NULL,
MRN_VERSION);
static mrn_bool grn_check_zlib_support()
{
bool is_zlib_support = false;
grn_obj grn_support_p;
GRN_BOOL_INIT(&grn_support_p, 0);
grn_obj_get_info(&mrn_ctx, NULL, GRN_INFO_SUPPORT_ZLIB, &grn_support_p);
is_zlib_support = (GRN_BOOL_VALUE(&grn_support_p));
grn_obj_unlink(&mrn_ctx, &grn_support_p);
return is_zlib_support;
}
static MYSQL_SYSVAR_BOOL(libgroonga_support_zlib, mrn_libgroonga_support_zlib,
PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
"The status of libgroonga supports zlib",
NULL,
NULL,
grn_check_zlib_support());
static mrn_bool grn_check_lz4_support()
{
bool is_lz4_support = false;
grn_obj grn_support_p;
GRN_BOOL_INIT(&grn_support_p, 0);
grn_obj_get_info(&mrn_ctx, NULL, GRN_INFO_SUPPORT_LZ4, &grn_support_p);
is_lz4_support = (GRN_BOOL_VALUE(&grn_support_p));
grn_obj_unlink(&mrn_ctx, &grn_support_p);
return is_lz4_support;
}
static MYSQL_SYSVAR_BOOL(libgroonga_support_lz4, mrn_libgroonga_support_lz4,
PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
"The status of libgroonga supports LZ4",
NULL,
NULL,
grn_check_lz4_support());
static mrn_bool grn_check_zstd_support()
{
bool is_zstd_support = false;
grn_obj grn_support_p;
GRN_BOOL_INIT(&grn_support_p, 0);
grn_obj_get_info(&mrn_ctx, NULL, GRN_INFO_SUPPORT_ZSTD, &grn_support_p);
is_zstd_support = (GRN_BOOL_VALUE(&grn_support_p));
grn_obj_unlink(&mrn_ctx, &grn_support_p);
return is_zstd_support;
}
static MYSQL_SYSVAR_BOOL(libgroonga_support_zstd, mrn_libgroonga_support_zstd,
PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
"The status of libgroonga supports Zstandard",
NULL,
NULL,
grn_check_zstd_support());
static void mrn_enable_operations_recording_update(THD *thd,
mrn_sys_var *var,
void *var_ptr,
const void *save)
{
MRN_DBUG_ENTER_FUNCTION();
const bool new_value = *static_cast<const bool *>(save);
bool *old_value_ptr = static_cast<bool *>(var_ptr);
*old_value_ptr = new_value;
DBUG_VOID_RETURN;
}
static MYSQL_SYSVAR_BOOL(enable_operations_recording, mrn_enable_operations_recording,
PLUGIN_VAR_RQCMDARG,
"Whether recording operations for recovery is enabled or not",
NULL,
mrn_enable_operations_recording_update,
true);
#ifdef MRN_SUPPORT_THDVAR_SET
static MYSQL_THDVAR_SET(boolean_mode_syntax_flags,
PLUGIN_VAR_RQCMDARG,
"The flags to custom syntax in BOOLEAN MODE. "
"Available flags: "
"DEFAULT(=SYNTAX_QUERY,ALLOW_LEADING_NOT), "
"SYNTAX_QUERY, SYNTAX_SCRIPT, "
"ALLOW_COLUMN, ALLOW_UPDATE and ALLOW_LEADING_NOT",
NULL,
NULL,
mrn::variables::BOOLEAN_MODE_SYNTAX_FLAG_DEFAULT,
&mrn_boolean_mode_syntax_flags_typelib);
#endif
static const int MRN_MAX_N_RECORDS_FOR_ESTIMATE_DEFAULT = 1000;
static MYSQL_THDVAR_INT(max_n_records_for_estimate,
PLUGIN_VAR_RQCMDARG,
"The max number of records to "
"estimate the number of matched records",
NULL,
NULL,
MRN_MAX_N_RECORDS_FOR_ESTIMATE_DEFAULT,
-1,
INT_MAX,
0);
static MYSQL_SYSVAR_BOOL(libgroonga_embedded, mrn_libgroonga_embedded,
PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
"Whether libgroonga is embedded or not",
NULL,
NULL,
mrn_libgroonga_embedded);
namespace mrn {
namespace condition_push_down {
enum type {
NONE,
ALL,
ONE_FULL_TEXT_SEARCH
};
}
}
static const char *mrn_condition_push_down_type_names[] = {
"NONE",
"ALL",
"ONE_FULL_TEXT_SEARCH",
NullS
};
static TYPELIB mrn_condition_push_down_type_typelib = {
array_elements(mrn_condition_push_down_type_names) - 1,
"mrn_condition_push_down_type_typelib",
mrn_condition_push_down_type_names,
NULL
};
static MYSQL_THDVAR_ENUM(condition_push_down_type,
PLUGIN_VAR_RQCMDARG,
"How to use condition push down",
NULL,
NULL,
static_cast<ulong>(
mrn::condition_push_down::ONE_FULL_TEXT_SEARCH),
&mrn_condition_push_down_type_typelib);
static mrn_sys_var *mrn_system_variables[] =
{
MYSQL_SYSVAR(log_level),
MYSQL_SYSVAR(log_file),
MYSQL_SYSVAR(default_parser),
MYSQL_SYSVAR(default_tokenizer),
MYSQL_SYSVAR(dry_write),
MYSQL_SYSVAR(enable_optimization),
MYSQL_SYSVAR(match_escalation_threshold),
MYSQL_SYSVAR(database_path_prefix),
MYSQL_SYSVAR(default_wrapper_engine),
MYSQL_SYSVAR(action_on_fulltext_query_error),
MYSQL_SYSVAR(lock_timeout),
MYSQL_SYSVAR(libgroonga_version),
MYSQL_SYSVAR(version),
MYSQL_SYSVAR(vector_column_delimiter),
MYSQL_SYSVAR(libgroonga_support_zlib),
MYSQL_SYSVAR(libgroonga_support_lz4),
MYSQL_SYSVAR(libgroonga_support_zstd),
#ifdef MRN_SUPPORT_THDVAR_SET
MYSQL_SYSVAR(boolean_mode_syntax_flags),
#endif
MYSQL_SYSVAR(max_n_records_for_estimate),
MYSQL_SYSVAR(libgroonga_embedded),
MYSQL_SYSVAR(query_log_file),
MYSQL_SYSVAR(enable_operations_recording),
MYSQL_SYSVAR(condition_push_down_type),
NULL
};
/* mroonga information schema */
static struct st_mysql_information_schema i_s_info =
{
MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION
};
static ST_FIELD_INFO i_s_mrn_stats_fields_info[] =
{
{
"VERSION",
40,
MYSQL_TYPE_STRING,
0,
0,
"",
SKIP_OPEN_TABLE
},
{
"rows_written",
MY_INT32_NUM_DECIMAL_DIGITS,
MYSQL_TYPE_LONG,
0,
0,
"Rows written to Groonga",
SKIP_OPEN_TABLE
},
{
"rows_read",
MY_INT32_NUM_DECIMAL_DIGITS,
MYSQL_TYPE_LONG,
0,
0,
"Rows read from Groonga",
SKIP_OPEN_TABLE
}
};
static int i_s_mrn_stats_deinit(void* p)
{
MRN_DBUG_ENTER_FUNCTION();
DBUG_RETURN(0);
}
static int i_s_mrn_stats_fill(
THD* thd, TABLE_LIST* tables, Item* cond)
{
TABLE* table = (TABLE *) tables->table;
int status = 0;
MRN_DBUG_ENTER_FUNCTION();
table->field[0]->store(grn_get_version(), strlen(grn_get_version()),
system_charset_info);
table->field[0]->set_notnull();
table->field[1]->store(1); /* TODO */
table->field[2]->store(2); /* TODO */
if (schema_table_store_record(thd, table)) {
status = 1;
}
DBUG_RETURN(status);
}
static int i_s_mrn_stats_init(void* p)
{
MRN_DBUG_ENTER_FUNCTION();
ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
schema->fields_info = i_s_mrn_stats_fields_info;
schema->fill_table = i_s_mrn_stats_fill;
DBUG_RETURN(0);
}
struct st_mysql_plugin i_s_mrn_stats =
{
MYSQL_INFORMATION_SCHEMA_PLUGIN,
&i_s_info,
MRN_STATUS_VARIABLE_NAME_PREFIX_STRING "_stats",
MRN_PLUGIN_AUTHOR,
"Statistics for " MRN_PLUGIN_NAME_STRING,
PLUGIN_LICENSE_GPL,
i_s_mrn_stats_init,
#ifdef MRN_ST_MYSQL_PLUGIN_HAVE_CHECK_UNINSTALL
NULL,
#endif
i_s_mrn_stats_deinit,
MRN_VERSION_IN_HEX,
NULL,
NULL,
MRN_PLUGIN_LAST_VALUES
};
/* End of mroonga information schema implementations */
static handler *mrn_handler_create(handlerton *hton,
TABLE_SHARE *share,
#ifdef MRN_HANDLERTON_CREATE_HAVE_PARTITIONED
bool partitioned,
#endif
MEM_ROOT *root)
{
MRN_DBUG_ENTER_FUNCTION();
handler *new_handler = new (root) ha_mroonga(hton, share);
DBUG_RETURN(new_handler);
}
static void mrn_drop_database(handlerton *hton, char *path)
{
MRN_DBUG_ENTER_FUNCTION();
mrn_db_manager->drop(path);
DBUG_VOID_RETURN;
}
static int mrn_close_connection(handlerton *hton, THD *thd)
{
MRN_DBUG_ENTER_FUNCTION();
void *p = thd_get_ha_data(thd, mrn_hton_ptr);
if (p) {
mrn_clear_slot_data(thd);
free(p);
mrn_thd_set_ha_data(thd, mrn_hton_ptr, NULL);
{
mrn::Lock lock(&mrn_allocated_thds_mutex);
grn_hash_delete(&mrn_ctx, mrn_allocated_thds, &thd, sizeof(thd), NULL);
}
}
DBUG_RETURN(0);
}
#ifdef MRN_FLUSH_LOGS_HAVE_BINLOG_GROUP_FLUSH
static bool mrn_flush_logs(handlerton *hton, bool binlog_group_flush)
#else
static bool mrn_flush_logs(handlerton *hton)
#endif
{
MRN_DBUG_ENTER_FUNCTION();
bool result = 0;
grn_logger_reopen(&mrn_ctx);
grn_query_logger_reopen(&mrn_ctx);
DBUG_RETURN(result);
}
static grn_builtin_type mrn_grn_type_from_field(grn_ctx *ctx, Field *field,
bool for_index_key)
{
grn_builtin_type type = GRN_DB_VOID;
enum_field_types mysql_field_type = field->real_type();
switch (mysql_field_type) {
case MYSQL_TYPE_DECIMAL: // DECIMAL; <= 65bytes
type = GRN_DB_SHORT_TEXT; // 4Kbytes
break;
case MYSQL_TYPE_TINY: // TINYINT; 1byte
if (static_cast<Field_num *>(field)->unsigned_flag) {
type = GRN_DB_UINT8; // 1byte
} else {
type = GRN_DB_INT8; // 1byte
}
break;
case MYSQL_TYPE_SHORT: // SMALLINT; 2bytes
if (static_cast<Field_num *>(field)->unsigned_flag) {
type = GRN_DB_UINT16; // 2bytes
} else {
type = GRN_DB_INT16; // 2bytes
}
break;
case MYSQL_TYPE_LONG: // INT; 4bytes
if (static_cast<Field_num *>(field)->unsigned_flag) {
type = GRN_DB_UINT32; // 4bytes
} else {
type = GRN_DB_INT32; // 4bytes
}
break;
case MYSQL_TYPE_FLOAT: // FLOAT; 4 or 8bytes
case MYSQL_TYPE_DOUBLE: // DOUBLE; 8bytes
type = GRN_DB_FLOAT; // 8bytes
break;
case MYSQL_TYPE_NULL: // NULL; 1byte
type = GRN_DB_INT8; // 1byte
break;
case MYSQL_TYPE_TIMESTAMP: // TIMESTAMP; 4bytes
type = GRN_DB_TIME; // 8bytes
break;
case MYSQL_TYPE_LONGLONG: // BIGINT; 8bytes
if (static_cast<Field_num *>(field)->unsigned_flag) {
type = GRN_DB_UINT64; // 8bytes
} else {
type = GRN_DB_INT64; // 8bytes
}
break;
case MYSQL_TYPE_INT24: // MEDIUMINT; 3bytes
if (static_cast<Field_num *>(field)->unsigned_flag) {
type = GRN_DB_UINT32; // 4bytes
} else {
type = GRN_DB_INT32; // 4bytes
}
break;
case MYSQL_TYPE_DATE: // DATE; 4bytes
case MYSQL_TYPE_TIME: // TIME; 3bytes
case MYSQL_TYPE_DATETIME: // DATETIME; 8bytes
case MYSQL_TYPE_YEAR: // YEAR; 1byte
case MYSQL_TYPE_NEWDATE: // DATE; 3bytes
type = GRN_DB_TIME; // 8bytes
break;
case MYSQL_TYPE_VARCHAR: // VARCHAR; <= 64KB * 4 + 2bytes
#ifdef MRN_HAVE_MYSQL_TYPE_VARCHAR_COMPRESSED
case MYSQL_TYPE_VARCHAR_COMPRESSED:
#endif
if (for_index_key) {
type = GRN_DB_SHORT_TEXT; // 4Kbytes
} else {
if (field->field_length <= MRN_SHORT_TEXT_SIZE) {
type = GRN_DB_SHORT_TEXT; // 4Kbytes
} else if (field->field_length <= MRN_TEXT_SIZE) {
type = GRN_DB_TEXT; // 64Kbytes
} else {
type = GRN_DB_LONG_TEXT; // 2Gbytes
}
}
break;
case MYSQL_TYPE_BIT: // BIT; <= 8bytes
type = GRN_DB_INT64; // 8bytes
break;
#ifdef MRN_HAVE_MYSQL_TYPE_TIMESTAMP2
case MYSQL_TYPE_TIMESTAMP2: // TIMESTAMP; 4bytes
type = GRN_DB_TIME; // 8bytes
break;
#endif
#ifdef MRN_HAVE_MYSQL_TYPE_DATETIME2
case MYSQL_TYPE_DATETIME2: // DATETIME; 8bytes
type = GRN_DB_TIME; // 8bytes
break;
#endif
#ifdef MRN_HAVE_MYSQL_TYPE_TIME2
case MYSQL_TYPE_TIME2: // TIME(FSP); 3 + (FSP + 1) / 2 bytes
// 0 <= FSP <= 6; 3-6bytes
type = GRN_DB_TIME; // 8bytes
break;
#endif
case MYSQL_TYPE_NEWDECIMAL: // DECIMAL; <= 9bytes
type = GRN_DB_SHORT_TEXT; // 4Kbytes
break;
case MYSQL_TYPE_ENUM: // ENUM; <= 2bytes
if (field->pack_length() == 1) {
type = GRN_DB_UINT8; // 1bytes
} else {
type = GRN_DB_UINT16; // 2bytes
}
break;
case MYSQL_TYPE_SET: // SET; <= 8bytes
switch (field->pack_length()) {
case 1:
type = GRN_DB_UINT8; // 1byte
break;
case 2:
type = GRN_DB_UINT16; // 2bytes
break;
case 3:
case 4:
type = GRN_DB_UINT32; // 3bytes
break;
case 8:
default:
type = GRN_DB_UINT64; // 8bytes
break;
}
break;
case MYSQL_TYPE_TINY_BLOB: // TINYBLOB; <= 256bytes + 1byte
type = GRN_DB_SHORT_TEXT; // 4Kbytes
break;
case MYSQL_TYPE_MEDIUM_BLOB: // MEDIUMBLOB; <= 16Mbytes + 3bytes
if (for_index_key) {
type = GRN_DB_SHORT_TEXT; // 4Kbytes
} else {
type = GRN_DB_LONG_TEXT; // 2Gbytes
}
break;
case MYSQL_TYPE_LONG_BLOB: // LONGBLOB; <= 4Gbytes + 4bytes
if (for_index_key) {
type = GRN_DB_SHORT_TEXT; // 4Kbytes
} else {
type = GRN_DB_LONG_TEXT; // 2Gbytes
}
break;
case MYSQL_TYPE_BLOB: // BLOB; <= 64Kbytes + 2bytes
#ifdef MRN_HAVE_MYSQL_TYPE_BLOB_COMPRESSED
case MYSQL_TYPE_BLOB_COMPRESSED:
#endif
if (for_index_key) {
type = GRN_DB_SHORT_TEXT; // 4Kbytes
} else {
type = GRN_DB_LONG_TEXT; // 2Gbytes
}
break;
case MYSQL_TYPE_VAR_STRING: // VARCHAR; <= 255byte * 4 + 1bytes
if (for_index_key) {
type = GRN_DB_SHORT_TEXT; // 4Kbytes
} else {
if (field->field_length <= MRN_SHORT_TEXT_SIZE) {
type = GRN_DB_SHORT_TEXT; // 4Kbytes
} else if (field->field_length <= MRN_TEXT_SIZE) {
type = GRN_DB_TEXT; // 64Kbytes
} else {
type = GRN_DB_LONG_TEXT; // 2Gbytes
}
}
break;
case MYSQL_TYPE_STRING: // CHAR; < 1Kbytes =~ (255 * 4)bytes
// 4 is the maximum size of a character
type = GRN_DB_SHORT_TEXT; // 4Kbytes
break;
case MYSQL_TYPE_GEOMETRY: // case-by-case
type = GRN_DB_WGS84_GEO_POINT; // 8bytes
break;
#ifdef MRN_HAVE_MYSQL_TYPE_JSON
case MYSQL_TYPE_JSON:
type = GRN_DB_TEXT;
break;
#endif
}
return type;
}
static bool mrn_parse_grn_table_create_flags(THD *thd,
grn_ctx *ctx,
const char *flag_names,
uint flag_names_length,
grn_table_flags *flags)
{
const char *flag_names_end = flag_names + flag_names_length;
bool found = false;
while (flag_names < flag_names_end) {
uint rest_length = flag_names_end - flag_names;
if (*flag_names == '|' || *flag_names == ' ') {
flag_names += 1;
continue;
}
if (rest_length >= 14 && !memcmp(flag_names, "TABLE_HASH_KEY", 14)) {
*flags |= GRN_OBJ_TABLE_HASH_KEY;
flag_names += 14;
found = true;
} else if (rest_length >= 13 && !memcmp(flag_names, "TABLE_PAT_KEY", 13)) {
*flags |= GRN_OBJ_TABLE_PAT_KEY;
flag_names += 13;
found = true;
} else if (rest_length >= 13 && !memcmp(flag_names, "TABLE_DAT_KEY", 13)) {
*flags |= GRN_OBJ_TABLE_DAT_KEY;
flag_names += 13;
found = true;
} else if (rest_length >= 9 && !memcmp(flag_names, "KEY_LARGE", 9)) {
*flags |= GRN_OBJ_KEY_LARGE;
flag_names += 9;
found = true;
} else {
char invalid_flag_name[MRN_MESSAGE_BUFFER_SIZE];
snprintf(invalid_flag_name, MRN_MESSAGE_BUFFER_SIZE,
"%.*s",
static_cast<int>(rest_length),
flag_names);
push_warning_printf(thd, MRN_SEVERITY_WARNING,
ER_MRN_INVALID_TABLE_FLAG_NUM,
ER_MRN_INVALID_TABLE_FLAG_STR,
invalid_flag_name);
break;
}
}
return found;
}
static bool mrn_parse_grn_column_create_flags(THD *thd,
grn_ctx *ctx,
const char *flag_names,
uint flag_names_length,
grn_obj_flags *column_flags)
{
const char *flag_names_end = flag_names + flag_names_length;
bool found = false;
while (flag_names < flag_names_end) {
uint rest_length = flag_names_end - flag_names;
if (*flag_names == '|' || *flag_names == ' ') {
flag_names += 1;
continue;
}
if (rest_length >= 13 && !memcmp(flag_names, "COLUMN_SCALAR", 13)) {
*column_flags |= GRN_OBJ_COLUMN_SCALAR;
flag_names += 13;
found = true;
} else if (rest_length >= 13 && !memcmp(flag_names, "COLUMN_VECTOR", 13)) {
*column_flags |= GRN_OBJ_COLUMN_VECTOR;
flag_names += 13;
found = true;
} else if (rest_length >= 13 && !memcmp(flag_names, "COMPRESS_ZLIB", 13)) {
if (mrn_libgroonga_support_zlib) {
*column_flags |= GRN_OBJ_COMPRESS_ZLIB;
found = true;
} else {
push_warning_printf(thd, MRN_SEVERITY_WARNING,
ER_MRN_UNSUPPORTED_COLUMN_FLAG_NUM,
ER_MRN_UNSUPPORTED_COLUMN_FLAG_STR,
"COMPRESS_ZLIB");
}
flag_names += 13;
} else if (rest_length >= 12 && !memcmp(flag_names, "COMPRESS_LZ4", 12)) {
if (mrn_libgroonga_support_lz4) {
*column_flags |= GRN_OBJ_COMPRESS_LZ4;
found = true;
} else {
push_warning_printf(thd, MRN_SEVERITY_WARNING,
ER_MRN_UNSUPPORTED_COLUMN_FLAG_NUM,
ER_MRN_UNSUPPORTED_COLUMN_FLAG_STR,
"COMPRESS_LZ4");
}
flag_names += 12;
} else if (rest_length >= 13 && !memcmp(flag_names, "COMPRESS_ZSTD", 13)) {
if (mrn_libgroonga_support_zstd) {
*column_flags |= GRN_OBJ_COMPRESS_ZSTD;
found = true;
} else {
push_warning_printf(thd, MRN_SEVERITY_WARNING,
ER_MRN_UNSUPPORTED_COLUMN_FLAG_NUM,
ER_MRN_UNSUPPORTED_COLUMN_FLAG_STR,
"COMPRESS_ZSTD");
}
flag_names += 13;
} else {
char invalid_flag_name[MRN_MESSAGE_BUFFER_SIZE];
snprintf(invalid_flag_name, MRN_MESSAGE_BUFFER_SIZE,
"%.*s",
static_cast<int>(rest_length),
flag_names);
push_warning_printf(thd, MRN_SEVERITY_WARNING,
ER_MRN_INVALID_COLUMN_FLAG_NUM,
ER_MRN_INVALID_COLUMN_FLAG_STR,
invalid_flag_name);
break;
}
}
return found;
}
static bool mrn_parse_grn_index_column_flags(THD *thd,
grn_ctx *ctx,
const char *flag_names,
uint flag_names_length,
grn_column_flags *index_column_flags)
{
const char *flag_names_end = flag_names + flag_names_length;
bool found = false;
while (flag_names < flag_names_end) {
uint rest_length = flag_names_end - flag_names;
if (*flag_names == '|' || *flag_names == ' ') {
flag_names += 1;
continue;
}
if (rest_length >= 4 && !memcmp(flag_names, "NONE", 4)) {
flag_names += 4;
found = true;
} else if (rest_length >= 13 && !memcmp(flag_names, "WITH_POSITION", 13)) {
*index_column_flags |= GRN_OBJ_WITH_POSITION;
flag_names += 13;
found = true;
} else if (rest_length >= 12 && !memcmp(flag_names, "WITH_SECTION", 12)) {
*index_column_flags |= GRN_OBJ_WITH_SECTION;
flag_names += 12;
found = true;
} else if (rest_length >= 11 && !memcmp(flag_names, "WITH_WEIGHT", 11)) {
*index_column_flags |= GRN_OBJ_WITH_WEIGHT;
flag_names += 11;
found = true;
} else if (rest_length >= 11 && !memcmp(flag_names, "INDEX_SMALL", 11)) {
*index_column_flags |= GRN_OBJ_INDEX_SMALL;
flag_names += 11;
found = true;
} else if (rest_length >= 12 && !memcmp(flag_names, "INDEX_MEDIUM", 12)) {
*index_column_flags |= GRN_OBJ_INDEX_MEDIUM;
flag_names += 12;
found = true;
} else {
char invalid_flag_name[MRN_MESSAGE_BUFFER_SIZE];
snprintf(invalid_flag_name, MRN_MESSAGE_BUFFER_SIZE,
"%.*s",
static_cast<int>(rest_length),
flag_names);
push_warning_printf(thd, MRN_SEVERITY_WARNING,
ER_MRN_INVALID_INDEX_FLAG_NUM,
ER_MRN_INVALID_INDEX_FLAG_STR,
invalid_flag_name);
}
}
return found;
}
#ifdef MRN_HAVE_SPATIAL
static int mrn_set_geometry(grn_ctx *ctx, grn_obj *buf,
const char *wkb, uint wkb_size)
{
int error = 0;
Geometry_buffer buffer;
Geometry *geometry;
geometry = Geometry::construct(&buffer, wkb, wkb_size);
if (!geometry) {
return ER_CANT_CREATE_GEOMETRY_OBJECT;
}
switch (geometry->get_class_info()->m_type_id) {
case Geometry::wkb_point:
{
Gis_point *point = (Gis_point *)geometry;
double latitude = 0.0, longitude = 0.0;
#ifdef MRN_HAVE_POINT_XY
point_xy xy(0.0, 0.0);
point->get_xy(&xy);
longitude = xy.x;
latitude = xy.y;
#else
point->get_xy(&longitude, &latitude);
#endif
grn_obj_reinit(ctx, buf, GRN_DB_WGS84_GEO_POINT, 0);
GRN_GEO_POINT_SET(ctx, buf,
GRN_GEO_DEGREE2MSEC(latitude),
GRN_GEO_DEGREE2MSEC(longitude));
break;
}
default:
my_printf_error(ER_MRN_GEOMETRY_NOT_SUPPORT_NUM,
ER_MRN_GEOMETRY_NOT_SUPPORT_STR, MYF(0));
error = ER_MRN_GEOMETRY_NOT_SUPPORT_NUM;
break;
}
MRN_GEOMETRY_FREE(geometry);
return error;
}
#endif
#ifdef MRN_HAVE_HTON_ALTER_TABLE_FLAGS
static mrn_alter_table_flags
mrn_hton_alter_table_flags(mrn_alter_table_flags flags)
{
mrn_alter_table_flags alter_flags = 0;
#ifdef HA_INPLACE_ADD_INDEX_NO_READ_WRITE
bool is_inplace_index_change;
# ifdef MRN_HAVE_ALTER_INFO
is_inplace_index_change = (((flags & MRN_ALTER_INFO_FLAG(ADD_INDEX)) &&
(flags & MRN_ALTER_INFO_FLAG(DROP_INDEX))) ||
(flags & MRN_ALTER_INFO_FLAG(CHANGE_COLUMN)));
# else
is_inplace_index_change = (((flags & ALTER_ADD_INDEX) &&
(flags & ALTER_DROP_INDEX)) ||
(flags & ALTER_CHANGE_COLUMN));
# endif
if (!is_inplace_index_change) {
alter_flags |=
HA_INPLACE_ADD_INDEX_NO_READ_WRITE |
HA_INPLACE_DROP_INDEX_NO_READ_WRITE |
HA_INPLACE_ADD_UNIQUE_INDEX_NO_READ_WRITE |
HA_INPLACE_DROP_UNIQUE_INDEX_NO_READ_WRITE |
HA_INPLACE_ADD_INDEX_NO_WRITE |
HA_INPLACE_DROP_INDEX_NO_WRITE |
HA_INPLACE_ADD_UNIQUE_INDEX_NO_WRITE |
HA_INPLACE_DROP_UNIQUE_INDEX_NO_WRITE;
}
#endif
return alter_flags;
}
#endif
#ifdef MRN_SUPPORT_CUSTOM_OPTIONS
struct ha_table_option_struct
{
const char *flags;
};
static ha_create_table_option mrn_table_options[] =
{
HA_TOPTION_STRING("FLAGS", flags),
HA_TOPTION_END
};
static ha_create_table_option mrn_field_options[] =
{
HA_FOPTION_STRING("GROONGA_TYPE", groonga_type),
HA_FOPTION_STRING("FLAGS", flags),
HA_FOPTION_END
};
static ha_create_table_option mrn_index_options[] =
{
HA_IOPTION_STRING("TOKENIZER", tokenizer),
HA_IOPTION_STRING("NORMALIZER", normalizer),
HA_IOPTION_STRING("TOKEN_FILTERS", token_filters),
HA_IOPTION_STRING("FLAGS", flags),
HA_IOPTION_END
};
#endif
#ifdef MRN_HAVE_DB_TYPE_ROCKSDB
static void
mrn_fix_db_type_static_rocksdb_db_type()
{
// Percona Server 5.6.34 or later and 5.7.21 or later assigns static
// plugin ID for RocksDB that ID was able to be used by third party
// plugin before:
// https://github.com/percona/percona-server/commit/805173fed3db20c9c7be7a5bb41bda9d2a53b6ca
THD *thd = current_thd;
handlerton *tokudb_hton = ha_resolve_by_legacy_type(thd, DB_TYPE_TOKUDB);
if (tokudb_hton) {
return;
}
handlerton *rocksdb_hton = ha_resolve_by_legacy_type(thd, DB_TYPE_ROCKSDB);
if (rocksdb_hton) {
return;
}
enum legacy_db_type mroonga_db_type = DB_TYPE_FIRST_DYNAMIC;
while (ha_resolve_by_legacy_type(thd, mroonga_db_type)) {
mroonga_db_type =
static_cast<enum legacy_db_type>(static_cast<int>(mroonga_db_type) + 1);
}
struct st_my_dir *data_dir = my_dir(mysql_real_data_home,
MYF(MY_DONT_SORT | MY_WANT_STAT));
if (!data_dir) {
return;
}
struct fileinfo *data_file_info = data_dir->dir_entry;
for (uint i = 0; i < data_dir->number_off_files; ++i, ++data_file_info) {
if (data_file_info->name[0] == '.')
continue;
if (!MY_S_ISDIR(data_file_info->mystat->st_mode))
continue;
String db_path(mysql_real_data_home, &my_charset_bin);
db_path.append(FN_DIRSEP);
db_path.append(data_file_info->name);
struct st_my_dir *db_dir = my_dir(db_path.c_ptr(), MYF(MY_DONT_SORT));
if (!db_dir)
continue;
struct fileinfo *db_file_info = db_dir->dir_entry;
for (uint j = 0; j < db_dir->number_off_files; ++j, ++db_file_info) {
const char *ext = strrchr(db_file_info->name, '.');
if (!ext)
continue;
if (is_prefix(db_file_info->name, tmp_file_prefix))
continue;
if (strcmp(ext, ".frm") != 0)
continue;
String full_frm_path(db_path);
full_frm_path.append(FN_DIRSEP);
full_frm_path.append(db_file_info->name);
enum legacy_db_type db_type;
frm_type_enum type = dd_frm_type(thd, full_frm_path.c_ptr(), &db_type);
if (type != FRMTYPE_TABLE)
continue;
bool is_target_frm =
((db_type == DB_TYPE_TOKUDB && !tokudb_hton) ||
(db_type == DB_TYPE_ROCKSDB && !rocksdb_hton));
if (!is_target_frm)
continue;
File frm_file = mysql_file_open(mrn_key_file_frm,
full_frm_path.c_ptr(),
O_WRONLY,
MYF(0));
if (frm_file < 0)
continue;
uchar db_type_buffer[1];
db_type_buffer[0] = static_cast<uchar>(mroonga_db_type);
mysql_file_pwrite(frm_file,
db_type_buffer,
sizeof(db_type_buffer),
3,
MYF(0));
mysql_file_close(frm_file, MYF(0));
}
my_dirend(db_dir);
}
my_dirend(data_dir);
}
#endif
static void
mrn_fix_db_type()
{
#ifdef MRN_HAVE_DB_TYPE_ROCKSDB
mrn_fix_db_type_static_rocksdb_db_type();
#endif
}
static int mrn_init(void *p)
{
// init handlerton
grn_ctx *ctx = NULL;
handlerton *hton = static_cast<handlerton *>(p);
hton->state = SHOW_OPTION_YES;
hton->create = mrn_handler_create;
hton->flags = HTON_NO_FLAGS;
#ifndef MRN_SUPPORT_PARTITION
hton->flags |= HTON_NO_PARTITION;
#endif
#ifdef HTON_SUPPORTS_ATOMIC_DDL
// For supporting wrapper mode for InnoDB
// Is it OK?
hton->flags |= HTON_SUPPORTS_ATOMIC_DDL;
#endif
hton->drop_database = mrn_drop_database;
hton->close_connection = mrn_close_connection;
hton->flush_logs = mrn_flush_logs;
#ifdef MRN_HAVE_HTON_ALTER_TABLE_FLAGS
hton->alter_table_flags = mrn_hton_alter_table_flags;
#endif
#ifdef MRN_SUPPORT_CUSTOM_OPTIONS
hton->table_options = mrn_table_options;
hton->field_options = mrn_field_options;
hton->index_options = mrn_index_options;
#endif
mrn_hton_ptr = hton;
#ifdef _WIN32
HMODULE current_module = GetModuleHandle(NULL);
mrn_binlog_filter =
*((Rpl_filter **)GetProcAddress(current_module, MRN_BINLOG_FILTER_PROC));
mrn_my_tz_UTC =
*((Time_zone **)GetProcAddress(current_module, MRN_MY_TZ_UTC_PROC));
# ifdef MRN_HAVE_TABLE_DEF_CACHE
# ifdef MRN_TABLE_DEF_CACHE_TYPE_IS_MAP
# error must confirm mangled name of mrn_table_def_cache
# else
mrn_table_def_cache = (HASH *)GetProcAddress(current_module,
"?table_def_cache@@3Ust_hash@@A");
# endif
# endif
# ifndef MRN_HAVE_TDC_LOCK_TABLE_SHARE
mrn_LOCK_open =
(mysql_mutex_t *)GetProcAddress(current_module,
"?LOCK_open@@3Ust_mysql_mutex@@A");
# endif
# ifdef HAVE_PSI_INTERFACE
# ifdef MRN_TABLE_SHARE_HAVE_LOCK_SHARE
mrn_table_share_lock_share =
(PSI_mutex_key *)GetProcAddress(current_module,
MRN_TABLE_SHARE_LOCK_SHARE_PROC);
# endif
mrn_table_share_lock_ha_data =
(PSI_mutex_key *)GetProcAddress(current_module,
MRN_TABLE_SHARE_LOCK_HA_DATA_PROC);
# endif
#else
mrn_binlog_filter = binlog_filter;
mrn_my_tz_UTC = my_tz_UTC;
# ifdef MRN_HAVE_TABLE_DEF_CACHE
mrn_table_def_cache = &table_def_cache;
# endif
# ifndef MRN_HAVE_TDC_LOCK_TABLE_SHARE
mrn_LOCK_open = &LOCK_open;
# endif
#endif
MRN_REGISTER_MUTEXES("mroonga", mrn_mutexes);
grn_default_logger_set_path(mrn_log_file_path);
grn_default_logger_set_max_level(static_cast<grn_log_level>(mrn_log_level));
{
int flags = grn_default_logger_get_flags() | GRN_LOG_PID;
#ifdef GRN_LOG_THREAD_ID
flags |= GRN_LOG_THREAD_ID;
#endif
grn_default_logger_set_flags(flags);
}
grn_default_query_logger_set_path(mrn_query_log_file_path);
if (grn_init() != GRN_SUCCESS) {
goto err_grn_init;
}
grn_set_lock_timeout(mrn_lock_timeout);
mrn_init_encoding_map();
grn_ctx_init(&mrn_ctx, 0);
ctx = &mrn_ctx;
if (mrn_change_encoding(ctx, system_charset_info))
goto err_mrn_change_encoding;
GRN_LOG(ctx, GRN_LOG_NOTICE, "%s started.", MRN_PACKAGE_STRING);
#ifdef MRN_HAVE_PSI_MEMORY_KEY
{
const char *category = "mroonga";
int n_keys = array_elements(mrn_all_memory_keys);
mysql_memory_register(category, mrn_all_memory_keys, n_keys);
}
#endif
#ifdef MRN_HAVE_DB_TYPE_ROCKSDB
{
const char *category = "mroonga";
int n_keys = array_elements(mrn_all_file_keys);
mysql_file_register(category, mrn_all_file_keys, n_keys);
}
#endif
// init meta-info database
if (!(mrn_db = grn_db_create(ctx, NULL, NULL))) {
GRN_LOG(ctx, GRN_LOG_ERROR, "cannot create system database, exiting");
goto err_db_create;
}
grn_ctx_use(ctx, mrn_db);
grn_ctx_init(&mrn_db_manager_ctx, 0);
if (mysql_mutex_init(mrn_db_manager_mutex_key,
&mrn_db_manager_mutex,
MY_MUTEX_INIT_FAST) != 0) {
GRN_LOG(&mrn_db_manager_ctx, GRN_LOG_ERROR,
"failed to initialize mutex for database manager");
goto err_db_manager_mutex_init;
}
mrn_db_manager = new mrn::DatabaseManager(&mrn_db_manager_ctx,
&mrn_db_manager_mutex);
if (!mrn_db_manager->init()) {
goto err_db_manager_init;
}
if (mysql_mutex_init(mrn_context_pool_mutex_key,
&mrn_context_pool_mutex,
MY_MUTEX_INIT_FAST) != 0) {
GRN_LOG(ctx, GRN_LOG_ERROR,
"failed to initialize mutex for context pool");
goto error_context_pool_mutex_init;
}
mrn_context_pool = new mrn::ContextPool(&mrn_context_pool_mutex,
&mrn_n_pooling_contexts);
if (mysql_mutex_init(mrn_operations_mutex_key,
&mrn_operations_mutex,
MY_MUTEX_INIT_FAST) != 0) {
GRN_LOG(ctx, GRN_LOG_ERROR,
"failed to initialize mutex for operations");
goto error_operations_mutex_init;
}
if ((mysql_mutex_init(mrn_allocated_thds_mutex_key,
&mrn_allocated_thds_mutex,
MY_MUTEX_INIT_FAST) != 0)) {
goto err_allocated_thds_mutex_init;
}
mrn_allocated_thds = grn_hash_create(ctx,
NULL,
sizeof(THD *),
0,
GRN_OBJ_TABLE_HASH_KEY);
if (!mrn_allocated_thds) {
goto error_allocated_thds_hash_init;
}
if ((mysql_mutex_init(mrn_open_tables_mutex_key,
&mrn_open_tables_mutex,
MY_MUTEX_INIT_FAST) != 0)) {
goto err_allocated_open_tables_mutex_init;
}
mrn_open_tables = grn_hash_create(ctx,
NULL,
GRN_TABLE_MAX_KEY_SIZE,
sizeof(MRN_SHARE *),
GRN_OBJ_TABLE_HASH_KEY |
GRN_OBJ_KEY_VAR_SIZE);
if (!mrn_open_tables) {
goto error_allocated_open_tables_init;
}
if ((mysql_mutex_init(mrn_long_term_shares_mutex_key,
&mrn_long_term_shares_mutex,
MY_MUTEX_INIT_FAST) != 0)) {
goto error_allocated_long_term_shares_mutex_init;
}
mrn_long_term_shares = grn_hash_create(ctx,
NULL,
GRN_TABLE_MAX_KEY_SIZE,
sizeof(MRN_LONG_TERM_SHARE *),
GRN_OBJ_TABLE_HASH_KEY |
GRN_OBJ_KEY_VAR_SIZE);
if (!mrn_long_term_shares) {
goto error_allocated_long_term_shares_init;
}
#ifdef MRN_USE_MYSQL_DATA_HOME
mrn::PathMapper::default_mysql_data_home_path = mysql_data_home;
#endif
mrn_fix_db_type();
return 0;
error_allocated_long_term_shares_init:
mysql_mutex_destroy(&mrn_long_term_shares_mutex);
error_allocated_long_term_shares_mutex_init:
grn_hash_close(ctx, mrn_open_tables);
error_allocated_open_tables_init:
mysql_mutex_destroy(&mrn_open_tables_mutex);
err_allocated_open_tables_mutex_init:
grn_hash_close(&mrn_ctx, mrn_allocated_thds);
error_allocated_thds_hash_init:
mysql_mutex_destroy(&mrn_allocated_thds_mutex);
err_allocated_thds_mutex_init:
mysql_mutex_destroy(&mrn_operations_mutex);
error_operations_mutex_init:
delete mrn_context_pool;
mysql_mutex_destroy(&mrn_context_pool_mutex);
error_context_pool_mutex_init:
err_db_manager_init:
delete mrn_db_manager;
mysql_mutex_destroy(&mrn_db_manager_mutex);
err_db_manager_mutex_init:
grn_ctx_fin(&mrn_db_manager_ctx);
grn_obj_unlink(ctx, mrn_db);
err_db_create:
err_mrn_change_encoding:
grn_ctx_fin(ctx);
grn_fin();
err_grn_init:
return -1;
}
static int mrn_deinit(void *p)
{
THD *thd = current_thd;
grn_ctx *ctx = &mrn_ctx;
GRN_LOG(ctx, GRN_LOG_NOTICE, "%s deinit", MRN_PACKAGE_STRING);
if (thd && thd_sql_command(thd) == SQLCOM_UNINSTALL_PLUGIN) {
mrn::Lock lock(&mrn_allocated_thds_mutex);
GRN_HASH_EACH_BEGIN(ctx, mrn_allocated_thds, cursor, id) {
void *allocated_thd_address;
grn_hash_cursor_get_key(ctx, cursor, &allocated_thd_address);
THD *allocated_thd;
grn_memcpy(&allocated_thd,
allocated_thd_address,
sizeof(allocated_thd));
mrn_clear_slot_data(allocated_thd);
void *slot_ptr = mrn_get_slot_data(allocated_thd, false);
if (slot_ptr) free(slot_ptr);
*thd_ha_data(allocated_thd, mrn_hton_ptr) = (void *) NULL;
} GRN_HASH_EACH_END(ctx, cursor);
}
while (grn_hash_size(&mrn_ctx, mrn_long_term_shares) > 0) {
GRN_HASH_EACH_BEGIN(ctx, mrn_long_term_shares, cursor, id) {
void *long_term_share_address;
grn_hash_cursor_get_value(ctx, cursor, &long_term_share_address);
MRN_LONG_TERM_SHARE *long_term_share;
grn_memcpy(&long_term_share,
long_term_share_address,
sizeof(long_term_share));
mrn_free_long_term_share(long_term_share);
break;
} GRN_HASH_EACH_END(ctx, cursor);
}
grn_hash_close(ctx, mrn_long_term_shares);
mysql_mutex_destroy(&mrn_long_term_shares_mutex);
grn_hash_close(ctx, mrn_open_tables);
mysql_mutex_destroy(&mrn_open_tables_mutex);
grn_hash_close(ctx, mrn_allocated_thds);
mysql_mutex_destroy(&mrn_allocated_thds_mutex);
mysql_mutex_destroy(&mrn_operations_mutex);
delete mrn_context_pool;
mysql_mutex_destroy(&mrn_context_pool_mutex);
delete mrn_db_manager;
mysql_mutex_destroy(&mrn_db_manager_mutex);
grn_ctx_fin(&mrn_db_manager_ctx);
grn_obj_unlink(ctx, mrn_db);
grn_ctx_fin(ctx);
grn_fin();
return 0;
}
mrn_declare_plugin(MRN_PLUGIN_NAME)
{
MYSQL_STORAGE_ENGINE_PLUGIN,
&storage_engine_structure,
MRN_PLUGIN_NAME_STRING,
MRN_PLUGIN_AUTHOR,
"CJK-ready fulltext search, column store",
PLUGIN_LICENSE_GPL,
mrn_init,
#ifdef MRN_ST_MYSQL_PLUGIN_HAVE_CHECK_UNINSTALL
NULL,
#endif
mrn_deinit,
MRN_VERSION_IN_HEX,
mrn_status_variables,
mrn_system_variables,
MRN_PLUGIN_LAST_VALUES
},
i_s_mrn_stats
mrn_declare_plugin_end;
static double mrn_get_score_value(grn_obj *score)
{
MRN_DBUG_ENTER_FUNCTION();
double score_value;
if (score->header.domain == GRN_DB_FLOAT) {
score_value = GRN_FLOAT_VALUE(score);
} else {
score_value = (double)GRN_INT32_VALUE(score);
}
DBUG_RETURN(score_value);
}
static void mrn_generic_ft_clear(FT_INFO *handler)
{
MRN_DBUG_ENTER_FUNCTION();
st_mrn_ft_info *info = (st_mrn_ft_info *)handler;
if (!info->ctx) {
DBUG_VOID_RETURN;
}
if (info->cursor) {
grn_obj_unlink(info->ctx, info->cursor);
}
if (info->id_accessor) {
grn_obj_unlink(info->ctx, info->id_accessor);
}
if (info->key_accessor) {
grn_obj_unlink(info->ctx, info->key_accessor);
}
grn_obj_unlink(info->ctx, info->result);
grn_obj_unlink(info->ctx, info->score_column);
grn_obj_unlink(info->ctx, &(info->key));
grn_obj_unlink(info->ctx, &(info->score));
info->ctx = NULL;
DBUG_VOID_RETURN;
}
static void mrn_generic_ft_close_search(FT_INFO *handler)
{
MRN_DBUG_ENTER_FUNCTION();
st_mrn_ft_info *info = (st_mrn_ft_info *)handler;
mrn_generic_ft_clear(handler);
delete info;
DBUG_VOID_RETURN;
}
static int mrn_wrapper_ft_read_next(FT_INFO *handler, char *record)
{
MRN_DBUG_ENTER_FUNCTION();
DBUG_RETURN(HA_ERR_END_OF_FILE);
}
static float mrn_wrapper_ft_find_relevance(FT_INFO *handler, uchar *record,
uint length)
{
MRN_DBUG_ENTER_FUNCTION();
st_mrn_ft_info *info = (st_mrn_ft_info *)handler;
float score = 0.0;
grn_id record_id;
mrn_change_encoding(info->ctx, NULL);
key_copy((uchar *)(GRN_TEXT_VALUE(&(info->key))), record,
info->primary_key_info, info->primary_key_info->key_length);
record_id = grn_table_get(info->ctx,
info->table,
GRN_TEXT_VALUE(&(info->key)),
GRN_TEXT_LEN(&(info->key)));
if (record_id != GRN_ID_NIL) {
grn_id result_record_id;
result_record_id = grn_table_get(info->ctx, info->result,
&record_id, sizeof(grn_id));
if (result_record_id != GRN_ID_NIL) {
GRN_BULK_REWIND(&(info->score));
grn_obj_get_value(info->ctx, info->score_column,
result_record_id, &(info->score));
score = mrn_get_score_value(&(info->score));
}
}
DBUG_PRINT("info",
("mroonga: record_id=%d score=%g", record_id, score));
DBUG_RETURN(score);
}
static void mrn_wrapper_ft_close_search(FT_INFO *handler)
{
MRN_DBUG_ENTER_FUNCTION();
mrn_generic_ft_close_search(handler);
DBUG_VOID_RETURN;
}
static float mrn_wrapper_ft_get_relevance(FT_INFO *handler)
{
MRN_DBUG_ENTER_FUNCTION();
st_mrn_ft_info *info = (st_mrn_ft_info *)handler;
float score = 0.0;
grn_id record_id;
ha_mroonga *mroonga = info->mroonga;
mrn_change_encoding(info->ctx, NULL);
record_id = grn_table_get(info->ctx,
info->table,
GRN_TEXT_VALUE(&(mroonga->key_buffer)),
GRN_TEXT_LEN(&(mroonga->key_buffer)));
if (record_id != GRN_ID_NIL) {
grn_id result_record_id;
result_record_id = grn_table_get(info->ctx, info->result,
&record_id, sizeof(grn_id));
if (result_record_id != GRN_ID_NIL) {
GRN_BULK_REWIND(&(info->score));
grn_obj_get_value(info->ctx, info->score_column,
result_record_id, &(info->score));
score = mrn_get_score_value(&(info->score));
}
}
DBUG_PRINT("info",
("mroonga: record_id=%d score=%g", record_id, score));
DBUG_RETURN(score);
}
static void mrn_wrapper_ft_reinit_search(FT_INFO *handler)
{
MRN_DBUG_ENTER_FUNCTION();
DBUG_VOID_RETURN;
}
static _ft_vft mrn_wrapper_ft_vft = {
mrn_wrapper_ft_read_next,
mrn_wrapper_ft_find_relevance,
mrn_wrapper_ft_close_search,
mrn_wrapper_ft_get_relevance,
mrn_wrapper_ft_reinit_search
};
static int mrn_storage_ft_read_next(FT_INFO *handler, char *record)
{
MRN_DBUG_ENTER_FUNCTION();
DBUG_RETURN(HA_ERR_END_OF_FILE);
}
static float mrn_storage_ft_find_relevance(FT_INFO *handler, uchar *record,
uint length)
{
MRN_DBUG_ENTER_FUNCTION();
st_mrn_ft_info *info = (st_mrn_ft_info *)handler;
ha_mroonga *mroonga = info->mroonga;
mrn_change_encoding(info->ctx, NULL);
float score = 0.0;
if (mroonga->record_id != GRN_ID_NIL) {
grn_id result_record_id;
result_record_id = grn_table_get(info->ctx, info->result,
&(mroonga->record_id), sizeof(grn_id));
if (result_record_id != GRN_ID_NIL) {
GRN_BULK_REWIND(&(info->score));
grn_obj_get_value(info->ctx, info->score_column,
result_record_id, &(info->score));
score = mrn_get_score_value(&(info->score));
}
}
DBUG_PRINT("info", ("mroonga: record_id=%d score=%g",
mroonga->record_id, score));
DBUG_RETURN(score);
}
static void mrn_storage_ft_close_search(FT_INFO *handler)
{
MRN_DBUG_ENTER_FUNCTION();
mrn_generic_ft_close_search(handler);
DBUG_VOID_RETURN;
}
static float mrn_storage_ft_get_relevance(FT_INFO *handler)
{
MRN_DBUG_ENTER_FUNCTION();
st_mrn_ft_info *info = (st_mrn_ft_info *)handler;
ha_mroonga *mroonga = info->mroonga;
mrn_change_encoding(info->ctx, NULL);
float score = 0.0;
if (mroonga->record_id != GRN_ID_NIL) {
grn_id result_record_id;
result_record_id = grn_table_get(info->ctx, info->result,
&(mroonga->record_id), sizeof(grn_id));
if (result_record_id != GRN_ID_NIL) {
GRN_BULK_REWIND(&(info->score));
grn_obj_get_value(info->ctx, info->score_column,
result_record_id, &(info->score));
score = mrn_get_score_value(&(info->score));
}
}
DBUG_PRINT("info",
("mroonga: record_id=%d score=%g", mroonga->record_id, score));
DBUG_RETURN(score);
}
static void mrn_storage_ft_reinit_search(FT_INFO *handler)
{
MRN_DBUG_ENTER_FUNCTION();
DBUG_VOID_RETURN;
}
static _ft_vft mrn_storage_ft_vft = {
mrn_storage_ft_read_next,
mrn_storage_ft_find_relevance,
mrn_storage_ft_close_search,
mrn_storage_ft_get_relevance,
mrn_storage_ft_reinit_search
};
static int mrn_no_such_key_ft_read_next(FT_INFO *handler, char *record)
{
MRN_DBUG_ENTER_FUNCTION();
DBUG_RETURN(HA_ERR_END_OF_FILE);
}
static float mrn_no_such_key_ft_find_relevance(FT_INFO *handler, uchar *record,
uint length)
{
MRN_DBUG_ENTER_FUNCTION();
DBUG_RETURN(0.0);
}
static void mrn_no_such_key_ft_close_search(FT_INFO *handler)
{
MRN_DBUG_ENTER_FUNCTION();
st_mrn_ft_info *info = (st_mrn_ft_info *)handler;
delete info;
DBUG_VOID_RETURN;
}
static float mrn_no_such_key_ft_get_relevance(FT_INFO *handler)
{
MRN_DBUG_ENTER_FUNCTION();
DBUG_RETURN(0.0);
}
static void mrn_no_such_key_ft_reinit_search(FT_INFO *handler)
{
MRN_DBUG_ENTER_FUNCTION();
DBUG_VOID_RETURN;
}
static _ft_vft mrn_no_such_key_ft_vft = {
mrn_no_such_key_ft_read_next,
mrn_no_such_key_ft_find_relevance,
mrn_no_such_key_ft_close_search,
mrn_no_such_key_ft_get_relevance,
mrn_no_such_key_ft_reinit_search
};
#ifdef HA_CAN_FULLTEXT_EXT
static uint mrn_generic_ft_get_version()
{
MRN_DBUG_ENTER_FUNCTION();
// This value is not used in MySQL 5.6.7-rc. So it is
// meaningless. It may be used in the future...
uint version = 1;
DBUG_RETURN(version);
}
static ulonglong mrn_generic_ft_ext_get_flags()
{
MRN_DBUG_ENTER_FUNCTION();
// TODO: Should we support FTS_ORDERED_RESULT?
// TODO: Shuold we support FTS_DOCID_IN_RESULT?
ulonglong flags = 0;
DBUG_RETURN(flags);
}
// This function is used if we enable FTS_DOCID_IN_RESULT flag and the
// table has "FTS_DOC_ID" (defined as FTS_DOC_ID_COL_NAME macro)
// special name column. Should we support "FTS_DOC_ID" special name
// column?
// See also sql/sql_optimizer.cc:JOIN::optimize_fts_query().
static ulonglong mrn_generic_ft_ext_get_docid(FT_INFO_EXT *handler)
{
MRN_DBUG_ENTER_FUNCTION();
ulonglong id = GRN_ID_NIL;
DBUG_RETURN(id);
}
static ulonglong mrn_generic_ft_ext_count_matches(FT_INFO_EXT *handler)
{
MRN_DBUG_ENTER_FUNCTION();
st_mrn_ft_info *info = reinterpret_cast<st_mrn_ft_info *>(handler);
ulonglong n_records = grn_table_size(info->ctx, info->result);
DBUG_RETURN(n_records);
}
static uint mrn_wrapper_ft_ext_get_version()
{
MRN_DBUG_ENTER_FUNCTION();
uint version = mrn_generic_ft_get_version();
DBUG_RETURN(version);
}
static ulonglong mrn_wrapper_ft_ext_get_flags()
{
MRN_DBUG_ENTER_FUNCTION();
ulonglong flags = mrn_generic_ft_ext_get_flags();
DBUG_RETURN(flags);
}
static ulonglong mrn_wrapper_ft_ext_get_docid(FT_INFO_EXT *handler)
{
MRN_DBUG_ENTER_FUNCTION();
ulonglong id = mrn_generic_ft_ext_get_docid(handler);
DBUG_RETURN(id);
}
static ulonglong mrn_wrapper_ft_ext_count_matches(FT_INFO_EXT *handler)
{
MRN_DBUG_ENTER_FUNCTION();
ulonglong n_records = mrn_generic_ft_ext_count_matches(handler);
DBUG_RETURN(n_records);
}
static _ft_vft_ext mrn_wrapper_ft_vft_ext = {
mrn_wrapper_ft_ext_get_version,
mrn_wrapper_ft_ext_get_flags,
mrn_wrapper_ft_ext_get_docid,
mrn_wrapper_ft_ext_count_matches
};
static uint mrn_storage_ft_ext_get_version()
{
MRN_DBUG_ENTER_FUNCTION();
uint version = mrn_generic_ft_get_version();
DBUG_RETURN(version);
}
static ulonglong mrn_storage_ft_ext_get_flags()
{
MRN_DBUG_ENTER_FUNCTION();
ulonglong flags = mrn_generic_ft_ext_get_flags();
DBUG_RETURN(flags);
}
static ulonglong mrn_storage_ft_ext_get_docid(FT_INFO_EXT *handler)
{
MRN_DBUG_ENTER_FUNCTION();
ulonglong id = mrn_generic_ft_ext_get_docid(handler);
DBUG_RETURN(id);
}
static ulonglong mrn_storage_ft_ext_count_matches(FT_INFO_EXT *handler)
{
MRN_DBUG_ENTER_FUNCTION();
ulonglong n_records = mrn_generic_ft_ext_count_matches(handler);
DBUG_RETURN(n_records);
}
static _ft_vft_ext mrn_storage_ft_vft_ext = {
mrn_storage_ft_ext_get_version,
mrn_storage_ft_ext_get_flags,
mrn_storage_ft_ext_get_docid,
mrn_storage_ft_ext_count_matches
};
static uint mrn_no_such_key_ft_ext_get_version()
{
MRN_DBUG_ENTER_FUNCTION();
uint version = mrn_generic_ft_get_version();
DBUG_RETURN(version);
}
static ulonglong mrn_no_such_key_ft_ext_get_flags()
{
MRN_DBUG_ENTER_FUNCTION();
ulonglong flags = mrn_generic_ft_ext_get_flags();
DBUG_RETURN(flags);
}
static ulonglong mrn_no_such_key_ft_ext_get_docid(FT_INFO_EXT *handler)
{
MRN_DBUG_ENTER_FUNCTION();
ulonglong id = GRN_ID_NIL;
DBUG_RETURN(id);
}
static ulonglong mrn_no_such_key_ft_ext_count_matches(FT_INFO_EXT *handler)
{
MRN_DBUG_ENTER_FUNCTION();
ulonglong n_records = 0;
DBUG_RETURN(n_records);
}
static _ft_vft_ext mrn_no_such_key_ft_vft_ext = {
mrn_no_such_key_ft_ext_get_version,
mrn_no_such_key_ft_ext_get_flags,
mrn_no_such_key_ft_ext_get_docid,
mrn_no_such_key_ft_ext_count_matches
};
#endif
/* handler implementation */
ha_mroonga::ha_mroonga(handlerton *hton, TABLE_SHARE *share_arg)
:handler(hton, share_arg),
wrap_handler(NULL),
is_clone(false),
parent_for_clone(NULL),
mem_root_for_clone(NULL),
record_id(GRN_ID_NIL),
key_id(NULL),
del_key_id(NULL),
wrap_ft_init_count(0),
share(NULL),
wrap_key_info(NULL),
base_key_info(NULL),
analyzed_for_create(false),
wrap_handler_for_create(NULL),
#ifdef MRN_HANDLER_HAVE_FINAL_ADD_INDEX
hnd_add_index(NULL),
#endif
#ifdef MRN_HANDLER_HAVE_CHECK_IF_SUPPORTED_INPLACE_ALTER
alter_key_info_buffer(NULL),
#else
wrap_alter_key_info(NULL),
#endif
mrn_lock_type(F_UNLCK),
ctx_entity_(),
ctx(&ctx_entity_),
grn_table(NULL),
grn_columns(NULL),
grn_column_caches(NULL),
grn_column_ranges(NULL),
grn_index_tables(NULL),
grn_index_columns(NULL),
grn_source_column_geo(NULL),
cursor_geo(NULL),
cursor(NULL),
index_table_cursor(NULL),
empty_value_records(NULL),
empty_value_records_cursor(NULL),
sorted_result(NULL),
matched_record_keys(NULL),
matched_record_keys_cursor(NULL),
condition_push_down_result(NULL),
condition_push_down_result_cursor(NULL),
blob_buffers_(ctx),
dup_key(0),
count_skip(false),
fast_order_limit(false),
fast_order_limit_with_index(false),
ignoring_duplicated_key(false),
inserting_with_update(false),
fulltext_searching(false),
ignoring_no_key_columns(false),
replacing_(false),
written_by_row_based_binlog(0),
current_ft_item(NULL),
operations_(NULL)
{
MRN_DBUG_ENTER_METHOD();
grn_ctx_init(ctx, 0);
mrn_change_encoding(ctx, system_charset_info);
grn_ctx_use(ctx, mrn_db);
GRN_WGS84_GEO_POINT_INIT(&top_left_point, 0);
GRN_WGS84_GEO_POINT_INIT(&bottom_right_point, 0);
GRN_WGS84_GEO_POINT_INIT(&source_point, 0);
GRN_TEXT_INIT(&key_buffer, 0);
GRN_TEXT_INIT(&encoded_key_buffer, 0);
GRN_VOID_INIT(&old_value_buffer);
GRN_VOID_INIT(&new_value_buffer);
DBUG_VOID_RETURN;
}
ha_mroonga::~ha_mroonga()
{
MRN_DBUG_ENTER_METHOD();
delete operations_;
if (analyzed_for_create) {
if (wrap_handler_for_create) {
mrn_destroy(wrap_handler_for_create);
}
if (share_for_create.wrapper_mode) {
plugin_unlock(NULL, share_for_create.plugin);
}
if (share_for_create.table_name) {
my_free(share_for_create.table_name);
}
mrn_free_share_alloc(&share_for_create);
free_root(&mem_root_for_create, MYF(0));
}
grn_obj_unlink(ctx, &top_left_point);
grn_obj_unlink(ctx, &bottom_right_point);
grn_obj_unlink(ctx, &source_point);
grn_obj_unlink(ctx, &key_buffer);
grn_obj_unlink(ctx, &encoded_key_buffer);
grn_obj_unlink(ctx, &old_value_buffer);
grn_obj_unlink(ctx, &new_value_buffer);
grn_ctx_fin(ctx);
DBUG_VOID_RETURN;
}
const char *ha_mroonga::table_type() const
{
MRN_DBUG_ENTER_METHOD();
DBUG_RETURN(MRN_PLUGIN_NAME_STRING);
}
const char *ha_mroonga::index_type(uint key_nr)
{
MRN_DBUG_ENTER_METHOD();
KEY *key_info = &(table->s->key_info[key_nr]);
if (key_info->algorithm == HA_KEY_ALG_FULLTEXT) {
DBUG_RETURN("FULLTEXT");
} else if (key_info->algorithm == HA_KEY_ALG_HASH) {
DBUG_RETURN("HASH");
} else {
DBUG_RETURN("BTREE");
}
}
static const char *ha_mroonga_exts[] = {
NullS
};
const char **ha_mroonga::bas_ext() const
{
MRN_DBUG_ENTER_METHOD();
DBUG_RETURN(ha_mroonga_exts);
}
uint ha_mroonga::wrapper_max_supported_record_length() const
{
uint res;
MRN_DBUG_ENTER_METHOD();
if (analyzed_for_create && share_for_create.wrapper_mode) {
res = wrap_handler_for_create->max_supported_record_length();
} else {
MRN_SET_WRAP_SHARE_KEY(share, table->s);
MRN_SET_WRAP_TABLE_KEY(this, table);
res = wrap_handler->max_supported_record_length();
MRN_SET_BASE_SHARE_KEY(share, table->s);
MRN_SET_BASE_TABLE_KEY(this, table);
}
DBUG_RETURN(res);
}
uint ha_mroonga::storage_max_supported_record_length() const
{
MRN_DBUG_ENTER_METHOD();
DBUG_RETURN(HA_MAX_REC_LENGTH);
}
uint ha_mroonga::max_supported_record_length() const
{
MRN_DBUG_ENTER_METHOD();
uint res;
if (!share && !analyzed_for_create &&
(
thd_sql_command(ha_thd()) == SQLCOM_CREATE_TABLE ||
thd_sql_command(ha_thd()) == SQLCOM_CREATE_INDEX ||
thd_sql_command(ha_thd()) == SQLCOM_ALTER_TABLE
)
) {
create_share_for_create();
}
if (analyzed_for_create && share_for_create.wrapper_mode) {
res = wrapper_max_supported_record_length();
} else if (wrap_handler && share && share->wrapper_mode) {
res = wrapper_max_supported_record_length();
} else {
res = storage_max_supported_record_length();
}
DBUG_RETURN(res);
}
uint ha_mroonga::wrapper_max_supported_keys() const
{
uint res;
MRN_DBUG_ENTER_METHOD();
if (analyzed_for_create && share_for_create.wrapper_mode) {
res = wrap_handler_for_create->max_supported_keys();
} else {
MRN_SET_WRAP_SHARE_KEY(share, table->s);
MRN_SET_WRAP_TABLE_KEY(this, table);
res = wrap_handler->max_supported_keys();
MRN_SET_BASE_SHARE_KEY(share, table->s);
MRN_SET_BASE_TABLE_KEY(this, table);
}
DBUG_RETURN(res);
}
uint ha_mroonga::storage_max_supported_keys() const
{
MRN_DBUG_ENTER_METHOD();
DBUG_RETURN(HA_MAX_REC_LENGTH);
}
uint ha_mroonga::max_supported_keys() const
{
MRN_DBUG_ENTER_METHOD();
uint res;
if (!share && !analyzed_for_create &&
(
thd_sql_command(ha_thd()) == SQLCOM_CREATE_TABLE ||
thd_sql_command(ha_thd()) == SQLCOM_CREATE_INDEX ||
thd_sql_command(ha_thd()) == SQLCOM_ALTER_TABLE
)
) {
create_share_for_create();
}
if (analyzed_for_create && share_for_create.wrapper_mode) {
res = wrapper_max_supported_keys();
} else if (wrap_handler && share && share->wrapper_mode) {
res = wrapper_max_supported_keys();
} else {
res = storage_max_supported_keys();
}
DBUG_RETURN(res);
}
uint ha_mroonga::wrapper_max_supported_key_length() const
{
uint res;
MRN_DBUG_ENTER_METHOD();
if (analyzed_for_create && share_for_create.wrapper_mode) {
res = wrap_handler_for_create->max_supported_key_length();
} else {
MRN_SET_WRAP_SHARE_KEY(share, table->s);
MRN_SET_WRAP_TABLE_KEY(this, table);
res = wrap_handler->max_supported_key_length();
MRN_SET_BASE_SHARE_KEY(share, table->s);
MRN_SET_BASE_TABLE_KEY(this, table);
}
DBUG_RETURN(res);
}
uint ha_mroonga::storage_max_supported_key_length() const
{
MRN_DBUG_ENTER_METHOD();
DBUG_RETURN(GRN_TABLE_MAX_KEY_SIZE);
}
uint ha_mroonga::max_supported_key_length() const
{
MRN_DBUG_ENTER_METHOD();
uint res;
if (!share && !analyzed_for_create &&
(
thd_sql_command(ha_thd()) == SQLCOM_CREATE_TABLE ||
thd_sql_command(ha_thd()) == SQLCOM_CREATE_INDEX ||
thd_sql_command(ha_thd()) == SQLCOM_ALTER_TABLE
)
) {
create_share_for_create();
}
if (analyzed_for_create && share_for_create.wrapper_mode) {
res = wrapper_max_supported_key_length();
} else if (wrap_handler && share && share->wrapper_mode) {
res = wrapper_max_supported_key_length();
} else {
res = storage_max_supported_key_length();
}
DBUG_RETURN(res);
}
uint ha_mroonga::wrapper_max_supported_key_part_length(
#ifdef MRN_HANDLER_MAX_SUPPORTED_KEY_PART_LENGTH_HAVE_CREATE_INFO
HA_CREATE_INFO *create_info
#endif
) const
{
uint res;
MRN_DBUG_ENTER_METHOD();
if (analyzed_for_create && share_for_create.wrapper_mode) {
#ifdef MRN_HANDLER_MAX_SUPPORTED_KEY_PART_LENGTH_HAVE_CREATE_INFO
res = wrap_handler_for_create->max_supported_key_part_length(create_info);
#else
res = wrap_handler_for_create->max_supported_key_part_length();
#endif
} else {
MRN_SET_WRAP_SHARE_KEY(share, table->s);
MRN_SET_WRAP_TABLE_KEY(this, table);
#ifdef MRN_HANDLER_MAX_SUPPORTED_KEY_PART_LENGTH_HAVE_CREATE_INFO
res = wrap_handler->max_supported_key_part_length(create_info);
#else
res = wrap_handler->max_supported_key_part_length();
#endif
MRN_SET_BASE_SHARE_KEY(share, table->s);
MRN_SET_BASE_TABLE_KEY(this, table);
}
DBUG_RETURN(res);
}
uint ha_mroonga::storage_max_supported_key_part_length(
#ifdef MRN_HANDLER_MAX_SUPPORTED_KEY_PART_LENGTH_HAVE_CREATE_INFO
HA_CREATE_INFO *create_info
#endif
) const
{
MRN_DBUG_ENTER_METHOD();
DBUG_RETURN(GRN_TABLE_MAX_KEY_SIZE);
}
uint ha_mroonga::max_supported_key_part_length(
#ifdef MRN_HANDLER_MAX_SUPPORTED_KEY_PART_LENGTH_HAVE_CREATE_INFO
HA_CREATE_INFO *create_info
#endif
) const
{
MRN_DBUG_ENTER_METHOD();
uint res;
if (!share && !analyzed_for_create &&
(
thd_sql_command(ha_thd()) == SQLCOM_CREATE_TABLE ||
thd_sql_command(ha_thd()) == SQLCOM_CREATE_INDEX ||
thd_sql_command(ha_thd()) == SQLCOM_ALTER_TABLE
)
) {
create_share_for_create();
}
if ((analyzed_for_create && share_for_create.wrapper_mode) ||
(wrap_handler && share && share->wrapper_mode)) {
#ifdef MRN_HANDLER_MAX_SUPPORTED_KEY_PART_LENGTH_HAVE_CREATE_INFO
res = wrapper_max_supported_key_part_length(create_info);
#else
res = wrapper_max_supported_key_part_length();
#endif
} else {
#ifdef MRN_HANDLER_MAX_SUPPORTED_KEY_PART_LENGTH_HAVE_CREATE_INFO
res = storage_max_supported_key_part_length(create_info);
#else
res = storage_max_supported_key_part_length();
#endif
}
DBUG_RETURN(res);
}
ulonglong ha_mroonga::wrapper_table_flags() const
{
ulonglong table_flags;
MRN_DBUG_ENTER_METHOD();
if (analyzed_for_create && share_for_create.wrapper_mode) {
table_flags = wrap_handler_for_create->ha_table_flags();
} else {
MRN_SET_WRAP_SHARE_KEY(share, table->s);
MRN_SET_WRAP_TABLE_KEY(this, table);
table_flags = wrap_handler->ha_table_flags();
MRN_SET_BASE_SHARE_KEY(share, table->s);
MRN_SET_BASE_TABLE_KEY(this, table);
}
table_flags |= HA_CAN_FULLTEXT | HA_PRIMARY_KEY_REQUIRED_FOR_DELETE |
HA_CAN_RTREEKEYS;
#ifdef HA_CAN_REPAIR
table_flags |= HA_CAN_REPAIR;
#endif
#ifdef HA_CAN_FULLTEXT_EXT
table_flags |= HA_CAN_FULLTEXT_EXT;
#endif
#ifdef HA_GENERATED_COLUMNS
table_flags |= HA_GENERATED_COLUMNS;
#endif
#ifdef HA_CAN_VIRTUAL_COLUMNS
table_flags |= HA_CAN_VIRTUAL_COLUMNS;
#endif
#ifdef HA_REC_NOT_IN_SEQ
table_flags |= HA_REC_NOT_IN_SEQ;
#endif
DBUG_RETURN(table_flags);
}
ulonglong ha_mroonga::storage_table_flags() const
{
MRN_DBUG_ENTER_METHOD();
ulonglong flags =
HA_NO_TRANSACTIONS |
HA_PARTIAL_COLUMN_READ |
HA_NULL_IN_KEY |
HA_CAN_INDEX_BLOBS |
HA_STATS_RECORDS_IS_EXACT |
HA_CAN_FULLTEXT |
HA_BINLOG_FLAGS |
HA_CAN_BIT_FIELD |
HA_DUPLICATE_POS |
HA_CAN_GEOMETRY |
HA_CAN_RTREEKEYS;
//HA_HAS_RECORDS;
#ifdef HA_MUST_USE_TABLE_CONDITION_PUSHDOWN
# ifndef HA_CAN_TABLE_CONDITION_PUSHDOWN
# define HA_CAN_TABLE_CONDITION_PUSHDOWN HA_MUST_USE_TABLE_CONDITION_PUSHDOWN
# endif
#endif
#ifdef HA_CAN_TABLE_CONDITION_PUSHDOWN
flags |= HA_CAN_TABLE_CONDITION_PUSHDOWN;
#endif
#ifdef HA_CAN_REPAIR
flags |= HA_CAN_REPAIR;
#endif
#ifdef HA_CAN_FULLTEXT_EXT
flags |= HA_CAN_FULLTEXT_EXT;
#endif
#ifdef HA_GENERATED_COLUMNS
flags |= HA_GENERATED_COLUMNS;
#endif
#ifdef HA_CAN_VIRTUAL_COLUMNS
flags |= HA_CAN_VIRTUAL_COLUMNS;
#endif
#ifdef HA_REC_NOT_IN_SEQ
flags |= HA_REC_NOT_IN_SEQ;
#endif
DBUG_RETURN(flags);
}
ulonglong ha_mroonga::table_flags() const
{
MRN_DBUG_ENTER_METHOD();
ulonglong flags;
if (!share && !analyzed_for_create &&
(
thd_sql_command(ha_thd()) == SQLCOM_CREATE_TABLE ||
thd_sql_command(ha_thd()) == SQLCOM_CREATE_INDEX ||
thd_sql_command(ha_thd()) == SQLCOM_ALTER_TABLE
)
) {
create_share_for_create();
}
if (analyzed_for_create && share_for_create.wrapper_mode) {
flags = wrapper_table_flags();
} else if (wrap_handler && share && share->wrapper_mode) {
flags = wrapper_table_flags();
} else {
flags = storage_table_flags();
}
DBUG_RETURN(flags);
}
ulong ha_mroonga::wrapper_index_flags(uint idx, uint part, bool all_parts) const
{
ulong index_flags;
MRN_DBUG_ENTER_METHOD();
MRN_SET_WRAP_SHARE_KEY(share, table->s);
MRN_SET_WRAP_TABLE_KEY(this, table);
index_flags = wrap_handler->index_flags(idx, part, all_parts);
MRN_SET_BASE_SHARE_KEY(share, table->s);
MRN_SET_BASE_TABLE_KEY(this, table);
DBUG_RETURN(index_flags);
}
ulong ha_mroonga::storage_index_flags(uint idx, uint part, bool all_parts) const
{
MRN_DBUG_ENTER_METHOD();
ulong flags = HA_READ_NEXT | HA_READ_PREV | HA_READ_RANGE;
KEY *key = &(table_share->key_info[idx]);
bool need_normalize_p = false;
// TODO: MariaDB 10.1 passes key->user_defined_key_parts as part
// for ORDER BY DESC. We just it fallback to part = 0. We may use
// it for optimization in the future.
//
// See also: test_if_order_by_key() in sql/sql_select.cc.
if (KEY_N_KEY_PARTS(key) == part) {
part = 0;
}
Field *field = &(key->key_part[part].field[0]);
if (field &&
(have_custom_normalizer(key) ||
should_normalize(field, key->algorithm == HA_KEY_ALG_FULLTEXT))) {
need_normalize_p = true;
}
if (!need_normalize_p) {
flags |= HA_KEYREAD_ONLY;
}
if (KEY_N_KEY_PARTS(key) > 1 || !need_normalize_p) {
flags |= HA_READ_ORDER;
}
DBUG_RETURN(flags);
}
ulong ha_mroonga::index_flags(uint idx, uint part, bool all_parts) const
{
MRN_DBUG_ENTER_METHOD();
KEY *key = &(table_share->key_info[idx]);
if (key->algorithm == HA_KEY_ALG_FULLTEXT) {
DBUG_RETURN(HA_ONLY_WHOLE_INDEX | HA_KEY_SCAN_NOT_ROR);
}
if (mrn_is_geo_key(key)) {
DBUG_RETURN(HA_ONLY_WHOLE_INDEX | HA_KEY_SCAN_NOT_ROR | HA_READ_RANGE);
}
int error = 0;
if (wrap_handler && share && share->wrapper_mode)
{
error = wrapper_index_flags(idx, part, all_parts);
} else {
error = storage_index_flags(idx, part, all_parts);
}
DBUG_RETURN(error);
}
int ha_mroonga::create_share_for_create() const
{
int error;
THD *thd = ha_thd();
LEX *lex = thd->lex;
HA_CREATE_INFO *create_info = MRN_LEX_GET_CREATE_INFO(lex);
TABLE_LIST *table_list = MRN_LEX_GET_TABLE_LIST(lex);
MRN_DBUG_ENTER_METHOD();
wrap_handler_for_create = NULL;
memset(&table_for_create, 0, sizeof(TABLE));
memset(&share_for_create, 0, sizeof(MRN_SHARE));
memset(&table_share_for_create, 0, sizeof(TABLE_SHARE));
if (table_share) {
table_share_for_create.comment = table_share->comment;
table_share_for_create.connect_string = table_share->connect_string;
} else {
#ifdef MRN_HANDLER_HAVE_CHECK_IF_SUPPORTED_INPLACE_ALTER
if (thd_sql_command(ha_thd()) != SQLCOM_CREATE_INDEX) {
#endif
table_share_for_create.comment = create_info->comment;
table_share_for_create.connect_string = create_info->connect_string;
#ifdef MRN_HANDLER_HAVE_CHECK_IF_SUPPORTED_INPLACE_ALTER
}
#endif
if (thd_sql_command(ha_thd()) == SQLCOM_ALTER_TABLE ||
thd_sql_command(ha_thd()) == SQLCOM_CREATE_INDEX) {
st_mrn_slot_data *slot_data = mrn_get_slot_data(thd, false);
if (slot_data && slot_data->alter_create_info) {
create_info = slot_data->alter_create_info;
if (slot_data->alter_connect_string) {
table_share_for_create.connect_string.str =
slot_data->alter_connect_string;
table_share_for_create.connect_string.length =
strlen(slot_data->alter_connect_string);
} else {
table_share_for_create.connect_string.str = NULL;
table_share_for_create.connect_string.length = 0;
}
if (slot_data->alter_comment) {
table_share_for_create.comment.str =
slot_data->alter_comment;
table_share_for_create.comment.length =
strlen(slot_data->alter_comment);
} else {
table_share_for_create.comment.str = NULL;
table_share_for_create.comment.length = 0;
}
}
}
}
mrn_init_alloc_root(&mem_root_for_create, "mroonga::create", 1024, 0, MYF(0));
analyzed_for_create = true;
if (table_list) {
share_for_create.table_name =
mrn_my_strndup(MRN_TABLE_LIST_TABLE_NAME_DATA(table_list),
MRN_TABLE_LIST_TABLE_NAME_LENGTH(table_list),
MYF(MY_WME));
share_for_create.table_name_length =
MRN_TABLE_LIST_TABLE_NAME_LENGTH(table_list);
}
share_for_create.table_share = &table_share_for_create;
table_for_create.s = &table_share_for_create;
#ifdef WITH_PARTITION_STORAGE_ENGINE
table_for_create.part_info = NULL;
#endif
if ((error = mrn_parse_table_param(&share_for_create, &table_for_create)))
goto error;
if (share_for_create.wrapper_mode)
{
wrap_handler_for_create =
MRN_HANDLERTON_CREATE(share_for_create.hton,
NULL,
false,
&mem_root_for_create);
if (!wrap_handler_for_create) {
error = HA_ERR_OUT_OF_MEM;
goto error;
}
wrap_handler_for_create->init();
}
DBUG_RETURN(0);
error:
if (share_for_create.wrapper_mode) {
plugin_unlock(NULL, share_for_create.plugin);
}
mrn_free_share_alloc(&share_for_create);
free_root(&mem_root_for_create, MYF(0));
analyzed_for_create = false;
thd->clear_error();
DBUG_RETURN(error);
}
int ha_mroonga::wrapper_create(const char *name,
TABLE *table,
HA_CREATE_INFO *info,
#ifdef MRN_HANDLER_CREATE_HAVE_TABLE_DEFINITION
dd::Table *table_def,
#endif
MRN_SHARE *tmp_share)
{
int error = 0;
handler *hnd;
MRN_DBUG_ENTER_METHOD();
if (table_share->primary_key == MAX_KEY)
{
my_message(ER_REQUIRES_PRIMARY_KEY,
MRN_GET_ERR_MSG(ER_REQUIRES_PRIMARY_KEY), MYF(0));
DBUG_RETURN(ER_REQUIRES_PRIMARY_KEY);
}
error = ensure_database_open(name);
if (error)
DBUG_RETURN(error);
error = wrapper_create_index(name, table, info, tmp_share);
if (error)
DBUG_RETURN(error);
wrap_key_info = mrn_create_key_info_for_table(tmp_share, table, &error);
if (error)
DBUG_RETURN(error);
base_key_info = table->key_info;
share = tmp_share;
MRN_SET_WRAP_SHARE_KEY(tmp_share, table->s);
MRN_SET_WRAP_TABLE_KEY(this, table);
#ifdef MRN_SUPPORT_CUSTOM_OPTIONS
if (parse_engine_table_options(ha_thd(), tmp_share->hton, table->s)) {
MRN_SET_BASE_SHARE_KEY(tmp_share, table->s);
MRN_SET_BASE_TABLE_KEY(this, table);
share = NULL;
if (wrap_key_info)
{
my_free(wrap_key_info);
wrap_key_info = NULL;
}
base_key_info = NULL;
error = MRN_GET_ERROR_NUMBER;
DBUG_RETURN(error);
}
#endif
hnd = mrn_get_new_handler(table->s,
table->s->m_part_info != NULL,
current_thd->mem_root,
tmp_share->hton);
if (!hnd)
{
MRN_SET_BASE_SHARE_KEY(tmp_share, table->s);
MRN_SET_BASE_TABLE_KEY(this, table);
share = NULL;
if (wrap_key_info)
{
my_free(wrap_key_info);
wrap_key_info = NULL;
}
base_key_info = NULL;
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
}
#ifdef MRN_HANDLER_CREATE_HAVE_TABLE_DEFINITION
error = hnd->ha_create(name, table, info, table_def);
#else
error = hnd->ha_create(name, table, info);
#endif
MRN_SET_BASE_SHARE_KEY(tmp_share, table->s);
MRN_SET_BASE_TABLE_KEY(this, table);
share = NULL;
mrn_destroy(hnd);
if (error) {
mrn::PathMapper mapper(name);
#ifdef MRN_HANDLER_DELETE_TABLE_HAVE_TABLE_DEFINITION
generic_delete_table(name, table_def, mapper.table_name());
#else
generic_delete_table(name, mapper.table_name());
#endif
}
if (wrap_key_info)
{
my_free(wrap_key_info);
wrap_key_info = NULL;
}
base_key_info = NULL;
DBUG_RETURN(error);
}
int ha_mroonga::wrapper_create_index_fulltext_validate(KEY *key_info)
{
MRN_DBUG_ENTER_METHOD();
int error = 0;
uint i;
for (i = 0; i < KEY_N_KEY_PARTS(key_info); i++) {
Field *field = key_info->key_part[i].field;
grn_builtin_type gtype = mrn_grn_type_from_field(ctx, field, true);
if (gtype != GRN_DB_SHORT_TEXT)
{
error = ER_CANT_CREATE_TABLE;
GRN_LOG(ctx, GRN_LOG_ERROR,
"key type must be text: <%d> "
"(TODO: We should show type name not type ID.)",
field->type());
my_message(ER_CANT_CREATE_TABLE,
"key type must be text. (TODO: We should show type name.)",
MYF(0));
DBUG_RETURN(error);
}
}
DBUG_RETURN(error);
}
int ha_mroonga::wrapper_create_index_fulltext(const char *grn_table_name,
int i,
KEY *key_info,
grn_obj **index_tables,
grn_obj **index_columns)
{
MRN_DBUG_ENTER_METHOD();
int error = 0;
error = wrapper_create_index_fulltext_validate(key_info);
if (error) {
DBUG_RETURN(error);
}
error = mrn_change_encoding(ctx, system_charset_info);
if (error)
DBUG_RETURN(error);
grn_obj_flags index_table_flags =
GRN_OBJ_TABLE_PAT_KEY |
GRN_OBJ_PERSISTENT;
grn_obj *index_table;
grn_column_flags index_column_flags = GRN_OBJ_COLUMN_INDEX | GRN_OBJ_PERSISTENT;
if (!find_index_column_flags(key_info, &index_column_flags)) {
index_column_flags |= GRN_OBJ_WITH_POSITION;
if (KEY_N_KEY_PARTS(key_info) > 1) {
index_column_flags |= GRN_OBJ_WITH_SECTION;
}
}
mrn::SmartGrnObj lexicon_key_type(ctx, GRN_DB_SHORT_TEXT);
error = mrn_change_encoding(ctx, key_info->key_part->field->charset());
if (error) {
DBUG_RETURN(error);
}
mrn::IndexTableName index_table_name(grn_table_name, KEY_NAME(key_info));
index_table = grn_table_create(ctx,
index_table_name.c_str(),
index_table_name.length(),
NULL,
index_table_flags,
lexicon_key_type.get(),
0);
if (ctx->rc) {
error = ER_CANT_CREATE_TABLE;
my_message(ER_CANT_CREATE_TABLE, ctx->errbuf, MYF(0));
DBUG_RETURN(error);
}
mrn_change_encoding(ctx, system_charset_info);
index_tables[i] = index_table;
set_tokenizer(index_table, key_info);
{
grn_obj token_filters;
GRN_PTR_INIT(&token_filters, GRN_OBJ_VECTOR, 0);
if (find_token_filters(key_info, &token_filters)) {
grn_obj_set_info(ctx, index_table,
GRN_INFO_TOKEN_FILTERS, &token_filters);
}
grn_obj_unlink(ctx, &token_filters);
}
if (have_custom_normalizer(key_info) ||
should_normalize(&key_info->key_part->field[0], true)) {
set_normalizer(index_table, key_info);
}
grn_obj *index_column = grn_column_create(ctx, index_table,
INDEX_COLUMN_NAME,
strlen(INDEX_COLUMN_NAME),
NULL,
index_column_flags,
grn_table);
if (ctx->rc) {
error = ER_CANT_CREATE_TABLE;
my_message(error, ctx->errbuf, MYF(0));
DBUG_RETURN(error);
}
if (index_columns) {
index_columns[i] = index_column;
} else {
grn_obj_unlink(ctx, index_column);
}
DBUG_RETURN(error);
}
int ha_mroonga::wrapper_create_index_geo(const char *grn_table_name,
int i,
KEY *key_info,
grn_obj **index_tables,
grn_obj **index_columns)
{
MRN_DBUG_ENTER_METHOD();
int error;
error = mrn_change_encoding(ctx, system_charset_info);
if (error)
DBUG_RETURN(error);
mrn::IndexTableName index_table_name(grn_table_name, KEY_NAME(key_info));
grn_obj_flags index_table_flags =
GRN_OBJ_TABLE_PAT_KEY |
GRN_OBJ_PERSISTENT;
grn_obj *index_table;
grn_obj_flags index_column_flags =
GRN_OBJ_COLUMN_INDEX | GRN_OBJ_PERSISTENT;
grn_obj *lexicon_key_type = grn_ctx_at(ctx, GRN_DB_WGS84_GEO_POINT);
index_table = grn_table_create(ctx,
index_table_name.c_str(),
index_table_name.length(),
NULL,
index_table_flags, lexicon_key_type, 0);
if (ctx->rc) {
error = ER_CANT_CREATE_TABLE;
my_message(ER_CANT_CREATE_TABLE, ctx->errbuf, MYF(0));
grn_obj_unlink(ctx, lexicon_key_type);
DBUG_RETURN(error);
}
grn_obj_unlink(ctx, lexicon_key_type);
index_tables[i] = index_table;
grn_obj *index_column = grn_column_create(ctx, index_table,
INDEX_COLUMN_NAME,
strlen(INDEX_COLUMN_NAME),
NULL,
index_column_flags,
grn_table);
if (ctx->rc) {
error = ER_CANT_CREATE_TABLE;
my_message(error, ctx->errbuf, MYF(0));
DBUG_RETURN(error);
}
if (index_columns) {
index_columns[i] = index_column;
} else {
grn_obj_unlink(ctx, index_column);
}
DBUG_RETURN(error);
}
int ha_mroonga::wrapper_create_index(const char *name,
TABLE *table,
HA_CREATE_INFO *info,
MRN_SHARE *tmp_share)
{
MRN_DBUG_ENTER_METHOD();
int error = 0;
error = mrn_change_encoding(ctx, system_charset_info);
if (error)
DBUG_RETURN(error);
mrn::PathMapper mapper(name);
const char *grn_table_name = mapper.table_name();
{
char *path = NULL; // we don't specify path
grn_obj *pkey_type = grn_ctx_at(ctx, GRN_DB_SHORT_TEXT);
grn_obj *pkey_value_type = NULL; // we don't use this
grn_table_flags flags = GRN_OBJ_PERSISTENT;
if (!find_table_flags(info, tmp_share, &flags)) {
flags |= GRN_OBJ_TABLE_HASH_KEY;
}
grn_obj *table = grn_table_create(ctx,
grn_table_name, strlen(grn_table_name),
path,
flags,
pkey_type,
pkey_value_type);
if (ctx->rc) {
error = ER_CANT_CREATE_TABLE;
my_message(error, ctx->errbuf, MYF(0));
DBUG_RETURN(error);
}
if (grn_table) {
grn_obj_unlink(ctx, grn_table);
}
grn_table = table;
}
uint i;
uint n_keys = table->s->keys;
MRN_ALLOCATE_VARIABLE_LENGTH_ARRAYS(grn_obj *, index_tables, n_keys);
if (!tmp_share->disable_keys) {
for (i = 0; i < n_keys; i++) {
index_tables[i] = NULL;
KEY *key_info = &(table->s->key_info[i]);
if (key_info->algorithm == HA_KEY_ALG_FULLTEXT) {
error = wrapper_create_index_fulltext(grn_table_name,
i, key_info,
index_tables, NULL);
} else if (mrn_is_geo_key(key_info)) {
error = wrapper_create_index_geo(grn_table_name,
i, key_info,
index_tables, NULL);
}
}
}
if (error) {
for (uint j = 0; j < i; j++) {
if (index_tables[j]) {
grn_obj_remove(ctx, index_tables[j]);
}
}
grn_obj_remove(ctx, grn_table);
grn_table = NULL;
}
MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_tables);
DBUG_RETURN(error);
}
int ha_mroonga::storage_create(const char *name,
TABLE *table,
HA_CREATE_INFO *info,
#ifdef MRN_HANDLER_CREATE_HAVE_TABLE_DEFINITION
dd::Table *table_def,
#endif
MRN_SHARE *tmp_share)
{
int error;
MRN_LONG_TERM_SHARE *long_term_share = tmp_share->long_term_share;
MRN_DBUG_ENTER_METHOD();
if (info->auto_increment_value) {
mrn::Lock lock(&long_term_share->auto_inc_mutex);
long_term_share->auto_inc_value = info->auto_increment_value;
DBUG_PRINT("info", ("mroonga: auto_inc_value=%llu",
long_term_share->auto_inc_value));
long_term_share->auto_inc_inited = true;
}
error = storage_create_validate_pseudo_column(table);
if (error)
DBUG_RETURN(error);
error = storage_create_validate_index(table);
if (error)
DBUG_RETURN(error);
error = ensure_database_open(name);
if (error)
DBUG_RETURN(error);
error = mrn_change_encoding(ctx, system_charset_info);
if (error)
DBUG_RETURN(error);
grn_obj_flags table_flags = GRN_OBJ_PERSISTENT;
/* primary key must be handled before creating table */
grn_obj *pkey_type;
uint pkey_nr = table->s->primary_key;
if (pkey_nr != MAX_INDEXES) {
KEY *key_info = &(table->s->key_info[pkey_nr]);
bool is_id;
int key_parts = KEY_N_KEY_PARTS(key_info);
if (key_parts == 1) {
Field *pkey_field = key_info->key_part[0].field;
is_id = FIELD_NAME_EQUAL(pkey_field, MRN_COLUMN_NAME_ID);
grn_builtin_type gtype = mrn_grn_type_from_field(ctx, pkey_field, false);
pkey_type = grn_ctx_at(ctx, gtype);
} else {
is_id = false;
pkey_type = grn_ctx_at(ctx, GRN_DB_SHORT_TEXT);
}
// default algorithm is BTREE ==> PAT
if (!is_id && key_info->algorithm == HA_KEY_ALG_HASH) {
table_flags |= GRN_OBJ_TABLE_HASH_KEY;
} else if (!is_id) {
table_flags |= GRN_OBJ_TABLE_PAT_KEY;
} else {
// for _id
table_flags |= GRN_OBJ_TABLE_NO_KEY;
pkey_type = NULL;
}
} else {
// primary key doesn't exists
table_flags |= GRN_OBJ_TABLE_NO_KEY;
pkey_type = NULL;
}
/* create table */
grn_obj *table_obj;
mrn::PathMapper mapper(name);
char *table_path = NULL; // we don't specify path
grn_obj *pkey_value_type = NULL; // we don't use this
table_obj = grn_table_create(ctx,
mapper.table_name(), strlen(mapper.table_name()),
table_path,
table_flags, pkey_type, pkey_value_type);
if (ctx->rc) {
error = ER_CANT_CREATE_TABLE;
my_message(error, ctx->errbuf, MYF(0));
DBUG_RETURN(error);
}
if (table_flags == (GRN_OBJ_PERSISTENT | GRN_OBJ_TABLE_PAT_KEY) ||
table_flags == (GRN_OBJ_PERSISTENT | GRN_OBJ_TABLE_HASH_KEY)) {
KEY *key_info = &(table->s->key_info[pkey_nr]);
int key_parts = KEY_N_KEY_PARTS(key_info);
if (key_parts == 1) {
if (tmp_share->normalizer) {
set_normalizer(table_obj,
NULL,
tmp_share->normalizer,
tmp_share->normalizer_length);
} else {
Field *field = &(key_info->key_part->field[0]);
if (should_normalize(field, false)) {
set_normalizer(table_obj, key_info);
}
}
if (tmp_share->default_tokenizer) {
grn_obj *default_tokenizer =
grn_ctx_get(ctx,
tmp_share->default_tokenizer,
tmp_share->default_tokenizer_length);
if (default_tokenizer) {
grn_info_type info_type = GRN_INFO_DEFAULT_TOKENIZER;
grn_obj_set_info(ctx, table_obj, info_type, default_tokenizer);
grn_obj_unlink(ctx, default_tokenizer);
}
}
if (tmp_share->token_filters) {
grn_obj token_filters;
GRN_PTR_INIT(&token_filters, GRN_OBJ_VECTOR, 0);
if (find_token_filters_fill(&token_filters,
tmp_share->token_filters,
tmp_share->token_filters_length)) {
grn_obj_set_info(ctx, table_obj,
GRN_INFO_TOKEN_FILTERS, &token_filters);
}
grn_obj_unlink(ctx, &token_filters);
}
}
}
/* create columns */
uint n_columns = table->s->fields;
for (uint i = 0; i < n_columns; i++) {
Field *field = table->s->field[i];
mrn::ColumnName column_name(FIELD_NAME(field));
if (strcmp(MRN_COLUMN_NAME_ID, column_name.mysql_name()) == 0) {
continue;
}
#ifdef MRN_SUPPORT_FOREIGN_KEYS
# ifdef MRN_OPEN_TABLE_DEF_USE_TABLE_DEFINITION
bool is_created = storage_create_foreign_key(table,
mapper.table_name(),
field,
table_obj,
table_def,
error);
# else
bool is_created = storage_create_foreign_key(table,
mapper.table_name(),
field,
table_obj,
<