1/* -*- c-basic-offset: 2 -*- */
2/*
3 Copyright(C) 2011-2013 Kentoku SHIBA
4 Copyright(C) 2011-2017 Kouhei Sutou <kou@clear-code.com>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19*/
20
21#include "mrn_mysql.h"
22
23#if MYSQL_VERSION_ID >= 50500
24# include <sql_servers.h>
25# include <sql_base.h>
26#endif
27#ifdef WITH_PARTITION_STORAGE_ENGINE
28# include <partition_info.h>
29#endif
30#include <sql_plugin.h>
31
32#include "mrn_err.h"
33#include "mrn_table.hpp"
34#include "mrn_mysql_compat.h"
35#include "mrn_variables.hpp"
36#include <mrn_lock.hpp>
37
38#ifdef MRN_MARIADB_P
39# if MYSQL_VERSION_ID >= 100100
40# define MRN_HA_RESOLVE_BY_NAME(name) ha_resolve_by_name(NULL, (name), TRUE)
41# else
42# define MRN_HA_RESOLVE_BY_NAME(name) ha_resolve_by_name(NULL, (name))
43# endif
44#else
45# if MYSQL_VERSION_ID >= 50603
46# define MRN_HA_RESOLVE_BY_NAME(name) ha_resolve_by_name(NULL, (name), TRUE)
47# else
48# define MRN_HA_RESOLVE_BY_NAME(name) ha_resolve_by_name(NULL, (name))
49# endif
50#endif
51
52#if MYSQL_VERSION_ID >= 50706 && !defined(MRN_MARIADB_P)
53# define MRN_PLUGIN_DATA(plugin, type) plugin_data<type>(plugin)
54#else
55# define MRN_PLUGIN_DATA(plugin, type) plugin_data(plugin, type)
56#endif
57
58#define LEX_STRING_IS_EMPTY(string) \
59 ((string).length == 0 || !(string).str || (string).str[0] == '\0')
60
61#define MRN_DEFAULT_STR "DEFAULT"
62#define MRN_DEFAULT_LEN (sizeof(MRN_DEFAULT_STR) - 1)
63#define MRN_GROONGA_STR "GROONGA"
64#define MRN_GROONGA_LEN (sizeof(MRN_GROONGA_STR) - 1)
65
66#ifdef MRN_HAVE_TABLE_DEF_CACHE
67extern HASH *mrn_table_def_cache;
68#endif
69
70#ifdef __cplusplus
71extern "C" {
72#endif
73
74#ifdef HAVE_PSI_INTERFACE
75# ifdef WIN32
76# ifdef MRN_TABLE_SHARE_HAVE_LOCK_SHARE
77extern PSI_mutex_key *mrn_table_share_lock_share;
78# endif
79extern PSI_mutex_key *mrn_table_share_lock_ha_data;
80# endif
81extern PSI_mutex_key mrn_share_mutex_key;
82extern PSI_mutex_key mrn_long_term_share_auto_inc_mutex_key;
83#endif
84
85extern HASH mrn_open_tables;
86extern mysql_mutex_t mrn_open_tables_mutex;
87extern HASH mrn_long_term_share;
88extern mysql_mutex_t mrn_long_term_share_mutex;
89extern char *mrn_default_tokenizer;
90extern char *mrn_default_wrapper_engine;
91extern handlerton *mrn_hton_ptr;
92extern HASH mrn_allocated_thds;
93extern mysql_mutex_t mrn_allocated_thds_mutex;
94
95static char *mrn_get_string_between_quote(const char *ptr)
96{
97 const char *start_ptr, *end_ptr, *tmp_ptr, *esc_ptr;
98 bool find_flg = FALSE, esc_flg = FALSE;
99 MRN_DBUG_ENTER_FUNCTION();
100
101 start_ptr = strchr(ptr, '\'');
102 end_ptr = strchr(ptr, '"');
103 if (start_ptr && (!end_ptr || start_ptr < end_ptr))
104 {
105 tmp_ptr = ++start_ptr;
106 while (!find_flg)
107 {
108 if (!(end_ptr = strchr(tmp_ptr, '\'')))
109 DBUG_RETURN(NULL);
110 esc_ptr = tmp_ptr;
111 while (!find_flg)
112 {
113 esc_ptr = strchr(esc_ptr, '\\');
114 if (!esc_ptr || esc_ptr > end_ptr)
115 find_flg = TRUE;
116 else if (esc_ptr == end_ptr - 1)
117 {
118 esc_flg = TRUE;
119 tmp_ptr = end_ptr + 1;
120 break;
121 } else {
122 esc_flg = TRUE;
123 esc_ptr += 2;
124 }
125 }
126 }
127 } else if (end_ptr)
128 {
129 start_ptr = end_ptr;
130 tmp_ptr = ++start_ptr;
131 while (!find_flg)
132 {
133 if (!(end_ptr = strchr(tmp_ptr, '"')))
134 DBUG_RETURN(NULL);
135 esc_ptr = tmp_ptr;
136 while (!find_flg)
137 {
138 esc_ptr = strchr(esc_ptr, '\\');
139 if (!esc_ptr || esc_ptr > end_ptr)
140 find_flg = TRUE;
141 else if (esc_ptr == end_ptr - 1)
142 {
143 esc_flg = TRUE;
144 tmp_ptr = end_ptr + 1;
145 break;
146 } else {
147 esc_flg = TRUE;
148 esc_ptr += 2;
149 }
150 }
151 }
152 } else
153 DBUG_RETURN(NULL);
154
155 size_t length = end_ptr - start_ptr;
156 char *extracted_string = (char *)mrn_my_malloc(length + 1, MYF(MY_WME));
157 if (esc_flg) {
158 size_t extracted_index = 0;
159 const char *current_ptr = start_ptr;
160 while (current_ptr < end_ptr) {
161 if (*current_ptr != '\\') {
162 extracted_string[extracted_index] = *current_ptr;
163 ++extracted_index;
164 current_ptr++;
165 continue;
166 }
167
168 if (current_ptr + 1 == end_ptr) {
169 break;
170 }
171
172 switch (*(current_ptr + 1))
173 {
174 case 'b':
175 extracted_string[extracted_index] = '\b';
176 break;
177 case 'n':
178 extracted_string[extracted_index] = '\n';
179 break;
180 case 'r':
181 extracted_string[extracted_index] = '\r';
182 break;
183 case 't':
184 extracted_string[extracted_index] = '\t';
185 break;
186 default:
187 extracted_string[extracted_index] = *(current_ptr + 1);
188 break;
189 }
190 ++extracted_index;
191 }
192 } else {
193 memcpy(extracted_string, start_ptr, length);
194 extracted_string[length] = '\0';
195 }
196
197 DBUG_RETURN(extracted_string);
198}
199
200#ifdef WITH_PARTITION_STORAGE_ENGINE
201void mrn_get_partition_info(const char *table_name, uint table_name_length,
202 const TABLE *table, partition_element **part_elem,
203 partition_element **sub_elem)
204{
205 partition_info *part_info = table->part_info;
206 partition_element *tmp_part_elem = NULL, *tmp_sub_elem = NULL;
207 bool tmp_flg = FALSE, tmp_find_flg = FALSE;
208 MRN_DBUG_ENTER_FUNCTION();
209 *part_elem = NULL;
210 *sub_elem = NULL;
211 if (!part_info)
212 DBUG_VOID_RETURN;
213
214 if (table_name && !memcmp(table_name + table_name_length - 5, "#TMP#", 5))
215 tmp_flg = TRUE;
216
217 DBUG_PRINT("info", ("mroonga table_name=%s", table_name));
218 List_iterator<partition_element> part_it(part_info->partitions);
219 while ((*part_elem = part_it++))
220 {
221 if ((*part_elem)->subpartitions.elements)
222 {
223 List_iterator<partition_element> sub_it((*part_elem)->subpartitions);
224 while ((*sub_elem = sub_it++))
225 {
226 char subpartition_name[FN_REFLEN + 1];
227 int error = mrn_create_subpartition_name(subpartition_name,
228 sizeof(subpartition_name),
229 table->s->path.str,
230 (*part_elem)->partition_name,
231 (*sub_elem)->partition_name,
232 NORMAL_PART_NAME);
233 if (error != 0)
234 DBUG_VOID_RETURN;
235 DBUG_PRINT("info", ("mroonga subpartition name=%s", subpartition_name));
236 if (table_name &&
237 memcmp(table_name, subpartition_name, table_name_length + 1) == 0)
238 DBUG_VOID_RETURN;
239 if (
240 tmp_flg &&
241 table_name &&
242 *(subpartition_name + table_name_length - 5) == '\0' &&
243 memcmp(table_name, subpartition_name, table_name_length - 5) == 0
244 ) {
245 tmp_part_elem = *part_elem;
246 tmp_sub_elem = *sub_elem;
247 tmp_flg = FALSE;
248 tmp_find_flg = TRUE;
249 }
250 }
251 } else {
252 char partition_name[FN_REFLEN + 1];
253 int error = mrn_create_partition_name(partition_name,
254 sizeof(partition_name),
255 table->s->path.str,
256 (*part_elem)->partition_name,
257 NORMAL_PART_NAME,
258 TRUE);
259 if (error != 0)
260 DBUG_VOID_RETURN;
261 DBUG_PRINT("info", ("mroonga partition name=%s", partition_name));
262 if (table_name &&
263 memcmp(table_name, partition_name, table_name_length + 1) == 0)
264 DBUG_VOID_RETURN;
265 if (
266 tmp_flg &&
267 table_name &&
268 *(partition_name + table_name_length - 5) == '\0' &&
269 memcmp(table_name, partition_name, table_name_length - 5) == 0
270 ) {
271 tmp_part_elem = *part_elem;
272 tmp_flg = FALSE;
273 tmp_find_flg = TRUE;
274 }
275 }
276 }
277 if (tmp_find_flg)
278 {
279 *part_elem = tmp_part_elem;
280 *sub_elem = tmp_sub_elem;
281 DBUG_PRINT("info", ("mroonga tmp find"));
282 DBUG_VOID_RETURN;
283 }
284 *part_elem = NULL;
285 *sub_elem = NULL;
286 DBUG_PRINT("info", ("mroonga no hit"));
287 DBUG_VOID_RETURN;
288}
289#endif
290
291#define MRN_PARAM_STR_LEN(name) name ## _length
292#define MRN_PARAM_STR(title_name, param_name) \
293 if (!strncasecmp(tmp_ptr, title_name, title_length)) \
294 { \
295 DBUG_PRINT("info", ("mroonga " title_name " start")); \
296 if (!share->param_name) \
297 { \
298 if ((share->param_name = mrn_get_string_between_quote( \
299 start_ptr))) \
300 share->MRN_PARAM_STR_LEN(param_name) = strlen(share->param_name); \
301 else { \
302 error = ER_MRN_INVALID_TABLE_PARAM_NUM; \
303 my_printf_error(error, ER_MRN_INVALID_TABLE_PARAM_STR, \
304 MYF(0), tmp_ptr); \
305 goto error; \
306 } \
307 DBUG_PRINT("info", ("mroonga " title_name "=%s", share->param_name)); \
308 } \
309 break; \
310 }
311
312#define MRN_PARAM_STR_LIST(title_name, param_name, param_pos) \
313 if (!strncasecmp(tmp_ptr, title_name, title_length)) \
314 { \
315 DBUG_PRINT("info", ("mroonga " title_name " start")); \
316 if (share->param_name && !share->param_name[param_pos]) \
317 { \
318 if ((share->param_name[param_pos] = mrn_get_string_between_quote( \
319 start_ptr))) \
320 share->MRN_PARAM_STR_LEN(param_name)[param_pos] = \
321 strlen(share->param_name[param_pos]); \
322 else { \
323 error = ER_MRN_INVALID_TABLE_PARAM_NUM; \
324 my_printf_error(error, ER_MRN_INVALID_TABLE_PARAM_STR, \
325 MYF(0), tmp_ptr); \
326 goto error; \
327 } \
328 DBUG_PRINT("info", ("mroonga " title_name "[%d]=%s", param_pos, \
329 share->param_name[param_pos])); \
330 } \
331 break; \
332 }
333
334int mrn_parse_table_param(MRN_SHARE *share, TABLE *table)
335{
336 int i, error = 0;
337 int title_length;
338 const char *sprit_ptr[2];
339 const char *tmp_ptr, *start_ptr;
340 char *params_string = NULL;
341#ifdef WITH_PARTITION_STORAGE_ENGINE
342 partition_element *part_elem;
343 partition_element *sub_elem;
344#endif
345 MRN_DBUG_ENTER_FUNCTION();
346#ifdef WITH_PARTITION_STORAGE_ENGINE
347 mrn_get_partition_info(share->table_name, share->table_name_length, table,
348 &part_elem, &sub_elem);
349#endif
350#ifdef WITH_PARTITION_STORAGE_ENGINE
351 for (i = 4; i > 0; i--)
352#else
353 for (i = 2; i > 0; i--)
354#endif
355 {
356 const char *params_string_value = NULL;
357 uint params_string_length = 0;
358 switch (i)
359 {
360#ifdef WITH_PARTITION_STORAGE_ENGINE
361 case 4:
362 if (!sub_elem || !sub_elem->part_comment)
363 continue;
364 DBUG_PRINT("info", ("mroonga create sub comment string"));
365 params_string_value = sub_elem->part_comment;
366 params_string_length = strlen(params_string_value);
367 DBUG_PRINT("info",
368 ("mroonga sub comment string=%s", params_string_value));
369 break;
370 case 3:
371 if (!part_elem || !part_elem->part_comment)
372 continue;
373 DBUG_PRINT("info", ("mroonga create part comment string"));
374 params_string_value = part_elem->part_comment;
375 params_string_length = strlen(params_string_value);
376 DBUG_PRINT("info",
377 ("mroonga part comment string=%s", params_string_value));
378 break;
379#endif
380 case 2:
381 if (LEX_STRING_IS_EMPTY(table->s->comment))
382 continue;
383 DBUG_PRINT("info", ("mroonga create comment string"));
384 params_string_value = table->s->comment.str;
385 params_string_length = table->s->comment.length;
386 DBUG_PRINT("info",
387 ("mroonga comment string=%.*s",
388 params_string_length, params_string_value));
389 break;
390 default:
391 if (LEX_STRING_IS_EMPTY(table->s->connect_string))
392 continue;
393 DBUG_PRINT("info", ("mroonga create connect_string string"));
394 params_string_value = table->s->connect_string.str;
395 params_string_length = table->s->connect_string.length;
396 DBUG_PRINT("info",
397 ("mroonga connect_string=%.*s",
398 params_string_length, params_string_value));
399 break;
400 }
401
402 if (!params_string_value) {
403 continue;
404 }
405
406 {
407 params_string = mrn_my_strndup(params_string_value,
408 params_string_length,
409 MYF(MY_WME));
410 if (!params_string) {
411 error = HA_ERR_OUT_OF_MEM;
412 goto error;
413 }
414
415 sprit_ptr[0] = params_string;
416 while (sprit_ptr[0])
417 {
418 if ((sprit_ptr[1] = strchr(sprit_ptr[0], ',')))
419 {
420 sprit_ptr[1]++;
421 }
422 tmp_ptr = sprit_ptr[0];
423 sprit_ptr[0] = sprit_ptr[1];
424 while (*tmp_ptr == ' ' || *tmp_ptr == '\r' ||
425 *tmp_ptr == '\n' || *tmp_ptr == '\t')
426 tmp_ptr++;
427
428 if (*tmp_ptr == '\0')
429 continue;
430
431 DBUG_PRINT("info", ("mroonga title_str=%s", tmp_ptr));
432 title_length = 0;
433 start_ptr = tmp_ptr;
434 while (*start_ptr != ' ' && *start_ptr != '\'' &&
435 *start_ptr != '"' && *start_ptr != '\0' &&
436 *start_ptr != '\r' && *start_ptr != '\n' &&
437 *start_ptr != '\t' && *start_ptr != ',')
438 {
439 title_length++;
440 start_ptr++;
441 }
442 DBUG_PRINT("info", ("mroonga title_length=%u", title_length));
443
444 switch (title_length)
445 {
446 case 6:
447 MRN_PARAM_STR("engine", engine);
448 break;
449 case 10:
450 MRN_PARAM_STR("normalizer", normalizer);
451 break;
452 case 13:
453 MRN_PARAM_STR("token_filters", token_filters);
454 break;
455 case 17:
456 MRN_PARAM_STR("default_tokenizer", default_tokenizer);
457 break;
458 default:
459 break;
460 }
461 }
462
463 my_free(params_string);
464 params_string = NULL;
465 }
466 }
467
468 if (!share->engine && mrn_default_wrapper_engine)
469 {
470 share->engine_length = strlen(mrn_default_wrapper_engine);
471 if (
472 !(share->engine = mrn_my_strndup(mrn_default_wrapper_engine,
473 share->engine_length,
474 MYF(MY_WME)))
475 ) {
476 error = HA_ERR_OUT_OF_MEM;
477 goto error;
478 }
479 }
480
481 if (share->engine)
482 {
483 LEX_CSTRING engine_name;
484 if (
485 (
486 share->engine_length == MRN_DEFAULT_LEN &&
487 !strncasecmp(share->engine, MRN_DEFAULT_STR, MRN_DEFAULT_LEN)
488 ) ||
489 (
490 share->engine_length == MRN_GROONGA_LEN &&
491 !strncasecmp(share->engine, MRN_GROONGA_STR, MRN_GROONGA_LEN)
492 )
493 ) {
494 my_free(share->engine);
495 share->engine = NULL;
496 share->engine_length = 0;
497 } else {
498 engine_name.str = share->engine;
499 engine_name.length = share->engine_length;
500 if (!(share->plugin = MRN_HA_RESOLVE_BY_NAME(&engine_name)))
501 {
502 my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), share->engine);
503 error = ER_UNKNOWN_STORAGE_ENGINE;
504 goto error;
505 }
506 share->hton = MRN_PLUGIN_DATA(share->plugin, handlerton *);
507 share->wrapper_mode = TRUE;
508 }
509 }
510
511error:
512 if (params_string)
513 my_free(params_string);
514 DBUG_RETURN(error);
515}
516
517bool mrn_is_geo_key(const KEY *key_info)
518{
519 return key_info->algorithm == HA_KEY_ALG_UNDEF &&
520 KEY_N_KEY_PARTS(key_info) == 1 &&
521 key_info->key_part[0].field->type() == MYSQL_TYPE_GEOMETRY;
522}
523
524int mrn_add_index_param(MRN_SHARE *share, KEY *key_info, int i)
525{
526 int error;
527 char *param_string = NULL;
528#if MYSQL_VERSION_ID >= 50500
529 int title_length;
530 char *sprit_ptr[2];
531 char *tmp_ptr, *start_ptr;
532#endif
533 THD *thd = current_thd;
534 MRN_DBUG_ENTER_FUNCTION();
535
536#if MYSQL_VERSION_ID >= 50500
537 if (key_info->comment.length == 0)
538 {
539 if (share->key_tokenizer[i]) {
540 my_free(share->key_tokenizer[i]);
541 }
542 share->key_tokenizer[i] = mrn_my_strdup(mrn_default_tokenizer, MYF(MY_WME));
543 if (!share->key_tokenizer[i]) {
544 error = HA_ERR_OUT_OF_MEM;
545 goto error;
546 }
547 share->key_tokenizer_length[i] = strlen(share->key_tokenizer[i]);
548
549 DBUG_RETURN(0);
550 }
551 DBUG_PRINT("info", ("mroonga create comment string"));
552 if (
553 !(param_string = mrn_my_strndup(key_info->comment.str,
554 key_info->comment.length,
555 MYF(MY_WME)))
556 ) {
557 error = HA_ERR_OUT_OF_MEM;
558 goto error_alloc_param_string;
559 }
560 DBUG_PRINT("info", ("mroonga comment string=%s", param_string));
561
562 sprit_ptr[0] = param_string;
563 while (sprit_ptr[0])
564 {
565 if ((sprit_ptr[1] = strchr(sprit_ptr[0], ',')))
566 {
567 *sprit_ptr[1] = '\0';
568 sprit_ptr[1]++;
569 }
570 tmp_ptr = sprit_ptr[0];
571 sprit_ptr[0] = sprit_ptr[1];
572 while (*tmp_ptr == ' ' || *tmp_ptr == '\r' ||
573 *tmp_ptr == '\n' || *tmp_ptr == '\t')
574 tmp_ptr++;
575
576 if (*tmp_ptr == '\0')
577 continue;
578
579 title_length = 0;
580 start_ptr = tmp_ptr;
581 while (*start_ptr != ' ' && *start_ptr != '\'' &&
582 *start_ptr != '"' && *start_ptr != '\0' &&
583 *start_ptr != '\r' && *start_ptr != '\n' &&
584 *start_ptr != '\t')
585 {
586 title_length++;
587 start_ptr++;
588 }
589
590 switch (title_length)
591 {
592 case 5:
593 MRN_PARAM_STR_LIST("table", index_table, i);
594 break;
595 case 6:
596 push_warning_printf(thd, MRN_SEVERITY_WARNING,
597 ER_WARN_DEPRECATED_SYNTAX,
598 ER(ER_WARN_DEPRECATED_SYNTAX),
599 "parser", "tokenizer");
600 MRN_PARAM_STR_LIST("parser", key_tokenizer, i);
601 break;
602 case 9:
603 MRN_PARAM_STR_LIST("tokenizer", key_tokenizer, i);
604 break;
605 default:
606 break;
607 }
608 }
609#endif
610 if (!share->key_tokenizer[i]) {
611 share->key_tokenizer[i] = mrn_my_strdup(mrn_default_tokenizer, MYF(MY_WME));
612 if (!share->key_tokenizer[i]) {
613 error = HA_ERR_OUT_OF_MEM;
614 goto error;
615 }
616 share->key_tokenizer_length[i] = strlen(share->key_tokenizer[i]);
617 }
618
619 if (param_string)
620 my_free(param_string);
621 DBUG_RETURN(0);
622
623error:
624 if (param_string)
625 my_free(param_string);
626#if MYSQL_VERSION_ID >= 50500
627error_alloc_param_string:
628#endif
629 DBUG_RETURN(error);
630}
631
632int mrn_parse_index_param(MRN_SHARE *share, TABLE *table)
633{
634 int error;
635 MRN_DBUG_ENTER_FUNCTION();
636 for (uint i = 0; i < table->s->keys; i++)
637 {
638 KEY *key_info = &table->s->key_info[i];
639 bool is_wrapper_mode = share->engine != NULL;
640
641 if (is_wrapper_mode) {
642 if (!(key_info->flags & HA_FULLTEXT) && !mrn_is_geo_key(key_info)) {
643 continue;
644 }
645 }
646
647 if ((error = mrn_add_index_param(share, key_info, i)))
648 goto error;
649 }
650 DBUG_RETURN(0);
651
652error:
653 DBUG_RETURN(error);
654}
655
656int mrn_add_column_param(MRN_SHARE *share, Field *field, int i)
657{
658 int error;
659 char *param_string = NULL;
660 int title_length;
661 char *sprit_ptr[2];
662 char *tmp_ptr, *start_ptr;
663
664 MRN_DBUG_ENTER_FUNCTION();
665
666 if (share->wrapper_mode) {
667 DBUG_RETURN(0);
668 }
669
670 DBUG_PRINT("info", ("mroonga create comment string"));
671 if (
672 !(param_string = mrn_my_strndup(field->comment.str,
673 field->comment.length,
674 MYF(MY_WME)))
675 ) {
676 error = HA_ERR_OUT_OF_MEM;
677 goto error_alloc_param_string;
678 }
679 DBUG_PRINT("info", ("mroonga comment string=%s", param_string));
680
681 sprit_ptr[0] = param_string;
682 while (sprit_ptr[0])
683 {
684 if ((sprit_ptr[1] = strchr(sprit_ptr[0], ',')))
685 {
686 *sprit_ptr[1] = '\0';
687 sprit_ptr[1]++;
688 }
689 tmp_ptr = sprit_ptr[0];
690 sprit_ptr[0] = sprit_ptr[1];
691 while (*tmp_ptr == ' ' || *tmp_ptr == '\r' ||
692 *tmp_ptr == '\n' || *tmp_ptr == '\t')
693 tmp_ptr++;
694
695 if (*tmp_ptr == '\0')
696 continue;
697
698 title_length = 0;
699 start_ptr = tmp_ptr;
700 while (*start_ptr != ' ' && *start_ptr != '\'' &&
701 *start_ptr != '"' && *start_ptr != '\0' &&
702 *start_ptr != '\r' && *start_ptr != '\n' &&
703 *start_ptr != '\t')
704 {
705 title_length++;
706 start_ptr++;
707 }
708
709 switch (title_length)
710 {
711 case 4:
712 MRN_PARAM_STR_LIST("type", col_type, i);
713 break;
714 case 5:
715 MRN_PARAM_STR_LIST("flags", col_flags, i);
716 break;
717 case 12:
718 MRN_PARAM_STR_LIST("groonga_type", col_type, i);
719 break;
720 default:
721 break;
722 }
723 }
724
725 if (param_string)
726 my_free(param_string);
727 DBUG_RETURN(0);
728
729error:
730 if (param_string)
731 my_free(param_string);
732error_alloc_param_string:
733 DBUG_RETURN(error);
734}
735
736int mrn_parse_column_param(MRN_SHARE *share, TABLE *table)
737{
738 int error;
739 MRN_DBUG_ENTER_FUNCTION();
740 for (uint i = 0; i < table->s->fields; i++)
741 {
742 Field *field = table->s->field[i];
743
744 if (LEX_STRING_IS_EMPTY(field->comment)) {
745 continue;
746 }
747
748 if ((error = mrn_add_column_param(share, field, i)))
749 goto error;
750 }
751 DBUG_RETURN(0);
752
753error:
754 DBUG_RETURN(error);
755}
756
757int mrn_free_share_alloc(
758 MRN_SHARE *share
759) {
760 uint i;
761 MRN_DBUG_ENTER_FUNCTION();
762 if (share->engine)
763 my_free(share->engine);
764 if (share->default_tokenizer)
765 my_free(share->default_tokenizer);
766 if (share->normalizer)
767 my_free(share->normalizer);
768 if (share->token_filters)
769 my_free(share->token_filters);
770 for (i = 0; i < share->table_share->keys; i++)
771 {
772 if (share->index_table && share->index_table[i])
773 my_free(share->index_table[i]);
774 if (share->key_tokenizer[i])
775 my_free(share->key_tokenizer[i]);
776 }
777 for (i = 0; i < share->table_share->fields; i++)
778 {
779 if (share->col_flags && share->col_flags[i])
780 my_free(share->col_flags[i]);
781 if (share->col_type && share->col_type[i])
782 my_free(share->col_type[i]);
783 }
784 DBUG_RETURN(0);
785}
786
787void mrn_free_long_term_share(MRN_LONG_TERM_SHARE *long_term_share)
788{
789 MRN_DBUG_ENTER_FUNCTION();
790 {
791 mrn::Lock lock(&mrn_long_term_share_mutex);
792 my_hash_delete(&mrn_long_term_share, (uchar*) long_term_share);
793 }
794 mysql_mutex_destroy(&long_term_share->auto_inc_mutex);
795 my_free(long_term_share);
796 DBUG_VOID_RETURN;
797}
798
799MRN_LONG_TERM_SHARE *mrn_get_long_term_share(const char *table_name,
800 uint table_name_length,
801 int *error)
802{
803 MRN_LONG_TERM_SHARE *long_term_share;
804 char *tmp_name;
805 MRN_DBUG_ENTER_FUNCTION();
806 DBUG_PRINT("info", ("mroonga: table_name=%s", table_name));
807 mrn::Lock lock(&mrn_long_term_share_mutex);
808 if (!(long_term_share = (MRN_LONG_TERM_SHARE*)
809 my_hash_search(&mrn_long_term_share, (uchar*) table_name,
810 table_name_length)))
811 {
812 if (!(long_term_share = (MRN_LONG_TERM_SHARE *)
813 mrn_my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
814 &long_term_share, sizeof(*long_term_share),
815 &tmp_name, table_name_length + 1,
816 NullS))
817 ) {
818 *error = HA_ERR_OUT_OF_MEM;
819 goto error_alloc_long_term_share;
820 }
821 long_term_share->table_name = tmp_name;
822 long_term_share->table_name_length = table_name_length;
823 memcpy(long_term_share->table_name, table_name, table_name_length);
824 if (mysql_mutex_init(mrn_long_term_share_auto_inc_mutex_key,
825 &long_term_share->auto_inc_mutex,
826 MY_MUTEX_INIT_FAST) != 0)
827 {
828 *error = HA_ERR_OUT_OF_MEM;
829 goto error_init_auto_inc_mutex;
830 }
831 if (my_hash_insert(&mrn_long_term_share, (uchar*) long_term_share))
832 {
833 *error = HA_ERR_OUT_OF_MEM;
834 goto error_hash_insert;
835 }
836 }
837 DBUG_RETURN(long_term_share);
838
839error_hash_insert:
840 mysql_mutex_destroy(&long_term_share->auto_inc_mutex);
841error_init_auto_inc_mutex:
842 my_free(long_term_share);
843error_alloc_long_term_share:
844 DBUG_RETURN(NULL);
845}
846
847MRN_SHARE *mrn_get_share(const char *table_name, TABLE *table, int *error)
848{
849 MRN_SHARE *share;
850 char *tmp_name, **index_table, **key_tokenizer, **col_flags, **col_type;
851 uint length, *wrap_key_nr, *index_table_length;
852 uint *key_tokenizer_length, *col_flags_length, *col_type_length, i, j;
853 KEY *wrap_key_info;
854 TABLE_SHARE *wrap_table_share;
855 MRN_DBUG_ENTER_FUNCTION();
856 length = (uint) strlen(table_name);
857 mrn::Lock lock(&mrn_open_tables_mutex);
858 if (!(share = (MRN_SHARE*) my_hash_search(&mrn_open_tables,
859 (uchar*) table_name, length)))
860 {
861 if (!(share = (MRN_SHARE *)
862 mrn_my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
863 &share, sizeof(*share),
864 &tmp_name, length + 1,
865 &index_table, sizeof(char *) * table->s->keys,
866 &index_table_length, sizeof(uint) * table->s->keys,
867 &key_tokenizer, sizeof(char *) * table->s->keys,
868 &key_tokenizer_length, sizeof(uint) * table->s->keys,
869 &col_flags, sizeof(char *) * table->s->fields,
870 &col_flags_length, sizeof(uint) * table->s->fields,
871 &col_type, sizeof(char *) * table->s->fields,
872 &col_type_length, sizeof(uint) * table->s->fields,
873 &wrap_key_nr, sizeof(*wrap_key_nr) * table->s->keys,
874 &wrap_key_info, sizeof(*wrap_key_info) * table->s->keys,
875 &wrap_table_share, sizeof(*wrap_table_share),
876 NullS))
877 ) {
878 *error = HA_ERR_OUT_OF_MEM;
879 goto error_alloc_share;
880 }
881 share->use_count = 0;
882 share->table_name_length = length;
883 share->table_name = tmp_name;
884 share->index_table = index_table;
885 share->index_table_length = index_table_length;
886 share->key_tokenizer = key_tokenizer;
887 share->key_tokenizer_length = key_tokenizer_length;
888 share->col_flags = col_flags;
889 share->col_flags_length = col_flags_length;
890 share->col_type = col_type;
891 share->col_type_length = col_type_length;
892 mrn_my_stpmov(share->table_name, table_name);
893 share->table_share = table->s;
894
895 if (
896 (*error = mrn_parse_table_param(share, table)) ||
897 (*error = mrn_parse_column_param(share, table)) ||
898 (*error = mrn_parse_index_param(share, table))
899 )
900 goto error_parse_table_param;
901
902 if (share->wrapper_mode)
903 {
904 j = 0;
905 for (i = 0; i < table->s->keys; i++)
906 {
907 if (table->s->key_info[i].algorithm != HA_KEY_ALG_FULLTEXT &&
908 !mrn_is_geo_key(&table->s->key_info[i]))
909 {
910 wrap_key_nr[i] = j;
911 memcpy(&wrap_key_info[j], &table->s->key_info[i],
912 sizeof(*wrap_key_info));
913 j++;
914 } else {
915 wrap_key_nr[i] = MAX_KEY;
916 }
917 }
918 share->wrap_keys = j;
919 share->base_keys = table->s->keys;
920 share->base_key_info = table->s->key_info;
921 share->base_primary_key = table->s->primary_key;
922 if (i)
923 {
924 share->wrap_key_nr = wrap_key_nr;
925 share->wrap_key_info = wrap_key_info;
926 if (table->s->primary_key == MAX_KEY)
927 share->wrap_primary_key = MAX_KEY;
928 else
929 share->wrap_primary_key = wrap_key_nr[table->s->primary_key];
930 } else {
931 share->wrap_key_nr = NULL;
932 share->wrap_key_info = NULL;
933 share->wrap_primary_key = MAX_KEY;
934 }
935 memcpy(wrap_table_share, table->s, sizeof(*wrap_table_share));
936 mrn_init_sql_alloc(current_thd, &(wrap_table_share->mem_root));
937 wrap_table_share->keys = share->wrap_keys;
938 wrap_table_share->key_info = share->wrap_key_info;
939 wrap_table_share->primary_key = share->wrap_primary_key;
940 wrap_table_share->keys_in_use.init(share->wrap_keys);
941 wrap_table_share->keys_for_keyread.init(share->wrap_keys);
942#ifdef MRN_TABLE_SHARE_HAVE_LOCK_SHARE
943# ifdef WIN32
944 mysql_mutex_init(*mrn_table_share_lock_share,
945 &(wrap_table_share->LOCK_share), MY_MUTEX_INIT_SLOW);
946# else
947 mysql_mutex_init(key_TABLE_SHARE_LOCK_share,
948 &(wrap_table_share->LOCK_share), MY_MUTEX_INIT_SLOW);
949# endif
950#endif
951#ifdef WIN32
952 mysql_mutex_init(*mrn_table_share_lock_ha_data,
953 &(wrap_table_share->LOCK_ha_data), MY_MUTEX_INIT_FAST);
954#else
955 mysql_mutex_init(key_TABLE_SHARE_LOCK_ha_data,
956 &(wrap_table_share->LOCK_ha_data), MY_MUTEX_INIT_FAST);
957#endif
958 share->wrap_table_share = wrap_table_share;
959 }
960
961 if (mysql_mutex_init(mrn_share_mutex_key,
962 &share->record_mutex,
963 MY_MUTEX_INIT_FAST) != 0)
964 {
965 *error = HA_ERR_OUT_OF_MEM;
966 goto error_init_mutex;
967 }
968 thr_lock_init(&share->lock);
969 if (!(share->long_term_share = mrn_get_long_term_share(table_name, length,
970 error)))
971 {
972 goto error_get_long_term_share;
973 }
974 if (my_hash_insert(&mrn_open_tables, (uchar*) share))
975 {
976 *error = HA_ERR_OUT_OF_MEM;
977 goto error_hash_insert;
978 }
979 }
980 share->use_count++;
981 DBUG_RETURN(share);
982
983error_hash_insert:
984error_get_long_term_share:
985 mysql_mutex_destroy(&share->record_mutex);
986error_init_mutex:
987error_parse_table_param:
988 mrn_free_share_alloc(share);
989 my_free(share);
990error_alloc_share:
991 DBUG_RETURN(NULL);
992}
993
994int mrn_free_share(MRN_SHARE *share)
995{
996 MRN_DBUG_ENTER_FUNCTION();
997 mrn::Lock lock(&mrn_open_tables_mutex);
998 if (!--share->use_count)
999 {
1000 my_hash_delete(&mrn_open_tables, (uchar*) share);
1001 if (share->wrapper_mode)
1002 plugin_unlock(NULL, share->plugin);
1003 mrn_free_share_alloc(share);
1004 thr_lock_delete(&share->lock);
1005 mysql_mutex_destroy(&share->record_mutex);
1006 if (share->wrapper_mode) {
1007#ifdef MRN_TABLE_SHARE_HAVE_LOCK_SHARE
1008 mysql_mutex_destroy(&(share->wrap_table_share->LOCK_share));
1009#endif
1010 mysql_mutex_destroy(&(share->wrap_table_share->LOCK_ha_data));
1011 free_root(&(share->wrap_table_share->mem_root), MYF(0));
1012 }
1013 my_free(share);
1014 }
1015 DBUG_RETURN(0);
1016}
1017
1018TABLE_SHARE *mrn_get_table_share(TABLE_LIST *table_list, int *error)
1019{
1020 TABLE_SHARE *share;
1021 THD *thd = current_thd;
1022 MRN_DBUG_ENTER_FUNCTION();
1023#if defined(MRN_HAVE_TDC_ACQUIRE_SHARE) && \
1024 !defined(MRN_TDC_ACQUIRE_SHARE_REQUIRE_KEY)
1025 share = tdc_acquire_share(thd, table_list, GTS_TABLE);
1026#else
1027 uint key_length;
1028# ifdef MRN_HAVE_GET_TABLE_DEF_KEY
1029 const char *key;
1030 key_length = get_table_def_key(table_list, &key);
1031# else
1032 char key[MAX_DBKEY_LENGTH];
1033 key_length = create_table_def_key(thd, key, table_list, FALSE);
1034# endif
1035# ifdef MRN_HAVE_TABLE_DEF_CACHE
1036 my_hash_value_type hash_value;
1037 hash_value = my_calc_hash(mrn_table_def_cache, (uchar*) key, key_length);
1038 share = get_table_share(thd, table_list, key, key_length, 0, error,
1039 hash_value);
1040# elif defined(MRN_HAVE_TDC_ACQUIRE_SHARE)
1041 share = tdc_acquire_share(thd, table_list, GTS_TABLE);
1042# else
1043 share = get_table_share(thd, table_list, key, key_length, 0, error);
1044# endif
1045#endif
1046 DBUG_RETURN(share);
1047}
1048
1049TABLE_SHARE *mrn_create_tmp_table_share(TABLE_LIST *table_list, const char *path,
1050 int *error)
1051{
1052 uint key_length;
1053 TABLE_SHARE *share;
1054 THD *thd = current_thd;
1055
1056 MRN_DBUG_ENTER_FUNCTION();
1057#ifdef MRN_HAVE_GET_TABLE_DEF_KEY
1058 const char *key;
1059 key_length = get_table_def_key(table_list, &key);
1060#else
1061 char key[MAX_DBKEY_LENGTH];
1062 key_length = create_table_def_key(thd, key, table_list, FALSE);
1063#endif
1064#if MYSQL_VERSION_ID >= 100002 && defined(MRN_MARIADB_P)
1065 share = alloc_table_share(table_list->db.str, table_list->table_name.str, key,
1066 key_length);
1067#else
1068 share = alloc_table_share(table_list, key, key_length);
1069#endif
1070 if (!share)
1071 {
1072 *error = ER_CANT_OPEN_FILE;
1073 DBUG_RETURN(NULL);
1074 }
1075 share->tmp_table = NO_TMP_TABLE; // TODO: is this right?
1076 share->path.str = (char *) path;
1077 share->path.length = strlen(share->path.str);
1078 share->normalized_path.str = mrn_my_strdup(path, MYF(MY_WME));
1079 share->normalized_path.length = strlen(share->normalized_path.str);
1080 if (open_table_def(thd, share, GTS_TABLE))
1081 {
1082 *error = ER_CANT_OPEN_FILE;
1083 DBUG_RETURN(NULL);
1084 }
1085 DBUG_RETURN(share);
1086}
1087
1088void mrn_free_tmp_table_share(TABLE_SHARE *tmp_table_share)
1089{
1090 MRN_DBUG_ENTER_FUNCTION();
1091 const char *normalized_path = tmp_table_share->normalized_path.str;
1092 free_table_share(tmp_table_share);
1093 my_free((char*) normalized_path);
1094 DBUG_VOID_RETURN;
1095}
1096
1097KEY *mrn_create_key_info_for_table(MRN_SHARE *share, TABLE *table, int *error)
1098{
1099 uint *wrap_key_nr = share->wrap_key_nr, i, j;
1100 KEY *wrap_key_info;
1101 MRN_DBUG_ENTER_FUNCTION();
1102 if (share->wrap_keys)
1103 {
1104 if (!(wrap_key_info = (KEY *)
1105 mrn_my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
1106 &wrap_key_info, sizeof(*wrap_key_info) * share->wrap_keys,
1107 NullS))
1108 ) {
1109 *error = HA_ERR_OUT_OF_MEM;
1110 DBUG_RETURN(NULL);
1111 }
1112 for (i = 0; i < table->s->keys; i++)
1113 {
1114 j = wrap_key_nr[i];
1115 if (j < MAX_KEY)
1116 {
1117 memcpy(&wrap_key_info[j], &table->key_info[i],
1118 sizeof(*wrap_key_info));
1119 }
1120 }
1121 } else
1122 wrap_key_info = NULL;
1123 *error = 0;
1124 DBUG_RETURN(wrap_key_info);
1125}
1126
1127void mrn_set_bitmap_by_key(MY_BITMAP *map, KEY *key_info)
1128{
1129 uint i;
1130 MRN_DBUG_ENTER_FUNCTION();
1131 for (i = 0; i < KEY_N_KEY_PARTS(key_info); i++)
1132 {
1133 Field *field = key_info->key_part[i].field;
1134 bitmap_set_bit(map, field->field_index);
1135 }
1136 DBUG_VOID_RETURN;
1137}
1138
1139st_mrn_slot_data *mrn_get_slot_data(THD *thd, bool can_create)
1140{
1141 MRN_DBUG_ENTER_FUNCTION();
1142 st_mrn_slot_data *slot_data =
1143 (st_mrn_slot_data*) *thd_ha_data(thd, mrn_hton_ptr);
1144 if (slot_data == NULL) {
1145 slot_data = (st_mrn_slot_data*) malloc(sizeof(st_mrn_slot_data));
1146 slot_data->last_insert_record_id = GRN_ID_NIL;
1147 slot_data->first_wrap_hton = NULL;
1148 slot_data->alter_create_info = NULL;
1149 slot_data->disable_keys_create_info = NULL;
1150 slot_data->alter_connect_string = NULL;
1151 slot_data->alter_comment = NULL;
1152 *thd_ha_data(thd, mrn_hton_ptr) = (void *) slot_data;
1153 {
1154 mrn::Lock lock(&mrn_allocated_thds_mutex);
1155 if (my_hash_insert(&mrn_allocated_thds, (uchar*) thd))
1156 {
1157 free(slot_data);
1158 DBUG_RETURN(NULL);
1159 }
1160 }
1161 }
1162 DBUG_RETURN(slot_data);
1163}
1164
1165void mrn_clear_slot_data(THD *thd)
1166{
1167 MRN_DBUG_ENTER_FUNCTION();
1168 st_mrn_slot_data *slot_data = mrn_get_slot_data(thd, FALSE);
1169 if (slot_data) {
1170 if (slot_data->first_wrap_hton) {
1171 st_mrn_wrap_hton *tmp_wrap_hton;
1172 st_mrn_wrap_hton *wrap_hton = slot_data->first_wrap_hton;
1173 while (wrap_hton)
1174 {
1175 tmp_wrap_hton = wrap_hton->next;
1176 free(wrap_hton);
1177 wrap_hton = tmp_wrap_hton;
1178 }
1179 slot_data->first_wrap_hton = NULL;
1180 }
1181 slot_data->alter_create_info = NULL;
1182 slot_data->disable_keys_create_info = NULL;
1183 if (slot_data->alter_connect_string) {
1184 my_free(slot_data->alter_connect_string);
1185 slot_data->alter_connect_string = NULL;
1186 }
1187 if (slot_data->alter_comment) {
1188 my_free(slot_data->alter_comment);
1189 slot_data->alter_comment = NULL;
1190 }
1191 }
1192 DBUG_VOID_RETURN;
1193}
1194
1195#ifdef __cplusplus
1196}
1197#endif
1198