diff options
Diffstat (limited to '')
-rw-r--r-- | storage/mroonga/mrn_table.cpp | 1198 |
1 files changed, 1198 insertions, 0 deletions
diff --git a/storage/mroonga/mrn_table.cpp b/storage/mroonga/mrn_table.cpp new file mode 100644 index 00000000..037a6a59 --- /dev/null +++ b/storage/mroonga/mrn_table.cpp @@ -0,0 +1,1198 @@ +/* -*- c-basic-offset: 2 -*- */ +/* + Copyright(C) 2011-2013 Kentoku SHIBA + Copyright(C) 2011-2017 Kouhei Sutou <kou@clear-code.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-1335 USA +*/ + +#include "mrn_mysql.h" + +#if MYSQL_VERSION_ID >= 50500 +# include <sql_servers.h> +# include <sql_base.h> +#endif +#ifdef WITH_PARTITION_STORAGE_ENGINE +# include <partition_info.h> +#endif +#include <sql_plugin.h> + +#include "mrn_err.h" +#include "mrn_table.hpp" +#include "mrn_mysql_compat.h" +#include "mrn_variables.hpp" +#include <mrn_lock.hpp> + +#ifdef MRN_MARIADB_P +# if MYSQL_VERSION_ID >= 100100 +# define MRN_HA_RESOLVE_BY_NAME(name) ha_resolve_by_name(NULL, (name), TRUE) +# else +# define MRN_HA_RESOLVE_BY_NAME(name) ha_resolve_by_name(NULL, (name)) +# endif +#else +# if MYSQL_VERSION_ID >= 50603 +# define MRN_HA_RESOLVE_BY_NAME(name) ha_resolve_by_name(NULL, (name), TRUE) +# else +# define MRN_HA_RESOLVE_BY_NAME(name) ha_resolve_by_name(NULL, (name)) +# endif +#endif + +#if MYSQL_VERSION_ID >= 50706 && !defined(MRN_MARIADB_P) +# define MRN_PLUGIN_DATA(plugin, type) plugin_data<type>(plugin) +#else +# define MRN_PLUGIN_DATA(plugin, type) plugin_data(plugin, type) +#endif + +#define LEX_STRING_IS_EMPTY(string) \ + ((string).length == 0 || !(string).str || (string).str[0] == '\0') + +#define MRN_DEFAULT_STR "DEFAULT" +#define MRN_DEFAULT_LEN (sizeof(MRN_DEFAULT_STR) - 1) +#define MRN_GROONGA_STR "GROONGA" +#define MRN_GROONGA_LEN (sizeof(MRN_GROONGA_STR) - 1) + +#ifdef MRN_HAVE_TABLE_DEF_CACHE +extern HASH *mrn_table_def_cache; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef HAVE_PSI_INTERFACE +# ifdef WIN32 +# ifdef MRN_TABLE_SHARE_HAVE_LOCK_SHARE +extern PSI_mutex_key *mrn_table_share_lock_share; +# endif +extern PSI_mutex_key *mrn_table_share_lock_ha_data; +# endif +extern PSI_mutex_key mrn_share_mutex_key; +extern PSI_mutex_key mrn_long_term_share_auto_inc_mutex_key; +#endif + +extern HASH mrn_open_tables; +extern mysql_mutex_t mrn_open_tables_mutex; +extern HASH mrn_long_term_share; +extern mysql_mutex_t mrn_long_term_share_mutex; +extern char *mrn_default_tokenizer; +extern char *mrn_default_wrapper_engine; +extern handlerton *mrn_hton_ptr; +extern HASH mrn_allocated_thds; +extern mysql_mutex_t mrn_allocated_thds_mutex; + +static char *mrn_get_string_between_quote(const char *ptr) +{ + const char *start_ptr, *end_ptr, *tmp_ptr, *esc_ptr; + bool find_flg = FALSE, esc_flg = FALSE; + MRN_DBUG_ENTER_FUNCTION(); + + start_ptr = strchr(ptr, '\''); + end_ptr = strchr(ptr, '"'); + if (start_ptr && (!end_ptr || start_ptr < end_ptr)) + { + tmp_ptr = ++start_ptr; + while (!find_flg) + { + if (!(end_ptr = strchr(tmp_ptr, '\''))) + DBUG_RETURN(NULL); + esc_ptr = tmp_ptr; + while (!find_flg) + { + esc_ptr = strchr(esc_ptr, '\\'); + if (!esc_ptr || esc_ptr > end_ptr) + find_flg = TRUE; + else if (esc_ptr == end_ptr - 1) + { + esc_flg = TRUE; + tmp_ptr = end_ptr + 1; + break; + } else { + esc_flg = TRUE; + esc_ptr += 2; + } + } + } + } else if (end_ptr) + { + start_ptr = end_ptr; + tmp_ptr = ++start_ptr; + while (!find_flg) + { + if (!(end_ptr = strchr(tmp_ptr, '"'))) + DBUG_RETURN(NULL); + esc_ptr = tmp_ptr; + while (!find_flg) + { + esc_ptr = strchr(esc_ptr, '\\'); + if (!esc_ptr || esc_ptr > end_ptr) + find_flg = TRUE; + else if (esc_ptr == end_ptr - 1) + { + esc_flg = TRUE; + tmp_ptr = end_ptr + 1; + break; + } else { + esc_flg = TRUE; + esc_ptr += 2; + } + } + } + } else + DBUG_RETURN(NULL); + + size_t length = end_ptr - start_ptr; + char *extracted_string = (char *)mrn_my_malloc(length + 1, MYF(MY_WME)); + if (esc_flg) { + size_t extracted_index = 0; + const char *current_ptr = start_ptr; + while (current_ptr < end_ptr) { + if (*current_ptr != '\\') { + extracted_string[extracted_index] = *current_ptr; + ++extracted_index; + current_ptr++; + continue; + } + + if (current_ptr + 1 == end_ptr) { + break; + } + + switch (*(current_ptr + 1)) + { + case 'b': + extracted_string[extracted_index] = '\b'; + break; + case 'n': + extracted_string[extracted_index] = '\n'; + break; + case 'r': + extracted_string[extracted_index] = '\r'; + break; + case 't': + extracted_string[extracted_index] = '\t'; + break; + default: + extracted_string[extracted_index] = *(current_ptr + 1); + break; + } + ++extracted_index; + } + } else { + memcpy(extracted_string, start_ptr, length); + extracted_string[length] = '\0'; + } + + DBUG_RETURN(extracted_string); +} + +#ifdef WITH_PARTITION_STORAGE_ENGINE +void mrn_get_partition_info(const char *table_name, uint table_name_length, + const TABLE *table, partition_element **part_elem, + partition_element **sub_elem) +{ + partition_info *part_info = table->part_info; + partition_element *tmp_part_elem = NULL, *tmp_sub_elem = NULL; + bool tmp_flg = FALSE, tmp_find_flg = FALSE; + MRN_DBUG_ENTER_FUNCTION(); + *part_elem = NULL; + *sub_elem = NULL; + if (!part_info) + DBUG_VOID_RETURN; + + if (table_name && !memcmp(table_name + table_name_length - 5, "#TMP#", 5)) + tmp_flg = TRUE; + + DBUG_PRINT("info", ("mroonga table_name=%s", table_name)); + List_iterator<partition_element> part_it(part_info->partitions); + while ((*part_elem = part_it++)) + { + if ((*part_elem)->subpartitions.elements) + { + List_iterator<partition_element> sub_it((*part_elem)->subpartitions); + while ((*sub_elem = sub_it++)) + { + char subpartition_name[FN_REFLEN + 1]; + int error = mrn_create_subpartition_name(subpartition_name, + sizeof(subpartition_name), + table->s->path.str, + (*part_elem)->partition_name, + (*sub_elem)->partition_name, + NORMAL_PART_NAME); + if (error != 0) + DBUG_VOID_RETURN; + DBUG_PRINT("info", ("mroonga subpartition name=%s", subpartition_name)); + if (table_name && + memcmp(table_name, subpartition_name, table_name_length + 1) == 0) + DBUG_VOID_RETURN; + if ( + tmp_flg && + table_name && + *(subpartition_name + table_name_length - 5) == '\0' && + memcmp(table_name, subpartition_name, table_name_length - 5) == 0 + ) { + tmp_part_elem = *part_elem; + tmp_sub_elem = *sub_elem; + tmp_flg = FALSE; + tmp_find_flg = TRUE; + } + } + } else { + char partition_name[FN_REFLEN + 1]; + int error = mrn_create_partition_name(partition_name, + sizeof(partition_name), + table->s->path.str, + (*part_elem)->partition_name, + NORMAL_PART_NAME, + TRUE); + if (error != 0) + DBUG_VOID_RETURN; + DBUG_PRINT("info", ("mroonga partition name=%s", partition_name)); + if (table_name && + memcmp(table_name, partition_name, table_name_length + 1) == 0) + DBUG_VOID_RETURN; + if ( + tmp_flg && + table_name && + *(partition_name + table_name_length - 5) == '\0' && + memcmp(table_name, partition_name, table_name_length - 5) == 0 + ) { + tmp_part_elem = *part_elem; + tmp_flg = FALSE; + tmp_find_flg = TRUE; + } + } + } + if (tmp_find_flg) + { + *part_elem = tmp_part_elem; + *sub_elem = tmp_sub_elem; + DBUG_PRINT("info", ("mroonga tmp find")); + DBUG_VOID_RETURN; + } + *part_elem = NULL; + *sub_elem = NULL; + DBUG_PRINT("info", ("mroonga no hit")); + DBUG_VOID_RETURN; +} +#endif + +#define MRN_PARAM_STR_LEN(name) name ## _length +#define MRN_PARAM_STR(title_name, param_name) \ + if (!strncasecmp(tmp_ptr, title_name, title_length)) \ + { \ + DBUG_PRINT("info", ("mroonga " title_name " start")); \ + if (!share->param_name) \ + { \ + if ((share->param_name = mrn_get_string_between_quote( \ + start_ptr))) \ + share->MRN_PARAM_STR_LEN(param_name) = strlen(share->param_name); \ + else { \ + error = ER_MRN_INVALID_TABLE_PARAM_NUM; \ + my_printf_error(error, ER_MRN_INVALID_TABLE_PARAM_STR, \ + MYF(0), tmp_ptr); \ + goto error; \ + } \ + DBUG_PRINT("info", ("mroonga " title_name "=%s", share->param_name)); \ + } \ + break; \ + } + +#define MRN_PARAM_STR_LIST(title_name, param_name, param_pos) \ + if (!strncasecmp(tmp_ptr, title_name, title_length)) \ + { \ + DBUG_PRINT("info", ("mroonga " title_name " start")); \ + if (share->param_name && !share->param_name[param_pos]) \ + { \ + if ((share->param_name[param_pos] = mrn_get_string_between_quote( \ + start_ptr))) \ + share->MRN_PARAM_STR_LEN(param_name)[param_pos] = \ + strlen(share->param_name[param_pos]); \ + else { \ + error = ER_MRN_INVALID_TABLE_PARAM_NUM; \ + my_printf_error(error, ER_MRN_INVALID_TABLE_PARAM_STR, \ + MYF(0), tmp_ptr); \ + goto error; \ + } \ + DBUG_PRINT("info", ("mroonga " title_name "[%d]=%s", param_pos, \ + share->param_name[param_pos])); \ + } \ + break; \ + } + +int mrn_parse_table_param(MRN_SHARE *share, TABLE *table) +{ + int i, error = 0; + int title_length; + const char *sprit_ptr[2]; + const char *tmp_ptr, *start_ptr; + char *params_string = NULL; +#ifdef WITH_PARTITION_STORAGE_ENGINE + partition_element *part_elem; + partition_element *sub_elem; +#endif + MRN_DBUG_ENTER_FUNCTION(); +#ifdef WITH_PARTITION_STORAGE_ENGINE + mrn_get_partition_info(share->table_name, share->table_name_length, table, + &part_elem, &sub_elem); +#endif +#ifdef WITH_PARTITION_STORAGE_ENGINE + for (i = 4; i > 0; i--) +#else + for (i = 2; i > 0; i--) +#endif + { + const char *params_string_value = NULL; + uint params_string_length = 0; + switch (i) + { +#ifdef WITH_PARTITION_STORAGE_ENGINE + case 4: + if (!sub_elem || !sub_elem->part_comment) + continue; + DBUG_PRINT("info", ("mroonga create sub comment string")); + params_string_value = sub_elem->part_comment; + params_string_length = strlen(params_string_value); + DBUG_PRINT("info", + ("mroonga sub comment string=%s", params_string_value)); + break; + case 3: + if (!part_elem || !part_elem->part_comment) + continue; + DBUG_PRINT("info", ("mroonga create part comment string")); + params_string_value = part_elem->part_comment; + params_string_length = strlen(params_string_value); + DBUG_PRINT("info", + ("mroonga part comment string=%s", params_string_value)); + break; +#endif + case 2: + if (LEX_STRING_IS_EMPTY(table->s->comment)) + continue; + DBUG_PRINT("info", ("mroonga create comment string")); + params_string_value = table->s->comment.str; + params_string_length = table->s->comment.length; + DBUG_PRINT("info", + ("mroonga comment string=%.*s", + params_string_length, params_string_value)); + break; + default: + if (LEX_STRING_IS_EMPTY(table->s->connect_string)) + continue; + DBUG_PRINT("info", ("mroonga create connect_string string")); + params_string_value = table->s->connect_string.str; + params_string_length = table->s->connect_string.length; + DBUG_PRINT("info", + ("mroonga connect_string=%.*s", + params_string_length, params_string_value)); + break; + } + + if (!params_string_value) { + continue; + } + + { + params_string = mrn_my_strndup(params_string_value, + params_string_length, + MYF(MY_WME)); + if (!params_string) { + error = HA_ERR_OUT_OF_MEM; + goto error; + } + + sprit_ptr[0] = params_string; + while (sprit_ptr[0]) + { + if ((sprit_ptr[1] = strchr(sprit_ptr[0], ','))) + { + sprit_ptr[1]++; + } + tmp_ptr = sprit_ptr[0]; + sprit_ptr[0] = sprit_ptr[1]; + while (*tmp_ptr == ' ' || *tmp_ptr == '\r' || + *tmp_ptr == '\n' || *tmp_ptr == '\t') + tmp_ptr++; + + if (*tmp_ptr == '\0') + continue; + + DBUG_PRINT("info", ("mroonga title_str=%s", tmp_ptr)); + title_length = 0; + start_ptr = tmp_ptr; + while (*start_ptr != ' ' && *start_ptr != '\'' && + *start_ptr != '"' && *start_ptr != '\0' && + *start_ptr != '\r' && *start_ptr != '\n' && + *start_ptr != '\t' && *start_ptr != ',') + { + title_length++; + start_ptr++; + } + DBUG_PRINT("info", ("mroonga title_length=%u", title_length)); + + switch (title_length) + { + case 6: + MRN_PARAM_STR("engine", engine); + break; + case 10: + MRN_PARAM_STR("normalizer", normalizer); + break; + case 13: + MRN_PARAM_STR("token_filters", token_filters); + break; + case 17: + MRN_PARAM_STR("default_tokenizer", default_tokenizer); + break; + default: + break; + } + } + + my_free(params_string); + params_string = NULL; + } + } + + if (!share->engine && mrn_default_wrapper_engine) + { + share->engine_length = strlen(mrn_default_wrapper_engine); + if ( + !(share->engine = mrn_my_strndup(mrn_default_wrapper_engine, + share->engine_length, + MYF(MY_WME))) + ) { + error = HA_ERR_OUT_OF_MEM; + goto error; + } + } + + if (share->engine) + { + LEX_CSTRING engine_name; + if ( + ( + share->engine_length == MRN_DEFAULT_LEN && + !strncasecmp(share->engine, MRN_DEFAULT_STR, MRN_DEFAULT_LEN) + ) || + ( + share->engine_length == MRN_GROONGA_LEN && + !strncasecmp(share->engine, MRN_GROONGA_STR, MRN_GROONGA_LEN) + ) + ) { + my_free(share->engine); + share->engine = NULL; + share->engine_length = 0; + } else { + engine_name.str = share->engine; + engine_name.length = share->engine_length; + if (!(share->plugin = MRN_HA_RESOLVE_BY_NAME(&engine_name))) + { + my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), share->engine); + error = ER_UNKNOWN_STORAGE_ENGINE; + goto error; + } + share->hton = MRN_PLUGIN_DATA(share->plugin, handlerton *); + share->wrapper_mode = TRUE; + } + } + +error: + if (params_string) + my_free(params_string); + DBUG_RETURN(error); +} + +bool mrn_is_geo_key(const KEY *key_info) +{ + return key_info->algorithm == HA_KEY_ALG_UNDEF && + KEY_N_KEY_PARTS(key_info) == 1 && + key_info->key_part[0].field->type() == MYSQL_TYPE_GEOMETRY; +} + +int mrn_add_index_param(MRN_SHARE *share, KEY *key_info, int i) +{ + int error; + char *param_string = NULL; +#if MYSQL_VERSION_ID >= 50500 + int title_length; + char *sprit_ptr[2]; + char *tmp_ptr, *start_ptr; +#endif + THD *thd = current_thd; + MRN_DBUG_ENTER_FUNCTION(); + +#if MYSQL_VERSION_ID >= 50500 + if (key_info->comment.length == 0) + { + if (share->key_tokenizer[i]) { + my_free(share->key_tokenizer[i]); + } + share->key_tokenizer[i] = mrn_my_strdup(mrn_default_tokenizer, MYF(MY_WME)); + if (!share->key_tokenizer[i]) { + error = HA_ERR_OUT_OF_MEM; + goto error; + } + share->key_tokenizer_length[i] = strlen(share->key_tokenizer[i]); + + DBUG_RETURN(0); + } + DBUG_PRINT("info", ("mroonga create comment string")); + if ( + !(param_string = mrn_my_strndup(key_info->comment.str, + key_info->comment.length, + MYF(MY_WME))) + ) { + error = HA_ERR_OUT_OF_MEM; + goto error_alloc_param_string; + } + DBUG_PRINT("info", ("mroonga comment string=%s", param_string)); + + sprit_ptr[0] = param_string; + while (sprit_ptr[0]) + { + if ((sprit_ptr[1] = strchr(sprit_ptr[0], ','))) + { + *sprit_ptr[1] = '\0'; + sprit_ptr[1]++; + } + tmp_ptr = sprit_ptr[0]; + sprit_ptr[0] = sprit_ptr[1]; + while (*tmp_ptr == ' ' || *tmp_ptr == '\r' || + *tmp_ptr == '\n' || *tmp_ptr == '\t') + tmp_ptr++; + + if (*tmp_ptr == '\0') + continue; + + title_length = 0; + start_ptr = tmp_ptr; + while (*start_ptr != ' ' && *start_ptr != '\'' && + *start_ptr != '"' && *start_ptr != '\0' && + *start_ptr != '\r' && *start_ptr != '\n' && + *start_ptr != '\t') + { + title_length++; + start_ptr++; + } + + switch (title_length) + { + case 5: + MRN_PARAM_STR_LIST("table", index_table, i); + break; + case 6: + push_warning_printf(thd, MRN_SEVERITY_WARNING, + ER_WARN_DEPRECATED_SYNTAX, + ER(ER_WARN_DEPRECATED_SYNTAX), + "parser", "tokenizer"); + MRN_PARAM_STR_LIST("parser", key_tokenizer, i); + break; + case 9: + MRN_PARAM_STR_LIST("tokenizer", key_tokenizer, i); + break; + default: + break; + } + } +#endif + if (!share->key_tokenizer[i]) { + share->key_tokenizer[i] = mrn_my_strdup(mrn_default_tokenizer, MYF(MY_WME)); + if (!share->key_tokenizer[i]) { + error = HA_ERR_OUT_OF_MEM; + goto error; + } + share->key_tokenizer_length[i] = strlen(share->key_tokenizer[i]); + } + + if (param_string) + my_free(param_string); + DBUG_RETURN(0); + +error: + if (param_string) + my_free(param_string); +#if MYSQL_VERSION_ID >= 50500 +error_alloc_param_string: +#endif + DBUG_RETURN(error); +} + +int mrn_parse_index_param(MRN_SHARE *share, TABLE *table) +{ + int error; + MRN_DBUG_ENTER_FUNCTION(); + for (uint i = 0; i < table->s->keys; i++) + { + KEY *key_info = &table->s->key_info[i]; + bool is_wrapper_mode = share->engine != NULL; + + if (is_wrapper_mode) { + if (!(key_info->flags & HA_FULLTEXT) && !mrn_is_geo_key(key_info)) { + continue; + } + } + + if ((error = mrn_add_index_param(share, key_info, i))) + goto error; + } + DBUG_RETURN(0); + +error: + DBUG_RETURN(error); +} + +int mrn_add_column_param(MRN_SHARE *share, Field *field, int i) +{ + int error; + char *param_string = NULL; + int title_length; + char *sprit_ptr[2]; + char *tmp_ptr, *start_ptr; + + MRN_DBUG_ENTER_FUNCTION(); + + if (share->wrapper_mode) { + DBUG_RETURN(0); + } + + DBUG_PRINT("info", ("mroonga create comment string")); + if ( + !(param_string = mrn_my_strndup(field->comment.str, + field->comment.length, + MYF(MY_WME))) + ) { + error = HA_ERR_OUT_OF_MEM; + goto error_alloc_param_string; + } + DBUG_PRINT("info", ("mroonga comment string=%s", param_string)); + + sprit_ptr[0] = param_string; + while (sprit_ptr[0]) + { + if ((sprit_ptr[1] = strchr(sprit_ptr[0], ','))) + { + *sprit_ptr[1] = '\0'; + sprit_ptr[1]++; + } + tmp_ptr = sprit_ptr[0]; + sprit_ptr[0] = sprit_ptr[1]; + while (*tmp_ptr == ' ' || *tmp_ptr == '\r' || + *tmp_ptr == '\n' || *tmp_ptr == '\t') + tmp_ptr++; + + if (*tmp_ptr == '\0') + continue; + + title_length = 0; + start_ptr = tmp_ptr; + while (*start_ptr != ' ' && *start_ptr != '\'' && + *start_ptr != '"' && *start_ptr != '\0' && + *start_ptr != '\r' && *start_ptr != '\n' && + *start_ptr != '\t') + { + title_length++; + start_ptr++; + } + + switch (title_length) + { + case 4: + MRN_PARAM_STR_LIST("type", col_type, i); + break; + case 5: + MRN_PARAM_STR_LIST("flags", col_flags, i); + break; + case 12: + MRN_PARAM_STR_LIST("groonga_type", col_type, i); + break; + default: + break; + } + } + + if (param_string) + my_free(param_string); + DBUG_RETURN(0); + +error: + if (param_string) + my_free(param_string); +error_alloc_param_string: + DBUG_RETURN(error); +} + +int mrn_parse_column_param(MRN_SHARE *share, TABLE *table) +{ + int error; + MRN_DBUG_ENTER_FUNCTION(); + for (uint i = 0; i < table->s->fields; i++) + { + Field *field = table->s->field[i]; + + if (LEX_STRING_IS_EMPTY(field->comment)) { + continue; + } + + if ((error = mrn_add_column_param(share, field, i))) + goto error; + } + DBUG_RETURN(0); + +error: + DBUG_RETURN(error); +} + +int mrn_free_share_alloc( + MRN_SHARE *share +) { + uint i; + MRN_DBUG_ENTER_FUNCTION(); + if (share->engine) + my_free(share->engine); + if (share->default_tokenizer) + my_free(share->default_tokenizer); + if (share->normalizer) + my_free(share->normalizer); + if (share->token_filters) + my_free(share->token_filters); + for (i = 0; i < share->table_share->keys; i++) + { + if (share->index_table && share->index_table[i]) + my_free(share->index_table[i]); + if (share->key_tokenizer[i]) + my_free(share->key_tokenizer[i]); + } + for (i = 0; i < share->table_share->fields; i++) + { + if (share->col_flags && share->col_flags[i]) + my_free(share->col_flags[i]); + if (share->col_type && share->col_type[i]) + my_free(share->col_type[i]); + } + DBUG_RETURN(0); +} + +void mrn_free_long_term_share(MRN_LONG_TERM_SHARE *long_term_share) +{ + MRN_DBUG_ENTER_FUNCTION(); + { + mrn::Lock lock(&mrn_long_term_share_mutex); + my_hash_delete(&mrn_long_term_share, (uchar*) long_term_share); + } + mysql_mutex_destroy(&long_term_share->auto_inc_mutex); + my_free(long_term_share); + DBUG_VOID_RETURN; +} + +MRN_LONG_TERM_SHARE *mrn_get_long_term_share(const char *table_name, + uint table_name_length, + int *error) +{ + MRN_LONG_TERM_SHARE *long_term_share; + char *tmp_name; + MRN_DBUG_ENTER_FUNCTION(); + DBUG_PRINT("info", ("mroonga: table_name=%s", table_name)); + mrn::Lock lock(&mrn_long_term_share_mutex); + if (!(long_term_share = (MRN_LONG_TERM_SHARE*) + my_hash_search(&mrn_long_term_share, (uchar*) table_name, + table_name_length))) + { + if (!(long_term_share = (MRN_LONG_TERM_SHARE *) + mrn_my_multi_malloc(MYF(MY_WME | MY_ZEROFILL), + &long_term_share, sizeof(*long_term_share), + &tmp_name, table_name_length + 1, + NullS)) + ) { + *error = HA_ERR_OUT_OF_MEM; + goto error_alloc_long_term_share; + } + long_term_share->table_name = tmp_name; + long_term_share->table_name_length = table_name_length; + memcpy(long_term_share->table_name, table_name, table_name_length); + if (mysql_mutex_init(mrn_long_term_share_auto_inc_mutex_key, + &long_term_share->auto_inc_mutex, + MY_MUTEX_INIT_FAST) != 0) + { + *error = HA_ERR_OUT_OF_MEM; + goto error_init_auto_inc_mutex; + } + if (my_hash_insert(&mrn_long_term_share, (uchar*) long_term_share)) + { + *error = HA_ERR_OUT_OF_MEM; + goto error_hash_insert; + } + } + DBUG_RETURN(long_term_share); + +error_hash_insert: + mysql_mutex_destroy(&long_term_share->auto_inc_mutex); +error_init_auto_inc_mutex: + my_free(long_term_share); +error_alloc_long_term_share: + DBUG_RETURN(NULL); +} + +MRN_SHARE *mrn_get_share(const char *table_name, TABLE *table, int *error) +{ + MRN_SHARE *share; + char *tmp_name, **index_table, **key_tokenizer, **col_flags, **col_type; + uint length, *wrap_key_nr, *index_table_length; + uint *key_tokenizer_length, *col_flags_length, *col_type_length, i, j; + KEY *wrap_key_info; + TABLE_SHARE *wrap_table_share; + MRN_DBUG_ENTER_FUNCTION(); + length = (uint) strlen(table_name); + mrn::Lock lock(&mrn_open_tables_mutex); + if (!(share = (MRN_SHARE*) my_hash_search(&mrn_open_tables, + (uchar*) table_name, length))) + { + if (!(share = (MRN_SHARE *) + mrn_my_multi_malloc(MYF(MY_WME | MY_ZEROFILL), + &share, sizeof(*share), + &tmp_name, length + 1, + &index_table, sizeof(char *) * table->s->keys, + &index_table_length, sizeof(uint) * table->s->keys, + &key_tokenizer, sizeof(char *) * table->s->keys, + &key_tokenizer_length, sizeof(uint) * table->s->keys, + &col_flags, sizeof(char *) * table->s->fields, + &col_flags_length, sizeof(uint) * table->s->fields, + &col_type, sizeof(char *) * table->s->fields, + &col_type_length, sizeof(uint) * table->s->fields, + &wrap_key_nr, sizeof(*wrap_key_nr) * table->s->keys, + &wrap_key_info, sizeof(*wrap_key_info) * table->s->keys, + &wrap_table_share, sizeof(*wrap_table_share), + NullS)) + ) { + *error = HA_ERR_OUT_OF_MEM; + goto error_alloc_share; + } + share->use_count = 0; + share->table_name_length = length; + share->table_name = tmp_name; + share->index_table = index_table; + share->index_table_length = index_table_length; + share->key_tokenizer = key_tokenizer; + share->key_tokenizer_length = key_tokenizer_length; + share->col_flags = col_flags; + share->col_flags_length = col_flags_length; + share->col_type = col_type; + share->col_type_length = col_type_length; + mrn_my_stpmov(share->table_name, table_name); + share->table_share = table->s; + + if ( + (*error = mrn_parse_table_param(share, table)) || + (*error = mrn_parse_column_param(share, table)) || + (*error = mrn_parse_index_param(share, table)) + ) + goto error_parse_table_param; + + if (share->wrapper_mode) + { + j = 0; + for (i = 0; i < table->s->keys; i++) + { + if (table->s->key_info[i].algorithm != HA_KEY_ALG_FULLTEXT && + !mrn_is_geo_key(&table->s->key_info[i])) + { + wrap_key_nr[i] = j; + memcpy(&wrap_key_info[j], &table->s->key_info[i], + sizeof(*wrap_key_info)); + j++; + } else { + wrap_key_nr[i] = MAX_KEY; + } + } + share->wrap_keys = j; + share->base_keys = table->s->keys; + share->base_key_info = table->s->key_info; + share->base_primary_key = table->s->primary_key; + if (i) + { + share->wrap_key_nr = wrap_key_nr; + share->wrap_key_info = wrap_key_info; + if (table->s->primary_key == MAX_KEY) + share->wrap_primary_key = MAX_KEY; + else + share->wrap_primary_key = wrap_key_nr[table->s->primary_key]; + } else { + share->wrap_key_nr = NULL; + share->wrap_key_info = NULL; + share->wrap_primary_key = MAX_KEY; + } + *wrap_table_share= *table->s; + mrn_init_sql_alloc(current_thd, &(wrap_table_share->mem_root)); + wrap_table_share->keys = share->wrap_keys; + wrap_table_share->key_info = share->wrap_key_info; + wrap_table_share->primary_key = share->wrap_primary_key; + wrap_table_share->keys_in_use.init(share->wrap_keys); + wrap_table_share->keys_for_keyread.init(share->wrap_keys); +#ifdef MRN_TABLE_SHARE_HAVE_LOCK_SHARE +# ifdef WIN32 + mysql_mutex_init(*mrn_table_share_lock_share, + &(wrap_table_share->LOCK_share), MY_MUTEX_INIT_SLOW); +# else + mysql_mutex_init(key_TABLE_SHARE_LOCK_share, + &(wrap_table_share->LOCK_share), MY_MUTEX_INIT_SLOW); +# endif +#endif +#ifdef WIN32 + mysql_mutex_init(*mrn_table_share_lock_ha_data, + &(wrap_table_share->LOCK_ha_data), MY_MUTEX_INIT_FAST); +#else + mysql_mutex_init(key_TABLE_SHARE_LOCK_ha_data, + &(wrap_table_share->LOCK_ha_data), MY_MUTEX_INIT_FAST); +#endif + share->wrap_table_share = wrap_table_share; + } + + if (mysql_mutex_init(mrn_share_mutex_key, + &share->record_mutex, + MY_MUTEX_INIT_FAST) != 0) + { + *error = HA_ERR_OUT_OF_MEM; + goto error_init_mutex; + } + thr_lock_init(&share->lock); + if (!(share->long_term_share = mrn_get_long_term_share(table_name, length, + error))) + { + goto error_get_long_term_share; + } + if (my_hash_insert(&mrn_open_tables, (uchar*) share)) + { + *error = HA_ERR_OUT_OF_MEM; + goto error_hash_insert; + } + } + share->use_count++; + DBUG_RETURN(share); + +error_hash_insert: +error_get_long_term_share: + mysql_mutex_destroy(&share->record_mutex); +error_init_mutex: +error_parse_table_param: + mrn_free_share_alloc(share); + my_free(share); +error_alloc_share: + DBUG_RETURN(NULL); +} + +int mrn_free_share(MRN_SHARE *share) +{ + MRN_DBUG_ENTER_FUNCTION(); + mrn::Lock lock(&mrn_open_tables_mutex); + if (!--share->use_count) + { + my_hash_delete(&mrn_open_tables, (uchar*) share); + if (share->wrapper_mode) + plugin_unlock(NULL, share->plugin); + mrn_free_share_alloc(share); + thr_lock_delete(&share->lock); + mysql_mutex_destroy(&share->record_mutex); + if (share->wrapper_mode) { +#ifdef MRN_TABLE_SHARE_HAVE_LOCK_SHARE + mysql_mutex_destroy(&(share->wrap_table_share->LOCK_share)); +#endif + mysql_mutex_destroy(&(share->wrap_table_share->LOCK_ha_data)); + free_root(&(share->wrap_table_share->mem_root), MYF(0)); + } + my_free(share); + } + DBUG_RETURN(0); +} + +TABLE_SHARE *mrn_get_table_share(TABLE_LIST *table_list, int *error) +{ + TABLE_SHARE *share; + THD *thd = current_thd; + MRN_DBUG_ENTER_FUNCTION(); +#if defined(MRN_HAVE_TDC_ACQUIRE_SHARE) && \ + !defined(MRN_TDC_ACQUIRE_SHARE_REQUIRE_KEY) + share = tdc_acquire_share(thd, table_list, GTS_TABLE); +#else + uint key_length; +# ifdef MRN_HAVE_GET_TABLE_DEF_KEY + const char *key; + key_length = get_table_def_key(table_list, &key); +# else + char key[MAX_DBKEY_LENGTH]; + key_length = create_table_def_key(thd, key, table_list, FALSE); +# endif +# ifdef MRN_HAVE_TABLE_DEF_CACHE + my_hash_value_type hash_value; + hash_value = my_calc_hash(mrn_table_def_cache, (uchar*) key, key_length); + share = get_table_share(thd, table_list, key, key_length, 0, error, + hash_value); +# elif defined(MRN_HAVE_TDC_ACQUIRE_SHARE) + share = tdc_acquire_share(thd, table_list, GTS_TABLE); +# else + share = get_table_share(thd, table_list, key, key_length, 0, error); +# endif +#endif + DBUG_RETURN(share); +} + +TABLE_SHARE *mrn_create_tmp_table_share(TABLE_LIST *table_list, const char *path, + int *error) +{ + uint key_length; + TABLE_SHARE *share; + THD *thd = current_thd; + + MRN_DBUG_ENTER_FUNCTION(); +#ifdef MRN_HAVE_GET_TABLE_DEF_KEY + const char *key; + key_length = get_table_def_key(table_list, &key); +#else + char key[MAX_DBKEY_LENGTH]; + key_length = create_table_def_key(thd, key, table_list, FALSE); +#endif +#if MYSQL_VERSION_ID >= 100002 && defined(MRN_MARIADB_P) + share = alloc_table_share(table_list->db.str, table_list->table_name.str, key, + key_length); +#else + share = alloc_table_share(table_list, key, key_length); +#endif + if (!share) + { + *error = ER_CANT_OPEN_FILE; + DBUG_RETURN(NULL); + } + share->tmp_table = NO_TMP_TABLE; // TODO: is this right? + share->path.str = (char *) path; + share->path.length = strlen(share->path.str); + share->normalized_path.str = mrn_my_strdup(path, MYF(MY_WME)); + share->normalized_path.length = strlen(share->normalized_path.str); + if (open_table_def(thd, share, GTS_TABLE)) + { + *error = ER_CANT_OPEN_FILE; + mrn_free_tmp_table_share(share); + DBUG_RETURN(NULL); + } + DBUG_RETURN(share); +} + +void mrn_free_tmp_table_share(TABLE_SHARE *tmp_table_share) +{ + MRN_DBUG_ENTER_FUNCTION(); + const char *normalized_path = tmp_table_share->normalized_path.str; + free_table_share(tmp_table_share); + my_free((char*) normalized_path); + DBUG_VOID_RETURN; +} + +KEY *mrn_create_key_info_for_table(MRN_SHARE *share, TABLE *table, int *error) +{ + uint *wrap_key_nr = share->wrap_key_nr, i, j; + KEY *wrap_key_info; + MRN_DBUG_ENTER_FUNCTION(); + if (share->wrap_keys) + { + if (!(wrap_key_info = (KEY *) + mrn_my_multi_malloc(MYF(MY_WME | MY_ZEROFILL), + &wrap_key_info, sizeof(*wrap_key_info) * share->wrap_keys, + NullS)) + ) { + *error = HA_ERR_OUT_OF_MEM; + DBUG_RETURN(NULL); + } + for (i = 0; i < table->s->keys; i++) + { + j = wrap_key_nr[i]; + if (j < MAX_KEY) + { + memcpy(&wrap_key_info[j], &table->key_info[i], + sizeof(*wrap_key_info)); + } + } + } else + wrap_key_info = NULL; + *error = 0; + DBUG_RETURN(wrap_key_info); +} + +void mrn_set_bitmap_by_key(MY_BITMAP *map, KEY *key_info) +{ + uint i; + MRN_DBUG_ENTER_FUNCTION(); + for (i = 0; i < KEY_N_KEY_PARTS(key_info); i++) + { + Field *field = key_info->key_part[i].field; + bitmap_set_bit(map, field->field_index); + } + DBUG_VOID_RETURN; +} + +st_mrn_slot_data *mrn_get_slot_data(THD *thd, bool can_create) +{ + MRN_DBUG_ENTER_FUNCTION(); + st_mrn_slot_data *slot_data = + (st_mrn_slot_data*) thd_get_ha_data(thd, mrn_hton_ptr); + if (slot_data == NULL) { + slot_data = (st_mrn_slot_data*) malloc(sizeof(st_mrn_slot_data)); + slot_data->last_insert_record_id = GRN_ID_NIL; + slot_data->first_wrap_hton = NULL; + slot_data->alter_create_info = NULL; + slot_data->disable_keys_create_info = NULL; + slot_data->alter_connect_string = NULL; + slot_data->alter_comment = NULL; + thd_set_ha_data(thd, mrn_hton_ptr, slot_data); + { + mrn::Lock lock(&mrn_allocated_thds_mutex); + if (my_hash_insert(&mrn_allocated_thds, (uchar*) thd)) + { + free(slot_data); + DBUG_RETURN(NULL); + } + } + } + DBUG_RETURN(slot_data); +} + +void mrn_clear_slot_data(THD *thd) +{ + MRN_DBUG_ENTER_FUNCTION(); + st_mrn_slot_data *slot_data = mrn_get_slot_data(thd, FALSE); + if (slot_data) { + if (slot_data->first_wrap_hton) { + st_mrn_wrap_hton *tmp_wrap_hton; + st_mrn_wrap_hton *wrap_hton = slot_data->first_wrap_hton; + while (wrap_hton) + { + tmp_wrap_hton = wrap_hton->next; + free(wrap_hton); + wrap_hton = tmp_wrap_hton; + } + slot_data->first_wrap_hton = NULL; + } + slot_data->alter_create_info = NULL; + slot_data->disable_keys_create_info = NULL; + if (slot_data->alter_connect_string) { + my_free(slot_data->alter_connect_string); + slot_data->alter_connect_string = NULL; + } + if (slot_data->alter_comment) { + my_free(slot_data->alter_comment); + slot_data->alter_comment = NULL; + } + } + DBUG_VOID_RETURN; +} + +#ifdef __cplusplus +} +#endif |