1 /* -*- c-basic-offset: 2; indent-tabs-mode: nil -*- */
2 /*
3   Copyright(C) 2010 Tetsuro IKEDA
4   Copyright(C) 2010-2013 Kentoku SHIBA
5   Copyright(C) 2011-2017 Kouhei Sutou <kou@clear-code.com>
6   Copyright(C) 2013 Kenji Maruyama <mmmaru777@gmail.com>
7 
8   This library is free software; you can redistribute it and/or
9   modify it under the terms of the GNU Lesser General Public
10   License as published by the Free Software Foundation; either
11   version 2.1 of the License, or (at your option) any later version.
12 
13   This library is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16   Lesser General Public License for more details.
17 
18   You should have received a copy of the GNU Lesser General Public
19   License along with this library; if not, write to the Free Software
20   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1335  USA
21 */
22 
23 #include "mrn_mysql.h"
24 #include "mrn_mysql_compat.h"
25 
26 #ifdef USE_PRAGMA_IMPLEMENTATION
27 #pragma implementation
28 #endif
29 
30 #include <sql_plugin.h>
31 #include <sql_show.h>
32 #include <key.h>
33 #include <tztime.h>
34 #include <sql_base.h>
35 #include <sql_select.h>
36 #include <item_sum.h>
37 
38 #ifdef MRN_HAVE_BINLOG_H
39 #  include <binlog.h>
40 #endif
41 
42 #ifdef MRN_HAVE_SQL_OPTIMIZER_H
43 #  include <sql_optimizer.h>
44 #endif
45 
46 #include <ft_global.h>
47 #include <spatial.h>
48 #include <mysql.h>
49 #include <sys/types.h>
50 #include <sys/stat.h>
51 
52 #ifdef WIN32
53 #  include <math.h>
54 #  include <direct.h>
55 #  define MRN_TABLE_SHARE_LOCK_SHARE_PROC "?key_TABLE_SHARE_LOCK_share@@3IA"
56 #  define MRN_TABLE_SHARE_LOCK_HA_DATA_PROC "?key_TABLE_SHARE_LOCK_ha_data@@3IA"
57 #  ifdef _WIN64
58 #    define MRN_BINLOG_FILTER_PROC "?binlog_filter@@3PEAVRpl_filter@@EA"
59 #    define MRN_MY_TZ_UTC_PROC "?my_tz_UTC@@3PEAVTime_zone@@EA"
60 #  else
61 #    define MRN_BINLOG_FILTER_PROC "?binlog_filter@@3PAVRpl_filter@@A"
62 #    define MRN_MY_TZ_UTC_PROC "?my_tz_UTC@@3PAVTime_zone@@A"
63 #  endif
64 #else
65 #  include <dirent.h>
66 #  include <unistd.h>
67 #endif
68 
69 #include "mrn_err.h"
70 #include "mrn_table.hpp"
71 #include <groonga/plugin.h>
72 #include "ha_mroonga.hpp"
73 #include <mrn_path_mapper.hpp>
74 #include <mrn_index_table_name.hpp>
75 #include <mrn_index_column_name.hpp>
76 #include <mrn_debug_column_access.hpp>
77 #include <mrn_auto_increment_value_lock.hpp>
78 #include <mrn_external_lock.hpp>
79 #include <mrn_match_escalation_threshold_scope.hpp>
80 #include <mrn_multiple_column_key_codec.hpp>
81 #include <mrn_field_normalizer.hpp>
82 #include <mrn_encoding.hpp>
83 #include <mrn_parameters_parser.hpp>
84 #include <mrn_lock.hpp>
85 #include <mrn_condition_converter.hpp>
86 #include <mrn_time_converter.hpp>
87 #include <mrn_smart_grn_obj.hpp>
88 #include <mrn_database_manager.hpp>
89 #include <mrn_context_pool.hpp>
90 #include <mrn_grn.hpp>
91 #include <mrn_value_decoder.hpp>
92 #include <mrn_database_repairer.hpp>
93 #include <mrn_operation.hpp>
94 #include <mrn_column_name.hpp>
95 #include <mrn_count_skip_checker.hpp>
96 #include <mrn_variables.hpp>
97 #include <mrn_query_parser.hpp>
98 #include <mrn_smart_bitmap.hpp>
99 #include <mrn_table_fields_offset_mover.hpp>
100 
101 #ifdef MRN_SUPPORT_FOREIGN_KEYS
102 #  include <sql_table.h>
103 #endif
104 
105 #ifdef MRN_SUPPORT_CUSTOM_OPTIONS
106 #  include <create_options.h>
107 #endif
108 
109 // for debug
110 #define MRN_CLASS_NAME "ha_mroonga"
111 
112 #define MRN_SHORT_TEXT_SIZE (1 << 12) //  4Kbytes
113 #define MRN_TEXT_SIZE       (1 << 16) // 64Kbytes
114 #define MRN_LONG_TEXT_SIZE  (1 << 31) //  2Gbytes
115 
116 #ifdef MRN_HAVE_TDC_LOCK_TABLE_SHARE
117 #  ifdef MRN_TABLE_SHARE_TDC_IS_POINTER
118 #    define mrn_open_mutex(share) &((share)->tdc->LOCK_table_share)
119 #  else
120 #    define mrn_open_mutex(share) &((share)->tdc.LOCK_table_share)
121 #  endif
122 #  define mrn_open_mutex_lock(share) do {               \
123   TABLE_SHARE *share_ = share;                          \
124   if (share_ && share_->tmp_table == NO_TMP_TABLE) {    \
125     mysql_mutex_lock(mrn_open_mutex(share_));           \
126   }                                                     \
127 } while (0)
128 #  define mrn_open_mutex_unlock(share) do {             \
129   TABLE_SHARE *share_ = share;                          \
130   if (share_ && share_->tmp_table == NO_TMP_TABLE) {    \
131     mysql_mutex_unlock(mrn_open_mutex(share_));         \
132   }                                                     \
133 } while (0)
134 #else
135 #  ifdef DBUG_OFF
136 #    ifndef _WIN32
137 extern mysql_mutex_t LOCK_open;
138 #    endif
139 #  endif
140 static mysql_mutex_t *mrn_LOCK_open;
141 #  define mrn_open_mutex_lock(share) mysql_mutex_lock(mrn_LOCK_open)
142 #  define mrn_open_mutex_unlock(share) mysql_mutex_unlock(mrn_LOCK_open)
143 #endif
144 
145 #if MYSQL_VERSION_ID >= 50600
146 #  define MRN_NEED_M_LOCK_TYPE_CHECK_FOR_WRAPPER_EXTERNAL_LOCK
147 #endif
148 
149 #ifdef MRN_MARIADB_P
150 #  if MYSQL_VERSION_ID >= 100200
151 #    define MRN_ORDER_IS_ASC(order) ((order)->direction == ORDER::ORDER_ASC)
152 #  else
153 #    define MRN_ORDER_IS_ASC(order) ((order)->asc)
154 #  endif
155 #else
156 #  if MYSQL_VERSION_ID >= 50603
157 #    define MRN_ORDER_IS_ASC(order) ((order)->direction == ORDER::ORDER_ASC)
158 #  else
159 #    define MRN_ORDER_IS_ASC(order) ((order)->asc)
160 #  endif
161 #endif
162 
163 #define MRN_STRINGIFY(macro_or_string)  MRN_STRINGIFY_ARG(macro_or_string)
164 #define MRN_STRINGIFY_ARG(contents)     #contents
165 
166 #define MRN_PLUGIN_NAME mroonga
167 #define MRN_PLUGIN_NAME_STRING "Mroonga"
168 #define MRN_STATUS_VARIABLE_NAME_PREFIX_STRING "Mroonga"
169 
170 #ifdef MRN_MARIADB_P
171 #  define st_mysql_plugin           st_maria_plugin
172 #  define mrn_declare_plugin(NAME)  maria_declare_plugin(NAME)
173 #  define mrn_declare_plugin_end    maria_declare_plugin_end
174 #  define MRN_PLUGIN_LAST_VALUES    MRN_VERSION, MariaDB_PLUGIN_MATURITY_STABLE
175 #else
176 #  define mrn_declare_plugin(NAME)  mysql_declare_plugin(NAME)
177 #  define mrn_declare_plugin_end    mysql_declare_plugin_end
178 #  define MRN_PLUGIN_LAST_VALUES    NULL, 0
179 #endif
180 
181 #if MYSQL_VERSION_ID >= 100007 && defined(MRN_MARIADB_P)
182 #  define MRN_THD_GET_AUTOINC(thd, off, inc) thd_get_autoinc(thd, off, inc)
183 #  define MRN_GET_ERR_MSG(code) my_get_err_msg(code)
184 #else
185 #  define MRN_THD_GET_AUTOINC(thd, off, inc) \
186      { \
187         *(off) = thd->variables.auto_increment_offset; \
188         *(inc) = thd->variables.auto_increment_increment; \
189      }
190 #  define MRN_GET_ERR_MSG(code) ER(code)
191 #endif
192 
193 #if MYSQL_VERSION_ID >= 50706 && !defined(MRN_MARIADB_P)
194 #  define MRN_LEX_GET_TABLE_LIST(lex) (lex)->select_lex->table_list.first
195 #else
196 #  define MRN_LEX_GET_TABLE_LIST(lex) (lex)->select_lex.table_list.first
197 #endif
198 
199 #if MYSQL_VERSION_ID >= 50706 && !defined(MRN_MARIADB_P)
200 #  define MRN_KEYTYPE_FOREIGN KEYTYPE_FOREIGN
201 #else
202 #  define MRN_KEYTYPE_FOREIGN Key::FOREIGN_KEY
203 #endif
204 
205 #if MYSQL_VERSION_ID >= 50706 && !defined(MRN_MARIADB_P)
206 #  define mrn_calculate_key_len(table, key_index, buffer, keypart_map) \
207   calculate_key_len(table, key_index, keypart_map)
208 #else
209 #  define mrn_calculate_key_len(table, key_index, buffer, keypart_map) \
210   calculate_key_len(table, key_index, buffer, keypart_map)
211 #endif
212 
213 #if MYSQL_VERSION_ID >= 50706 && !defined(MRN_MARIADB_P)
214 #  define MRN_TABLE_LIST_GET_DERIVED(table_list) NULL
215 #else
216 #  define MRN_TABLE_LIST_GET_DERIVED(table_list) (table_list)->derived
217 #endif
218 
219 #if MYSQL_VERSION_ID >= 50706 && !defined(MRN_MARIADB_P)
220 #  define MRN_GEOMETRY_FREE(geometry)
221 #else
222 #  define MRN_GEOMETRY_FREE(geometry) delete (geometry)
223 #endif
224 
225 Rpl_filter *mrn_binlog_filter;
226 Time_zone *mrn_my_tz_UTC;
227 #ifdef MRN_HAVE_TABLE_DEF_CACHE
228 HASH *mrn_table_def_cache;
229 #endif
230 
231 #ifdef MRN_HAVE_PSI_MEMORY_KEY
232 PSI_memory_key mrn_memory_key;
233 
234 static PSI_memory_info mrn_all_memory_keys[]=
235 {
236   {&mrn_memory_key, "Mroonga", 0}
237 };
238 #endif
239 
240 static const char *INDEX_COLUMN_NAME = "index";
241 static const char *MRN_PLUGIN_AUTHOR = "The Mroonga project";
242 
243 #ifdef __cplusplus
244 extern "C" {
245 #endif
246 
247 #ifdef HAVE_PSI_INTERFACE
248 #  ifdef WIN32
249 #    ifdef MRN_TABLE_SHARE_HAVE_LOCK_SHARE
250 PSI_mutex_key *mrn_table_share_lock_share;
251 #    endif
252 PSI_mutex_key *mrn_table_share_lock_ha_data;
253 #  endif
254 static PSI_mutex_key mrn_open_tables_mutex_key;
255 static PSI_mutex_key mrn_long_term_share_mutex_key;
256 static PSI_mutex_key mrn_allocated_thds_mutex_key;
257 PSI_mutex_key mrn_share_mutex_key;
258 PSI_mutex_key mrn_long_term_share_auto_inc_mutex_key;
259 static PSI_mutex_key mrn_log_mutex_key;
260 static PSI_mutex_key mrn_query_log_mutex_key;
261 static PSI_mutex_key mrn_db_manager_mutex_key;
262 static PSI_mutex_key mrn_context_pool_mutex_key;
263 static PSI_mutex_key mrn_operations_mutex_key;
264 
265 #  if (!defined(MRN_MARIADB_P) && MYSQL_VERSION_ID >= 80002)
266 #    define MRN_MUTEXT_INFO_ENTRY(key, name, flags, volatility) \
267   {key, name, flags, volatility}
268 #  else
269 #    define MRN_MUTEXT_INFO_ENTRY(key, name, flags, volatility) \
270   {key, name, flags}
271 #  endif
272 
273 static PSI_mutex_info mrn_mutexes[] =
274 {
275   MRN_MUTEXT_INFO_ENTRY(&mrn_open_tables_mutex_key,
276                         "mrn::open_tables", PSI_FLAG_GLOBAL, 0),
277   MRN_MUTEXT_INFO_ENTRY(&mrn_long_term_share_mutex_key,
278                         "mrn::long_term_share", PSI_FLAG_GLOBAL, 0),
279   MRN_MUTEXT_INFO_ENTRY(&mrn_allocated_thds_mutex_key,
280                         "mrn::allocated_thds", PSI_FLAG_GLOBAL, 0),
281   MRN_MUTEXT_INFO_ENTRY(&mrn_share_mutex_key,
282                         "mrn::share", 0, 0),
283   MRN_MUTEXT_INFO_ENTRY(&mrn_long_term_share_auto_inc_mutex_key,
284                         "mrn::long_term_share::auto_inc", 0, 0),
285   MRN_MUTEXT_INFO_ENTRY(&mrn_log_mutex_key,
286                         "mrn::log", PSI_FLAG_GLOBAL, 0),
287   MRN_MUTEXT_INFO_ENTRY(&mrn_query_log_mutex_key,
288                         "mrn::query_log", PSI_FLAG_GLOBAL, 0),
289   MRN_MUTEXT_INFO_ENTRY(&mrn_db_manager_mutex_key,
290                         "mrn::DatabaseManager", PSI_FLAG_GLOBAL, 0),
291   MRN_MUTEXT_INFO_ENTRY(&mrn_context_pool_mutex_key,
292                         "mrn::ContextPool", PSI_FLAG_GLOBAL, 0),
293   MRN_MUTEXT_INFO_ENTRY(&mrn_operations_mutex_key,
294                         "mrn::Operations", PSI_FLAG_GLOBAL, 0)
295 };
296 #endif
297 
298 /* global variables */
299 handlerton *mrn_hton_ptr;
300 HASH mrn_open_tables;
301 mysql_mutex_t mrn_open_tables_mutex;
302 HASH mrn_long_term_share;
303 mysql_mutex_t mrn_long_term_share_mutex;
304 
305 HASH mrn_allocated_thds;
306 mysql_mutex_t mrn_allocated_thds_mutex;
307 
308 /* internal variables */
309 static grn_ctx mrn_ctx;
310 static mysql_mutex_t mrn_log_mutex;
311 static mysql_mutex_t mrn_query_log_mutex;
312 static grn_obj *mrn_db;
313 static grn_ctx mrn_db_manager_ctx;
314 static mysql_mutex_t mrn_db_manager_mutex;
315 mrn::DatabaseManager *mrn_db_manager = NULL;
316 static mysql_mutex_t mrn_context_pool_mutex;
317 mrn::ContextPool *mrn_context_pool = NULL;
318 static mysql_mutex_t mrn_operations_mutex;
319 
320 
321 #ifdef WIN32
round(double x)322 static inline double round(double x)
323 {
324   return (floor(x + 0.5));
325 }
326 #endif
327 
mrn_init_encoding_map()328 static void mrn_init_encoding_map()
329 {
330   mrn::encoding::init();
331 }
332 
mrn_change_encoding(grn_ctx * ctx,const CHARSET_INFO * charset)333 static int mrn_change_encoding(grn_ctx *ctx, const CHARSET_INFO *charset)
334 {
335   return mrn::encoding::set(ctx, charset);
336 }
337 
338 #if !defined(DBUG_OFF) && !defined(_lint)
mrn_inspect_thr_lock_type(enum thr_lock_type lock_type)339 static const char *mrn_inspect_thr_lock_type(enum thr_lock_type lock_type)
340 {
341   const char *inspected = "<unknown>";
342   switch (lock_type) {
343   case TL_IGNORE:
344     inspected = "TL_IGNORE";
345     break;
346   case TL_UNLOCK:
347     inspected = "TL_UNLOCK";
348     break;
349   case TL_READ_DEFAULT:
350     inspected = "TL_READ_DEFAULT";
351     break;
352   case TL_READ:
353     inspected = "TL_READ";
354     break;
355   case TL_READ_WITH_SHARED_LOCKS:
356     inspected = "TL_READ_WITH_SHARED_LOCKS";
357     break;
358   case TL_READ_HIGH_PRIORITY:
359     inspected = "TL_READ_HIGH_PRIORITY";
360     break;
361   case TL_READ_NO_INSERT:
362     inspected = "TL_READ_NO_INSERT";
363     break;
364   case TL_WRITE_ALLOW_WRITE:
365     inspected = "TL_WRITE_ALLOW_WRITE";
366     break;
367 #ifdef MRN_HAVE_TL_WRITE_CONCURRENT_DEFAULT
368   case TL_WRITE_CONCURRENT_DEFAULT:
369     inspected = "TL_WRITE_CONCURRENT_DEFAULT";
370     break;
371 #endif
372   case TL_WRITE_CONCURRENT_INSERT:
373     inspected = "TL_WRITE_CONCURRENT_INSERT";
374     break;
375 #ifdef MRN_HAVE_TL_WRITE_DELAYED
376   case TL_WRITE_DELAYED:
377     inspected = "TL_WRITE_DELAYED";
378     break;
379 #endif
380   case TL_WRITE_DEFAULT:
381     inspected = "TL_WRITE_DEFAULT";
382     break;
383   case TL_WRITE_LOW_PRIORITY:
384     inspected = "TL_WRITE_LOW_PRIORITY";
385     break;
386   case TL_WRITE:
387     inspected = "TL_WRITE";
388     break;
389   case TL_WRITE_ONLY:
390     inspected = "TL_WRITE_ONLY";
391     break;
392   }
393   return inspected;
394 }
395 
mrn_inspect_extra_function(enum ha_extra_function operation)396 static const char *mrn_inspect_extra_function(enum ha_extra_function operation)
397 {
398   const char *inspected = "<unknown>";
399   switch (operation) {
400   case HA_EXTRA_NORMAL:
401     inspected = "HA_EXTRA_NORMAL";
402     break;
403   case HA_EXTRA_QUICK:
404     inspected = "HA_EXTRA_QUICK";
405     break;
406   case HA_EXTRA_NOT_USED:
407     inspected = "HA_EXTRA_NOT_USED";
408     break;
409   case HA_EXTRA_CACHE:
410     inspected = "HA_EXTRA_CACHE";
411     break;
412   case HA_EXTRA_NO_CACHE:
413     inspected = "HA_EXTRA_NO_CACHE";
414     break;
415   case HA_EXTRA_NO_READCHECK:
416     inspected = "HA_EXTRA_NO_READCHECK";
417     break;
418   case HA_EXTRA_READCHECK:
419     inspected = "HA_EXTRA_READCHECK";
420     break;
421   case HA_EXTRA_KEYREAD:
422     inspected = "HA_EXTRA_KEYREAD";
423     break;
424   case HA_EXTRA_NO_KEYREAD:
425     inspected = "HA_EXTRA_NO_KEYREAD";
426     break;
427   case HA_EXTRA_NO_USER_CHANGE:
428     inspected = "HA_EXTRA_NO_USER_CHANGE";
429     break;
430   case HA_EXTRA_KEY_CACHE:
431     inspected = "HA_EXTRA_KEY_CACHE";
432     break;
433   case HA_EXTRA_NO_KEY_CACHE:
434     inspected = "HA_EXTRA_NO_KEY_CACHE";
435     break;
436   case HA_EXTRA_WAIT_LOCK:
437     inspected = "HA_EXTRA_WAIT_LOCK";
438     break;
439   case HA_EXTRA_NO_WAIT_LOCK:
440     inspected = "HA_EXTRA_NO_WAIT_LOCK";
441     break;
442   case HA_EXTRA_WRITE_CACHE:
443     inspected = "HA_EXTRA_WRITE_CACHE";
444     break;
445   case HA_EXTRA_FLUSH_CACHE:
446     inspected = "HA_EXTRA_FLUSH_CACHE";
447     break;
448   case HA_EXTRA_NO_KEYS:
449     inspected = "HA_EXTRA_NO_KEYS";
450     break;
451   case HA_EXTRA_KEYREAD_CHANGE_POS:
452     inspected = "HA_EXTRA_KEYREAD_CHANGE_POS";
453     break;
454   case HA_EXTRA_REMEMBER_POS:
455     inspected = "HA_EXTRA_REMEMBER_POS";
456     break;
457   case HA_EXTRA_RESTORE_POS:
458     inspected = "HA_EXTRA_RESTORE_POS";
459     break;
460   case HA_EXTRA_REINIT_CACHE:
461     inspected = "HA_EXTRA_REINIT_CACHE";
462     break;
463   case HA_EXTRA_FORCE_REOPEN:
464     inspected = "HA_EXTRA_FORCE_REOPEN";
465     break;
466   case HA_EXTRA_FLUSH:
467     inspected = "HA_EXTRA_FLUSH";
468     break;
469   case HA_EXTRA_NO_ROWS:
470     inspected = "HA_EXTRA_NO_ROWS";
471     break;
472   case HA_EXTRA_RESET_STATE:
473     inspected = "HA_EXTRA_RESET_STATE";
474     break;
475   case HA_EXTRA_IGNORE_DUP_KEY:
476     inspected = "HA_EXTRA_IGNORE_DUP_KEY";
477     break;
478   case HA_EXTRA_NO_IGNORE_DUP_KEY:
479     inspected = "HA_EXTRA_NO_IGNORE_DUP_KEY";
480     break;
481   case HA_EXTRA_PREPARE_FOR_DROP:
482     inspected = "HA_EXTRA_PREPARE_FOR_DROP";
483     break;
484   case HA_EXTRA_PREPARE_FOR_ALTER_TABLE:
485     inspected = "HA_EXTRA_PREPARE_FOR_ALTER_TABLE";
486     break;
487   case HA_EXTRA_PREPARE_FOR_UPDATE:
488     inspected = "HA_EXTRA_PREPARE_FOR_UPDATE";
489     break;
490   case HA_EXTRA_PRELOAD_BUFFER_SIZE:
491     inspected = "HA_EXTRA_PRELOAD_BUFFER_SIZE";
492     break;
493   case HA_EXTRA_CHANGE_KEY_TO_UNIQUE:
494     inspected = "HA_EXTRA_CHANGE_KEY_TO_UNIQUE";
495     break;
496   case HA_EXTRA_CHANGE_KEY_TO_DUP:
497     inspected = "HA_EXTRA_CHANGE_KEY_TO_DUP";
498     break;
499   case HA_EXTRA_KEYREAD_PRESERVE_FIELDS:
500     inspected = "HA_EXTRA_KEYREAD_PRESERVE_FIELDS";
501     break;
502   case HA_EXTRA_MMAP:
503     inspected = "HA_EXTRA_MMAP";
504     break;
505   case HA_EXTRA_IGNORE_NO_KEY:
506     inspected = "HA_EXTRA_IGNORE_NO_KEY";
507     break;
508   case HA_EXTRA_NO_IGNORE_NO_KEY:
509     inspected = "HA_EXTRA_NO_IGNORE_NO_KEY";
510     break;
511   case HA_EXTRA_MARK_AS_LOG_TABLE:
512     inspected = "HA_EXTRA_MARK_AS_LOG_TABLE";
513     break;
514   case HA_EXTRA_WRITE_CAN_REPLACE:
515     inspected = "HA_EXTRA_WRITE_CAN_REPLACE";
516     break;
517   case HA_EXTRA_WRITE_CANNOT_REPLACE:
518     inspected = "HA_EXTRA_WRITE_CANNOT_REPLACE";
519     break;
520   case HA_EXTRA_DELETE_CANNOT_BATCH:
521     inspected = "HA_EXTRA_DELETE_CANNOT_BATCH";
522     break;
523   case HA_EXTRA_UPDATE_CANNOT_BATCH:
524     inspected = "HA_EXTRA_UPDATE_CANNOT_BATCH";
525     break;
526   case HA_EXTRA_INSERT_WITH_UPDATE:
527     inspected = "HA_EXTRA_INSERT_WITH_UPDATE";
528     break;
529   case HA_EXTRA_PREPARE_FOR_RENAME:
530     inspected = "HA_EXTRA_PREPARE_FOR_RENAME";
531     break;
532   case HA_EXTRA_ADD_CHILDREN_LIST:
533     inspected = "HA_EXTRA_ADD_CHILDREN_LIST";
534     break;
535   case HA_EXTRA_ATTACH_CHILDREN:
536     inspected = "HA_EXTRA_ATTACH_CHILDREN";
537     break;
538   case HA_EXTRA_IS_ATTACHED_CHILDREN:
539     inspected = "HA_EXTRA_IS_ATTACHED_CHILDREN";
540     break;
541   case HA_EXTRA_DETACH_CHILDREN:
542     inspected = "HA_EXTRA_DETACH_CHILDREN";
543     break;
544   case HA_EXTRA_STARTING_ORDERED_INDEX_SCAN:
545     inspected = "HA_EXTRA_STARTING_ORDERED_INDEX_SCAN";
546     break;
547   case HA_EXTRA_BEGIN_ALTER_COPY:
548     inspected = "HA_EXTRA_BEGIN_ALTER_COPY";
549     break;
550   case HA_EXTRA_END_ALTER_COPY:
551     inspected = "HA_EXTRA_END_ALTER_COPY";
552     break;
553   case HA_EXTRA_FAKE_START_STMT:
554     inspected = "HA_EXTRA_FAKE_START_STMT";
555     break;
556 #ifdef MRN_HAVE_HA_EXTRA_EXPORT
557   case HA_EXTRA_EXPORT:
558     inspected = "HA_EXTRA_EXPORT";
559     break;
560 #endif
561 #ifdef MRN_HAVE_HA_EXTRA_SECONDARY_SORT_ROWID
562   case HA_EXTRA_SECONDARY_SORT_ROWID:
563     inspected = "HA_EXTRA_SECONDARY_SORT_ROWID";
564     break;
565 #endif
566 #ifdef MRN_HAVE_HA_EXTRA_DETACH_CHILD
567   case HA_EXTRA_DETACH_CHILD:
568     inspected = "HA_EXTRA_DETACH_CHILD";
569     break;
570 #endif
571 #ifdef MRN_HAVE_HA_EXTRA_PREPARE_FOR_FORCED_CLOSE
572   case HA_EXTRA_PREPARE_FOR_FORCED_CLOSE:
573     inspected = "HA_EXTRA_PREPARE_FOR_FORCED_CLOSE";
574     break;
575 #endif
576 #ifdef MRN_HAVE_HA_EXTRA_SKIP_SERIALIZABLE_DD_VIEW
577   case HA_EXTRA_SKIP_SERIALIZABLE_DD_VIEW:
578     inspected = "HA_EXTRA_SKIP_SERIALIZABLE_DD_VIEW";
579     break;
580 #endif
581 #ifdef MRN_HAVE_HA_EXTRA_BEGIN_ALTER_COPY
582   case HA_EXTRA_BEGIN_ALTER_COPY:
583     inspected = "HA_EXTRA_BEGIN_ALTER_COPY";
584     break;
585 #endif
586 #ifdef MRN_HAVE_HA_EXTRA_END_ALTER_COPY
587   case HA_EXTRA_END_ALTER_COPY:
588     inspected = "HA_EXTRA_END_ALTER_COPY";
589     break;
590 #endif
591 #ifdef MRN_HAVE_HA_EXTRA_NO_AUTOINC_LOCKING
592   case HA_EXTRA_NO_AUTOINC_LOCKING:
593     inspected = "HA_EXTRA_NO_AUTOINC_LOCKING";
594     break;
595 #endif
596   }
597   return inspected;
598 }
599 #endif
600 
mrn_open_tables_get_key(const uchar * record,size_t * length,my_bool not_used)601 static uchar *mrn_open_tables_get_key(const uchar *record,
602                                       size_t *length,
603                                       my_bool not_used __attribute__ ((unused)))
604 {
605   MRN_DBUG_ENTER_FUNCTION();
606   MRN_SHARE *share = reinterpret_cast<MRN_SHARE *>(const_cast<uchar *>(record));
607   *length = share->table_name_length;
608   DBUG_RETURN(reinterpret_cast<uchar *>(share->table_name));
609 }
610 
mrn_long_term_share_get_key(const uchar * record,size_t * length,my_bool not_used)611 static uchar *mrn_long_term_share_get_key(const uchar *record,
612                                           size_t *length,
613                                           my_bool not_used __attribute__ ((unused)))
614 {
615   MRN_DBUG_ENTER_FUNCTION();
616   MRN_LONG_TERM_SHARE *long_term_share =
617     reinterpret_cast<MRN_LONG_TERM_SHARE *>(const_cast<uchar *>(record));
618   *length = long_term_share->table_name_length;
619   DBUG_RETURN(reinterpret_cast<uchar *>(long_term_share->table_name));
620 }
621 
622 /* status */
623 static long mrn_count_skip = 0;
624 static long mrn_fast_order_limit = 0;
625 
626 /* logging */
627 static char *mrn_log_file_path = NULL;
628 static FILE *mrn_log_file = NULL;
629 static bool mrn_log_file_opened = false;
630 static grn_log_level mrn_log_level_default = GRN_LOG_DEFAULT_LEVEL;
631 static ulong mrn_log_level = mrn_log_level_default;
632 static char *mrn_query_log_file_path = NULL;
633 
634 char *mrn_default_tokenizer = NULL;
635 char *mrn_default_wrapper_engine = NULL;
636 static int mrn_lock_timeout = grn_get_lock_timeout();
637 static char *mrn_libgroonga_version = const_cast<char *>(grn_get_version());
638 static char *mrn_version = const_cast<char *>(MRN_VERSION);
639 static char *mrn_vector_column_delimiter = NULL;
640 static mrn_bool mrn_libgroonga_support_zlib = false;
641 static mrn_bool mrn_libgroonga_support_lz4 = false;
642 static mrn_bool mrn_libgroonga_support_zstd = false;
643 static mrn_bool mrn_enable_operations_recording = true;
644 #ifdef MRN_SUPPORT_THDVAR_SET
645 static const char *mrn_boolean_mode_sytnax_flag_names[] = {
646   "DEFAULT",
647   "SYNTAX_QUERY",
648   "SYNTAX_SCRIPT",
649   "ALLOW_COLUMN",
650   "ALLOW_UPDATE",
651   "ALLOW_LEADING_NOT",
652   NullS
653 };
654 static TYPELIB mrn_boolean_mode_syntax_flags_typelib = {
655   array_elements(mrn_boolean_mode_sytnax_flag_names) - 1,
656   "",
657   mrn_boolean_mode_sytnax_flag_names,
658   NULL
659 };
660 #endif
661 #ifdef MRN_GROONGA_EMBEDDED
662 static mrn_bool mrn_libgroonga_embedded = true;
663 #else
664 static mrn_bool mrn_libgroonga_embedded = false;
665 #endif
666 
667 static mrn::variables::ActionOnError mrn_action_on_fulltext_query_error_default =
668   mrn::variables::ACTION_ON_ERROR_ERROR_AND_LOG;
669 
mrn_logger_log(grn_ctx * ctx,grn_log_level level,const char * timestamp,const char * title,const char * message,const char * location,void * user_data)670 static void mrn_logger_log(grn_ctx *ctx, grn_log_level level,
671                            const char *timestamp, const char *title,
672                            const char *message, const char *location,
673                            void *user_data)
674 {
675   const char level_marks[] = " EACewnid-";
676   if (mrn_log_file_opened) {
677     mrn::Lock lock(&mrn_log_mutex);
678     fprintf(mrn_log_file,
679             "%s|%c|%08x|%s\n",
680             timestamp,
681             level_marks[level],
682             static_cast<uint>((ulong)(pthread_self())),
683             message);
684     fflush(mrn_log_file);
685   }
686 }
687 
688 static grn_logger mrn_logger = {
689   mrn_log_level_default,
690   GRN_LOG_TIME|GRN_LOG_MESSAGE,
691   NULL,
692   mrn_logger_log,
693   NULL,
694   NULL
695 };
696 
mrn_allocated_thds_get_key(const uchar * record,size_t * length,my_bool not_used)697 static uchar *mrn_allocated_thds_get_key(const uchar *record,
698                                          size_t *length,
699                                          my_bool not_used __attribute__ ((unused)))
700 {
701   MRN_DBUG_ENTER_FUNCTION();
702   *length = sizeof(THD *);
703   DBUG_RETURN(const_cast<uchar *>(record));
704 }
705 
706 /* system functions */
707 
708 static struct st_mysql_storage_engine storage_engine_structure =
709 { MYSQL_HANDLERTON_INTERFACE_VERSION };
710 
711 #if MYSQL_VERSION_ID >= 50706 && !defined(MRN_MARIADB_P)
712 #  define MRN_STATUS_VARIABLE_ENTRY(name, value, type, scope) \
713   {name, value, type, scope}
714 #else
715 #  define MRN_STATUS_VARIABLE_ENTRY(name, value, type, scope) \
716   {name, value, type}
717 #endif
718 
719 static struct st_mysql_show_var mrn_status_variables[] =
720 {
721   MRN_STATUS_VARIABLE_ENTRY(MRN_STATUS_VARIABLE_NAME_PREFIX_STRING "_count_skip",
722                             (char *)&mrn_count_skip,
723                             SHOW_LONG,
724                             SHOW_SCOPE_GLOBAL),
725   MRN_STATUS_VARIABLE_ENTRY(MRN_STATUS_VARIABLE_NAME_PREFIX_STRING "_fast_order_limit",
726                             (char *)&mrn_fast_order_limit,
727                             SHOW_LONG,
728                             SHOW_SCOPE_GLOBAL),
729   MRN_STATUS_VARIABLE_ENTRY(NullS, NullS, SHOW_LONG, SHOW_SCOPE_GLOBAL)
730 };
731 
732 static const char *mrn_log_level_type_names[] = {
733   "NONE",
734   "EMERG",
735   "ALERT",
736   "CRIT",
737   "ERROR",
738   "WARNING",
739   "NOTICE",
740   "INFO",
741   "DEBUG",
742   "DUMP",
743   NullS
744 };
745 static TYPELIB mrn_log_level_typelib = {
746   array_elements(mrn_log_level_type_names) - 1,
747   "mrn_log_level_typelib",
748   mrn_log_level_type_names,
749   NULL
750 };
751 
mrn_log_level_update(THD * thd,struct st_mysql_sys_var * var,void * var_ptr,const void * save)752 static void mrn_log_level_update(THD *thd, struct st_mysql_sys_var *var,
753                                  void *var_ptr, const void *save)
754 {
755   MRN_DBUG_ENTER_FUNCTION();
756   ulong new_value = *static_cast<const ulong *>(save);
757   ulong old_value = mrn_log_level;
758   mrn_log_level = new_value;
759   mrn_logger.max_level = static_cast<grn_log_level>(mrn_log_level);
760   grn_logger_set(&mrn_ctx, &mrn_logger);
761   grn_ctx *ctx = grn_ctx_open(0);
762   mrn_change_encoding(ctx, system_charset_info);
763   GRN_LOG(ctx, GRN_LOG_NOTICE, "log level changed from '%s' to '%s'",
764           mrn_log_level_type_names[old_value],
765           mrn_log_level_type_names[new_value]);
766   grn_ctx_fin(ctx);
767   DBUG_VOID_RETURN;
768 }
769 
770 static MYSQL_SYSVAR_ENUM(log_level, mrn_log_level,
771                          PLUGIN_VAR_RQCMDARG,
772                          "logging level",
773                          NULL,
774                          mrn_log_level_update,
775                          static_cast<ulong>(mrn_log_level),
776                          &mrn_log_level_typelib);
777 
mrn_log_file_update(THD * thd,struct st_mysql_sys_var * var,void * var_ptr,const void * save)778 static void mrn_log_file_update(THD *thd, struct st_mysql_sys_var *var,
779                                 void *var_ptr, const void *save)
780 {
781   MRN_DBUG_ENTER_FUNCTION();
782   const char *new_value = *((const char **)save);
783   char **old_value_ptr = (char **)var_ptr;
784 
785   grn_ctx *ctx = &mrn_ctx;
786   mrn_change_encoding(ctx, system_charset_info);
787 
788   const char *new_log_file_name;
789   new_log_file_name = *old_value_ptr;
790 
791   if (strcmp(*old_value_ptr, new_value) == 0) {
792     GRN_LOG(ctx, GRN_LOG_NOTICE,
793             "log file isn't changed "
794             "because the requested path isn't different: <%s>",
795             new_value);
796   } else {
797     GRN_LOG(ctx, GRN_LOG_NOTICE,
798             "log file is changed: <%s> -> <%s>",
799             *old_value_ptr, new_value);
800 
801     int log_file_open_errno = 0;
802     {
803       mrn::Lock lock(&mrn_log_mutex);
804       FILE *new_log_file;
805       new_log_file = fopen(new_value, "a");
806       if (new_log_file) {
807         if (mrn_log_file_opened) {
808           fclose(mrn_log_file);
809         }
810         mrn_log_file = new_log_file;
811         mrn_log_file_opened = true;
812       } else {
813         log_file_open_errno = errno;
814       }
815     }
816 
817     if (log_file_open_errno == 0) {
818       GRN_LOG(ctx, GRN_LOG_NOTICE,
819               "log file is changed: <%s> -> <%s>",
820               *old_value_ptr, new_value);
821       new_log_file_name = new_value;
822     } else {
823       if (mrn_log_file) {
824         GRN_LOG(ctx, GRN_LOG_ERROR,
825                 "log file isn't changed "
826                 "because the requested path can't be opened: <%s>: <%s>",
827                 new_value, strerror(log_file_open_errno));
828       } else {
829         GRN_LOG(ctx, GRN_LOG_ERROR,
830                 "log file can't be opened: <%s>: <%s>",
831                 new_value, strerror(log_file_open_errno));
832       }
833     }
834   }
835 
836 #ifdef MRN_NEED_FREE_STRING_MEMALLOC_PLUGIN_VAR
837   char *old_log_file_name = *old_value_ptr;
838   *old_value_ptr = mrn_my_strdup(new_log_file_name, MYF(MY_WME));
839   my_free(old_log_file_name);
840 #else
841   *old_value_ptr = mrn_my_strdup(new_log_file_name, MYF(MY_WME));
842 #endif
843 
844   DBUG_VOID_RETURN;
845 }
846 
847 static MYSQL_SYSVAR_STR(log_file, mrn_log_file_path,
848                         PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
849                         "log file for " MRN_PLUGIN_NAME_STRING,
850                         NULL,
851                         mrn_log_file_update,
852                         MRN_LOG_FILE_PATH);
853 
mrn_query_log_file_update(THD * thd,struct st_mysql_sys_var * var,void * var_ptr,const void * save)854 static void mrn_query_log_file_update(THD *thd, struct st_mysql_sys_var *var,
855                                       void *var_ptr, const void *save)
856 {
857   MRN_DBUG_ENTER_FUNCTION();
858   const char *new_value = *((const char **)save);
859   char **old_value_ptr = (char **)var_ptr;
860   const char *normalized_new_value = NULL;
861 
862   grn_ctx *ctx = &mrn_ctx;
863   mrn_change_encoding(ctx, system_charset_info);
864 
865   const char *new_query_log_file_name;
866   new_query_log_file_name = *old_value_ptr;
867 
868   bool need_update = false;
869   if (!*old_value_ptr) {
870     if (new_value && new_value[0] != '\0') {
871       GRN_LOG(ctx, GRN_LOG_NOTICE,
872               "query log is enabled: <%s>",
873               new_value);
874       need_update = true;
875       normalized_new_value = new_value;
876     } else {
877       GRN_LOG(ctx, GRN_LOG_NOTICE,
878               "query log file is still disabled");
879     }
880   } else {
881     if (!new_value || new_value[0] == '\0') {
882       GRN_LOG(ctx, GRN_LOG_NOTICE,
883               "query log file is disabled: <%s>",
884               *old_value_ptr);
885       need_update = true;
886       normalized_new_value = NULL;
887     } else if (strcmp(*old_value_ptr, new_value) == 0) {
888       GRN_LOG(ctx, GRN_LOG_NOTICE,
889               "query log file isn't changed "
890               "because the requested path isn't different: <%s>",
891               new_value);
892     } else {
893       GRN_LOG(ctx, GRN_LOG_NOTICE,
894               "query log file is changed: <%s> -> <%s>",
895               *old_value_ptr, new_value);
896       need_update = true;
897       normalized_new_value = new_value;
898     }
899   }
900 
901   if (need_update) {
902     { // TODO: Remove me when Groonga 7.0.5 is released.
903       mrn::Lock lock(&mrn_query_log_mutex);
904       grn_default_query_logger_set_path(normalized_new_value);
905     }
906     grn_query_logger_reopen(ctx);
907     new_query_log_file_name = normalized_new_value;
908   }
909 
910 #ifdef MRN_NEED_FREE_STRING_MEMALLOC_PLUGIN_VAR
911   char *old_query_log_file_name = *old_value_ptr;
912 #endif
913   if (new_query_log_file_name) {
914     *old_value_ptr = mrn_my_strdup(new_query_log_file_name, MYF(0));
915   } else {
916     *old_value_ptr = NULL;
917   }
918 #ifdef MRN_NEED_FREE_STRING_MEMALLOC_PLUGIN_VAR
919   my_free(old_query_log_file_name);
920 #endif
921 
922   DBUG_VOID_RETURN;
923 }
924 
925 static MYSQL_SYSVAR_STR(query_log_file, mrn_query_log_file_path,
926                         PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
927                         "query log file for " MRN_PLUGIN_NAME_STRING,
928                         NULL,
929                         mrn_query_log_file_update,
930                         NULL);
931 
mrn_default_tokenizer_update(THD * thd,struct st_mysql_sys_var * var,void * var_ptr,const void * save)932 static void mrn_default_tokenizer_update(THD *thd, struct st_mysql_sys_var *var,
933                                          void *var_ptr, const void *save)
934 {
935   MRN_DBUG_ENTER_FUNCTION();
936   const char *new_value = *((const char **)save);
937   char **old_value_ptr = (char **)var_ptr;
938   grn_ctx *ctx = &mrn_ctx;
939 
940   mrn_change_encoding(ctx, system_charset_info);
941   if (strcmp(*old_value_ptr, new_value) == 0) {
942     GRN_LOG(ctx, GRN_LOG_NOTICE,
943             "default tokenizer for fulltext index isn't changed "
944             "because the requested default tokenizer isn't different: <%s>",
945             new_value);
946   } else {
947     GRN_LOG(ctx, GRN_LOG_NOTICE,
948             "default tokenizer for fulltext index is changed: <%s> -> <%s>",
949             *old_value_ptr, new_value);
950   }
951 
952 #ifdef MRN_NEED_FREE_STRING_MEMALLOC_PLUGIN_VAR
953   my_free(*old_value_ptr);
954   *old_value_ptr = mrn_my_strdup(new_value, MYF(MY_WME));
955 #else
956   *old_value_ptr = (char *)new_value;
957 #endif
958 
959   DBUG_VOID_RETURN;
960 }
961 
962 static MYSQL_SYSVAR_STR(default_parser, mrn_default_tokenizer,
963                         PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
964                         "default fulltext parser "
965                         "(Deprecated. Use mroonga_default_tokenizer instead.)",
966                         NULL,
967                         mrn_default_tokenizer_update,
968                         MRN_DEFAULT_TOKENIZER);
969 
970 static MYSQL_SYSVAR_STR(default_tokenizer, mrn_default_tokenizer,
971                         PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
972                         "default tokenizer for fulltext index",
973                         NULL,
974                         mrn_default_tokenizer_update,
975                         MRN_DEFAULT_TOKENIZER);
976 
977 static MYSQL_THDVAR_BOOL(
978   dry_write, /* name */
979   PLUGIN_VAR_OPCMDARG, /* options */
980   "If dry_write is true, any write operations are ignored.", /* comment */
981   NULL, /* check */
982   NULL, /* update */
983   false /* default */
984 );
985 
986 static MYSQL_THDVAR_BOOL(
987   enable_optimization, /* name */
988   PLUGIN_VAR_OPCMDARG, /* options */
989   "If enable_optimization is true, some optimizations will be applied.", /* comment */
990   NULL, /* check */
991   NULL, /* update */
992   true /* default */
993 );
994 
995 static MYSQL_THDVAR_LONGLONG(match_escalation_threshold,
996                              PLUGIN_VAR_RQCMDARG,
997                              "The threshold to determin whether search method is escalated",
998                              NULL,
999                              NULL,
1000                              grn_get_default_match_escalation_threshold(),
1001                              -1,
1002                              INT_MAX64,
1003                              0);
1004 
mrn_vector_column_delimiter_update(THD * thd,struct st_mysql_sys_var * var,void * var_ptr,const void * save)1005 static void mrn_vector_column_delimiter_update(THD *thd, struct st_mysql_sys_var *var,
1006                                                void *var_ptr, const void *save)
1007 {
1008   MRN_DBUG_ENTER_FUNCTION();
1009   const char *new_value = *((const char **)save);
1010   char **old_value_ptr = (char **)var_ptr;
1011 
1012 #ifdef MRN_NEED_FREE_STRING_MEMALLOC_PLUGIN_VAR
1013   my_free(*old_value_ptr);
1014   *old_value_ptr = mrn_my_strdup(new_value, MYF(MY_WME));
1015 #else
1016   *old_value_ptr = (char *)new_value;
1017 #endif
1018 
1019   DBUG_VOID_RETURN;
1020 }
1021 
1022 static MYSQL_SYSVAR_STR(vector_column_delimiter, mrn_vector_column_delimiter,
1023                         PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
1024                         "The vector column delimiter",
1025                         NULL,
1026                         &mrn_vector_column_delimiter_update,
1027                         " ");
1028 
mrn_database_path_prefix_update(THD * thd,struct st_mysql_sys_var * var,void * var_ptr,const void * save)1029 static void mrn_database_path_prefix_update(THD *thd,
1030                                             struct st_mysql_sys_var *var,
1031                                             void *var_ptr, const void *save)
1032 {
1033   MRN_DBUG_ENTER_FUNCTION();
1034   const char *new_value = *((const char **)save);
1035   char **old_value_ptr = (char **)var_ptr;
1036 #ifdef MRN_NEED_FREE_STRING_MEMALLOC_PLUGIN_VAR
1037   if (*old_value_ptr)
1038     my_free(*old_value_ptr);
1039   if (new_value)
1040     *old_value_ptr = mrn_my_strdup(new_value, MYF(MY_WME));
1041   else
1042     *old_value_ptr = NULL;
1043 #else
1044   *old_value_ptr = (char *)new_value;
1045 #endif
1046   DBUG_VOID_RETURN;
1047 }
1048 
1049 static MYSQL_SYSVAR_STR(database_path_prefix,
1050                         mrn::PathMapper::default_path_prefix,
1051                         PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
1052                         "The database path prefix",
1053                         NULL,
1054                         &mrn_database_path_prefix_update,
1055                         NULL);
1056 
1057 static MYSQL_SYSVAR_STR(default_wrapper_engine, mrn_default_wrapper_engine,
1058                         PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1059                         "The default engine for wrapper mode",
1060                         NULL,
1061                         NULL,
1062                         NULL);
1063 
1064 static const char *mrn_action_on_error_names[] = {
1065   "ERROR",
1066   "ERROR_AND_LOG",
1067   "IGNORE",
1068   "IGNORE_AND_LOG",
1069   NullS,
1070 };
1071 
1072 static TYPELIB mrn_action_on_error_typelib =
1073 {
1074   array_elements(mrn_action_on_error_names) - 1,
1075   "mrn_action_on_error_typelib",
1076   mrn_action_on_error_names,
1077   NULL
1078 };
1079 
1080 static MYSQL_THDVAR_ENUM(action_on_fulltext_query_error,
1081                          PLUGIN_VAR_RQCMDARG,
1082                          "action on fulltext query error",
1083                          NULL,
1084                          NULL,
1085                          mrn_action_on_fulltext_query_error_default,
1086                          &mrn_action_on_error_typelib);
1087 
mrn_lock_timeout_update(THD * thd,struct st_mysql_sys_var * var,void * var_ptr,const void * save)1088 static void mrn_lock_timeout_update(THD *thd, struct st_mysql_sys_var *var,
1089                                     void *var_ptr, const void *save)
1090 {
1091   MRN_DBUG_ENTER_FUNCTION();
1092   const int new_value = *static_cast<const int *>(save);
1093   int *old_value_ptr = static_cast<int *>(var_ptr);
1094 
1095   *old_value_ptr = new_value;
1096   grn_set_lock_timeout(new_value);
1097 
1098   DBUG_VOID_RETURN;
1099 }
1100 
1101 static MYSQL_SYSVAR_INT(lock_timeout,
1102                         mrn_lock_timeout,
1103                         PLUGIN_VAR_RQCMDARG,
1104                         "lock timeout used in Groonga",
1105                         NULL,
1106                         mrn_lock_timeout_update,
1107                         grn_get_lock_timeout(),
1108                         -1,
1109                         INT_MAX,
1110                         1);
1111 
1112 static MYSQL_SYSVAR_STR(libgroonga_version, mrn_libgroonga_version,
1113                         PLUGIN_VAR_NOCMDOPT | PLUGIN_VAR_READONLY,
1114                         "The version of libgroonga",
1115                         NULL,
1116                         NULL,
1117                         grn_get_version());
1118 
1119 static MYSQL_SYSVAR_STR(version, mrn_version,
1120                         PLUGIN_VAR_NOCMDOPT | PLUGIN_VAR_READONLY,
1121                         "The version of mroonga",
1122                         NULL,
1123                         NULL,
1124                         MRN_VERSION);
1125 
grn_check_zlib_support()1126 static mrn_bool grn_check_zlib_support()
1127 {
1128   bool is_zlib_support = false;
1129   grn_obj grn_support_p;
1130 
1131   GRN_BOOL_INIT(&grn_support_p, 0);
1132   grn_obj_get_info(&mrn_ctx, NULL, GRN_INFO_SUPPORT_ZLIB, &grn_support_p);
1133   is_zlib_support = (GRN_BOOL_VALUE(&grn_support_p));
1134   grn_obj_unlink(&mrn_ctx, &grn_support_p);
1135 
1136   return is_zlib_support;
1137 }
1138 
1139 static MYSQL_SYSVAR_BOOL(libgroonga_support_zlib, mrn_libgroonga_support_zlib,
1140                          PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
1141                          "The status of libgroonga supports zlib",
1142                          NULL,
1143                          NULL,
1144                          grn_check_zlib_support());
1145 
grn_check_lz4_support()1146 static mrn_bool grn_check_lz4_support()
1147 {
1148   bool is_lz4_support = false;
1149   grn_obj grn_support_p;
1150 
1151   GRN_BOOL_INIT(&grn_support_p, 0);
1152   grn_obj_get_info(&mrn_ctx, NULL, GRN_INFO_SUPPORT_LZ4, &grn_support_p);
1153   is_lz4_support = (GRN_BOOL_VALUE(&grn_support_p));
1154   grn_obj_unlink(&mrn_ctx, &grn_support_p);
1155 
1156   return is_lz4_support;
1157 }
1158 
1159 static MYSQL_SYSVAR_BOOL(libgroonga_support_lz4, mrn_libgroonga_support_lz4,
1160                          PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
1161                          "The status of libgroonga supports LZ4",
1162                          NULL,
1163                          NULL,
1164                          grn_check_lz4_support());
1165 
grn_check_zstd_support()1166 static mrn_bool grn_check_zstd_support()
1167 {
1168   bool is_zstd_support = false;
1169   grn_obj grn_support_p;
1170 
1171   GRN_BOOL_INIT(&grn_support_p, 0);
1172   grn_obj_get_info(&mrn_ctx, NULL, GRN_INFO_SUPPORT_ZSTD, &grn_support_p);
1173   is_zstd_support = (GRN_BOOL_VALUE(&grn_support_p));
1174   grn_obj_unlink(&mrn_ctx, &grn_support_p);
1175 
1176   return is_zstd_support;
1177 }
1178 
1179 static MYSQL_SYSVAR_BOOL(libgroonga_support_zstd, mrn_libgroonga_support_zstd,
1180                          PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
1181                          "The status of libgroonga supports Zstandard",
1182                          NULL,
1183                          NULL,
1184                          grn_check_zstd_support());
1185 
mrn_enable_operations_recording_update(THD * thd,struct st_mysql_sys_var * var,void * var_ptr,const void * save)1186 static void mrn_enable_operations_recording_update(THD *thd, struct st_mysql_sys_var *var,
1187                                                    void *var_ptr, const void *save)
1188 {
1189   MRN_DBUG_ENTER_FUNCTION();
1190   const bool new_value = *static_cast<const bool *>(save);
1191   bool *old_value_ptr = static_cast<bool *>(var_ptr);
1192 
1193   *old_value_ptr = new_value;
1194 
1195   DBUG_VOID_RETURN;
1196 }
1197 
1198 static MYSQL_SYSVAR_BOOL(enable_operations_recording, mrn_enable_operations_recording,
1199                          PLUGIN_VAR_RQCMDARG,
1200                          "Whether recording operations for recovery is enabled or not",
1201                          NULL,
1202                          mrn_enable_operations_recording_update,
1203                          true);
1204 
1205 #ifdef MRN_SUPPORT_THDVAR_SET
1206 static MYSQL_THDVAR_SET(boolean_mode_syntax_flags,
1207                         PLUGIN_VAR_RQCMDARG,
1208                         "The flags to custom syntax in BOOLEAN MODE. "
1209                         "Available flags: "
1210                         "DEFAULT(=SYNTAX_QUERY,ALLOW_LEADING_NOT), "
1211                         "SYNTAX_QUERY, SYNTAX_SCRIPT, "
1212                         "ALLOW_COLUMN, ALLOW_UPDATE and ALLOW_LEADING_NOT",
1213                         NULL,
1214                         NULL,
1215                         mrn::variables::BOOLEAN_MODE_SYNTAX_FLAG_DEFAULT,
1216                         &mrn_boolean_mode_syntax_flags_typelib);
1217 #endif
1218 
1219 static const int MRN_MAX_N_RECORDS_FOR_ESTIMATE_DEFAULT = 1000;
1220 
1221 static MYSQL_THDVAR_INT(max_n_records_for_estimate,
1222                         PLUGIN_VAR_RQCMDARG,
1223                         "The max number of records to "
1224                         "estimate the number of matched records",
1225                         NULL,
1226                         NULL,
1227                         MRN_MAX_N_RECORDS_FOR_ESTIMATE_DEFAULT,
1228                         -1,
1229                         INT_MAX,
1230                         0);
1231 
1232 static MYSQL_SYSVAR_BOOL(libgroonga_embedded, mrn_libgroonga_embedded,
1233                          PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
1234                          "Whether libgroonga is embedded or not",
1235                          NULL,
1236                          NULL,
1237                          mrn_libgroonga_embedded);
1238 
1239 static struct st_mysql_sys_var *mrn_system_variables[] =
1240 {
1241   MYSQL_SYSVAR(log_level),
1242   MYSQL_SYSVAR(log_file),
1243   MYSQL_SYSVAR(default_parser),
1244   MYSQL_SYSVAR(default_tokenizer),
1245   MYSQL_SYSVAR(dry_write),
1246   MYSQL_SYSVAR(enable_optimization),
1247   MYSQL_SYSVAR(match_escalation_threshold),
1248   MYSQL_SYSVAR(database_path_prefix),
1249   MYSQL_SYSVAR(default_wrapper_engine),
1250   MYSQL_SYSVAR(action_on_fulltext_query_error),
1251   MYSQL_SYSVAR(lock_timeout),
1252   MYSQL_SYSVAR(libgroonga_version),
1253   MYSQL_SYSVAR(version),
1254   MYSQL_SYSVAR(vector_column_delimiter),
1255   MYSQL_SYSVAR(libgroonga_support_zlib),
1256   MYSQL_SYSVAR(libgroonga_support_lz4),
1257   MYSQL_SYSVAR(libgroonga_support_zstd),
1258 #ifdef MRN_SUPPORT_THDVAR_SET
1259   MYSQL_SYSVAR(boolean_mode_syntax_flags),
1260 #endif
1261   MYSQL_SYSVAR(max_n_records_for_estimate),
1262   MYSQL_SYSVAR(libgroonga_embedded),
1263   MYSQL_SYSVAR(query_log_file),
1264   MYSQL_SYSVAR(enable_operations_recording),
1265   NULL
1266 };
1267 
1268 /* mroonga information schema */
1269 static struct st_mysql_information_schema i_s_info =
1270 {
1271   MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION
1272 };
1273 
1274 static ST_FIELD_INFO i_s_mrn_stats_fields_info[] =
1275 {
1276   {
1277     "VERSION",
1278     40,
1279     MYSQL_TYPE_STRING,
1280     0,
1281     0,
1282     "",
1283     SKIP_OPEN_TABLE
1284   },
1285   {
1286     "rows_written",
1287     MY_INT32_NUM_DECIMAL_DIGITS,
1288     MYSQL_TYPE_LONG,
1289     0,
1290     0,
1291     "Rows written to Groonga",
1292     SKIP_OPEN_TABLE
1293   },
1294   {
1295     "rows_read",
1296     MY_INT32_NUM_DECIMAL_DIGITS,
1297     MYSQL_TYPE_LONG,
1298     0,
1299     0,
1300     "Rows read from Groonga",
1301     SKIP_OPEN_TABLE
1302   },
1303   { 0, 0, MYSQL_TYPE_NULL, 0, 0, 0, 0}
1304 };
1305 
i_s_mrn_stats_deinit(void * p)1306 static int i_s_mrn_stats_deinit(void* p)
1307 {
1308   MRN_DBUG_ENTER_FUNCTION();
1309   DBUG_RETURN(0);
1310 }
1311 
i_s_mrn_stats_fill(THD * thd,TABLE_LIST * tables,Item * cond)1312 static int i_s_mrn_stats_fill(
1313   THD* thd, TABLE_LIST* tables, Item* cond)
1314 {
1315   TABLE* table = (TABLE *) tables->table;
1316   int status = 0;
1317   MRN_DBUG_ENTER_FUNCTION();
1318   table->field[0]->store(grn_get_version(), strlen(grn_get_version()),
1319      system_charset_info);
1320   table->field[0]->set_notnull();
1321   table->field[1]->store(1); /* TODO */
1322   table->field[2]->store(2); /* TODO */
1323   if (schema_table_store_record(thd, table)) {
1324     status = 1;
1325   }
1326   DBUG_RETURN(status);
1327 }
1328 
i_s_mrn_stats_init(void * p)1329 static int i_s_mrn_stats_init(void* p)
1330 {
1331   MRN_DBUG_ENTER_FUNCTION();
1332   ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
1333   schema->fields_info = i_s_mrn_stats_fields_info;
1334   schema->fill_table = i_s_mrn_stats_fill;
1335   DBUG_RETURN(0);
1336 }
1337 
1338 struct st_mysql_plugin i_s_mrn_stats =
1339 {
1340   MYSQL_INFORMATION_SCHEMA_PLUGIN,
1341   &i_s_info,
1342   MRN_STATUS_VARIABLE_NAME_PREFIX_STRING "_stats",
1343   MRN_PLUGIN_AUTHOR,
1344   "Statistics for " MRN_PLUGIN_NAME_STRING,
1345   PLUGIN_LICENSE_GPL,
1346   i_s_mrn_stats_init,
1347 #ifdef MRN_ST_MYSQL_PLUGIN_HAVE_CHECK_UNINSTALL
1348   NULL,
1349 #endif
1350   i_s_mrn_stats_deinit,
1351   MRN_VERSION_IN_HEX,
1352   NULL,
1353   NULL,
1354   MRN_PLUGIN_LAST_VALUES
1355 };
1356 /* End of mroonga information schema implementations */
1357 
mrn_handler_create(handlerton * hton,TABLE_SHARE * share,bool partitioned,MEM_ROOT * root)1358 static handler *mrn_handler_create(handlerton *hton,
1359                                    TABLE_SHARE *share,
1360 #ifdef MRN_HANDLERTON_CREATE_HAVE_PARTITIONED
1361                                    bool partitioned,
1362 #endif
1363                                    MEM_ROOT *root)
1364 {
1365   MRN_DBUG_ENTER_FUNCTION();
1366   handler *new_handler = new (root) ha_mroonga(hton, share);
1367   DBUG_RETURN(new_handler);
1368 }
1369 
mrn_drop_database(handlerton * hton,char * path)1370 static void mrn_drop_database(handlerton *hton, char *path)
1371 {
1372   MRN_DBUG_ENTER_FUNCTION();
1373   mrn_db_manager->drop(path);
1374   DBUG_VOID_RETURN;
1375 }
1376 
mrn_close_connection(handlerton * hton,THD * thd)1377 static int mrn_close_connection(handlerton *hton, THD *thd)
1378 {
1379   MRN_DBUG_ENTER_FUNCTION();
1380   void *p = *thd_ha_data(thd, mrn_hton_ptr);
1381   if (p) {
1382     mrn_clear_slot_data(thd);
1383     free(p);
1384     *thd_ha_data(thd, mrn_hton_ptr) = (void *) NULL;
1385     {
1386       mrn::Lock lock(&mrn_allocated_thds_mutex);
1387       my_hash_delete(&mrn_allocated_thds, (uchar*) thd);
1388     }
1389   }
1390   DBUG_RETURN(0);
1391 }
1392 
1393 #ifdef MRN_FLUSH_LOGS_HAVE_BINLOG_GROUP_FLUSH
mrn_flush_logs(handlerton * hton,bool binlog_group_flush)1394 static bool mrn_flush_logs(handlerton *hton, bool binlog_group_flush)
1395 #else
1396 static bool mrn_flush_logs(handlerton *hton)
1397 #endif
1398 {
1399   MRN_DBUG_ENTER_FUNCTION();
1400   bool result = 0;
1401   if (mrn_log_file_opened) {
1402     mrn::Lock lock(&mrn_log_mutex);
1403     fclose(mrn_log_file);
1404     mrn_log_file = fopen(mrn_log_file_path, "a");
1405   }
1406   DBUG_RETURN(result);
1407 }
1408 
mrn_grn_type_from_field(grn_ctx * ctx,Field * field,bool for_index_key)1409 static grn_builtin_type mrn_grn_type_from_field(grn_ctx *ctx, Field *field,
1410                                                 bool for_index_key)
1411 {
1412   grn_builtin_type type = GRN_DB_VOID;
1413   enum_field_types mysql_field_type = field->real_type();
1414   switch (mysql_field_type) {
1415   case MYSQL_TYPE_DECIMAL:      // DECIMAL; <= 65bytes
1416     type = GRN_DB_SHORT_TEXT;   // 4Kbytes
1417     break;
1418   case MYSQL_TYPE_TINY:         // TINYINT; 1byte
1419     if (static_cast<Field_num *>(field)->unsigned_flag) {
1420       type = GRN_DB_UINT8;      // 1byte
1421     } else {
1422       type = GRN_DB_INT8;       // 1byte
1423     }
1424     break;
1425   case MYSQL_TYPE_SHORT:        // SMALLINT; 2bytes
1426     if (static_cast<Field_num *>(field)->unsigned_flag) {
1427       type = GRN_DB_UINT16;     // 2bytes
1428     } else {
1429       type = GRN_DB_INT16;      // 2bytes
1430     }
1431     break;
1432   case MYSQL_TYPE_LONG:         // INT; 4bytes
1433     if (static_cast<Field_num *>(field)->unsigned_flag) {
1434       type = GRN_DB_UINT32;     // 4bytes
1435     } else {
1436       type = GRN_DB_INT32;      // 4bytes
1437     }
1438     break;
1439   case MYSQL_TYPE_FLOAT:        // FLOAT; 4 or 8bytes
1440   case MYSQL_TYPE_DOUBLE:       // DOUBLE; 8bytes
1441     type = GRN_DB_FLOAT;        // 8bytes
1442     break;
1443   case MYSQL_TYPE_NULL:         // NULL; 1byte
1444     type = GRN_DB_INT8;         // 1byte
1445     break;
1446   case MYSQL_TYPE_TIMESTAMP:    // TIMESTAMP; 4bytes
1447     type = GRN_DB_TIME;         // 8bytes
1448     break;
1449   case MYSQL_TYPE_LONGLONG:     // BIGINT; 8bytes
1450     if (static_cast<Field_num *>(field)->unsigned_flag) {
1451       type = GRN_DB_UINT64;     // 8bytes
1452     } else {
1453       type = GRN_DB_INT64;      // 8bytes
1454     }
1455     break;
1456   case MYSQL_TYPE_INT24:        // MEDIUMINT; 3bytes
1457     if (static_cast<Field_num *>(field)->unsigned_flag) {
1458       type = GRN_DB_UINT32;     // 4bytes
1459     } else {
1460       type = GRN_DB_INT32;      // 4bytes
1461     }
1462     break;
1463   case MYSQL_TYPE_DATE:         // DATE; 4bytes
1464   case MYSQL_TYPE_TIME:         // TIME; 3bytes
1465   case MYSQL_TYPE_DATETIME:     // DATETIME; 8bytes
1466   case MYSQL_TYPE_YEAR:         // YEAR; 1byte
1467   case MYSQL_TYPE_NEWDATE:      // DATE; 3bytes
1468     type = GRN_DB_TIME;         // 8bytes
1469     break;
1470   case MYSQL_TYPE_VARCHAR:      // VARCHAR; <= 64KB * 4 + 2bytes
1471     if (for_index_key) {
1472       type = GRN_DB_SHORT_TEXT; // 4Kbytes
1473     } else {
1474       if (field->field_length <= MRN_SHORT_TEXT_SIZE) {
1475         type = GRN_DB_SHORT_TEXT; //  4Kbytes
1476       } else if (field->field_length <= MRN_TEXT_SIZE) {
1477         type = GRN_DB_TEXT;       // 64Kbytes
1478       } else {
1479         type = GRN_DB_LONG_TEXT;  //  2Gbytes
1480       }
1481     }
1482     break;
1483   case MYSQL_TYPE_BIT:          // BIT; <= 8bytes
1484     type = GRN_DB_INT64;        // 8bytes
1485     break;
1486 #ifdef MRN_HAVE_MYSQL_TYPE_TIMESTAMP2
1487   case MYSQL_TYPE_TIMESTAMP2:   // TIMESTAMP; 4bytes
1488     type = GRN_DB_TIME;         // 8bytes
1489     break;
1490 #endif
1491 #ifdef MRN_HAVE_MYSQL_TYPE_DATETIME2
1492   case MYSQL_TYPE_DATETIME2:    // DATETIME; 8bytes
1493     type = GRN_DB_TIME;         // 8bytes
1494     break;
1495 #endif
1496 #ifdef MRN_HAVE_MYSQL_TYPE_TIME2
1497   case MYSQL_TYPE_TIME2:        // TIME(FSP); 3 + (FSP + 1) / 2 bytes
1498                                 // 0 <= FSP <= 6; 3-6bytes
1499     type = GRN_DB_TIME;         // 8bytes
1500     break;
1501 #endif
1502   case MYSQL_TYPE_NEWDECIMAL:   // DECIMAL; <= 9bytes
1503     type = GRN_DB_SHORT_TEXT;   // 4Kbytes
1504     break;
1505   case MYSQL_TYPE_ENUM:         // ENUM; <= 2bytes
1506     if (field->pack_length() == 1) {
1507       type = GRN_DB_UINT8;      // 1bytes
1508     } else {
1509       type = GRN_DB_UINT16;     // 2bytes
1510     }
1511     break;
1512   case MYSQL_TYPE_SET:          // SET; <= 8bytes
1513     switch (field->pack_length()) {
1514     case 1:
1515       type = GRN_DB_UINT8;      // 1byte
1516       break;
1517     case 2:
1518       type = GRN_DB_UINT16;     // 2bytes
1519       break;
1520     case 3:
1521     case 4:
1522       type = GRN_DB_UINT32;     // 3bytes
1523       break;
1524     case 8:
1525     default:
1526       type = GRN_DB_UINT64;     // 8bytes
1527       break;
1528     }
1529     break;
1530   case MYSQL_TYPE_TINY_BLOB:    // TINYBLOB; <= 256bytes + 1byte
1531     type = GRN_DB_SHORT_TEXT;   // 4Kbytes
1532     break;
1533   case MYSQL_TYPE_MEDIUM_BLOB:  // MEDIUMBLOB; <= 16Mbytes + 3bytes
1534     if (for_index_key) {
1535       type = GRN_DB_SHORT_TEXT; // 4Kbytes
1536     } else {
1537       type = GRN_DB_LONG_TEXT;  // 2Gbytes
1538     }
1539     break;
1540   case MYSQL_TYPE_LONG_BLOB:    // LONGBLOB; <= 4Gbytes + 4bytes
1541     if (for_index_key) {
1542       type = GRN_DB_SHORT_TEXT; // 4Kbytes
1543     } else {
1544       type = GRN_DB_LONG_TEXT;  // 2Gbytes
1545     }
1546     break;
1547   case MYSQL_TYPE_BLOB:         // BLOB; <= 64Kbytes + 2bytes
1548     if (for_index_key) {
1549       type = GRN_DB_SHORT_TEXT; // 4Kbytes
1550     } else {
1551       type = GRN_DB_LONG_TEXT;  // 2Gbytes
1552     }
1553     break;
1554   case MYSQL_TYPE_VAR_STRING:   // VARCHAR; <= 255byte * 4 + 1bytes
1555     if (for_index_key) {
1556       type = GRN_DB_SHORT_TEXT; // 4Kbytes
1557     } else {
1558       if (field->field_length <= MRN_SHORT_TEXT_SIZE) {
1559         type = GRN_DB_SHORT_TEXT; //  4Kbytes
1560       } else if (field->field_length <= MRN_TEXT_SIZE) {
1561         type = GRN_DB_TEXT;       // 64Kbytes
1562       } else {
1563         type = GRN_DB_LONG_TEXT;  //  2Gbytes
1564       }
1565     }
1566     break;
1567   case MYSQL_TYPE_STRING:       // CHAR; < 1Kbytes =~ (255 * 4)bytes
1568                                 //              4 is the maximum size of a character
1569     type = GRN_DB_SHORT_TEXT;   // 4Kbytes
1570     break;
1571   case MYSQL_TYPE_GEOMETRY:     // case-by-case
1572     type = GRN_DB_WGS84_GEO_POINT; // 8bytes
1573     break;
1574   case MYSQL_TYPE_VARCHAR_COMPRESSED:
1575   case MYSQL_TYPE_BLOB_COMPRESSED:
1576     DBUG_ASSERT(0);
1577 #ifdef MRN_HAVE_MYSQL_TYPE_JSON
1578   case MYSQL_TYPE_JSON:
1579     type = GRN_DB_TEXT;
1580     break;
1581 #endif
1582   }
1583   return type;
1584 }
1585 
mrn_parse_grn_column_create_flags(THD * thd,grn_ctx * ctx,const char * flag_names,uint flag_names_length,grn_obj_flags * column_flags)1586 static bool mrn_parse_grn_column_create_flags(THD *thd,
1587                                               grn_ctx *ctx,
1588                                               const char *flag_names,
1589                                               uint flag_names_length,
1590                                               grn_obj_flags *column_flags)
1591 {
1592   const char *flag_names_end = flag_names + flag_names_length;
1593   bool found = false;
1594 
1595   while (flag_names < flag_names_end) {
1596     uint rest_length = flag_names_end - flag_names;
1597 
1598     if (*flag_names == '|' || *flag_names == ' ') {
1599       flag_names += 1;
1600       continue;
1601     }
1602     if (rest_length >= 13 && !memcmp(flag_names, "COLUMN_SCALAR", 13)) {
1603       *column_flags |= GRN_OBJ_COLUMN_SCALAR;
1604       flag_names += 13;
1605       found = true;
1606     } else if (rest_length >= 13 && !memcmp(flag_names, "COLUMN_VECTOR", 13)) {
1607       *column_flags |= GRN_OBJ_COLUMN_VECTOR;
1608       flag_names += 13;
1609       found = true;
1610     } else if (rest_length >= 13 && !memcmp(flag_names, "COMPRESS_ZLIB", 13)) {
1611       if (mrn_libgroonga_support_zlib) {
1612         *column_flags |= GRN_OBJ_COMPRESS_ZLIB;
1613         found = true;
1614       } else {
1615         push_warning_printf(thd, MRN_SEVERITY_WARNING,
1616                             ER_MRN_UNSUPPORTED_COLUMN_FLAG_NUM,
1617                             ER_MRN_UNSUPPORTED_COLUMN_FLAG_STR,
1618                             "COMPRESS_ZLIB");
1619       }
1620       flag_names += 13;
1621     } else if (rest_length >= 12 && !memcmp(flag_names, "COMPRESS_LZ4", 12)) {
1622       if (mrn_libgroonga_support_lz4) {
1623         *column_flags |= GRN_OBJ_COMPRESS_LZ4;
1624         found = true;
1625       } else {
1626         push_warning_printf(thd, MRN_SEVERITY_WARNING,
1627                             ER_MRN_UNSUPPORTED_COLUMN_FLAG_NUM,
1628                             ER_MRN_UNSUPPORTED_COLUMN_FLAG_STR,
1629                             "COMPRESS_LZ4");
1630       }
1631       flag_names += 12;
1632     } else if (rest_length >= 13 && !memcmp(flag_names, "COMPRESS_ZSTD", 13)) {
1633       if (mrn_libgroonga_support_zstd) {
1634         *column_flags |= GRN_OBJ_COMPRESS_ZSTD;
1635         found = true;
1636       } else {
1637         push_warning_printf(thd, MRN_SEVERITY_WARNING,
1638                             ER_MRN_UNSUPPORTED_COLUMN_FLAG_NUM,
1639                             ER_MRN_UNSUPPORTED_COLUMN_FLAG_STR,
1640                             "COMPRESS_ZSTD");
1641       }
1642       flag_names += 13;
1643     } else {
1644       char invalid_flag_name[MRN_MESSAGE_BUFFER_SIZE];
1645       snprintf(invalid_flag_name, MRN_MESSAGE_BUFFER_SIZE,
1646                "%.*s",
1647                static_cast<int>(rest_length),
1648                flag_names);
1649       push_warning_printf(thd, MRN_SEVERITY_WARNING,
1650                           ER_MRN_INVALID_COLUMN_FLAG_NUM,
1651                           ER_MRN_INVALID_COLUMN_FLAG_STR,
1652                           invalid_flag_name);
1653       break;
1654     }
1655   }
1656   return found;
1657 }
1658 
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)1659 static bool mrn_parse_grn_index_column_flags(THD *thd,
1660                                              grn_ctx *ctx,
1661                                              const char *flag_names,
1662                                              uint flag_names_length,
1663                                              grn_column_flags *index_column_flags)
1664 {
1665   const char *flag_names_end = flag_names + flag_names_length;
1666   bool found = false;
1667 
1668   while (flag_names < flag_names_end) {
1669     uint rest_length = flag_names_end - flag_names;
1670 
1671     if (*flag_names == '|' || *flag_names == ' ') {
1672       flag_names += 1;
1673       continue;
1674     }
1675     if (rest_length >= 4 && !memcmp(flag_names, "NONE", 4)) {
1676       flag_names += 4;
1677       found = true;
1678     } else if (rest_length >= 13 && !memcmp(flag_names, "WITH_POSITION", 13)) {
1679       *index_column_flags |= GRN_OBJ_WITH_POSITION;
1680       flag_names += 13;
1681       found = true;
1682     } else if (rest_length >= 12 && !memcmp(flag_names, "WITH_SECTION", 12)) {
1683       *index_column_flags |= GRN_OBJ_WITH_SECTION;
1684       flag_names += 12;
1685       found = true;
1686     } else if (rest_length >= 11 && !memcmp(flag_names, "WITH_WEIGHT", 11)) {
1687       *index_column_flags |= GRN_OBJ_WITH_WEIGHT;
1688       flag_names += 11;
1689       found = true;
1690     } else if (rest_length >= 11 && !memcmp(flag_names, "INDEX_SMALL", 11)) {
1691       *index_column_flags |= GRN_OBJ_INDEX_SMALL;
1692       flag_names += 11;
1693       found = true;
1694     } else if (rest_length >= 12 && !memcmp(flag_names, "INDEX_MEDIUM", 12)) {
1695       *index_column_flags |= GRN_OBJ_INDEX_MEDIUM;
1696       flag_names += 12;
1697       found = true;
1698     } else {
1699       char invalid_flag_name[MRN_MESSAGE_BUFFER_SIZE];
1700       snprintf(invalid_flag_name, MRN_MESSAGE_BUFFER_SIZE,
1701                "%.*s",
1702                static_cast<int>(rest_length),
1703                flag_names);
1704       push_warning_printf(thd, MRN_SEVERITY_WARNING,
1705                           ER_MRN_INVALID_INDEX_FLAG_NUM,
1706                           ER_MRN_INVALID_INDEX_FLAG_STR,
1707                           invalid_flag_name);
1708     }
1709   }
1710   return found;
1711 }
1712 
1713 #ifdef MRN_HAVE_SPATIAL
mrn_set_geometry(grn_ctx * ctx,grn_obj * buf,const char * wkb,uint wkb_size)1714 static int mrn_set_geometry(grn_ctx *ctx, grn_obj *buf,
1715                             const char *wkb, uint wkb_size)
1716 {
1717   int error = 0;
1718   Geometry_buffer buffer;
1719   Geometry *geometry;
1720 
1721   geometry = Geometry::construct(&buffer, wkb, wkb_size);
1722   if (!geometry) {
1723     return ER_CANT_CREATE_GEOMETRY_OBJECT;
1724   }
1725   switch (geometry->get_class_info()->m_type_id) {
1726   case Geometry::wkb_point:
1727     {
1728       Gis_point *point = (Gis_point *)geometry;
1729       double latitude = 0.0, longitude = 0.0;
1730 #ifdef MRN_HAVE_POINT_XY
1731       point_xy xy(0.0, 0.0);
1732       point->get_xy(&xy);
1733       longitude = xy.x;
1734       latitude = xy.y;
1735 #else
1736       point->get_xy(&longitude, &latitude);
1737 #endif
1738       grn_obj_reinit(ctx, buf, GRN_DB_WGS84_GEO_POINT, 0);
1739       GRN_GEO_POINT_SET(ctx, buf,
1740                         GRN_GEO_DEGREE2MSEC(latitude),
1741                         GRN_GEO_DEGREE2MSEC(longitude));
1742       break;
1743     }
1744   default:
1745     my_printf_error(ER_MRN_GEOMETRY_NOT_SUPPORT_NUM,
1746       ER_MRN_GEOMETRY_NOT_SUPPORT_STR, MYF(0));
1747     error = ER_MRN_GEOMETRY_NOT_SUPPORT_NUM;
1748     break;
1749   }
1750   MRN_GEOMETRY_FREE(geometry);
1751 
1752   return error;
1753 }
1754 #endif
1755 
1756 #ifdef MRN_HAVE_HTON_ALTER_TABLE_FLAGS
mrn_alter_table_flags(alter_table_operations flags)1757 static alter_table_operations mrn_alter_table_flags(alter_table_operations flags)
1758 {
1759   ulonglong alter_flags = 0;
1760 #ifdef HA_INPLACE_ADD_INDEX_NO_READ_WRITE
1761   bool is_inplace_index_change;
1762 #  ifdef MRN_HAVE_ALTER_INFO
1763   is_inplace_index_change = (((flags & ALTER_ADD_INDEX) &&
1764                               (flags & ALTER_DROP_INDEX)) ||
1765                              (flags & ALTER_CHANGE_COLUMN));
1766 #  else
1767   is_inplace_index_change = (((flags & ALTER_ADD_INDEX) &&
1768                               (flags & ALTER_DROP_INDEX)) ||
1769                              (flags & ALTER_CHANGE_COLUMN));
1770 #  endif
1771   if (!is_inplace_index_change) {
1772     alter_flags |=
1773       HA_INPLACE_ADD_INDEX_NO_READ_WRITE |
1774       HA_INPLACE_DROP_INDEX_NO_READ_WRITE |
1775       HA_INPLACE_ADD_UNIQUE_INDEX_NO_READ_WRITE |
1776       HA_INPLACE_DROP_UNIQUE_INDEX_NO_READ_WRITE |
1777       HA_INPLACE_ADD_INDEX_NO_WRITE |
1778       HA_INPLACE_DROP_INDEX_NO_WRITE |
1779       HA_INPLACE_ADD_UNIQUE_INDEX_NO_WRITE |
1780       HA_INPLACE_DROP_UNIQUE_INDEX_NO_WRITE;
1781   }
1782 #endif
1783   return alter_flags;
1784 }
1785 #endif
1786 
1787 #ifdef MRN_SUPPORT_CUSTOM_OPTIONS
1788 static ha_create_table_option mrn_field_options[] =
1789 {
1790   HA_FOPTION_STRING("GROONGA_TYPE", groonga_type),
1791   HA_FOPTION_STRING("FLAGS", flags),
1792   HA_FOPTION_END
1793 };
1794 
1795 static ha_create_table_option mrn_index_options[] =
1796 {
1797   HA_IOPTION_STRING("TOKENIZER", tokenizer),
1798   HA_IOPTION_STRING("NORMALIZER", normalizer),
1799   HA_IOPTION_STRING("TOKEN_FILTERS", token_filters),
1800   HA_IOPTION_STRING("FLAGS", flags),
1801   HA_IOPTION_END
1802 };
1803 #endif
1804 
mrn_init(void * p)1805 static int mrn_init(void *p)
1806 {
1807   // init handlerton
1808   grn_ctx *ctx = NULL;
1809   handlerton *hton = static_cast<handlerton *>(p);
1810   hton->state = SHOW_OPTION_YES;
1811   hton->create = mrn_handler_create;
1812   hton->flags = HTON_NO_FLAGS;
1813 #ifndef MRN_SUPPORT_PARTITION
1814   hton->flags |= HTON_NO_PARTITION;
1815 #endif
1816   hton->drop_database = mrn_drop_database;
1817   hton->close_connection = mrn_close_connection;
1818   hton->flush_logs = mrn_flush_logs;
1819 #ifdef MRN_HAVE_HTON_ALTER_TABLE_FLAGS
1820   hton->alter_table_flags = mrn_alter_table_flags;
1821 #endif
1822 #ifdef MRN_SUPPORT_CUSTOM_OPTIONS
1823   hton->field_options = mrn_field_options;
1824   hton->index_options = mrn_index_options;
1825 #endif
1826   mrn_hton_ptr = hton;
1827 
1828 #ifdef _WIN32
1829   HMODULE current_module = GetModuleHandle(NULL);
1830   mrn_binlog_filter =
1831     *((Rpl_filter **)GetProcAddress(current_module, MRN_BINLOG_FILTER_PROC));
1832   mrn_my_tz_UTC =
1833     *((Time_zone **)GetProcAddress(current_module, MRN_MY_TZ_UTC_PROC));
1834 #  ifdef MRN_HAVE_TABLE_DEF_CACHE
1835   mrn_table_def_cache = (HASH *)GetProcAddress(current_module,
1836     "?table_def_cache@@3Ust_hash@@A");
1837 #  endif
1838 #  ifndef MRN_HAVE_TDC_LOCK_TABLE_SHARE
1839   mrn_LOCK_open =
1840     (mysql_mutex_t *)GetProcAddress(current_module,
1841       "?LOCK_open@@3Ust_mysql_mutex@@A");
1842 #  endif
1843 #  ifdef HAVE_PSI_INTERFACE
1844 #    ifdef MRN_TABLE_SHARE_HAVE_LOCK_SHARE
1845        mrn_table_share_lock_share =
1846          (PSI_mutex_key *)GetProcAddress(current_module,
1847                                          MRN_TABLE_SHARE_LOCK_SHARE_PROC);
1848 #    endif
1849      mrn_table_share_lock_ha_data =
1850        (PSI_mutex_key *)GetProcAddress(current_module,
1851                                        MRN_TABLE_SHARE_LOCK_HA_DATA_PROC);
1852 #  endif
1853 #else
1854   mrn_binlog_filter = binlog_filter;
1855   mrn_my_tz_UTC = my_tz_UTC;
1856 #  ifdef MRN_HAVE_TABLE_DEF_CACHE
1857   mrn_table_def_cache = &table_def_cache;
1858 #  endif
1859 #  ifndef MRN_HAVE_TDC_LOCK_TABLE_SHARE
1860   mrn_LOCK_open = &LOCK_open;
1861 #  endif
1862 #endif
1863 
1864 #ifdef MRN_HAVE_PSI_SERVER
1865   if (PSI_server) {
1866     const char *category = "mroonga";
1867     int n_mutexes = array_elements(mrn_mutexes);
1868     PSI_server->register_mutex(category, mrn_mutexes, n_mutexes);
1869   }
1870 #endif
1871 
1872   grn_default_query_logger_set_path(mrn_query_log_file_path);
1873 
1874   if (grn_init() != GRN_SUCCESS) {
1875     goto err_grn_init;
1876   }
1877 
1878   grn_set_lock_timeout(mrn_lock_timeout);
1879 
1880   mrn_init_encoding_map();
1881 
1882   grn_ctx_init(&mrn_ctx, 0);
1883   ctx = &mrn_ctx;
1884   if (mrn_change_encoding(ctx, system_charset_info))
1885     goto err_mrn_change_encoding;
1886 
1887 #ifdef MRN_HAVE_PSI_MEMORY_KEY
1888   {
1889     const char *category = "ha_mroonga";
1890     int n_keys = array_elements(mrn_all_memory_keys);
1891     mysql_memory_register(category, mrn_all_memory_keys, n_keys);
1892   }
1893 #endif
1894 
1895   if (mysql_mutex_init(mrn_log_mutex_key,
1896                        &mrn_log_mutex,
1897                        MY_MUTEX_INIT_FAST) != 0) {
1898     goto err_log_mutex_init;
1899   }
1900   if (mysql_mutex_init(mrn_query_log_mutex_key,
1901                        &mrn_query_log_mutex,
1902                        MY_MUTEX_INIT_FAST) != 0) {
1903     goto err_query_log_mutex_init;
1904   }
1905 
1906   mrn_logger.max_level = static_cast<grn_log_level>(mrn_log_level);
1907   grn_logger_set(ctx, &mrn_logger);
1908   if (!(mrn_log_file = fopen(mrn_log_file_path, "a"))) {
1909     goto err_log_file_open;
1910   }
1911   mrn_log_file_opened = true;
1912   GRN_LOG(ctx, GRN_LOG_NOTICE, "%s started.", MRN_PACKAGE_STRING);
1913   GRN_LOG(ctx, GRN_LOG_NOTICE, "log level is '%s'",
1914           mrn_log_level_type_names[mrn_log_level]);
1915 
1916   // init meta-info database
1917   if (!(mrn_db = grn_db_create(ctx, NULL, NULL))) {
1918     GRN_LOG(ctx, GRN_LOG_ERROR, "cannot create system database, exiting");
1919     goto err_db_create;
1920   }
1921   grn_ctx_use(ctx, mrn_db);
1922 
1923   grn_ctx_init(&mrn_db_manager_ctx, 0);
1924   grn_logger_set(&mrn_db_manager_ctx, &mrn_logger);
1925   if (mysql_mutex_init(mrn_db_manager_mutex_key,
1926                        &mrn_db_manager_mutex,
1927                        MY_MUTEX_INIT_FAST) != 0) {
1928     GRN_LOG(&mrn_db_manager_ctx, GRN_LOG_ERROR,
1929             "failed to initialize mutex for database manager");
1930     goto err_db_manager_mutex_init;
1931   }
1932   mrn_db_manager = new mrn::DatabaseManager(&mrn_db_manager_ctx,
1933                                             &mrn_db_manager_mutex);
1934   if (!mrn_db_manager->init()) {
1935     goto err_db_manager_init;
1936   }
1937 
1938   if (mysql_mutex_init(mrn_context_pool_mutex_key,
1939                        &mrn_context_pool_mutex,
1940                        MY_MUTEX_INIT_FAST) != 0) {
1941     GRN_LOG(ctx, GRN_LOG_ERROR,
1942             "failed to initialize mutex for context pool");
1943     goto error_context_pool_mutex_init;
1944   }
1945   mrn_context_pool = new mrn::ContextPool(&mrn_context_pool_mutex);
1946 
1947   if (mysql_mutex_init(mrn_operations_mutex_key,
1948                        &mrn_operations_mutex,
1949                        MY_MUTEX_INIT_FAST) != 0) {
1950     GRN_LOG(ctx, GRN_LOG_ERROR,
1951             "failed to initialize mutex for operations");
1952     goto error_operations_mutex_init;
1953   }
1954 
1955   if ((mysql_mutex_init(mrn_allocated_thds_mutex_key,
1956                         &mrn_allocated_thds_mutex,
1957                         MY_MUTEX_INIT_FAST) != 0)) {
1958     goto err_allocated_thds_mutex_init;
1959   }
1960   if (mrn_my_hash_init(&mrn_allocated_thds, system_charset_info, 32, 0, 0,
1961                        mrn_allocated_thds_get_key, 0, 0)) {
1962     goto error_allocated_thds_hash_init;
1963   }
1964   if ((mysql_mutex_init(mrn_open_tables_mutex_key,
1965                         &mrn_open_tables_mutex,
1966                         MY_MUTEX_INIT_FAST) != 0)) {
1967     goto err_allocated_open_tables_mutex_init;
1968   }
1969   if (mrn_my_hash_init(&mrn_open_tables, system_charset_info, 32, 0, 0,
1970                        mrn_open_tables_get_key, 0, 0)) {
1971     goto error_allocated_open_tables_hash_init;
1972   }
1973   if ((mysql_mutex_init(mrn_long_term_share_mutex_key,
1974                         &mrn_long_term_share_mutex,
1975                         MY_MUTEX_INIT_FAST) != 0)) {
1976     goto error_allocated_long_term_share_mutex_init;
1977   }
1978   if (mrn_my_hash_init(&mrn_long_term_share, system_charset_info, 32, 0, 0,
1979                        mrn_long_term_share_get_key, 0, 0)) {
1980     goto error_allocated_long_term_share_hash_init;
1981   }
1982 
1983 #ifdef MRN_USE_MYSQL_DATA_HOME
1984   mrn::PathMapper::default_mysql_data_home_path = mysql_data_home;
1985 #endif
1986 
1987   return 0;
1988 
1989 error_allocated_long_term_share_hash_init:
1990   mysql_mutex_destroy(&mrn_long_term_share_mutex);
1991 error_allocated_long_term_share_mutex_init:
1992   my_hash_free(&mrn_open_tables);
1993 error_allocated_open_tables_hash_init:
1994   mysql_mutex_destroy(&mrn_open_tables_mutex);
1995 err_allocated_open_tables_mutex_init:
1996   my_hash_free(&mrn_allocated_thds);
1997 error_allocated_thds_hash_init:
1998   mysql_mutex_destroy(&mrn_allocated_thds_mutex);
1999 err_allocated_thds_mutex_init:
2000   mysql_mutex_destroy(&mrn_operations_mutex);
2001 error_operations_mutex_init:
2002   delete mrn_context_pool;
2003   mysql_mutex_destroy(&mrn_context_pool_mutex);
2004 error_context_pool_mutex_init:
2005 err_db_manager_init:
2006   delete mrn_db_manager;
2007   mysql_mutex_destroy(&mrn_db_manager_mutex);
2008 err_db_manager_mutex_init:
2009   grn_ctx_fin(&mrn_db_manager_ctx);
2010   grn_obj_unlink(ctx, mrn_db);
2011 err_db_create:
2012   if (mrn_log_file_opened) {
2013     fclose(mrn_log_file);
2014     mrn_log_file_opened = false;
2015   }
2016 err_log_file_open:
2017   mysql_mutex_destroy(&mrn_query_log_mutex);
2018 err_query_log_mutex_init:
2019   mysql_mutex_destroy(&mrn_log_mutex);
2020 err_log_mutex_init:
2021 err_mrn_change_encoding:
2022   grn_ctx_fin(ctx);
2023   grn_fin();
2024 err_grn_init:
2025   return -1;
2026 }
2027 
mrn_deinit(void * p)2028 static int mrn_deinit(void *p)
2029 {
2030   THD *thd = current_thd, *tmp_thd;
2031   grn_ctx *ctx = &mrn_ctx;
2032   MRN_LONG_TERM_SHARE *long_term_share;
2033 
2034   GRN_LOG(ctx, GRN_LOG_NOTICE, "%s deinit", MRN_PACKAGE_STRING);
2035 
2036   if (thd && thd_sql_command(thd) == SQLCOM_UNINSTALL_PLUGIN) {
2037     mrn::Lock lock(&mrn_allocated_thds_mutex);
2038     while ((tmp_thd = (THD *) my_hash_element(&mrn_allocated_thds, 0)))
2039     {
2040       mrn_clear_slot_data(tmp_thd);
2041       void *slot_ptr = mrn_get_slot_data(tmp_thd, false);
2042       if (slot_ptr) free(slot_ptr);
2043       *thd_ha_data(tmp_thd, mrn_hton_ptr) = (void *) NULL;
2044       my_hash_delete(&mrn_allocated_thds, (uchar *) tmp_thd);
2045     }
2046   }
2047 
2048   {
2049     mrn::Lock lock(&mrn_open_tables_mutex);
2050     while ((long_term_share = (MRN_LONG_TERM_SHARE *)
2051       my_hash_element(&mrn_long_term_share, 0)))
2052     {
2053       mrn_free_long_term_share(long_term_share);
2054     }
2055   }
2056 
2057   my_hash_free(&mrn_long_term_share);
2058   mysql_mutex_destroy(&mrn_long_term_share_mutex);
2059   my_hash_free(&mrn_open_tables);
2060   mysql_mutex_destroy(&mrn_open_tables_mutex);
2061   my_hash_free(&mrn_allocated_thds);
2062   mysql_mutex_destroy(&mrn_allocated_thds_mutex);
2063   mysql_mutex_destroy(&mrn_operations_mutex);
2064   delete mrn_context_pool;
2065   mysql_mutex_destroy(&mrn_context_pool_mutex);
2066   delete mrn_db_manager;
2067   mysql_mutex_destroy(&mrn_db_manager_mutex);
2068   grn_ctx_fin(&mrn_db_manager_ctx);
2069 
2070   grn_obj_unlink(ctx, mrn_db);
2071   grn_ctx_fin(ctx);
2072   grn_fin();
2073 
2074   if (mrn_log_file_opened) {
2075     fclose(mrn_log_file);
2076     mrn_log_file_opened = false;
2077   }
2078   mysql_mutex_destroy(&mrn_query_log_mutex);
2079   mysql_mutex_destroy(&mrn_log_mutex);
2080 
2081   return 0;
2082 }
2083 
mrn_declare_plugin(MRN_PLUGIN_NAME)2084 mrn_declare_plugin(MRN_PLUGIN_NAME)
2085 {
2086   MYSQL_STORAGE_ENGINE_PLUGIN,
2087   &storage_engine_structure,
2088   MRN_PLUGIN_NAME_STRING,
2089   MRN_PLUGIN_AUTHOR,
2090   "CJK-ready fulltext search, column store",
2091   PLUGIN_LICENSE_GPL,
2092   mrn_init,
2093   mrn_deinit,
2094   MRN_VERSION_IN_HEX,
2095   mrn_status_variables,
2096   mrn_system_variables,
2097   MRN_PLUGIN_LAST_VALUES
2098 },
2099 i_s_mrn_stats
2100 mrn_declare_plugin_end;
2101 
mrn_get_score_value(grn_obj * score)2102 static double mrn_get_score_value(grn_obj *score)
2103 {
2104   MRN_DBUG_ENTER_FUNCTION();
2105   double score_value;
2106   if (score->header.domain == GRN_DB_FLOAT) {
2107     score_value = GRN_FLOAT_VALUE(score);
2108   } else {
2109     score_value = (double)GRN_INT32_VALUE(score);
2110   }
2111   DBUG_RETURN(score_value);
2112 }
2113 
mrn_generic_ft_clear(FT_INFO * handler)2114 static void mrn_generic_ft_clear(FT_INFO *handler)
2115 {
2116   MRN_DBUG_ENTER_FUNCTION();
2117   st_mrn_ft_info *info = (st_mrn_ft_info *)handler;
2118   if (!info->ctx) {
2119     DBUG_VOID_RETURN;
2120   }
2121 
2122   if (info->cursor) {
2123     grn_obj_unlink(info->ctx, info->cursor);
2124   }
2125   if (info->id_accessor) {
2126     grn_obj_unlink(info->ctx, info->id_accessor);
2127   }
2128   if (info->key_accessor) {
2129     grn_obj_unlink(info->ctx, info->key_accessor);
2130   }
2131   grn_obj_unlink(info->ctx, info->result);
2132   grn_obj_unlink(info->ctx, info->score_column);
2133   grn_obj_unlink(info->ctx, &(info->key));
2134   grn_obj_unlink(info->ctx, &(info->score));
2135 
2136   info->ctx = NULL;
2137 
2138   DBUG_VOID_RETURN;
2139 }
2140 
mrn_generic_ft_close_search(FT_INFO * handler)2141 static void mrn_generic_ft_close_search(FT_INFO *handler)
2142 {
2143   MRN_DBUG_ENTER_FUNCTION();
2144   st_mrn_ft_info *info = (st_mrn_ft_info *)handler;
2145   mrn_generic_ft_clear(handler);
2146   delete info;
2147   DBUG_VOID_RETURN;
2148 }
2149 
mrn_wrapper_ft_read_next(FT_INFO * handler,char * record)2150 static int mrn_wrapper_ft_read_next(FT_INFO *handler, char *record)
2151 {
2152   MRN_DBUG_ENTER_FUNCTION();
2153   DBUG_RETURN(HA_ERR_END_OF_FILE);
2154 }
2155 
mrn_wrapper_ft_find_relevance(FT_INFO * handler,uchar * record,uint length)2156 static float mrn_wrapper_ft_find_relevance(FT_INFO *handler, uchar *record,
2157                                            uint length)
2158 {
2159   MRN_DBUG_ENTER_FUNCTION();
2160   st_mrn_ft_info *info = (st_mrn_ft_info *)handler;
2161   float score = 0.0;
2162   grn_id record_id;
2163 
2164   mrn_change_encoding(info->ctx, NULL);
2165   key_copy((uchar *)(GRN_TEXT_VALUE(&(info->key))), record,
2166            info->primary_key_info, info->primary_key_info->key_length);
2167   record_id = grn_table_get(info->ctx,
2168                             info->table,
2169                             GRN_TEXT_VALUE(&(info->key)),
2170                             GRN_TEXT_LEN(&(info->key)));
2171 
2172   if (record_id != GRN_ID_NIL) {
2173     grn_id result_record_id;
2174     result_record_id = grn_table_get(info->ctx, info->result,
2175                                      &record_id, sizeof(grn_id));
2176     if (result_record_id != GRN_ID_NIL) {
2177       GRN_BULK_REWIND(&(info->score));
2178       grn_obj_get_value(info->ctx, info->score_column,
2179                         result_record_id, &(info->score));
2180       score = mrn_get_score_value(&(info->score));
2181     }
2182   }
2183 
2184   DBUG_PRINT("info",
2185              ("mroonga: record_id=%d score=%g", record_id, score));
2186 
2187   DBUG_RETURN(score);
2188 }
2189 
mrn_wrapper_ft_close_search(FT_INFO * handler)2190 static void mrn_wrapper_ft_close_search(FT_INFO *handler)
2191 {
2192   MRN_DBUG_ENTER_FUNCTION();
2193   mrn_generic_ft_close_search(handler);
2194   DBUG_VOID_RETURN;
2195 }
2196 
mrn_wrapper_ft_get_relevance(FT_INFO * handler)2197 static float mrn_wrapper_ft_get_relevance(FT_INFO *handler)
2198 {
2199   MRN_DBUG_ENTER_FUNCTION();
2200   st_mrn_ft_info *info = (st_mrn_ft_info *)handler;
2201   float score = 0.0;
2202   grn_id record_id;
2203   ha_mroonga *mroonga = info->mroonga;
2204   mrn_change_encoding(info->ctx, NULL);
2205   record_id = grn_table_get(info->ctx,
2206                             info->table,
2207                             GRN_TEXT_VALUE(&(mroonga->key_buffer)),
2208                             GRN_TEXT_LEN(&(mroonga->key_buffer)));
2209 
2210   if (record_id != GRN_ID_NIL) {
2211     grn_id result_record_id;
2212     result_record_id = grn_table_get(info->ctx, info->result,
2213                                      &record_id, sizeof(grn_id));
2214     if (result_record_id != GRN_ID_NIL) {
2215       GRN_BULK_REWIND(&(info->score));
2216       grn_obj_get_value(info->ctx, info->score_column,
2217                         result_record_id, &(info->score));
2218       score = mrn_get_score_value(&(info->score));
2219     }
2220   }
2221 
2222   DBUG_PRINT("info",
2223              ("mroonga: record_id=%d score=%g", record_id, score));
2224 
2225   DBUG_RETURN(score);
2226 }
2227 
mrn_wrapper_ft_reinit_search(FT_INFO * handler)2228 static void mrn_wrapper_ft_reinit_search(FT_INFO *handler)
2229 {
2230   MRN_DBUG_ENTER_FUNCTION();
2231   DBUG_VOID_RETURN;
2232 }
2233 
2234 static _ft_vft mrn_wrapper_ft_vft = {
2235   mrn_wrapper_ft_read_next,
2236   mrn_wrapper_ft_find_relevance,
2237   mrn_wrapper_ft_close_search,
2238   mrn_wrapper_ft_get_relevance,
2239   mrn_wrapper_ft_reinit_search
2240 };
2241 
mrn_storage_ft_read_next(FT_INFO * handler,char * record)2242 static int mrn_storage_ft_read_next(FT_INFO *handler, char *record)
2243 {
2244   MRN_DBUG_ENTER_FUNCTION();
2245   DBUG_RETURN(HA_ERR_END_OF_FILE);
2246 }
2247 
mrn_storage_ft_find_relevance(FT_INFO * handler,uchar * record,uint length)2248 static float mrn_storage_ft_find_relevance(FT_INFO *handler, uchar *record,
2249                                            uint length)
2250 {
2251   MRN_DBUG_ENTER_FUNCTION();
2252   st_mrn_ft_info *info = (st_mrn_ft_info *)handler;
2253   ha_mroonga *mroonga = info->mroonga;
2254   mrn_change_encoding(info->ctx, NULL);
2255 
2256   float score = 0.0;
2257   if (mroonga->record_id != GRN_ID_NIL) {
2258     grn_id result_record_id;
2259     result_record_id = grn_table_get(info->ctx, info->result,
2260                                      &(mroonga->record_id), sizeof(grn_id));
2261     if (result_record_id != GRN_ID_NIL) {
2262       GRN_BULK_REWIND(&(info->score));
2263       grn_obj_get_value(info->ctx, info->score_column,
2264                         result_record_id, &(info->score));
2265       score = mrn_get_score_value(&(info->score));
2266     }
2267   }
2268   DBUG_PRINT("info", ("mroonga: record_id=%d score=%g",
2269                       mroonga->record_id, score));
2270 
2271   DBUG_RETURN(score);
2272 }
2273 
mrn_storage_ft_close_search(FT_INFO * handler)2274 static void mrn_storage_ft_close_search(FT_INFO *handler)
2275 {
2276   MRN_DBUG_ENTER_FUNCTION();
2277   mrn_generic_ft_close_search(handler);
2278   DBUG_VOID_RETURN;
2279 }
2280 
mrn_storage_ft_get_relevance(FT_INFO * handler)2281 static float mrn_storage_ft_get_relevance(FT_INFO *handler)
2282 {
2283   MRN_DBUG_ENTER_FUNCTION();
2284   st_mrn_ft_info *info = (st_mrn_ft_info *)handler;
2285   ha_mroonga *mroonga = info->mroonga;
2286   mrn_change_encoding(info->ctx, NULL);
2287 
2288   float score = 0.0;
2289   if (mroonga->record_id != GRN_ID_NIL) {
2290     grn_id result_record_id;
2291     result_record_id = grn_table_get(info->ctx, info->result,
2292                                      &(mroonga->record_id), sizeof(grn_id));
2293     if (result_record_id != GRN_ID_NIL) {
2294       GRN_BULK_REWIND(&(info->score));
2295       grn_obj_get_value(info->ctx, info->score_column,
2296                         result_record_id, &(info->score));
2297       score = mrn_get_score_value(&(info->score));
2298     }
2299   }
2300   DBUG_PRINT("info",
2301              ("mroonga: record_id=%d score=%g", mroonga->record_id, score));
2302 
2303   DBUG_RETURN(score);
2304 }
2305 
mrn_storage_ft_reinit_search(FT_INFO * handler)2306 static void mrn_storage_ft_reinit_search(FT_INFO *handler)
2307 {
2308   MRN_DBUG_ENTER_FUNCTION();
2309   DBUG_VOID_RETURN;
2310 }
2311 
2312 static _ft_vft mrn_storage_ft_vft = {
2313   mrn_storage_ft_read_next,
2314   mrn_storage_ft_find_relevance,
2315   mrn_storage_ft_close_search,
2316   mrn_storage_ft_get_relevance,
2317   mrn_storage_ft_reinit_search
2318 };
2319 
mrn_no_such_key_ft_read_next(FT_INFO * handler,char * record)2320 static int mrn_no_such_key_ft_read_next(FT_INFO *handler, char *record)
2321 {
2322   MRN_DBUG_ENTER_FUNCTION();
2323   DBUG_RETURN(HA_ERR_END_OF_FILE);
2324 }
2325 
mrn_no_such_key_ft_find_relevance(FT_INFO * handler,uchar * record,uint length)2326 static float mrn_no_such_key_ft_find_relevance(FT_INFO *handler, uchar *record,
2327                                                uint length)
2328 {
2329   MRN_DBUG_ENTER_FUNCTION();
2330   DBUG_RETURN(0.0);
2331 }
2332 
mrn_no_such_key_ft_close_search(FT_INFO * handler)2333 static void mrn_no_such_key_ft_close_search(FT_INFO *handler)
2334 {
2335   MRN_DBUG_ENTER_FUNCTION();
2336   st_mrn_ft_info *info = (st_mrn_ft_info *)handler;
2337   delete info;
2338   DBUG_VOID_RETURN;
2339 }
2340 
mrn_no_such_key_ft_get_relevance(FT_INFO * handler)2341 static float mrn_no_such_key_ft_get_relevance(FT_INFO *handler)
2342 {
2343   MRN_DBUG_ENTER_FUNCTION();
2344   DBUG_RETURN(0.0);
2345 }
2346 
mrn_no_such_key_ft_reinit_search(FT_INFO * handler)2347 static void mrn_no_such_key_ft_reinit_search(FT_INFO *handler)
2348 {
2349   MRN_DBUG_ENTER_FUNCTION();
2350   DBUG_VOID_RETURN;
2351 }
2352 
2353 static _ft_vft mrn_no_such_key_ft_vft = {
2354   mrn_no_such_key_ft_read_next,
2355   mrn_no_such_key_ft_find_relevance,
2356   mrn_no_such_key_ft_close_search,
2357   mrn_no_such_key_ft_get_relevance,
2358   mrn_no_such_key_ft_reinit_search
2359 };
2360 
2361 #ifdef HA_CAN_FULLTEXT_EXT
mrn_generic_ft_get_version()2362 static uint mrn_generic_ft_get_version()
2363 {
2364   MRN_DBUG_ENTER_FUNCTION();
2365   // This value is not used in MySQL 5.6.7-rc. So it is
2366   // meaningless. It may be used in the future...
2367   uint version = 1;
2368   DBUG_RETURN(version);
2369 }
2370 
mrn_generic_ft_ext_get_flags()2371 static ulonglong mrn_generic_ft_ext_get_flags()
2372 {
2373   MRN_DBUG_ENTER_FUNCTION();
2374   // TODO: Should we support FTS_ORDERED_RESULT?
2375   // TODO: Shuold we support FTS_DOCID_IN_RESULT?
2376   ulonglong flags = 0;
2377   DBUG_RETURN(flags);
2378 }
2379 
2380 // This function is used if we enable FTS_DOCID_IN_RESULT flag and the
2381 // table has "FTS_DOC_ID" (defined as FTS_DOC_ID_COL_NAME macro)
2382 // special name column. Should we support "FTS_DOC_ID" special name
2383 // column?
2384 // See also sql/sql_optimizer.cc:JOIN::optimize_fts_query().
mrn_generic_ft_ext_get_docid(FT_INFO_EXT * handler)2385 static ulonglong mrn_generic_ft_ext_get_docid(FT_INFO_EXT *handler)
2386 {
2387   MRN_DBUG_ENTER_FUNCTION();
2388   ulonglong id = GRN_ID_NIL;
2389   DBUG_RETURN(id);
2390 }
2391 
mrn_generic_ft_ext_count_matches(FT_INFO_EXT * handler)2392 static ulonglong mrn_generic_ft_ext_count_matches(FT_INFO_EXT *handler)
2393 {
2394   MRN_DBUG_ENTER_FUNCTION();
2395   st_mrn_ft_info *info = reinterpret_cast<st_mrn_ft_info *>(handler);
2396   ulonglong n_records = grn_table_size(info->ctx, info->result);
2397   DBUG_RETURN(n_records);
2398 }
2399 
mrn_wrapper_ft_ext_get_version()2400 static uint mrn_wrapper_ft_ext_get_version()
2401 {
2402   MRN_DBUG_ENTER_FUNCTION();
2403   uint version = mrn_generic_ft_get_version();
2404   DBUG_RETURN(version);
2405 }
2406 
mrn_wrapper_ft_ext_get_flags()2407 static ulonglong mrn_wrapper_ft_ext_get_flags()
2408 {
2409   MRN_DBUG_ENTER_FUNCTION();
2410   ulonglong flags = mrn_generic_ft_ext_get_flags();
2411   DBUG_RETURN(flags);
2412 }
2413 
mrn_wrapper_ft_ext_get_docid(FT_INFO_EXT * handler)2414 static ulonglong mrn_wrapper_ft_ext_get_docid(FT_INFO_EXT *handler)
2415 {
2416   MRN_DBUG_ENTER_FUNCTION();
2417   ulonglong id = mrn_generic_ft_ext_get_docid(handler);
2418   DBUG_RETURN(id);
2419 }
2420 
mrn_wrapper_ft_ext_count_matches(FT_INFO_EXT * handler)2421 static ulonglong mrn_wrapper_ft_ext_count_matches(FT_INFO_EXT *handler)
2422 {
2423   MRN_DBUG_ENTER_FUNCTION();
2424   ulonglong n_records = mrn_generic_ft_ext_count_matches(handler);
2425   DBUG_RETURN(n_records);
2426 }
2427 
2428 static _ft_vft_ext mrn_wrapper_ft_vft_ext = {
2429   mrn_wrapper_ft_ext_get_version,
2430   mrn_wrapper_ft_ext_get_flags,
2431   mrn_wrapper_ft_ext_get_docid,
2432   mrn_wrapper_ft_ext_count_matches
2433 };
2434 
mrn_storage_ft_ext_get_version()2435 static uint mrn_storage_ft_ext_get_version()
2436 {
2437   MRN_DBUG_ENTER_FUNCTION();
2438   uint version = mrn_generic_ft_get_version();
2439   DBUG_RETURN(version);
2440 }
2441 
mrn_storage_ft_ext_get_flags()2442 static ulonglong mrn_storage_ft_ext_get_flags()
2443 {
2444   MRN_DBUG_ENTER_FUNCTION();
2445   ulonglong flags = mrn_generic_ft_ext_get_flags();
2446   DBUG_RETURN(flags);
2447 }
2448 
mrn_storage_ft_ext_get_docid(FT_INFO_EXT * handler)2449 static ulonglong mrn_storage_ft_ext_get_docid(FT_INFO_EXT *handler)
2450 {
2451   MRN_DBUG_ENTER_FUNCTION();
2452   ulonglong id = mrn_generic_ft_ext_get_docid(handler);
2453   DBUG_RETURN(id);
2454 }
2455 
mrn_storage_ft_ext_count_matches(FT_INFO_EXT * handler)2456 static ulonglong mrn_storage_ft_ext_count_matches(FT_INFO_EXT *handler)
2457 {
2458   MRN_DBUG_ENTER_FUNCTION();
2459   ulonglong n_records = mrn_generic_ft_ext_count_matches(handler);
2460   DBUG_RETURN(n_records);
2461 }
2462 
2463 static _ft_vft_ext mrn_storage_ft_vft_ext = {
2464   mrn_storage_ft_ext_get_version,
2465   mrn_storage_ft_ext_get_flags,
2466   mrn_storage_ft_ext_get_docid,
2467   mrn_storage_ft_ext_count_matches
2468 };
2469 
mrn_no_such_key_ft_ext_get_version()2470 static uint mrn_no_such_key_ft_ext_get_version()
2471 {
2472   MRN_DBUG_ENTER_FUNCTION();
2473   uint version = mrn_generic_ft_get_version();
2474   DBUG_RETURN(version);
2475 }
2476 
mrn_no_such_key_ft_ext_get_flags()2477 static ulonglong mrn_no_such_key_ft_ext_get_flags()
2478 {
2479   MRN_DBUG_ENTER_FUNCTION();
2480   ulonglong flags = mrn_generic_ft_ext_get_flags();
2481   DBUG_RETURN(flags);
2482 }
2483 
mrn_no_such_key_ft_ext_get_docid(FT_INFO_EXT * handler)2484 static ulonglong mrn_no_such_key_ft_ext_get_docid(FT_INFO_EXT *handler)
2485 {
2486   MRN_DBUG_ENTER_FUNCTION();
2487   ulonglong id = GRN_ID_NIL;
2488   DBUG_RETURN(id);
2489 }
2490 
mrn_no_such_key_ft_ext_count_matches(FT_INFO_EXT * handler)2491 static ulonglong mrn_no_such_key_ft_ext_count_matches(FT_INFO_EXT *handler)
2492 {
2493   MRN_DBUG_ENTER_FUNCTION();
2494   ulonglong n_records = 0;
2495   DBUG_RETURN(n_records);
2496 }
2497 
2498 static _ft_vft_ext mrn_no_such_key_ft_vft_ext = {
2499   mrn_no_such_key_ft_ext_get_version,
2500   mrn_no_such_key_ft_ext_get_flags,
2501   mrn_no_such_key_ft_ext_get_docid,
2502   mrn_no_such_key_ft_ext_count_matches
2503 };
2504 #endif
2505 
2506 /* handler implementation */
ha_mroonga(handlerton * hton,TABLE_SHARE * share_arg)2507 ha_mroonga::ha_mroonga(handlerton *hton, TABLE_SHARE *share_arg)
2508   :handler(hton, share_arg),
2509    wrap_handler(NULL),
2510    is_clone(false),
2511    parent_for_clone(NULL),
2512    mem_root_for_clone(NULL),
2513    record_id(GRN_ID_NIL),
2514    key_id(NULL),
2515    del_key_id(NULL),
2516 
2517    wrap_ft_init_count(0),
2518    share(NULL),
2519    wrap_key_info(NULL),
2520    base_key_info(NULL),
2521 
2522    analyzed_for_create(false),
2523    wrap_handler_for_create(NULL),
2524 #ifdef MRN_HANDLER_HAVE_FINAL_ADD_INDEX
2525    hnd_add_index(NULL),
2526 #endif
2527 #ifdef MRN_HANDLER_HAVE_CHECK_IF_SUPPORTED_INPLACE_ALTER
2528    alter_key_info_buffer(NULL),
2529 #else
2530    wrap_alter_key_info(NULL),
2531 #endif
2532    mrn_lock_type(F_UNLCK),
2533 
2534    ctx_entity_(),
2535    ctx(&ctx_entity_),
2536    grn_table(NULL),
2537    grn_columns(NULL),
2538    grn_column_ranges(NULL),
2539    grn_index_tables(NULL),
2540    grn_index_columns(NULL),
2541 
2542    grn_source_column_geo(NULL),
2543    cursor_geo(NULL),
2544    cursor(NULL),
2545    index_table_cursor(NULL),
2546    empty_value_records(NULL),
2547    empty_value_records_cursor(NULL),
2548 
2549    sorted_result(NULL),
2550    matched_record_keys(NULL),
2551    blob_buffers(NULL),
2552 
2553    dup_key(0),
2554 
2555    count_skip(false),
2556    fast_order_limit(false),
2557    fast_order_limit_with_index(false),
2558 
2559    ignoring_duplicated_key(false),
2560    inserting_with_update(false),
2561    fulltext_searching(false),
2562    ignoring_no_key_columns(false),
2563    replacing_(false),
2564    written_by_row_based_binlog(0),
2565    current_ft_item(NULL),
2566    operations_(NULL)
2567 {
2568   MRN_DBUG_ENTER_METHOD();
2569   grn_ctx_init(ctx, 0);
2570   mrn_change_encoding(ctx, system_charset_info);
2571   grn_ctx_use(ctx, mrn_db);
2572   GRN_WGS84_GEO_POINT_INIT(&top_left_point, 0);
2573   GRN_WGS84_GEO_POINT_INIT(&bottom_right_point, 0);
2574   GRN_WGS84_GEO_POINT_INIT(&source_point, 0);
2575   GRN_TEXT_INIT(&key_buffer, 0);
2576   GRN_TEXT_INIT(&encoded_key_buffer, 0);
2577   GRN_VOID_INIT(&old_value_buffer);
2578   GRN_VOID_INIT(&new_value_buffer);
2579   DBUG_VOID_RETURN;
2580 }
2581 
~ha_mroonga()2582 ha_mroonga::~ha_mroonga()
2583 {
2584   MRN_DBUG_ENTER_METHOD();
2585 
2586   delete operations_;
2587 
2588   if (analyzed_for_create) {
2589     if (wrap_handler_for_create) {
2590       delete wrap_handler_for_create;
2591     }
2592     if (share_for_create.wrapper_mode) {
2593       plugin_unlock(NULL, share_for_create.plugin);
2594     }
2595     if (share_for_create.table_name) {
2596       my_free(share_for_create.table_name);
2597     }
2598     mrn_free_share_alloc(&share_for_create);
2599     free_root(&mem_root_for_create, MYF(0));
2600   }
2601   if (blob_buffers)
2602   {
2603     delete [] blob_buffers;
2604   }
2605   grn_obj_unlink(ctx, &top_left_point);
2606   grn_obj_unlink(ctx, &bottom_right_point);
2607   grn_obj_unlink(ctx, &source_point);
2608   grn_obj_unlink(ctx, &key_buffer);
2609   grn_obj_unlink(ctx, &encoded_key_buffer);
2610   grn_obj_unlink(ctx, &old_value_buffer);
2611   grn_obj_unlink(ctx, &new_value_buffer);
2612   grn_ctx_fin(ctx);
2613   DBUG_VOID_RETURN;
2614 }
2615 
table_type() const2616 const char *ha_mroonga::table_type() const
2617 {
2618   MRN_DBUG_ENTER_METHOD();
2619   DBUG_RETURN(MRN_PLUGIN_NAME_STRING);
2620 }
2621 
index_type(uint key_nr)2622 const char *ha_mroonga::index_type(uint key_nr)
2623 {
2624   MRN_DBUG_ENTER_METHOD();
2625   KEY *key_info = &(table->s->key_info[key_nr]);
2626   if (key_info->algorithm == HA_KEY_ALG_FULLTEXT) {
2627     DBUG_RETURN("FULLTEXT");
2628   } else if (key_info->algorithm == HA_KEY_ALG_HASH) {
2629     DBUG_RETURN("HASH");
2630   } else {
2631     DBUG_RETURN("BTREE");
2632   }
2633 }
2634 
2635 static const char *ha_mroonga_exts[] = {
2636   NullS
2637 };
bas_ext() const2638 const char **ha_mroonga::bas_ext() const
2639 {
2640   MRN_DBUG_ENTER_METHOD();
2641   DBUG_RETURN(ha_mroonga_exts);
2642 }
2643 
wrapper_max_supported_record_length() const2644 uint ha_mroonga::wrapper_max_supported_record_length() const
2645 {
2646   uint res;
2647   MRN_DBUG_ENTER_METHOD();
2648   if (analyzed_for_create && share_for_create.wrapper_mode) {
2649     res = wrap_handler_for_create->max_supported_record_length();
2650   } else {
2651     MRN_SET_WRAP_SHARE_KEY(share, table->s);
2652     MRN_SET_WRAP_TABLE_KEY(this, table);
2653     res = wrap_handler->max_supported_record_length();
2654     MRN_SET_BASE_SHARE_KEY(share, table->s);
2655     MRN_SET_BASE_TABLE_KEY(this, table);
2656   }
2657   DBUG_RETURN(res);
2658 }
2659 
storage_max_supported_record_length() const2660 uint ha_mroonga::storage_max_supported_record_length() const
2661 {
2662   MRN_DBUG_ENTER_METHOD();
2663   DBUG_RETURN(HA_MAX_REC_LENGTH);
2664 }
2665 
max_supported_record_length() const2666 uint ha_mroonga::max_supported_record_length() const
2667 {
2668   MRN_DBUG_ENTER_METHOD();
2669 
2670   uint res;
2671   if (!share && !analyzed_for_create &&
2672     (
2673       thd_sql_command(ha_thd()) == SQLCOM_CREATE_TABLE ||
2674       thd_sql_command(ha_thd()) == SQLCOM_CREATE_INDEX ||
2675       thd_sql_command(ha_thd()) == SQLCOM_ALTER_TABLE
2676     )
2677   ) {
2678     create_share_for_create();
2679   }
2680   if (analyzed_for_create && share_for_create.wrapper_mode) {
2681     res = wrapper_max_supported_record_length();
2682   } else if (wrap_handler && share && share->wrapper_mode) {
2683     res = wrapper_max_supported_record_length();
2684   } else {
2685     res = storage_max_supported_record_length();
2686   }
2687 
2688   DBUG_RETURN(res);
2689 }
2690 
wrapper_max_supported_keys() const2691 uint ha_mroonga::wrapper_max_supported_keys() const
2692 {
2693   uint res;
2694   MRN_DBUG_ENTER_METHOD();
2695   if (analyzed_for_create && share_for_create.wrapper_mode) {
2696     res = wrap_handler_for_create->max_supported_keys();
2697   } else {
2698     MRN_SET_WRAP_SHARE_KEY(share, table->s);
2699     MRN_SET_WRAP_TABLE_KEY(this, table);
2700     res = wrap_handler->max_supported_keys();
2701     MRN_SET_BASE_SHARE_KEY(share, table->s);
2702     MRN_SET_BASE_TABLE_KEY(this, table);
2703   }
2704   DBUG_RETURN(res);
2705 }
2706 
storage_max_supported_keys() const2707 uint ha_mroonga::storage_max_supported_keys() const
2708 {
2709   MRN_DBUG_ENTER_METHOD();
2710   DBUG_RETURN(HA_MAX_REC_LENGTH);
2711 }
2712 
max_supported_keys() const2713 uint ha_mroonga::max_supported_keys() const
2714 {
2715   MRN_DBUG_ENTER_METHOD();
2716 
2717   uint res;
2718   if (!share && !analyzed_for_create &&
2719     (
2720       thd_sql_command(ha_thd()) == SQLCOM_CREATE_TABLE ||
2721       thd_sql_command(ha_thd()) == SQLCOM_CREATE_INDEX ||
2722       thd_sql_command(ha_thd()) == SQLCOM_ALTER_TABLE
2723     )
2724   ) {
2725     create_share_for_create();
2726   }
2727   if (analyzed_for_create && share_for_create.wrapper_mode) {
2728     res = wrapper_max_supported_keys();
2729   } else if (wrap_handler && share && share->wrapper_mode) {
2730     res = wrapper_max_supported_keys();
2731   } else {
2732     res = storage_max_supported_keys();
2733   }
2734 
2735   DBUG_RETURN(res);
2736 }
2737 
wrapper_max_supported_key_length() const2738 uint ha_mroonga::wrapper_max_supported_key_length() const
2739 {
2740   uint res;
2741   MRN_DBUG_ENTER_METHOD();
2742   if (analyzed_for_create && share_for_create.wrapper_mode) {
2743     res = wrap_handler_for_create->max_supported_key_length();
2744   } else {
2745     MRN_SET_WRAP_SHARE_KEY(share, table->s);
2746     MRN_SET_WRAP_TABLE_KEY(this, table);
2747     res = wrap_handler->max_supported_key_length();
2748     MRN_SET_BASE_SHARE_KEY(share, table->s);
2749     MRN_SET_BASE_TABLE_KEY(this, table);
2750   }
2751   DBUG_RETURN(res);
2752 }
2753 
storage_max_supported_key_length() const2754 uint ha_mroonga::storage_max_supported_key_length() const
2755 {
2756   MRN_DBUG_ENTER_METHOD();
2757   DBUG_RETURN(GRN_TABLE_MAX_KEY_SIZE);
2758 }
2759 
max_supported_key_length() const2760 uint ha_mroonga::max_supported_key_length() const
2761 {
2762   MRN_DBUG_ENTER_METHOD();
2763 
2764   uint res;
2765   if (!share && !analyzed_for_create &&
2766     (
2767       thd_sql_command(ha_thd()) == SQLCOM_CREATE_TABLE ||
2768       thd_sql_command(ha_thd()) == SQLCOM_CREATE_INDEX ||
2769       thd_sql_command(ha_thd()) == SQLCOM_ALTER_TABLE
2770     )
2771   ) {
2772     create_share_for_create();
2773   }
2774   if (analyzed_for_create && share_for_create.wrapper_mode) {
2775     res = wrapper_max_supported_key_length();
2776   } else if (wrap_handler && share && share->wrapper_mode) {
2777     res = wrapper_max_supported_key_length();
2778   } else {
2779     res = storage_max_supported_key_length();
2780   }
2781 
2782   DBUG_RETURN(res);
2783 }
2784 
wrapper_max_supported_key_part_length() const2785 uint ha_mroonga::wrapper_max_supported_key_part_length() const
2786 {
2787   uint res;
2788   MRN_DBUG_ENTER_METHOD();
2789   if (analyzed_for_create && share_for_create.wrapper_mode) {
2790     res = wrap_handler_for_create->max_supported_key_part_length();
2791   } else {
2792     MRN_SET_WRAP_SHARE_KEY(share, table->s);
2793     MRN_SET_WRAP_TABLE_KEY(this, table);
2794     res = wrap_handler->max_supported_key_part_length();
2795     MRN_SET_BASE_SHARE_KEY(share, table->s);
2796     MRN_SET_BASE_TABLE_KEY(this, table);
2797   }
2798   DBUG_RETURN(res);
2799 }
2800 
storage_max_supported_key_part_length() const2801 uint ha_mroonga::storage_max_supported_key_part_length() const
2802 {
2803   MRN_DBUG_ENTER_METHOD();
2804   DBUG_RETURN(GRN_TABLE_MAX_KEY_SIZE);
2805 }
2806 
max_supported_key_part_length() const2807 uint ha_mroonga::max_supported_key_part_length() const
2808 {
2809   MRN_DBUG_ENTER_METHOD();
2810 
2811   uint res;
2812   if (!share && !analyzed_for_create &&
2813     (
2814       thd_sql_command(ha_thd()) == SQLCOM_CREATE_TABLE ||
2815       thd_sql_command(ha_thd()) == SQLCOM_CREATE_INDEX ||
2816       thd_sql_command(ha_thd()) == SQLCOM_ALTER_TABLE
2817     )
2818   ) {
2819     create_share_for_create();
2820   }
2821   if (analyzed_for_create && share_for_create.wrapper_mode) {
2822     res = wrapper_max_supported_key_part_length();
2823   } else if (wrap_handler && share && share->wrapper_mode) {
2824     res = wrapper_max_supported_key_part_length();
2825   } else {
2826     res = storage_max_supported_key_part_length();
2827   }
2828 
2829   DBUG_RETURN(res);
2830 }
2831 
wrapper_table_flags() const2832 ulonglong ha_mroonga::wrapper_table_flags() const
2833 {
2834   ulonglong table_flags;
2835   MRN_DBUG_ENTER_METHOD();
2836   if (analyzed_for_create && share_for_create.wrapper_mode) {
2837     table_flags = wrap_handler_for_create->ha_table_flags();
2838   } else {
2839     MRN_SET_WRAP_SHARE_KEY(share, table->s);
2840     MRN_SET_WRAP_TABLE_KEY(this, table);
2841     table_flags = wrap_handler->ha_table_flags();
2842     MRN_SET_BASE_SHARE_KEY(share, table->s);
2843     MRN_SET_BASE_TABLE_KEY(this, table);
2844   }
2845   table_flags |= HA_CAN_FULLTEXT | HA_PRIMARY_KEY_REQUIRED_FOR_DELETE |
2846     HA_CAN_RTREEKEYS | HA_REC_NOT_IN_SEQ;
2847 #ifdef HA_CAN_REPAIR
2848   table_flags |= HA_CAN_REPAIR;
2849 #endif
2850 #ifdef HA_CAN_FULLTEXT_EXT
2851   table_flags |= HA_CAN_FULLTEXT_EXT;
2852 #endif
2853 #ifdef HA_GENERATED_COLUMNS
2854   table_flags |= HA_GENERATED_COLUMNS;
2855 #endif
2856 #ifdef HA_CAN_VIRTUAL_COLUMNS
2857   table_flags |= HA_CAN_VIRTUAL_COLUMNS;
2858 #endif
2859   DBUG_RETURN(table_flags);
2860 }
2861 
storage_table_flags() const2862 ulonglong ha_mroonga::storage_table_flags() const
2863 {
2864   MRN_DBUG_ENTER_METHOD();
2865   ulonglong flags =
2866     HA_NO_TRANSACTIONS |
2867     HA_PARTIAL_COLUMN_READ |
2868     HA_REC_NOT_IN_SEQ |
2869     HA_NULL_IN_KEY |
2870     HA_CAN_INDEX_BLOBS |
2871     HA_STATS_RECORDS_IS_EXACT |
2872     HA_CAN_FULLTEXT |
2873     HA_BINLOG_FLAGS |
2874     HA_CAN_BIT_FIELD |
2875     HA_DUPLICATE_POS |
2876     HA_CAN_GEOMETRY |
2877     HA_CAN_RTREEKEYS;
2878     //HA_HAS_RECORDS;
2879 #ifdef HA_MUST_USE_TABLE_CONDITION_PUSHDOWN
2880   flags |= HA_MUST_USE_TABLE_CONDITION_PUSHDOWN;
2881 #endif
2882 #ifdef HA_CAN_REPAIR
2883   flags |= HA_CAN_REPAIR;
2884 #endif
2885 #ifdef HA_CAN_FULLTEXT_EXT
2886   flags |= HA_CAN_FULLTEXT_EXT;
2887 #endif
2888 #ifdef HA_GENERATED_COLUMNS
2889   flags |= HA_GENERATED_COLUMNS;
2890 #endif
2891 #ifdef HA_CAN_VIRTUAL_COLUMNS
2892   flags |= HA_CAN_VIRTUAL_COLUMNS;
2893 #endif
2894   DBUG_RETURN(flags);
2895 }
2896 
table_flags() const2897 ulonglong ha_mroonga::table_flags() const
2898 {
2899   MRN_DBUG_ENTER_METHOD();
2900 
2901   ulonglong flags;
2902   if (!share && !analyzed_for_create &&
2903     (
2904       thd_sql_command(ha_thd()) == SQLCOM_CREATE_TABLE ||
2905       thd_sql_command(ha_thd()) == SQLCOM_CREATE_INDEX ||
2906       thd_sql_command(ha_thd()) == SQLCOM_ALTER_TABLE
2907     )
2908   ) {
2909     create_share_for_create();
2910   }
2911   if (analyzed_for_create && share_for_create.wrapper_mode) {
2912     flags = wrapper_table_flags();
2913   } else if (wrap_handler && share && share->wrapper_mode) {
2914     flags = wrapper_table_flags();
2915   } else {
2916     flags = storage_table_flags();
2917   }
2918 
2919   DBUG_RETURN(flags);
2920 }
2921 
wrapper_index_flags(uint idx,uint part,bool all_parts) const2922 ulong ha_mroonga::wrapper_index_flags(uint idx, uint part, bool all_parts) const
2923 {
2924   ulong index_flags;
2925   KEY *key = &(table_share->key_info[idx]);
2926   MRN_DBUG_ENTER_METHOD();
2927   if (key->algorithm == HA_KEY_ALG_BTREE ||
2928       key->algorithm == HA_KEY_ALG_UNDEF) {
2929     MRN_SET_WRAP_SHARE_KEY(share, table->s);
2930     MRN_SET_WRAP_TABLE_KEY(this, table);
2931     index_flags = wrap_handler->index_flags(idx, part, all_parts);
2932     MRN_SET_BASE_SHARE_KEY(share, table->s);
2933     MRN_SET_BASE_TABLE_KEY(this, table);
2934   } else {
2935     index_flags = HA_ONLY_WHOLE_INDEX | HA_KEY_SCAN_NOT_ROR;
2936   }
2937   DBUG_RETURN(index_flags);
2938 }
2939 
storage_index_flags(uint idx,uint part,bool all_parts) const2940 ulong ha_mroonga::storage_index_flags(uint idx, uint part, bool all_parts) const
2941 {
2942   MRN_DBUG_ENTER_METHOD();
2943   ulong flags;
2944   KEY *key = &(table_share->key_info[idx]);
2945   if (key->algorithm == HA_KEY_ALG_BTREE ||
2946       key->algorithm == HA_KEY_ALG_UNDEF) {
2947     flags = HA_READ_NEXT | HA_READ_PREV | HA_READ_RANGE;
2948     bool need_normalize_p = false;
2949     // TODO: MariaDB 10.1 passes key->user_defined_key_parts as part
2950     // for ORDER BY DESC. We just it fallback to part = 0. We may use
2951     // it for optimization in the future.
2952     //
2953     // See also: test_if_order_by_key() in sql/sql_select.cc.
2954     if (KEY_N_KEY_PARTS(key) == part) {
2955       part = 0;
2956     }
2957     Field *field = &(key->key_part[part].field[0]);
2958     if (field && (have_custom_normalizer(key) || should_normalize(field))) {
2959       need_normalize_p = true;
2960     }
2961     if (!need_normalize_p) {
2962       flags |= HA_KEYREAD_ONLY;
2963     }
2964     if (KEY_N_KEY_PARTS(key) > 1 || !need_normalize_p) {
2965       flags |= HA_READ_ORDER;
2966     }
2967   } else {
2968     flags = HA_ONLY_WHOLE_INDEX | HA_KEY_SCAN_NOT_ROR;
2969   }
2970   DBUG_RETURN(flags);
2971 }
2972 
index_flags(uint idx,uint part,bool all_parts) const2973 ulong ha_mroonga::index_flags(uint idx, uint part, bool all_parts) const
2974 {
2975   MRN_DBUG_ENTER_METHOD();
2976 
2977   KEY *key = &(table_share->key_info[idx]);
2978   if (key->algorithm == HA_KEY_ALG_FULLTEXT) {
2979     DBUG_RETURN(HA_ONLY_WHOLE_INDEX | HA_KEY_SCAN_NOT_ROR);
2980   }
2981   if (mrn_is_geo_key(key)) {
2982     DBUG_RETURN(HA_ONLY_WHOLE_INDEX | HA_KEY_SCAN_NOT_ROR | HA_READ_RANGE);
2983   }
2984 
2985   int error = 0;
2986   if (wrap_handler && share && share->wrapper_mode)
2987   {
2988     error = wrapper_index_flags(idx, part, all_parts);
2989   } else {
2990     error = storage_index_flags(idx, part, all_parts);
2991   }
2992   DBUG_RETURN(error);
2993 }
2994 
create_share_for_create() const2995 int ha_mroonga::create_share_for_create() const
2996 {
2997   int error;
2998   THD *thd = ha_thd();
2999   LEX *lex = thd->lex;
3000   HA_CREATE_INFO *create_info = &lex->create_info;
3001   TABLE_LIST *table_list = MRN_LEX_GET_TABLE_LIST(lex);
3002   MRN_DBUG_ENTER_METHOD();
3003   wrap_handler_for_create = NULL;
3004   table_for_create.reset();
3005   table_share_for_create.reset();
3006   memset(&share_for_create, 0, sizeof(MRN_SHARE));
3007   if (table_share) {
3008     table_share_for_create.comment = table_share->comment;
3009     table_share_for_create.connect_string = table_share->connect_string;
3010   } else {
3011 #ifdef MRN_HANDLER_HAVE_CHECK_IF_SUPPORTED_INPLACE_ALTER
3012     if (thd_sql_command(ha_thd()) != SQLCOM_CREATE_INDEX) {
3013 #endif
3014       table_share_for_create.comment = create_info->comment;
3015       table_share_for_create.connect_string = create_info->connect_string;
3016 #ifdef MRN_HANDLER_HAVE_CHECK_IF_SUPPORTED_INPLACE_ALTER
3017     }
3018 #endif
3019     if (thd_sql_command(ha_thd()) == SQLCOM_ALTER_TABLE ||
3020         thd_sql_command(ha_thd()) == SQLCOM_CREATE_INDEX) {
3021       st_mrn_slot_data *slot_data = mrn_get_slot_data(thd, false);
3022       if (slot_data && slot_data->alter_create_info) {
3023         create_info = slot_data->alter_create_info;
3024         if (slot_data->alter_connect_string) {
3025           table_share_for_create.connect_string.str =
3026             slot_data->alter_connect_string;
3027           table_share_for_create.connect_string.length =
3028             strlen(slot_data->alter_connect_string);
3029         } else {
3030           table_share_for_create.connect_string.str = NULL;
3031           table_share_for_create.connect_string.length = 0;
3032         }
3033         if (slot_data->alter_comment) {
3034           table_share_for_create.comment.str =
3035             slot_data->alter_comment;
3036           table_share_for_create.comment.length =
3037             strlen(slot_data->alter_comment);
3038         } else {
3039           table_share_for_create.comment.str = NULL;
3040           table_share_for_create.comment.length = 0;
3041         }
3042       }
3043     }
3044   }
3045   mrn_init_alloc_root(&mem_root_for_create, 1024, 0, MYF(0));
3046   analyzed_for_create = true;
3047   if (table_list) {
3048     share_for_create.table_name = mrn_my_strndup(table_list->table_name.str,
3049                                                  table_list->table_name.length,
3050                                                  MYF(MY_WME));
3051     share_for_create.table_name_length = table_list->table_name.length;
3052   }
3053   share_for_create.table_share = &table_share_for_create;
3054   table_for_create.s = &table_share_for_create;
3055 #ifdef WITH_PARTITION_STORAGE_ENGINE
3056   table_for_create.part_info = NULL;
3057 #endif
3058   if ((error = mrn_parse_table_param(&share_for_create, &table_for_create)))
3059     goto error;
3060 
3061   if (share_for_create.wrapper_mode)
3062   {
3063     wrap_handler_for_create =
3064       share_for_create.hton->create(share_for_create.hton, NULL,
3065                                     &mem_root_for_create);
3066     if (!wrap_handler_for_create) {
3067       error = HA_ERR_OUT_OF_MEM;
3068       goto error;
3069     }
3070     wrap_handler_for_create->init();
3071   }
3072   DBUG_RETURN(0);
3073 
3074 error:
3075   if (share_for_create.wrapper_mode) {
3076     plugin_unlock(NULL, share_for_create.plugin);
3077   }
3078   mrn_free_share_alloc(&share_for_create);
3079   free_root(&mem_root_for_create, MYF(0));
3080   analyzed_for_create = false;
3081   thd->clear_error();
3082   DBUG_RETURN(error);
3083 }
3084 
wrapper_create(const char * name,TABLE * table,HA_CREATE_INFO * info,MRN_SHARE * tmp_share)3085 int ha_mroonga::wrapper_create(const char *name, TABLE *table,
3086                                HA_CREATE_INFO *info, MRN_SHARE *tmp_share)
3087 {
3088   int error = 0;
3089   handler *hnd;
3090   MRN_DBUG_ENTER_METHOD();
3091 
3092   if (table_share->primary_key == MAX_KEY)
3093   {
3094     my_message(ER_REQUIRES_PRIMARY_KEY,
3095                MRN_GET_ERR_MSG(ER_REQUIRES_PRIMARY_KEY), MYF(0));
3096     DBUG_RETURN(ER_REQUIRES_PRIMARY_KEY);
3097   }
3098 
3099   error = ensure_database_open(name);
3100   if (error)
3101     DBUG_RETURN(error);
3102 
3103   error = wrapper_create_index(name, table, tmp_share);
3104   if (error)
3105     DBUG_RETURN(error);
3106 
3107   wrap_key_info = mrn_create_key_info_for_table(tmp_share, table, &error);
3108   if (error)
3109     DBUG_RETURN(error);
3110   base_key_info = table->key_info;
3111 
3112   share = tmp_share;
3113   MRN_SET_WRAP_SHARE_KEY(tmp_share, table->s);
3114   MRN_SET_WRAP_TABLE_KEY(this, table);
3115 #ifdef MRN_SUPPORT_CUSTOM_OPTIONS
3116   if (parse_engine_table_options(ha_thd(), tmp_share->hton, table->s)) {
3117     MRN_SET_BASE_SHARE_KEY(tmp_share, table->s);
3118     MRN_SET_BASE_TABLE_KEY(this, table);
3119     share = NULL;
3120     if (wrap_key_info)
3121     {
3122       my_free(wrap_key_info);
3123       wrap_key_info = NULL;
3124     }
3125     base_key_info = NULL;
3126     error = MRN_GET_ERROR_NUMBER;
3127     DBUG_RETURN(error);
3128   }
3129 #endif
3130   hnd = get_new_handler(table->s, current_thd->mem_root, tmp_share->hton);
3131   if (!hnd)
3132   {
3133     MRN_SET_BASE_SHARE_KEY(tmp_share, table->s);
3134     MRN_SET_BASE_TABLE_KEY(this, table);
3135     share = NULL;
3136     if (wrap_key_info)
3137     {
3138       my_free(wrap_key_info);
3139       wrap_key_info = NULL;
3140     }
3141     base_key_info = NULL;
3142     DBUG_RETURN(HA_ERR_OUT_OF_MEM);
3143   }
3144   error = hnd->ha_create(name, table, info);
3145   MRN_SET_BASE_SHARE_KEY(tmp_share, table->s);
3146   MRN_SET_BASE_TABLE_KEY(this, table);
3147   share = NULL;
3148   delete hnd;
3149 
3150   if (error) {
3151     mrn::PathMapper mapper(name);
3152     generic_delete_table(name, mapper.table_name());
3153   }
3154 
3155   if (wrap_key_info)
3156   {
3157     my_free(wrap_key_info);
3158     wrap_key_info = NULL;
3159   }
3160   base_key_info = NULL;
3161   DBUG_RETURN(error);
3162 }
3163 
wrapper_create_index_fulltext_validate(KEY * key_info)3164 int ha_mroonga::wrapper_create_index_fulltext_validate(KEY *key_info)
3165 {
3166   MRN_DBUG_ENTER_METHOD();
3167 
3168   int error = 0;
3169   uint i;
3170   for (i = 0; i < KEY_N_KEY_PARTS(key_info); i++) {
3171     Field *field = key_info->key_part[i].field;
3172 
3173     grn_builtin_type gtype = mrn_grn_type_from_field(ctx, field, true);
3174     if (gtype != GRN_DB_SHORT_TEXT)
3175     {
3176       error = ER_CANT_CREATE_TABLE;
3177       GRN_LOG(ctx, GRN_LOG_ERROR,
3178               "key type must be text: <%d> "
3179               "(TODO: We should show type name not type ID.)",
3180               field->type());
3181       my_message(ER_CANT_CREATE_TABLE,
3182                  "key type must be text. (TODO: We should show type name.)",
3183                  MYF(0));
3184       DBUG_RETURN(error);
3185     }
3186   }
3187 
3188   DBUG_RETURN(error);
3189 }
3190 
wrapper_create_index_fulltext(const char * grn_table_name,int i,KEY * key_info,grn_obj ** index_tables,grn_obj ** index_columns,MRN_SHARE * tmp_share)3191 int ha_mroonga::wrapper_create_index_fulltext(const char *grn_table_name,
3192                                               int i,
3193                                               KEY *key_info,
3194                                               grn_obj **index_tables,
3195                                               grn_obj **index_columns,
3196                                               MRN_SHARE *tmp_share)
3197 {
3198   MRN_DBUG_ENTER_METHOD();
3199   int error = 0;
3200 
3201   error = wrapper_create_index_fulltext_validate(key_info);
3202   if (error) {
3203     DBUG_RETURN(error);
3204   }
3205 
3206   error = mrn_change_encoding(ctx, system_charset_info);
3207   if (error)
3208     DBUG_RETURN(error);
3209 
3210   grn_obj_flags index_table_flags =
3211     GRN_OBJ_TABLE_PAT_KEY |
3212     GRN_OBJ_PERSISTENT;
3213   grn_obj *index_table;
3214 
3215   grn_column_flags index_column_flags = GRN_OBJ_COLUMN_INDEX | GRN_OBJ_PERSISTENT;
3216 
3217   if (!find_index_column_flags(key_info, &index_column_flags)) {
3218     index_column_flags |= GRN_OBJ_WITH_POSITION;
3219     if (KEY_N_KEY_PARTS(key_info) > 1) {
3220       index_column_flags |= GRN_OBJ_WITH_SECTION;
3221     }
3222   }
3223 
3224   mrn::SmartGrnObj lexicon_key_type(ctx, GRN_DB_SHORT_TEXT);
3225   error = mrn_change_encoding(ctx, key_info->key_part->field->charset());
3226   if (error) {
3227     DBUG_RETURN(error);
3228   }
3229   mrn::IndexTableName index_table_name(grn_table_name, key_info->name.str);
3230   index_table = grn_table_create(ctx,
3231                                  index_table_name.c_str(),
3232                                  index_table_name.length(),
3233                                  NULL,
3234                                  index_table_flags,
3235                                  lexicon_key_type.get(),
3236                                  0);
3237   if (ctx->rc) {
3238     error = ER_CANT_CREATE_TABLE;
3239     my_message(ER_CANT_CREATE_TABLE, ctx->errbuf, MYF(0));
3240     DBUG_RETURN(error);
3241   }
3242   mrn_change_encoding(ctx, system_charset_info);
3243   index_tables[i] = index_table;
3244 
3245   grn_obj *tokenizer = find_tokenizer(key_info, tmp_share, i);
3246   if (tokenizer) {
3247     grn_info_type info_type = GRN_INFO_DEFAULT_TOKENIZER;
3248     grn_obj_set_info(ctx, index_table, info_type, tokenizer);
3249     grn_obj_unlink(ctx, tokenizer);
3250   }
3251 
3252   {
3253     grn_obj token_filters;
3254     GRN_PTR_INIT(&token_filters, GRN_OBJ_VECTOR, 0);
3255     if (find_token_filters(key_info, &token_filters)) {
3256       grn_obj_set_info(ctx, index_table,
3257                        GRN_INFO_TOKEN_FILTERS, &token_filters);
3258     }
3259     grn_obj_unlink(ctx, &token_filters);
3260   }
3261 
3262   if (have_custom_normalizer(key_info) ||
3263       should_normalize(&key_info->key_part->field[0])) {
3264     grn_info_type info_type = GRN_INFO_NORMALIZER;
3265     grn_obj *normalizer = find_normalizer(key_info);
3266     if (normalizer) {
3267       grn_obj_set_info(ctx, index_table, info_type, normalizer);
3268       grn_obj_unlink(ctx, normalizer);
3269     }
3270   }
3271 
3272   grn_obj *index_column = grn_column_create(ctx, index_table,
3273                                             INDEX_COLUMN_NAME,
3274                                             strlen(INDEX_COLUMN_NAME),
3275                                             NULL,
3276                                             index_column_flags,
3277                                             grn_table);
3278   if (ctx->rc) {
3279     error = ER_CANT_CREATE_TABLE;
3280     my_message(error, ctx->errbuf, MYF(0));
3281     DBUG_RETURN(error);
3282   }
3283   if (index_columns) {
3284     index_columns[i] = index_column;
3285   } else {
3286     grn_obj_unlink(ctx, index_column);
3287   }
3288 
3289   DBUG_RETURN(error);
3290 }
3291 
wrapper_create_index_geo(const char * grn_table_name,int i,KEY * key_info,grn_obj ** index_tables,grn_obj ** index_columns,MRN_SHARE * tmp_share)3292 int ha_mroonga::wrapper_create_index_geo(const char *grn_table_name,
3293                                          int i,
3294                                          KEY *key_info,
3295                                          grn_obj **index_tables,
3296                                          grn_obj **index_columns,
3297                                          MRN_SHARE *tmp_share)
3298 {
3299   MRN_DBUG_ENTER_METHOD();
3300   int error;
3301 
3302   error = mrn_change_encoding(ctx, system_charset_info);
3303   if (error)
3304     DBUG_RETURN(error);
3305 
3306   mrn::IndexTableName index_table_name(grn_table_name, key_info->name.str);
3307 
3308   grn_obj_flags index_table_flags =
3309     GRN_OBJ_TABLE_PAT_KEY |
3310     GRN_OBJ_PERSISTENT;
3311   grn_obj *index_table;
3312 
3313   grn_obj_flags index_column_flags =
3314     GRN_OBJ_COLUMN_INDEX | GRN_OBJ_PERSISTENT;
3315 
3316   grn_obj *lexicon_key_type = grn_ctx_at(ctx, GRN_DB_WGS84_GEO_POINT);
3317   index_table = grn_table_create(ctx,
3318                                  index_table_name.c_str(),
3319                                  index_table_name.length(),
3320                                  NULL,
3321                                  index_table_flags, lexicon_key_type, 0);
3322   if (ctx->rc) {
3323     error = ER_CANT_CREATE_TABLE;
3324     my_message(ER_CANT_CREATE_TABLE, ctx->errbuf, MYF(0));
3325     grn_obj_unlink(ctx, lexicon_key_type);
3326     DBUG_RETURN(error);
3327   }
3328   grn_obj_unlink(ctx, lexicon_key_type);
3329   index_tables[i] = index_table;
3330 
3331   grn_obj *index_column = grn_column_create(ctx, index_table,
3332                                             INDEX_COLUMN_NAME,
3333                                             strlen(INDEX_COLUMN_NAME),
3334                                             NULL,
3335                                             index_column_flags,
3336                                             grn_table);
3337   if (ctx->rc) {
3338     error = ER_CANT_CREATE_TABLE;
3339     my_message(error, ctx->errbuf, MYF(0));
3340     DBUG_RETURN(error);
3341   }
3342   if (index_columns) {
3343     index_columns[i] = index_column;
3344   } else {
3345     grn_obj_unlink(ctx, index_column);
3346   }
3347 
3348   DBUG_RETURN(error);
3349 }
3350 
wrapper_create_index(const char * name,TABLE * table,MRN_SHARE * tmp_share)3351 int ha_mroonga::wrapper_create_index(const char *name, TABLE *table,
3352                                      MRN_SHARE *tmp_share)
3353 {
3354   MRN_DBUG_ENTER_METHOD();
3355 
3356   int error = 0;
3357   error = mrn_change_encoding(ctx, system_charset_info);
3358   if (error)
3359     DBUG_RETURN(error);
3360 
3361   grn_obj *grn_index_table;
3362   mrn::PathMapper mapper(name);
3363   const char *grn_table_name = mapper.table_name();
3364   char *grn_table_path = NULL;     // we don't specify path
3365   grn_obj *pkey_type = grn_ctx_at(ctx, GRN_DB_SHORT_TEXT);
3366   grn_obj *pkey_value_type = NULL; // we don't use this
3367   grn_obj_flags grn_table_flags = GRN_OBJ_PERSISTENT | GRN_OBJ_TABLE_HASH_KEY;
3368 
3369   grn_index_table = grn_table_create(ctx, grn_table_name, strlen(grn_table_name),
3370                                      grn_table_path, grn_table_flags,
3371                                      pkey_type, pkey_value_type);
3372   if (ctx->rc) {
3373     error = ER_CANT_CREATE_TABLE;
3374     my_message(error, ctx->errbuf, MYF(0));
3375     DBUG_RETURN(error);
3376   }
3377   if (grn_table) {
3378     grn_obj_unlink(ctx, grn_table);
3379   }
3380   grn_table = grn_index_table;
3381 
3382   uint i;
3383   uint n_keys = table->s->keys;
3384   MRN_ALLOCATE_VARIABLE_LENGTH_ARRAYS(grn_obj *, index_tables, n_keys);
3385   if (!tmp_share->disable_keys) {
3386     for (i = 0; i < n_keys; i++) {
3387       index_tables[i] = NULL;
3388 
3389       KEY *key_info = &(table->s->key_info[i]);
3390       if (key_info->algorithm == HA_KEY_ALG_FULLTEXT) {
3391         error = wrapper_create_index_fulltext(grn_table_name,
3392                                               i, key_info,
3393                                               index_tables, NULL, tmp_share);
3394       } else if (mrn_is_geo_key(key_info)) {
3395         error = wrapper_create_index_geo(grn_table_name,
3396                                          i, key_info,
3397                                          index_tables, NULL, tmp_share);
3398       }
3399     }
3400   }
3401 
3402   if (error) {
3403     for (uint j = 0; j < i; j++) {
3404       if (index_tables[j]) {
3405         grn_obj_remove(ctx, index_tables[j]);
3406       }
3407     }
3408     grn_obj_remove(ctx, grn_table);
3409     grn_table = NULL;
3410   }
3411   MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_tables);
3412   DBUG_RETURN(error);
3413 }
3414 
storage_create(const char * name,TABLE * table,HA_CREATE_INFO * info,MRN_SHARE * tmp_share)3415 int ha_mroonga::storage_create(const char *name, TABLE *table,
3416                                HA_CREATE_INFO *info, MRN_SHARE *tmp_share)
3417 {
3418   int error;
3419   MRN_LONG_TERM_SHARE *long_term_share = tmp_share->long_term_share;
3420   MRN_DBUG_ENTER_METHOD();
3421 
3422   if (info->auto_increment_value) {
3423     mrn::Lock lock(&long_term_share->auto_inc_mutex);
3424     long_term_share->auto_inc_value = info->auto_increment_value;
3425     DBUG_PRINT("info", ("mroonga: auto_inc_value=%llu",
3426       long_term_share->auto_inc_value));
3427     long_term_share->auto_inc_inited = true;
3428   }
3429 
3430   error = storage_create_validate_pseudo_column(table);
3431   if (error)
3432     DBUG_RETURN(error);
3433 
3434   error = storage_create_validate_index(table);
3435   if (error)
3436     DBUG_RETURN(error);
3437 
3438   error = ensure_database_open(name);
3439   if (error)
3440     DBUG_RETURN(error);
3441 
3442   error = mrn_change_encoding(ctx, system_charset_info);
3443   if (error)
3444     DBUG_RETURN(error);
3445 
3446   grn_obj_flags table_flags = GRN_OBJ_PERSISTENT;
3447 
3448   /* primary key must be handled before creating table */
3449   grn_obj *pkey_type;
3450   uint pkey_nr = table->s->primary_key;
3451   if (pkey_nr != MAX_INDEXES) {
3452     KEY *key_info = &(table->s->key_info[pkey_nr]);
3453     bool is_id;
3454 
3455     int key_parts = KEY_N_KEY_PARTS(key_info);
3456     if (key_parts == 1) {
3457       Field *pkey_field = key_info->key_part[0].field;
3458       const char *column_name = pkey_field->field_name.str;
3459       is_id = (strcmp(MRN_COLUMN_NAME_ID, column_name) == 0);
3460 
3461       grn_builtin_type gtype = mrn_grn_type_from_field(ctx, pkey_field, false);
3462       pkey_type = grn_ctx_at(ctx, gtype);
3463     } else {
3464       is_id = false;
3465       pkey_type = grn_ctx_at(ctx, GRN_DB_SHORT_TEXT);
3466     }
3467 
3468     // default algorithm is BTREE ==> PAT
3469     if (!is_id && key_info->algorithm == HA_KEY_ALG_HASH) {
3470       table_flags |= GRN_OBJ_TABLE_HASH_KEY;
3471     } else if (!is_id) {
3472       table_flags |= GRN_OBJ_TABLE_PAT_KEY;
3473     } else {
3474       // for _id
3475       table_flags |= GRN_OBJ_TABLE_NO_KEY;
3476       pkey_type = NULL;
3477     }
3478 
3479   } else {
3480     // primary key doesn't exists
3481     table_flags |= GRN_OBJ_TABLE_NO_KEY;
3482     pkey_type = NULL;
3483   }
3484 
3485   /* create table */
3486   grn_obj *table_obj;
3487   mrn::PathMapper mapper(name);
3488 
3489   char *table_path = NULL;           // we don't specify path
3490   grn_obj *pkey_value_type = NULL; // we don't use this
3491 
3492   table_obj = grn_table_create(ctx,
3493                                mapper.table_name(), strlen(mapper.table_name()),
3494                                table_path,
3495                                table_flags, pkey_type, pkey_value_type);
3496   if (ctx->rc) {
3497     error = ER_CANT_CREATE_TABLE;
3498     my_message(error, ctx->errbuf, MYF(0));
3499     DBUG_RETURN(error);
3500   }
3501 
3502   if (table_flags == (GRN_OBJ_PERSISTENT | GRN_OBJ_TABLE_PAT_KEY) ||
3503       table_flags == (GRN_OBJ_PERSISTENT | GRN_OBJ_TABLE_HASH_KEY)) {
3504     KEY *key_info = &(table->s->key_info[pkey_nr]);
3505     int key_parts = KEY_N_KEY_PARTS(key_info);
3506     if (key_parts == 1) {
3507       grn_obj *normalizer = NULL;
3508       if (tmp_share->normalizer) {
3509         normalizer = grn_ctx_get(ctx,
3510                                  tmp_share->normalizer,
3511                                  tmp_share->normalizer_length);
3512       } else {
3513         Field *field = &(key_info->key_part->field[0]);
3514         if (should_normalize(field)) {
3515           normalizer = find_normalizer(key_info);
3516         }
3517       }
3518       if (normalizer) {
3519         grn_info_type info_type = GRN_INFO_NORMALIZER;
3520         grn_obj_set_info(ctx, table_obj, info_type, normalizer);
3521         grn_obj_unlink(ctx, normalizer);
3522       }
3523       if (tmp_share->default_tokenizer) {
3524         grn_obj *default_tokenizer =
3525           grn_ctx_get(ctx,
3526                       tmp_share->default_tokenizer,
3527                       tmp_share->default_tokenizer_length);
3528         if (default_tokenizer) {
3529           grn_info_type info_type = GRN_INFO_DEFAULT_TOKENIZER;
3530           grn_obj_set_info(ctx, table_obj, info_type, default_tokenizer);
3531           grn_obj_unlink(ctx, default_tokenizer);
3532         }
3533       }
3534       if (tmp_share->token_filters) {
3535         grn_obj token_filters;
3536         GRN_PTR_INIT(&token_filters, GRN_OBJ_VECTOR, 0);
3537         if (find_token_filters_fill(&token_filters,
3538                                     tmp_share->token_filters,
3539                                     tmp_share->token_filters_length)) {
3540           grn_obj_set_info(ctx, table_obj,
3541                            GRN_INFO_TOKEN_FILTERS, &token_filters);
3542         }
3543         grn_obj_unlink(ctx, &token_filters);
3544       }
3545     }
3546   }
3547 
3548   /* create columns */
3549   uint n_columns = table->s->fields;
3550   for (uint i = 0; i < n_columns; i++) {
3551     Field *field = table->s->field[i];
3552     mrn::ColumnName column_name(field->field_name);
3553 
3554     if (strcmp(MRN_COLUMN_NAME_ID, column_name.mysql_name()) == 0) {
3555       continue;
3556     }
3557 
3558 #ifdef MRN_SUPPORT_FOREIGN_KEYS
3559     if (storage_create_foreign_key(table, mapper.table_name(), field, table_obj,
3560                                    error)) {
3561       continue;
3562     }
3563     if (error) {
3564       grn_obj_remove(ctx, table_obj);
3565       DBUG_RETURN(error);
3566     }
3567 #endif
3568 
3569 #ifdef MRN_SUPPORT_GENERATED_COLUMNS
3570     if (MRN_GENERATED_COLUMNS_FIELD_IS_VIRTUAL(field)) {
3571       continue;
3572     }
3573 #endif
3574 
3575     grn_obj_flags col_flags = GRN_OBJ_PERSISTENT;
3576     if (!find_column_flags(field, tmp_share, i, &col_flags)) {
3577       col_flags |= GRN_OBJ_COLUMN_SCALAR;
3578     }
3579 
3580     grn_obj *col_type;
3581     {
3582       int column_type_error_code = ER_CANT_CREATE_TABLE;
3583       col_type = find_column_type(field, tmp_share, i, column_type_error_code);
3584       if (!col_type) {
3585         grn_obj_remove(ctx, table_obj);
3586         DBUG_RETURN(column_type_error_code);
3587       }
3588     }
3589     char *col_path = NULL; // we don't specify path
3590 
3591     grn_column_create(ctx, table_obj,
3592                       column_name.c_str(), column_name.length(),
3593                       col_path, col_flags, col_type);
3594     if (ctx->rc) {
3595       error = ER_CANT_CREATE_TABLE;
3596       my_message(error, ctx->errbuf, MYF(0));
3597       grn_obj_remove(ctx, table_obj);
3598       DBUG_RETURN(error);
3599     }
3600   }
3601 
3602   error = storage_create_indexes(table, mapper.table_name(), table_obj,
3603                                  tmp_share);
3604   if (error) {
3605     grn_obj_remove(ctx, table_obj);
3606     table_obj = NULL;
3607   }
3608 
3609   if (table_obj) {
3610     grn_obj_unlink(ctx, table_obj);
3611   }
3612 
3613   DBUG_RETURN(error);
3614 }
3615 
storage_create_validate_pseudo_column(TABLE * table)3616 int ha_mroonga::storage_create_validate_pseudo_column(TABLE *table)
3617 {
3618   int error = 0;
3619   uint i, n_columns;
3620 
3621   MRN_DBUG_ENTER_METHOD();
3622   n_columns = table->s->fields;
3623   for (i = 0; i < n_columns; i++) {
3624     Field *field = table->s->field[i];
3625     const char *column_name = field->field_name.str;
3626     if (strcmp(MRN_COLUMN_NAME_ID, column_name) == 0) {
3627       switch (field->type()) {
3628       case MYSQL_TYPE_TINY :
3629       case MYSQL_TYPE_SHORT :
3630       case MYSQL_TYPE_INT24 :
3631       case MYSQL_TYPE_LONG :
3632       case MYSQL_TYPE_LONGLONG :
3633         break;
3634       default:
3635         GRN_LOG(ctx, GRN_LOG_ERROR, "_id must be numeric data type");
3636         error = ER_CANT_CREATE_TABLE;
3637         my_message(error, "_id must be numeric data type", MYF(0));
3638         DBUG_RETURN(error);
3639       }
3640     }
3641   }
3642 
3643   DBUG_RETURN(error);
3644 }
3645 
3646 #ifdef MRN_SUPPORT_FOREIGN_KEYS
storage_create_foreign_key(TABLE * table,const char * grn_table_name,Field * field,grn_obj * table_obj,int & error)3647 bool ha_mroonga::storage_create_foreign_key(TABLE *table,
3648                                             const char *grn_table_name,
3649                                             Field *field,
3650                                             grn_obj *table_obj, int &error)
3651 {
3652   MRN_DBUG_ENTER_METHOD();
3653   LEX *lex = ha_thd()->lex;
3654   Alter_info *alter_info = &lex->alter_info;
3655   List_iterator<Key> key_iterator(alter_info->key_list);
3656   Key *key;
3657   char ref_db_buff[NAME_LEN + 1], ref_table_buff[NAME_LEN + 1];
3658   while ((key = key_iterator++))
3659   {
3660     if (key->type != MRN_KEYTYPE_FOREIGN)
3661     {
3662       continue;
3663     }
3664     if (key->columns.elements > 1)
3665     {
3666       error = ER_CANT_CREATE_TABLE;
3667       my_message(error, "mroonga can't use FOREIGN_KEY with multiple columns",
3668         MYF(0));
3669       DBUG_RETURN(false);
3670     }
3671     List_iterator<Key_part_spec> key_part_col_iterator(key->columns);
3672     Key_part_spec *key_part_col = key_part_col_iterator++;
3673     LEX_CSTRING field_name = key_part_col->field_name;
3674     DBUG_PRINT("info", ("mroonga: field_name=%s", field_name.str));
3675     DBUG_PRINT("info", ("mroonga: field->field_name=%s", field->field_name.str));
3676     if (strcmp(field->field_name.str, field_name.str))
3677     {
3678       continue;
3679     }
3680     Foreign_key *fk = (Foreign_key *) key;
3681     List_iterator<Key_part_spec> key_part_ref_col_iterator(fk->ref_columns);
3682     Key_part_spec *key_part_ref_col = key_part_ref_col_iterator++;
3683     LEX_CSTRING ref_field_name = key_part_ref_col->field_name;
3684     DBUG_PRINT("info", ("mroonga: ref_field_name=%s", ref_field_name.str));
3685 #ifdef MRN_FOREIGN_KEY_USE_CONST_STRING
3686     LEX_CSTRING ref_db_name = fk->ref_db;
3687 #else
3688     LEX_STRING ref_db_name = fk->ref_db;
3689 #endif
3690     DBUG_PRINT("info", ("mroonga: ref_db_name=%s", ref_db_name.str));
3691     if (ref_db_name.str && lower_case_table_names) {
3692       strmake(ref_db_buff, ref_db_name.str, sizeof(ref_db_buff) - 1);
3693       my_casedn_str(system_charset_info, ref_db_buff);
3694       ref_db_name.str = ref_db_buff;
3695       DBUG_PRINT("info", ("mroonga: casedn ref_db_name=%s", ref_db_name.str));
3696     }
3697 #ifdef MRN_FOREIGN_KEY_USE_CONST_STRING
3698     LEX_CSTRING ref_table_name = fk->ref_table;
3699 #else
3700     LEX_STRING ref_table_name = fk->ref_table;
3701 #endif
3702     DBUG_PRINT("info", ("mroonga: ref_table_name=%s", ref_table_name.str));
3703     if (ref_table_name.str && lower_case_table_names) {
3704       strmake(ref_table_buff, ref_table_name.str, sizeof(ref_table_buff) - 1);
3705       my_casedn_str(system_charset_info, ref_table_buff);
3706       ref_table_name.str = ref_table_buff;
3707       DBUG_PRINT("info", ("mroonga: casedn ref_table_name=%s", ref_table_name.str));
3708     }
3709     if (ref_db_name.str && strcmp(table->s->db.str, ref_db_name.str))
3710     {
3711       error = ER_CANT_CREATE_TABLE;
3712       my_message(error,
3713         "mroonga can't use FOREIGN_KEY during different database tables",
3714         MYF(0));
3715       DBUG_RETURN(false);
3716     }
3717 
3718     grn_obj *column, *column_ref = NULL, *grn_table_ref = NULL;
3719     char ref_path[FN_REFLEN + 1];
3720     TABLE_LIST table_list;
3721     TABLE_SHARE *tmp_ref_table_share;
3722     build_table_filename(ref_path, sizeof(ref_path) - 1,
3723                          table->s->db.str, ref_table_name.str, "", 0);
3724 
3725     DBUG_PRINT("info", ("mroonga: ref_path=%s", ref_path));
3726     error = mrn_change_encoding(ctx, system_charset_info);
3727     if (error)
3728       DBUG_RETURN(false);
3729     mrn::PathMapper mapper(ref_path);
3730     grn_table_ref = grn_ctx_get(ctx, mapper.table_name(),
3731                                 strlen(mapper.table_name()));
3732     if (!grn_table_ref) {
3733       error = ER_CANT_CREATE_TABLE;
3734       char err_msg[MRN_BUFFER_SIZE];
3735       sprintf(err_msg, "reference table [%s.%s] is not mroonga table",
3736               table->s->db.str, ref_table_name.str);
3737       my_message(error, err_msg, MYF(0));
3738       DBUG_RETURN(false);
3739     }
3740 
3741     LEX_CSTRING tmp_db_name=    { mapper.db_name(), strlen(mapper.db_name()) };
3742     LEX_CSTRING tmp_table_name= { mapper.mysql_table_name(), strlen(mapper.mysql_table_name()) };
3743     table_list.init_one_table(&tmp_db_name, &tmp_table_name, 0, TL_WRITE);
3744     mrn_open_mutex_lock(table->s);
3745     tmp_ref_table_share =
3746       mrn_create_tmp_table_share(&table_list, ref_path, &error);
3747     mrn_open_mutex_unlock(table->s);
3748     if (!tmp_ref_table_share) {
3749       grn_obj_unlink(ctx, grn_table_ref);
3750       error = ER_CANT_CREATE_TABLE;
3751       char err_msg[MRN_BUFFER_SIZE];
3752       sprintf(err_msg, "reference table [%s.%s] is not found",
3753               table->s->db.str, ref_table_name.str);
3754       my_message(error, err_msg, MYF(0));
3755       DBUG_RETURN(false);
3756     }
3757     uint ref_pkey_nr = tmp_ref_table_share->primary_key;
3758     if (ref_pkey_nr == MAX_KEY) {
3759       mrn_open_mutex_lock(table->s);
3760       mrn_free_tmp_table_share(tmp_ref_table_share);
3761       mrn_open_mutex_unlock(table->s);
3762       grn_obj_unlink(ctx, grn_table_ref);
3763       error = ER_CANT_CREATE_TABLE;
3764       char err_msg[MRN_BUFFER_SIZE];
3765       sprintf(err_msg, "reference table [%s.%s] has no primary key",
3766               table->s->db.str, ref_table_name.str);
3767       my_message(error, err_msg, MYF(0));
3768       DBUG_RETURN(false);
3769     }
3770     KEY *ref_key_info = &tmp_ref_table_share->key_info[ref_pkey_nr];
3771     uint ref_key_parts = KEY_N_KEY_PARTS(ref_key_info);
3772     if (ref_key_parts > 1) {
3773       mrn_open_mutex_lock(table->s);
3774       mrn_free_tmp_table_share(tmp_ref_table_share);
3775       mrn_open_mutex_unlock(table->s);
3776       grn_obj_unlink(ctx, grn_table_ref);
3777       error = ER_CANT_CREATE_TABLE;
3778       char err_msg[MRN_BUFFER_SIZE];
3779       sprintf(err_msg,
3780               "reference table [%s.%s] primary key is multiple column",
3781               table->s->db.str, ref_table_name.str);
3782       my_message(error, err_msg, MYF(0));
3783       DBUG_RETURN(false);
3784     }
3785     Field *ref_field = &ref_key_info->key_part->field[0];
3786     if (strcmp(ref_field->field_name.str, ref_field_name.str)) {
3787       mrn_open_mutex_lock(table->s);
3788       mrn_free_tmp_table_share(tmp_ref_table_share);
3789       mrn_open_mutex_unlock(table->s);
3790       grn_obj_unlink(ctx, grn_table_ref);
3791       error = ER_CANT_CREATE_TABLE;
3792       char err_msg[MRN_BUFFER_SIZE];
3793       sprintf(err_msg,
3794               "reference column [%s.%s.%s] is not used for primary key",
3795               table->s->db.str, ref_table_name.str, ref_field_name.str);
3796       my_message(error, err_msg, MYF(0));
3797       DBUG_RETURN(false);
3798     }
3799     mrn_open_mutex_lock(table->s);
3800     mrn_free_tmp_table_share(tmp_ref_table_share);
3801     mrn_open_mutex_unlock(table->s);
3802     grn_obj_flags col_flags = GRN_OBJ_PERSISTENT;
3803     column = grn_column_create(ctx, table_obj, field->field_name.str,
3804                                field->field_name.length,
3805                                NULL, col_flags, grn_table_ref);
3806     if (ctx->rc) {
3807       grn_obj_unlink(ctx, grn_table_ref);
3808       error = ER_CANT_CREATE_TABLE;
3809       my_message(error, ctx->errbuf, MYF(0));
3810       DBUG_RETURN(false);
3811     }
3812 
3813     mrn::IndexColumnName index_column_name(grn_table_name, field->field_name.str);
3814     grn_obj_flags ref_col_flags = GRN_OBJ_COLUMN_INDEX | GRN_OBJ_PERSISTENT;
3815     column_ref = grn_column_create(ctx, grn_table_ref,
3816                                    index_column_name.c_str(),
3817                                    index_column_name.length(),
3818                                    NULL, ref_col_flags, table_obj);
3819     if (ctx->rc) {
3820       grn_obj_unlink(ctx, column);
3821       grn_obj_unlink(ctx, grn_table_ref);
3822       error = ER_CANT_CREATE_TABLE;
3823       my_message(error, ctx->errbuf, MYF(0));
3824       DBUG_RETURN(false);
3825     }
3826 
3827     grn_obj source_ids;
3828     grn_id source_id = grn_obj_id(ctx, column);
3829     GRN_UINT32_INIT(&source_ids, GRN_OBJ_VECTOR);
3830     GRN_UINT32_PUT(ctx, &source_ids, source_id);
3831     if (error) {
3832       grn_obj_unlink(ctx, &source_ids);
3833       grn_obj_unlink(ctx, column_ref);
3834       grn_obj_unlink(ctx, column);
3835       grn_obj_unlink(ctx, grn_table_ref);
3836       DBUG_RETURN(false);
3837     }
3838     grn_obj_set_info(ctx, column_ref, GRN_INFO_SOURCE, &source_ids);
3839     grn_obj_unlink(ctx, &source_ids);
3840     grn_obj_unlink(ctx, column_ref);
3841     grn_obj_unlink(ctx, column);
3842     grn_obj_unlink(ctx, grn_table_ref);
3843     error = 0;
3844     DBUG_RETURN(true);
3845   }
3846   error = 0;
3847   DBUG_RETURN(false);
3848 }
3849 #endif
3850 
storage_create_validate_index(TABLE * table)3851 int ha_mroonga::storage_create_validate_index(TABLE *table)
3852 {
3853   int error = 0;
3854   uint i;
3855 
3856   MRN_DBUG_ENTER_METHOD();
3857   /* checking if index is used for virtual columns  */
3858   uint n_keys = table->s->keys;
3859   for (i = 0; i < n_keys; i++) {
3860     KEY *key_info = &(table->s->key_info[i]);
3861     // must be single column key
3862     int key_parts = KEY_N_KEY_PARTS(key_info);
3863     if (key_parts != 1) {
3864       continue;
3865     }
3866     Field *field = key_info->key_part[0].field;
3867     const char *column_name = field->field_name.str;
3868     if (strcmp(MRN_COLUMN_NAME_ID, column_name) == 0) {
3869       if (key_info->algorithm == HA_KEY_ALG_HASH) {
3870         continue; // hash index is ok
3871       }
3872       GRN_LOG(ctx, GRN_LOG_ERROR, "only hash index can be defined for _id");
3873       error = ER_CANT_CREATE_TABLE;
3874       my_message(error, "only hash index can be defined for _id", MYF(0));
3875       DBUG_RETURN(error);
3876     }
3877   }
3878 
3879   DBUG_RETURN(error);
3880 }
3881 
storage_create_index_table(TABLE * table,const char * grn_table_name,grn_obj * grn_table,MRN_SHARE * tmp_share,KEY * key_info,grn_obj ** index_tables,uint i)3882 int ha_mroonga::storage_create_index_table(TABLE *table,
3883                                            const char *grn_table_name,
3884                                            grn_obj *grn_table,
3885                                            MRN_SHARE *tmp_share,
3886                                            KEY *key_info,
3887                                            grn_obj **index_tables,
3888                                            uint i)
3889 {
3890   MRN_DBUG_ENTER_METHOD();
3891   int error = 0;
3892   grn_obj *index_type;
3893   grn_obj *index_table;
3894   grn_obj_flags index_table_flags = GRN_OBJ_PERSISTENT;
3895   bool is_multiple_column_index = KEY_N_KEY_PARTS(key_info) > 1;
3896 
3897   if (tmp_share->index_table && tmp_share->index_table[i]) {
3898     index_table = grn_ctx_get(ctx,
3899                               tmp_share->index_table[i],
3900                               tmp_share->index_table_length[i]);
3901     // TODO: add error check
3902     index_tables[i] = index_table;
3903     DBUG_RETURN(error);
3904   }
3905 
3906   if (is_multiple_column_index) {
3907     index_type = grn_ctx_at(ctx, GRN_DB_SHORT_TEXT);
3908   } else {
3909     Field *field = key_info->key_part[0].field;
3910     grn_builtin_type groonga_type = mrn_grn_type_from_field(ctx, field, true);
3911     index_type = grn_ctx_at(ctx, groonga_type);
3912   }
3913   // TODO: Add NULL check for index_type
3914 
3915   int key_alg = key_info->algorithm;
3916   if (key_info->flags & HA_FULLTEXT) {
3917     index_table_flags |= GRN_OBJ_TABLE_PAT_KEY;
3918     error = mrn_change_encoding(ctx, key_info->key_part->field->charset());
3919     if (error) {
3920       grn_obj_remove(ctx, grn_table);
3921       DBUG_RETURN(error);
3922     }
3923   } else if (key_alg == HA_KEY_ALG_HASH) {
3924     index_table_flags |= GRN_OBJ_TABLE_HASH_KEY;
3925   } else {
3926     index_table_flags |= GRN_OBJ_TABLE_PAT_KEY;
3927   }
3928 
3929   {
3930     mrn::IndexTableName index_table_name(grn_table_name, key_info->name.str);
3931     index_table = grn_table_create(ctx,
3932                                    index_table_name.c_str(),
3933                                    index_table_name.length(),
3934                                    NULL,
3935                                    index_table_flags,
3936                                    index_type,
3937                                    NULL);
3938   }
3939   if (ctx->rc) {
3940     grn_obj_unlink(ctx, index_type);
3941     grn_obj_remove(ctx, grn_table);
3942     error = ER_CANT_CREATE_TABLE;
3943     my_message(ER_CANT_CREATE_TABLE, ctx->errbuf, MYF(0));
3944     DBUG_RETURN(error);
3945   }
3946 
3947   if (key_info->flags & HA_FULLTEXT) {
3948     grn_obj *tokenizer = find_tokenizer(key_info, tmp_share, i);
3949     if (tokenizer) {
3950       grn_info_type info_type = GRN_INFO_DEFAULT_TOKENIZER;
3951       grn_obj_set_info(ctx, index_table, info_type, tokenizer);
3952       grn_obj_unlink(ctx, tokenizer);
3953     }
3954 
3955     {
3956       grn_obj token_filters;
3957       GRN_PTR_INIT(&token_filters, GRN_OBJ_VECTOR, 0);
3958       if (find_token_filters(key_info, &token_filters)) {
3959         grn_obj_set_info(ctx, index_table,
3960                          GRN_INFO_TOKEN_FILTERS, &token_filters);
3961       }
3962       grn_obj_unlink(ctx, &token_filters);
3963     }
3964   }
3965 
3966   {
3967     grn_obj *normalizer = NULL;
3968     Field *field = &(key_info->key_part->field[0]);
3969     if (key_info->flags & HA_FULLTEXT) {
3970       if (have_custom_normalizer(key_info) ||
3971           should_normalize(field)) {
3972         normalizer = find_normalizer(key_info);
3973       }
3974     } else if (key_alg != HA_KEY_ALG_HASH) {
3975       if (!is_multiple_column_index &&
3976           (have_custom_normalizer(key_info) ||
3977            should_normalize(field))) {
3978         normalizer = find_normalizer(key_info);
3979       }
3980     }
3981     if (normalizer) {
3982       grn_info_type info_type = GRN_INFO_NORMALIZER;
3983       grn_obj_set_info(ctx, index_table, info_type, normalizer);
3984       grn_obj_unlink(ctx, normalizer);
3985     }
3986   }
3987 
3988   index_tables[i] = index_table;
3989 
3990   DBUG_RETURN(error);
3991 }
3992 
storage_create_index(TABLE * table,const char * grn_table_name,grn_obj * grn_table,MRN_SHARE * tmp_share,KEY * key_info,grn_obj ** index_tables,grn_obj ** index_columns,uint i)3993 int ha_mroonga::storage_create_index(TABLE *table, const char *grn_table_name,
3994                                      grn_obj *grn_table, MRN_SHARE *tmp_share,
3995                                      KEY *key_info, grn_obj **index_tables,
3996                                      grn_obj **index_columns, uint i)
3997 {
3998   MRN_DBUG_ENTER_METHOD();
3999   int error = 0;
4000   grn_obj *index_column;
4001 
4002   bool is_multiple_column_index = KEY_N_KEY_PARTS(key_info) > 1;
4003   if (!is_multiple_column_index) {
4004     Field *field = key_info->key_part[0].field;
4005     if (strcmp(MRN_COLUMN_NAME_ID, field->field_name.str) == 0) {
4006       // skipping _id virtual column
4007       DBUG_RETURN(0);
4008     }
4009 
4010     if (is_foreign_key_field(table->s->table_name.str,
4011                              field->field_name.str)) {
4012       DBUG_RETURN(0);
4013     }
4014 
4015 #ifdef HA_CAN_VIRTUAL_COLUMNS
4016     if (MRN_GENERATED_COLUMNS_FIELD_IS_VIRTUAL(field)) {
4017       char error_message[MRN_MESSAGE_BUFFER_SIZE];
4018       snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
4019                "mroonga: storage: failed to create index: "
4020                ER_MRN_KEY_BASED_ON_GENERATED_VIRTUAL_COLUMN_STR,
4021                field->field_name.str);
4022       error = ER_MRN_KEY_BASED_ON_GENERATED_VIRTUAL_COLUMN_NUM;
4023       my_message(error, error_message, MYF(0));
4024       DBUG_RETURN(error);
4025     }
4026   } else {
4027     int j, n_key_parts = KEY_N_KEY_PARTS(key_info);
4028     for (j = 0; j < n_key_parts; j++) {
4029       Field *field = key_info->key_part[j].field;
4030       if (MRN_GENERATED_COLUMNS_FIELD_IS_VIRTUAL(field)) {
4031         char error_message[MRN_MESSAGE_BUFFER_SIZE];
4032         snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
4033                  "mroonga: storage: failed to create index: "
4034                  ER_MRN_KEY_BASED_ON_GENERATED_VIRTUAL_COLUMN_STR,
4035                  field->field_name.str);
4036         error = ER_MRN_KEY_BASED_ON_GENERATED_VIRTUAL_COLUMN_NUM;
4037         my_message(error, error_message, MYF(0));
4038         DBUG_RETURN(error);
4039       }
4040     }
4041 #endif
4042   }
4043 
4044   error = mrn_change_encoding(ctx, system_charset_info);
4045   if (error)
4046     DBUG_RETURN(error);
4047 
4048   error = storage_create_index_table(table, grn_table_name,
4049                                      grn_table, tmp_share,
4050                                      key_info, index_tables, i);
4051   if (error)
4052     DBUG_RETURN(error);
4053 
4054   grn_obj *index_table = index_tables[i];
4055 
4056   grn_column_flags index_column_flags = GRN_OBJ_COLUMN_INDEX | GRN_OBJ_PERSISTENT;
4057 
4058   if (!find_index_column_flags(key_info, &index_column_flags)) {
4059     grn_obj *tokenizer = grn_obj_get_info(ctx, index_table,
4060                                           GRN_INFO_DEFAULT_TOKENIZER, NULL);
4061     if (tokenizer) {
4062       index_column_flags |= GRN_OBJ_WITH_POSITION;
4063     }
4064     if (is_multiple_column_index && (key_info->flags & HA_FULLTEXT)) {
4065       index_column_flags |= GRN_OBJ_WITH_SECTION;
4066     }
4067   }
4068 
4069   const char *index_column_name;
4070   if (tmp_share->index_table && tmp_share->index_table[i]) {
4071     index_column_name = key_info->name.str;
4072   } else {
4073     index_column_name = INDEX_COLUMN_NAME;
4074   }
4075   index_column = grn_column_create(ctx,
4076                                    index_table,
4077                                    index_column_name,
4078                                    strlen(index_column_name),
4079                                    NULL,
4080                                    index_column_flags,
4081                                    grn_table);
4082 
4083   if (ctx->rc) {
4084     grn_obj_remove(ctx, index_table);
4085     error = ER_CANT_CREATE_TABLE;
4086     my_message(error, ctx->errbuf, MYF(0));
4087     DBUG_RETURN(error);
4088   }
4089 
4090   mrn_change_encoding(ctx, system_charset_info);
4091   if (is_multiple_column_index) {
4092     if (key_info->flags & HA_FULLTEXT) {
4093       grn_obj source_ids;
4094       GRN_UINT32_INIT(&source_ids, GRN_OBJ_VECTOR);
4095 
4096       int j, n_key_parts = KEY_N_KEY_PARTS(key_info);
4097       for (j = 0; j < n_key_parts; j++) {
4098         Field *field = key_info->key_part[j].field;
4099         mrn::ColumnName column_name(field->field_name);
4100         grn_obj *source_column = grn_obj_column(ctx,
4101                                                 grn_table,
4102                                                 column_name.c_str(),
4103                                                 column_name.length());
4104         grn_id source_id = grn_obj_id(ctx, source_column);
4105         GRN_UINT32_PUT(ctx, &source_ids, source_id);
4106         grn_obj_unlink(ctx, source_column);
4107       }
4108       mrn_change_encoding(ctx, key_info->key_part->field->charset());
4109       grn_obj_set_info(ctx, index_column, GRN_INFO_SOURCE, &source_ids);
4110       grn_obj_unlink(ctx, &source_ids);
4111     }
4112   } else {
4113     Field *field = key_info->key_part[0].field;
4114     mrn::ColumnName column_name(field->field_name);
4115     grn_obj *column;
4116     column = grn_obj_column(ctx,
4117                             grn_table,
4118                             column_name.c_str(),
4119                             column_name.length());
4120     if (column) {
4121       grn_obj source_ids;
4122       grn_id source_id = grn_obj_id(ctx, column);
4123       GRN_UINT32_INIT(&source_ids, GRN_OBJ_VECTOR);
4124       GRN_UINT32_PUT(ctx, &source_ids, source_id);
4125       mrn_change_encoding(ctx, key_info->key_part->field->charset());
4126       grn_obj_set_info(ctx, index_column, GRN_INFO_SOURCE, &source_ids);
4127       grn_obj_unlink(ctx, &source_ids);
4128       grn_obj_unlink(ctx, column);
4129     }
4130   }
4131   mrn_change_encoding(ctx, system_charset_info);
4132 
4133   if (index_columns) {
4134     index_columns[i] = index_column;
4135   }
4136 
4137   DBUG_RETURN(error);
4138 }
4139 
storage_create_indexes(TABLE * table,const char * grn_table_name,grn_obj * grn_table,MRN_SHARE * tmp_share)4140 int ha_mroonga::storage_create_indexes(TABLE *table, const char *grn_table_name,
4141                                        grn_obj *grn_table, MRN_SHARE *tmp_share)
4142 {
4143   MRN_DBUG_ENTER_METHOD();
4144   int error = 0;
4145 
4146   uint n_keys = table->s->keys;
4147   uint i;
4148   MRN_ALLOCATE_VARIABLE_LENGTH_ARRAYS(grn_obj *, index_tables, n_keys);
4149   for (i = 0; i < n_keys; i++) {
4150     index_tables[i] = NULL;
4151     if (i == table->s->primary_key) {
4152       continue; // pkey is already handled
4153     }
4154     KEY *key_info = &table->s->key_info[i];
4155     if (tmp_share->disable_keys && !(key_info->flags & HA_NOSAME)) {
4156       continue; // key is disabled
4157     }
4158     if ((error = storage_create_index(table, grn_table_name, grn_table,
4159                                       tmp_share, key_info,
4160                                       index_tables, NULL, i))) {
4161       break;
4162     }
4163   }
4164   if (error) {
4165     while (true) {
4166       if (index_tables[i] &&
4167           !(tmp_share->index_table && tmp_share->index_table[i])) {
4168         grn_obj_remove(ctx, index_tables[i]);
4169       }
4170       if (!i)
4171         break;
4172       i--;
4173     }
4174   }
4175   MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_tables);
4176   DBUG_RETURN(error);
4177 }
4178 
ensure_database_open(const char * name,mrn::Database ** db)4179 int ha_mroonga::ensure_database_open(const char *name, mrn::Database **db)
4180 {
4181   int error;
4182 
4183   MRN_DBUG_ENTER_METHOD();
4184 
4185   if (db)
4186     *db = NULL;
4187 
4188   mrn::Database *local_db;
4189   error = mrn_db_manager->open(name, &local_db);
4190   if (error)
4191     DBUG_RETURN(error);
4192 
4193   if (db)
4194     *db = local_db;
4195   grn_ctx_use(ctx, local_db->get());
4196 
4197   delete operations_;
4198   operations_ = new mrn::Operations(ctx);
4199   if (mrn_enable_operations_recording) {
4200     operations_->enable_recording();
4201   } else {
4202     operations_->disable_recording();
4203   }
4204 
4205   DBUG_RETURN(error);
4206 }
4207 
ensure_database_remove(const char * name)4208 int ha_mroonga::ensure_database_remove(const char *name)
4209 {
4210   int error;
4211 
4212   MRN_DBUG_ENTER_METHOD();
4213 
4214   error = mrn_change_encoding(ctx, system_charset_info);
4215   if (error)
4216     DBUG_RETURN(error);
4217 
4218   delete operations_;
4219   operations_ = NULL;
4220 
4221   mrn_db_manager->close(name);
4222 
4223   mrn::PathMapper mapper(name);
4224   remove_related_files(mapper.db_path());
4225 
4226   DBUG_RETURN(error);
4227 }
4228 
4229 
create(const char * name,TABLE * table,HA_CREATE_INFO * info,dd::Table * table_def)4230 int ha_mroonga::create(const char *name,
4231                        TABLE *table,
4232                        HA_CREATE_INFO *info
4233 #ifdef MRN_HANDLER_CREATE_HAVE_TABLE_DEFINITION
4234                        ,
4235                        dd::Table *table_def
4236 #endif
4237   )
4238 {
4239   int error = 0;
4240   MRN_SHARE *tmp_share;
4241   MRN_DBUG_ENTER_METHOD();
4242   /* checking data type of virtual columns */
4243 
4244   if (!(tmp_share = mrn_get_share(name, table, &error)))
4245     DBUG_RETURN(error);
4246 
4247   st_mrn_slot_data *slot_data = mrn_get_slot_data(ha_thd(), false);
4248   if (slot_data && slot_data->disable_keys_create_info == info) {
4249     tmp_share->disable_keys = true;
4250   }
4251 
4252   if (tmp_share->wrapper_mode)
4253   {
4254     error = wrapper_create(name, table, info, tmp_share);
4255   } else {
4256     error = storage_create(name, table, info, tmp_share);
4257   }
4258 
4259   if (error) {
4260     mrn_free_long_term_share(tmp_share->long_term_share);
4261     tmp_share->long_term_share = NULL;
4262   } else {
4263     error = add_wrap_hton(tmp_share->table_name, tmp_share->hton);
4264   }
4265   mrn_free_share(tmp_share);
4266   DBUG_RETURN(error);
4267 }
4268 
wrapper_open(const char * name,int mode,uint open_options)4269 int ha_mroonga::wrapper_open(const char *name, int mode, uint open_options)
4270 {
4271   int error = 0;
4272   MRN_DBUG_ENTER_METHOD();
4273 
4274   mrn::Database *db = NULL;
4275   error = ensure_database_open(name, &db);
4276   if (error)
4277     DBUG_RETURN(error);
4278 
4279   if (!(open_options & HA_OPEN_FOR_REPAIR)) {
4280     error = open_table(name);
4281     if (error)
4282       DBUG_RETURN(error);
4283 
4284     error = wrapper_open_indexes(name);
4285     if (error) {
4286       grn_obj_unlink(ctx, grn_table);
4287       grn_table = NULL;
4288       DBUG_RETURN(error);
4289     }
4290   }
4291 
4292   mrn_init_alloc_root(&mem_root, 1024, 0, MYF(0));
4293   wrap_key_info = mrn_create_key_info_for_table(share, table, &error);
4294   if (error)
4295     DBUG_RETURN(error);
4296   base_key_info = table->key_info;
4297 
4298   MRN_SET_WRAP_SHARE_KEY(share, table->s);
4299   MRN_SET_WRAP_TABLE_KEY(this, table);
4300   if (!is_clone)
4301   {
4302     wrap_handler = get_new_handler(table->s, &mem_root, share->hton);
4303     if (!wrap_handler)
4304     {
4305       MRN_SET_BASE_SHARE_KEY(share, table->s);
4306       MRN_SET_BASE_TABLE_KEY(this, table);
4307       if (wrap_key_info)
4308       {
4309         my_free(wrap_key_info);
4310         wrap_key_info = NULL;
4311       }
4312       base_key_info = NULL;
4313       DBUG_RETURN(HA_ERR_OUT_OF_MEM);
4314     }
4315 #ifdef MRN_HANDLER_HAVE_SET_HA_SHARE_REF
4316     wrap_handler->set_ha_share_ref(&table->s->ha_share);
4317 #endif
4318     error = wrap_handler->ha_open(table, name, mode, open_options);
4319   } else {
4320     if (!(wrap_handler = parent_for_clone->wrap_handler->clone(name,
4321       mem_root_for_clone)))
4322     {
4323       MRN_SET_BASE_SHARE_KEY(share, table->s);
4324       MRN_SET_BASE_TABLE_KEY(this, table);
4325       if (wrap_key_info)
4326       {
4327         my_free(wrap_key_info);
4328         wrap_key_info = NULL;
4329       }
4330       base_key_info = NULL;
4331       DBUG_RETURN(HA_ERR_OUT_OF_MEM);
4332     }
4333   }
4334   ref_length = wrap_handler->ref_length;
4335   key_used_on_scan = wrap_handler->key_used_on_scan;
4336   MRN_SET_BASE_SHARE_KEY(share, table->s);
4337   MRN_SET_BASE_TABLE_KEY(this, table);
4338   init();
4339   wrapper_overwrite_index_bits();
4340   wrapper_set_keys_in_use();
4341 
4342   pk_keypart_map = make_prev_keypart_map(
4343     KEY_N_KEY_PARTS(&(table->key_info[table_share->primary_key])));
4344 
4345   if (!error) {
4346     if (open_options & HA_OPEN_FOR_REPAIR) {
4347       // TODO: How to check whether is DISABLE KEYS used or not?
4348       error = wrapper_recreate_indexes(ha_thd());
4349     } else if (db) {
4350       mrn::Lock lock(&mrn_operations_mutex);
4351       mrn::PathMapper mapper(name);
4352       const char *table_name = mapper.table_name();
4353       size_t table_name_size = strlen(table_name);
4354       if (db->is_broken_table(table_name, table_name_size)) {
4355         GRN_LOG(ctx, GRN_LOG_NOTICE,
4356                 "Auto repair is started: <%s>",
4357                 name);
4358         error = operations_->clear(table_name, table_name_size);
4359         if (!error) {
4360           db->mark_table_repaired(table_name, table_name_size);
4361           if (!share->disable_keys) {
4362             // TODO: implemented by "reindex" instead of "remove and recreate".
4363             // Because "remove and recreate" invalidates opened indexes by
4364             // other threads.
4365             error = wrapper_disable_indexes_mroonga(HA_KEY_SWITCH_ALL);
4366             if (!error) {
4367               error = wrapper_enable_indexes_mroonga(HA_KEY_SWITCH_ALL);
4368             }
4369           }
4370         }
4371         GRN_LOG(ctx, GRN_LOG_NOTICE,
4372                 "Auto repair is done: <%s>: %s",
4373                 name, error == 0 ? "success" : "failure");
4374       }
4375     }
4376   }
4377 
4378   if (error)
4379   {
4380     grn_obj_unlink(ctx, grn_table);
4381     grn_table = NULL;
4382     // TODO: free indexes.
4383 
4384     delete wrap_handler;
4385     wrap_handler = NULL;
4386     if (wrap_key_info)
4387     {
4388       my_free(wrap_key_info);
4389       wrap_key_info = NULL;
4390     }
4391     base_key_info = NULL;
4392   }
4393   DBUG_RETURN(error);
4394 }
4395 
wrapper_open_indexes(const char * name)4396 int ha_mroonga::wrapper_open_indexes(const char *name)
4397 {
4398   int error;
4399 
4400   MRN_DBUG_ENTER_METHOD();
4401 
4402   error = mrn_change_encoding(ctx, system_charset_info);
4403   if (error)
4404     DBUG_RETURN(error);
4405 
4406   uint n_keys = table->s->keys;
4407   uint n_primary_keys = table->s->primary_key;
4408   if (n_keys > 0) {
4409     // TODO: reduce allocate memories. We only need just
4410     // for HA_KEY_ALG_FULLTEXT keys.
4411     grn_index_tables = (grn_obj **)malloc(sizeof(grn_obj *) * n_keys);
4412     grn_index_columns = (grn_obj **)malloc(sizeof(grn_obj *) * n_keys);
4413   } else {
4414     grn_index_tables = grn_index_columns = NULL;
4415   }
4416 
4417   mrn::PathMapper mapper(name);
4418   uint i = 0;
4419   for (i = 0; i < n_keys; i++) {
4420     KEY *key_info = &(table->s->key_info[i]);
4421 
4422     grn_index_tables[i] = NULL;
4423     grn_index_columns[i] = NULL;
4424 
4425     if (!(wrapper_is_target_index(key_info))) {
4426       continue;
4427     }
4428 
4429     if (i == n_primary_keys) {
4430       continue;
4431     }
4432 
4433     mrn::IndexTableName index_table_name(mapper.table_name(), key_info->name.str);
4434     grn_index_tables[i] = grn_ctx_get(ctx,
4435                                       index_table_name.c_str(),
4436                                       index_table_name.length());
4437     if (ctx->rc == GRN_SUCCESS && !grn_index_tables[i]) {
4438       grn_index_tables[i] = grn_ctx_get(ctx,
4439                                         index_table_name.old_c_str(),
4440                                         index_table_name.old_length());
4441     }
4442     if (ctx->rc) {
4443       DBUG_PRINT("info",
4444                  ("mroonga: sql_command=%u", thd_sql_command(ha_thd())));
4445       error = ER_CANT_OPEN_FILE;
4446       my_message(error, ctx->errbuf, MYF(0));
4447       goto error;
4448     }
4449 
4450     grn_index_columns[i] = grn_obj_column(ctx, grn_index_tables[i],
4451                                           INDEX_COLUMN_NAME,
4452                                           strlen(INDEX_COLUMN_NAME));
4453     if (!grn_index_columns[i]) {
4454       /* just for backward compatibility before 1.0. */
4455       Field *field = key_info->key_part[0].field;
4456       grn_index_columns[i] = grn_obj_column(ctx, grn_index_tables[i],
4457                                             field->field_name.str,
4458                                             field->field_name.length);
4459     }
4460 
4461     if (ctx->rc) {
4462       DBUG_PRINT("info",
4463         ("mroonga: sql_command=%u", thd_sql_command(ha_thd())));
4464       error = ER_CANT_OPEN_FILE;
4465       my_message(error, ctx->errbuf, MYF(0));
4466       grn_obj_unlink(ctx, grn_index_tables[i]);
4467       goto error;
4468     }
4469   }
4470 
4471   grn_bulk_space(ctx, &key_buffer, table->key_info->key_length);
4472 
4473 error:
4474   if (error) {
4475     while (i-- > 0) {
4476       grn_obj *index_column = grn_index_columns[i];
4477       if (index_column) {
4478         grn_obj_unlink(ctx, index_column);
4479       }
4480       grn_obj *index_table = grn_index_tables[i];
4481       if (index_table) {
4482         grn_obj_unlink(ctx, index_table);
4483       }
4484     }
4485     free(grn_index_columns);
4486     free(grn_index_tables);
4487     grn_index_columns = NULL;
4488     grn_index_tables = NULL;
4489   }
4490 
4491   DBUG_RETURN(error);
4492 }
4493 
wrapper_overwrite_index_bits()4494 void ha_mroonga::wrapper_overwrite_index_bits()
4495 {
4496   uint i, j;
4497   longlong table_option = table_flags();
4498   MRN_DBUG_ENTER_METHOD();
4499   table_share->keys_for_keyread.clear_all();
4500   for (i = 0; i < table_share->fields; i++)
4501   {
4502     Field *field = table_share->field[i];
4503     field->part_of_key.clear_all();
4504 #ifdef MRN_HAVE_MYSQL_FIELD_PART_OF_KEY_NOT_CLUSTERED
4505     field->part_of_key_not_clustered.clear_all();
4506 #endif
4507     field->part_of_sortkey.clear_all();
4508     /*
4509       TODO: We may need to update field->part_of_key_not_extended for
4510       MySQL >= 5.7.18. If users report "raw InnoDB can use index for
4511       this case but Mroonga wrapper mode for InnoDB can't use index
4512       for the same case", we'll reconsider it again.
4513     */
4514   }
4515   for (i = 0; i < table_share->keys; i++) {
4516     KEY *key_info = &table->s->key_info[i];
4517     KEY_PART_INFO *key_part = key_info->key_part;
4518     for (j = 0 ; j < KEY_N_KEY_PARTS(key_info); key_part++, j++)
4519     {
4520       Field *field = key_part->field;
4521       if (field->key_length() == key_part->length &&
4522           !(field->flags & BLOB_FLAG))
4523       {
4524         if (index_flags(i, j, 0) & HA_KEYREAD_ONLY)
4525         {
4526           table_share->keys_for_keyread.set_bit(i);
4527           field->part_of_key.set_bit(i);
4528 #ifdef MRN_HAVE_MYSQL_FIELD_PART_OF_KEY_NOT_CLUSTERED
4529           field->part_of_key_not_clustered.set_bit(i);
4530 #endif
4531         }
4532         if (index_flags(i, j, 1) & HA_READ_ORDER)
4533           field->part_of_sortkey.set_bit(i);
4534       }
4535       if (i == table_share->primary_key &&
4536           (table_option & HA_PRIMARY_KEY_IN_READ_INDEX))
4537       {
4538         if (field->key_length() == key_part->length &&
4539             !(field->flags & BLOB_FLAG))
4540           field->part_of_key = table_share->keys_in_use;
4541         if (field->part_of_sortkey.is_set(i))
4542           field->part_of_sortkey = table_share->keys_in_use;
4543       }
4544     }
4545   }
4546   DBUG_VOID_RETURN;
4547 }
4548 
storage_reindex()4549 int ha_mroonga::storage_reindex()
4550 {
4551   int error = 0;
4552   MRN_DBUG_ENTER_METHOD();
4553 
4554   uint n_keys = table_share->keys;
4555   KEY *key_info = table->key_info;
4556 
4557   bool have_multiple_column_index = false;
4558   bitmap_clear_all(table->read_set);
4559   for (uint i = 0; i < n_keys; ++i) {
4560     if (!grn_index_columns[i])
4561       continue;
4562 
4563     grn_hash *columns = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
4564                                         GRN_OBJ_TABLE_HASH_KEY);
4565     grn_table_columns(ctx, grn_index_tables[i], NULL, 0,
4566                       reinterpret_cast<grn_obj *>(columns));
4567     unsigned int n_columns =
4568       grn_table_size(ctx, reinterpret_cast<grn_obj *>(columns));
4569     grn_hash_close(ctx, columns);
4570 
4571     bool is_multiple_column_index =
4572       (KEY_N_KEY_PARTS(&(key_info[i])) != 1 &&
4573        !(key_info[i].flags & HA_FULLTEXT));
4574 
4575     if (n_columns == 1 || is_multiple_column_index) {
4576       grn_table_truncate(ctx, grn_index_tables[i]);
4577       if (ctx->rc != GRN_SUCCESS) {
4578         error = ER_ERROR_ON_WRITE;
4579         char error_message[MRN_MESSAGE_BUFFER_SIZE];
4580         char index_table_name[GRN_TABLE_MAX_KEY_SIZE];
4581         int index_table_name_size;
4582         index_table_name_size =
4583           grn_obj_name(ctx, grn_index_tables[i],
4584                        index_table_name, GRN_TABLE_MAX_KEY_SIZE);
4585         snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
4586                  "mroonga: reindex: failed to truncate index table: "
4587                  "<%.*s>: <%s>(%d)",
4588                  index_table_name_size, index_table_name,
4589                  ctx->errbuf, ctx->rc);
4590         my_message(error, error_message, MYF(0));
4591         break;
4592       }
4593     }
4594 
4595     if (is_multiple_column_index) {
4596       mrn_set_bitmap_by_key(table->read_set, &key_info[i]);
4597       have_multiple_column_index = true;
4598     } else {
4599       grn_obj_reindex(ctx, grn_index_columns[i]);
4600       if (ctx->rc != GRN_SUCCESS) {
4601         error = ER_ERROR_ON_WRITE;
4602         char error_message[MRN_MESSAGE_BUFFER_SIZE];
4603         char index_column_name[GRN_TABLE_MAX_KEY_SIZE];
4604         int index_column_name_size;
4605         index_column_name_size =
4606           grn_obj_name(ctx, grn_index_columns[i],
4607                        index_column_name, GRN_TABLE_MAX_KEY_SIZE);
4608         snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
4609                  "mroonga: reindex: failed to reindex: "
4610                  "<%.*s>: <%s>(%d)",
4611                  index_column_name_size, index_column_name,
4612                  ctx->errbuf, ctx->rc);
4613         my_message(error, error_message, MYF(0));
4614         break;
4615       }
4616     }
4617   }
4618 
4619   if (!error && have_multiple_column_index)
4620     error = storage_add_index_multiple_columns(key_info, n_keys,
4621                                                grn_index_tables,
4622                                                grn_index_columns,
4623                                                false);
4624   bitmap_set_all(table->read_set);
4625 
4626   DBUG_RETURN(error);
4627 }
4628 
storage_open(const char * name,int mode,uint open_options)4629 int ha_mroonga::storage_open(const char *name, int mode, uint open_options)
4630 {
4631   int error = 0;
4632   MRN_DBUG_ENTER_METHOD();
4633 
4634   mrn::Database *db;
4635   error = ensure_database_open(name, &db);
4636   if (error)
4637     DBUG_RETURN(error);
4638 
4639   error = open_table(name);
4640   if (error)
4641     DBUG_RETURN(error);
4642 
4643   error = storage_open_columns();
4644   if (error) {
4645     grn_obj_unlink(ctx, grn_table);
4646     grn_table = NULL;
4647     DBUG_RETURN(error);
4648   }
4649 
4650   if (!(open_options & HA_OPEN_FOR_REPAIR)) {
4651     error = storage_open_indexes(name);
4652     if (error) {
4653       storage_close_columns();
4654       grn_obj_unlink(ctx, grn_table);
4655       grn_table = NULL;
4656       DBUG_RETURN(error);
4657     }
4658 
4659     storage_set_keys_in_use();
4660 
4661     {
4662       mrn::Lock lock(&mrn_operations_mutex);
4663       mrn::PathMapper mapper(name);
4664       const char *table_name = mapper.table_name();
4665       size_t table_name_size = strlen(table_name);
4666       if (db->is_broken_table(table_name, table_name_size)) {
4667         GRN_LOG(ctx, GRN_LOG_NOTICE,
4668                 "Auto repair is started: <%s>",
4669                 name);
4670         error = operations_->repair(table_name, table_name_size);
4671         if (!error)
4672           db->mark_table_repaired(table_name, table_name_size);
4673         if (!share->disable_keys) {
4674           if (!error)
4675             error = storage_reindex();
4676         }
4677         GRN_LOG(ctx, GRN_LOG_NOTICE,
4678                 "Auto repair is done: <%s>: %s",
4679                 name, error == 0 ? "success" : "failure");
4680       }
4681     }
4682   }
4683 
4684   ref_length = sizeof(grn_id);
4685   DBUG_RETURN(0);
4686 }
4687 
open_table(const char * name)4688 int ha_mroonga::open_table(const char *name)
4689 {
4690   int error;
4691   MRN_DBUG_ENTER_METHOD();
4692 
4693   error = mrn_change_encoding(ctx, system_charset_info);
4694   if (error)
4695     DBUG_RETURN(error);
4696 
4697   mrn::PathMapper mapper(name);
4698   grn_table = grn_ctx_get(ctx, mapper.table_name(), strlen(mapper.table_name()));
4699   if (ctx->rc) {
4700     error = ER_CANT_OPEN_FILE;
4701     my_message(error, ctx->errbuf, MYF(0));
4702     DBUG_RETURN(error);
4703   }
4704   if (!grn_table) {
4705     error = ER_CANT_OPEN_FILE;
4706     char error_message[MRN_MESSAGE_BUFFER_SIZE];
4707     snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
4708              "mroonga: failed to open table: <%s>",
4709              mapper.table_name());
4710     my_message(error, error_message, MYF(0));
4711     DBUG_RETURN(error);
4712   }
4713 
4714   DBUG_RETURN(0);
4715 }
4716 
storage_open_columns(void)4717 int ha_mroonga::storage_open_columns(void)
4718 {
4719   int error;
4720   MRN_DBUG_ENTER_METHOD();
4721 
4722   error = mrn_change_encoding(ctx, system_charset_info);
4723   if (error)
4724     DBUG_RETURN(error);
4725 
4726   int n_columns = table->s->fields;
4727   grn_columns = (grn_obj **)malloc(sizeof(grn_obj *) * n_columns);
4728   grn_column_ranges = (grn_obj **)malloc(sizeof(grn_obj *) * n_columns);
4729   for (int i = 0; i < n_columns; i++) {
4730       grn_columns[i] = NULL;
4731       grn_column_ranges[i] = NULL;
4732   }
4733 
4734   if (table_share->blob_fields)
4735   {
4736     DBUG_ASSERT(!blob_buffers);
4737     if (!(blob_buffers = new (&table->mem_root) String[n_columns]))
4738     {
4739       DBUG_RETURN(HA_ERR_OUT_OF_MEM);
4740     }
4741   }
4742 
4743   for (int i = 0; i < n_columns; i++) {
4744     Field *field = table->field[i];
4745     mrn::ColumnName column_name(field->field_name);
4746     if (table_share->blob_fields)
4747     {
4748       blob_buffers[i].set_charset(field->charset());
4749     }
4750     if (strcmp(MRN_COLUMN_NAME_ID, column_name.mysql_name()) == 0) {
4751       continue;
4752     }
4753 #ifdef MRN_SUPPORT_GENERATED_COLUMNS
4754     if (MRN_GENERATED_COLUMNS_FIELD_IS_VIRTUAL(field)) {
4755       grn_columns[i] = NULL;
4756       grn_column_ranges[i] = NULL;
4757       continue;
4758     }
4759 #endif
4760 
4761     grn_columns[i] = grn_obj_column(ctx,
4762                                     grn_table,
4763                                     column_name.c_str(),
4764                                     column_name.length());
4765     if (!grn_columns[i]) {
4766       error = ER_CANT_OPEN_FILE;
4767       my_message(error, ctx->errbuf, MYF(0));
4768       break;
4769     }
4770 
4771     grn_id range_id = grn_obj_get_range(ctx, grn_columns[i]);
4772     grn_column_ranges[i] = grn_ctx_at(ctx, range_id);
4773     if (!grn_column_ranges[i]) {
4774       error = ER_CANT_OPEN_FILE;
4775       my_message(error, ctx->errbuf, MYF(0));
4776       break;
4777     }
4778   }
4779 
4780   if (error != 0) {
4781     storage_close_columns();
4782   }
4783 
4784   DBUG_RETURN(error);
4785 }
4786 
storage_close_columns(void)4787 void ha_mroonga::storage_close_columns(void)
4788 {
4789   int n_columns = table->s->fields;
4790   for (int i = 0; i < n_columns; i++) {
4791     grn_obj *column = grn_columns[i];
4792     if (column) {
4793       grn_obj_unlink(ctx, column);
4794     }
4795 
4796     grn_obj *range = grn_column_ranges[i];
4797     if (range) {
4798       grn_obj_unlink(ctx, range);
4799     }
4800   }
4801 
4802   free(grn_columns);
4803   grn_columns = NULL;
4804   free(grn_column_ranges);
4805   grn_column_ranges = NULL;
4806 }
4807 
storage_open_indexes(const char * name)4808 int ha_mroonga::storage_open_indexes(const char *name)
4809 {
4810   int error;
4811 
4812   MRN_DBUG_ENTER_METHOD();
4813 
4814   error = mrn_change_encoding(ctx, system_charset_info);
4815   if (error)
4816     DBUG_RETURN(error);
4817 
4818   uint n_keys = table->s->keys;
4819   uint pkey_nr = table->s->primary_key;
4820   if (n_keys > 0) {
4821     grn_index_tables = (grn_obj **)malloc(sizeof(grn_obj *) * n_keys);
4822     grn_index_columns = (grn_obj **)malloc(sizeof(grn_obj *) * n_keys);
4823     key_id = (grn_id *)malloc(sizeof(grn_id) * n_keys);
4824     del_key_id = (grn_id *)malloc(sizeof(grn_id) * n_keys);
4825   } else {
4826     grn_index_tables = grn_index_columns = NULL;
4827     key_id = NULL;
4828     del_key_id = NULL;
4829   }
4830 
4831   mrn::PathMapper mapper(name);
4832   uint i, j;
4833   for (i = 0; i < n_keys; i++) {
4834     if (i == pkey_nr) {
4835       grn_index_tables[i] = grn_index_columns[i] = NULL;
4836       continue;
4837     }
4838 
4839     KEY *key_info = &(table->s->key_info[i]);
4840     if (KEY_N_KEY_PARTS(key_info) > 1) {
4841       KEY_PART_INFO *key_part = key_info->key_part;
4842       for (j = 0; j < KEY_N_KEY_PARTS(key_info); j++) {
4843         bitmap_set_bit(&multiple_column_key_bitmap,
4844                        key_part[j].field->field_index);
4845       }
4846     }
4847 
4848     MRN_SHARE *tmp_share;
4849     tmp_share = mrn_get_share(name, table, &error);
4850     if (tmp_share->index_table[i]) {
4851       grn_index_tables[i] = grn_ctx_get(ctx,
4852                                         tmp_share->index_table[i],
4853                                         tmp_share->index_table_length[i]);
4854       if (ctx->rc == GRN_SUCCESS) {
4855         grn_index_columns[i] = grn_obj_column(ctx,
4856                                               grn_index_tables[i],
4857                                               key_info->name.str,
4858                                               key_info->name.length);
4859       }
4860     } else {
4861       mrn::IndexTableName index_table_name(mapper.table_name(),
4862                                            key_info->name.str);
4863       grn_index_tables[i] = grn_ctx_get(ctx,
4864                                         index_table_name.c_str(),
4865                                         index_table_name.length());
4866       if (ctx->rc == GRN_SUCCESS && !grn_index_tables[i]) {
4867         grn_index_tables[i] = grn_ctx_get(ctx,
4868                                           index_table_name.old_c_str(),
4869                                           index_table_name.old_length());
4870       }
4871       if (ctx->rc == GRN_SUCCESS) {
4872         grn_index_columns[i] = grn_obj_column(ctx,
4873                                               grn_index_tables[i],
4874                                               INDEX_COLUMN_NAME,
4875                                               strlen(INDEX_COLUMN_NAME));
4876         if (!grn_index_columns[i] && ctx->rc == GRN_SUCCESS) {
4877           /* just for backward compatibility before 1.0. */
4878           Field *field = key_info->key_part[0].field;
4879           grn_index_columns[i] = grn_obj_column(ctx, grn_index_tables[i],
4880                                                 field->field_name.str,
4881                                                 field->field_name.length);
4882         }
4883       }
4884     }
4885     mrn_free_share(tmp_share);
4886     if (ctx->rc) {
4887       error = ER_CANT_OPEN_FILE;
4888       my_message(error, ctx->errbuf, MYF(0));
4889       goto error;
4890     }
4891 
4892     if (ctx->rc) {
4893       error = ER_CANT_OPEN_FILE;
4894       my_message(error, ctx->errbuf, MYF(0));
4895       goto error;
4896     }
4897   }
4898 
4899 error:
4900   if (error) {
4901     if (i) {
4902       while (true) {
4903         grn_obj *index_column = grn_index_columns[i];
4904         if (index_column) {
4905           grn_obj_unlink(ctx, index_column);
4906         }
4907         grn_obj *index_table = grn_index_tables[i];
4908         if (index_table) {
4909           grn_obj_unlink(ctx, index_table);
4910         }
4911         if (!i)
4912           break;
4913         i--;
4914       }
4915     }
4916     free(key_id);
4917     free(del_key_id);
4918     free(grn_index_columns);
4919     free(grn_index_tables);
4920     key_id = NULL;
4921     del_key_id = NULL;
4922     grn_index_columns = NULL;
4923     grn_index_tables = NULL;
4924   }
4925 
4926   DBUG_RETURN(error);
4927 }
4928 
open(const char * name,int mode,uint open_options,const dd::Table * table_def)4929 int ha_mroonga::open(const char *name,
4930                      int mode,
4931                      uint open_options
4932 #ifdef MRN_HANDLER_OPEN_HAVE_TABLE_DEFINITION
4933                      ,
4934                      const dd::Table *table_def
4935 #endif
4936   )
4937 {
4938   int error = 0;
4939   MRN_DBUG_ENTER_METHOD();
4940 
4941   if (!(share = mrn_get_share(name, table, &error)))
4942     DBUG_RETURN(error);
4943   thr_lock_data_init(&share->lock,&thr_lock_data,NULL);
4944 
4945   if (bitmap_init(&multiple_column_key_bitmap, NULL, table->s->fields, false))
4946   {
4947     mrn_free_share(share);
4948     share = NULL;
4949     DBUG_RETURN(HA_ERR_OUT_OF_MEM);
4950   }
4951 
4952   if (share->wrapper_mode)
4953   {
4954     error = wrapper_open(name, mode, open_options);
4955   } else {
4956     error = storage_open(name, mode, open_options);
4957   }
4958 
4959   if (error)
4960   {
4961     bitmap_free(&multiple_column_key_bitmap);
4962     mrn_free_share(share);
4963     share = NULL;
4964   }
4965   DBUG_RETURN(error);
4966 }
4967 
wrapper_close()4968 int ha_mroonga::wrapper_close()
4969 {
4970   int error = 0;
4971   MRN_DBUG_ENTER_METHOD();
4972   MRN_SET_WRAP_SHARE_KEY(share, table->s);
4973   MRN_SET_WRAP_TABLE_KEY(this, table);
4974 #ifdef MRN_HANDLER_HAVE_HA_CLOSE
4975   error = wrap_handler->ha_close();
4976 #else
4977   error = wrap_handler->close();
4978 #endif
4979   MRN_SET_BASE_SHARE_KEY(share, table->s);
4980   MRN_SET_BASE_TABLE_KEY(this, table);
4981   delete wrap_handler;
4982   wrap_handler = NULL;
4983   if (wrap_key_info)
4984   {
4985     my_free(wrap_key_info);
4986     wrap_key_info = NULL;
4987   }
4988   base_key_info = NULL;
4989   free_root(&mem_root, MYF(0));
4990   DBUG_RETURN(error);
4991 }
4992 
storage_close()4993 int ha_mroonga::storage_close()
4994 {
4995   MRN_DBUG_ENTER_METHOD();
4996   grn_obj_unlink(ctx, grn_table);
4997   // TODO: unlink elements
4998   free(grn_columns);
4999   // TODO: unlink elements
5000   free(grn_column_ranges);
5001   DBUG_RETURN(0);
5002 }
5003 
close()5004 int ha_mroonga::close()
5005 {
5006   int error = 0;
5007   THD *thd = ha_thd();
5008   MRN_DBUG_ENTER_METHOD();
5009 
5010   clear_indexes();
5011 
5012   if (share->wrapper_mode)
5013   {
5014     error = wrapper_close();
5015   } else {
5016     error = storage_close();
5017   }
5018 
5019   if (error != 0)
5020   {
5021     DBUG_RETURN(error);
5022   }
5023 
5024   if (thd)
5025   {
5026     error = add_wrap_hton(share->table_name, share->hton);
5027   }
5028   bitmap_free(&multiple_column_key_bitmap);
5029   if (share->use_count == 1) {
5030     mrn_free_long_term_share(share->long_term_share);
5031   }
5032   mrn_free_share(share);
5033   share = NULL;
5034   is_clone = false;
5035 
5036   if (
5037     thd &&
5038     thd_sql_command(thd) == SQLCOM_FLUSH
5039   ) {
5040     /* flush tables */
5041     mrn::Lock lock(&mrn_open_tables_mutex);
5042     if (!mrn_open_tables.records)
5043     {
5044       int tmp_error = mrn_db_manager->clear();
5045       if (tmp_error)
5046         error = tmp_error;
5047     }
5048   }
5049   DBUG_RETURN(error);
5050 }
5051 
wrapper_delete_table(const char * name,handlerton * wrap_handlerton,const char * table_name)5052 int ha_mroonga::wrapper_delete_table(const char *name,
5053                                      handlerton *wrap_handlerton,
5054                                      const char *table_name)
5055 {
5056   int error = 0;
5057   MRN_DBUG_ENTER_METHOD();
5058 
5059   handler *hnd = get_new_handler(NULL, current_thd->mem_root, wrap_handlerton);
5060   if (!hnd)
5061   {
5062     DBUG_RETURN(HA_ERR_OUT_OF_MEM);
5063   }
5064 
5065   error = hnd->ha_delete_table(name);
5066   delete hnd;
5067 
5068   DBUG_RETURN(error);
5069 }
5070 
generic_delete_table(const char * name,const char * table_name)5071 int ha_mroonga::generic_delete_table(const char *name, const char *table_name)
5072 {
5073   int error = 0;
5074   MRN_DBUG_ENTER_METHOD();
5075 
5076   error = ensure_database_open(name);
5077   if (error)
5078     DBUG_RETURN(error);
5079 
5080   error = mrn_change_encoding(ctx, system_charset_info);
5081   if (error)
5082     DBUG_RETURN(error);
5083 
5084   error = drop_indexes(table_name);
5085   grn_obj *table_obj = grn_ctx_get(ctx, table_name, strlen(table_name));
5086   if (table_obj) {
5087     grn_obj_remove(ctx, table_obj);
5088   }
5089   if (ctx->rc) {
5090     error = ER_CANT_OPEN_FILE;
5091     my_message(error, ctx->errbuf, MYF(0));
5092     DBUG_RETURN(error);
5093   }
5094   DBUG_RETURN(error);
5095 }
5096 
delete_table(const char * name)5097 int ha_mroonga::delete_table(const char *name)
5098 {
5099   MRN_DBUG_ENTER_METHOD();
5100 
5101   int error = 0;
5102   THD *thd = ha_thd();
5103   handlerton *wrap_handlerton = NULL;
5104   mrn::PathMapper mapper(name);
5105   st_mrn_slot_data *slot_data = mrn_get_slot_data(thd, false);
5106   if (slot_data && slot_data->first_wrap_hton)
5107   {
5108     st_mrn_wrap_hton *wrap_hton, *tmp_wrap_hton;
5109     tmp_wrap_hton = NULL;
5110     wrap_hton = slot_data->first_wrap_hton;
5111     while (wrap_hton)
5112     {
5113       if (!strcmp(wrap_hton->path, name))
5114       {
5115         /* found */
5116         wrap_handlerton = wrap_hton->hton;
5117         if (tmp_wrap_hton)
5118           tmp_wrap_hton->next = wrap_hton->next;
5119         else
5120           slot_data->first_wrap_hton = wrap_hton->next;
5121         free(wrap_hton);
5122         break;
5123       }
5124       tmp_wrap_hton = wrap_hton;
5125       wrap_hton = wrap_hton->next;
5126     }
5127   }
5128 
5129   if (!wrap_handlerton) {
5130     bool open_table_to_get_wrap_handlerton = true;
5131     if (mapper.is_internal_table_name()) {
5132       open_table_to_get_wrap_handlerton = false;
5133     }
5134     if (open_table_to_get_wrap_handlerton) {
5135       TABLE_LIST table_list;
5136       LEX_CSTRING db_name=    { mapper.db_name(), strlen(mapper.db_name()) };
5137       LEX_CSTRING table_name= { mapper.mysql_table_name(), strlen(mapper.mysql_table_name()) };
5138 
5139       table_list.init_one_table(&db_name, &table_name, 0, TL_WRITE);
5140       mrn_open_mutex_lock(NULL);
5141       TABLE_SHARE *tmp_table_share =
5142         mrn_create_tmp_table_share(&table_list, name, &error);
5143       error = 0;
5144       mrn_open_mutex_unlock(NULL);
5145       if (tmp_table_share) {
5146         TABLE tmp_table;
5147         tmp_table.s = tmp_table_share;
5148 #ifdef WITH_PARTITION_STORAGE_ENGINE
5149         tmp_table.part_info = NULL;
5150 #endif
5151         MRN_SHARE *tmp_share = mrn_get_share(name, &tmp_table, &error);
5152         if (tmp_share) {
5153           wrap_handlerton = tmp_share->hton;
5154           mrn_free_long_term_share(tmp_share->long_term_share);
5155           tmp_share->long_term_share = NULL;
5156           mrn_free_share(tmp_share);
5157         }
5158         mrn_open_mutex_lock(NULL);
5159         mrn_free_tmp_table_share(tmp_table_share);
5160         mrn_open_mutex_unlock(NULL);
5161         if (error) {
5162           DBUG_RETURN(error);
5163         }
5164       }
5165     }
5166   }
5167 
5168   if (wrap_handlerton)
5169   {
5170     error = wrapper_delete_table(name, wrap_handlerton, mapper.table_name());
5171   }
5172 
5173   if (!error)
5174   {
5175     error = generic_delete_table(name, mapper.table_name());
5176   }
5177 
5178   if (!error) {
5179     error = operations_->clear(name, strlen(name));
5180   }
5181 
5182   DBUG_RETURN(error);
5183 }
5184 
wrapper_set_keys_in_use()5185 void ha_mroonga::wrapper_set_keys_in_use()
5186 {
5187   uint i, j;
5188   MRN_DBUG_ENTER_METHOD();
5189   mrn::AutoIncrementValueLock lock_(table_share);
5190   table_share->keys_in_use.set_prefix(table_share->keys);
5191   share->disable_keys = false;
5192   for (i = 0; i < table_share->keys; i++) {
5193     j = share->wrap_key_nr[i];
5194     if (j < MAX_KEY) {
5195       if (!share->wrap_table_share->keys_in_use.is_set(j)) {
5196         /* copy bitmap */
5197         table_share->keys_in_use.clear_bit(i);
5198         share->disable_keys = true;
5199       }
5200     } else {
5201       if (!grn_index_tables || !grn_index_tables[i]) {
5202         /* disabled */
5203         table_share->keys_in_use.clear_bit(i);
5204         share->disable_keys = true;
5205       }
5206     }
5207   }
5208   table_share->keys_for_keyread.set_prefix(table_share->keys);
5209   table_share->keys_for_keyread.intersect(table_share->keys_in_use);
5210   DBUG_VOID_RETURN;
5211 }
5212 
storage_set_keys_in_use()5213 void ha_mroonga::storage_set_keys_in_use()
5214 {
5215   uint i;
5216   MRN_DBUG_ENTER_METHOD();
5217   mrn::AutoIncrementValueLock lock_(table_share);
5218   table_share->keys_in_use.set_prefix(table_share->keys);
5219   share->disable_keys = false;
5220   for (i = 0; i < table_share->keys; i++) {
5221     if (i == table_share->primary_key) {
5222       continue;
5223     }
5224     if (!grn_index_tables[i]) {
5225       /* disabled */
5226       table_share->keys_in_use.clear_bit(i);
5227       DBUG_PRINT("info", ("mroonga: key %u disabled", i));
5228       share->disable_keys = true;
5229     }
5230   }
5231   table_share->keys_for_keyread.set_prefix(table_share->keys);
5232   table_share->keys_for_keyread.intersect(table_share->keys_in_use);
5233   DBUG_VOID_RETURN;
5234 }
5235 
wrapper_info(uint flag)5236 int ha_mroonga::wrapper_info(uint flag)
5237 {
5238   int error = 0;
5239   MRN_DBUG_ENTER_METHOD();
5240 
5241   MRN_SET_WRAP_SHARE_KEY(share, table->s);
5242   MRN_SET_WRAP_TABLE_KEY(this, table);
5243   error = wrap_handler->info(flag);
5244   MRN_SET_BASE_SHARE_KEY(share, table->s);
5245   MRN_SET_BASE_TABLE_KEY(this, table);
5246   if (flag & HA_STATUS_ERRKEY) {
5247     errkey = wrap_handler->errkey;
5248     memcpy(dup_ref, wrap_handler->dup_ref, wrap_handler->ref_length);
5249   }
5250   if (flag & HA_STATUS_TIME) {
5251     stats.update_time = wrap_handler->stats.update_time;
5252   }
5253   if (flag & HA_STATUS_CONST) {
5254     stats.max_data_file_length = wrap_handler->stats.max_data_file_length;
5255     stats.create_time = wrap_handler->stats.create_time;
5256     stats.block_size = wrap_handler->stats.block_size;
5257     wrapper_set_keys_in_use();
5258   }
5259   if (flag & HA_STATUS_VARIABLE) {
5260     stats.data_file_length = wrap_handler->stats.data_file_length;
5261     stats.index_file_length = wrap_handler->stats.index_file_length;
5262     stats.records = wrap_handler->stats.records;
5263     stats.mean_rec_length = wrap_handler->stats.mean_rec_length;
5264     stats.check_time = wrap_handler->stats.check_time;
5265   }
5266   if (flag & HA_STATUS_AUTO) {
5267     stats.auto_increment_value = wrap_handler->stats.auto_increment_value;
5268   }
5269   DBUG_RETURN(error);
5270 }
5271 
storage_info(uint flag)5272 int ha_mroonga::storage_info(uint flag)
5273 {
5274   MRN_DBUG_ENTER_METHOD();
5275   mrn_change_encoding(ctx, NULL);
5276 
5277   if (flag & (HA_STATUS_ERRKEY | HA_STATUS_NO_LOCK)) {
5278     errkey = dup_key;
5279   }
5280 
5281   if ((flag & HA_STATUS_AUTO) && table->found_next_number_field) {
5282     THD *thd = ha_thd();
5283     ulonglong nb_reserved_values;
5284     bool next_number_field_is_null = !table->next_number_field;
5285     mrn::ExternalLock mrn_external_lock(ha_thd(), this,
5286                                         mrn_lock_type == F_UNLCK ?
5287                                         F_RDLCK : F_UNLCK);
5288     if (mrn_external_lock.error()) {
5289       DBUG_RETURN(mrn_external_lock.error());
5290     }
5291     if (next_number_field_is_null) {
5292       table->next_number_field = table->found_next_number_field;
5293     }
5294     MRN_LONG_TERM_SHARE *long_term_share = share->long_term_share;
5295     {
5296       mrn::Lock lock(&long_term_share->auto_inc_mutex);
5297       unsigned long auto_increment_offset, auto_increment_increment;
5298       MRN_THD_GET_AUTOINC(thd, &auto_increment_offset,
5299                           &auto_increment_increment);
5300       storage_get_auto_increment(auto_increment_offset,
5301                                  auto_increment_increment, 1,
5302                                  &stats.auto_increment_value,
5303                                  &nb_reserved_values);
5304     }
5305     if (next_number_field_is_null) {
5306       table->next_number_field = NULL;
5307     }
5308   }
5309 
5310   if (flag & HA_STATUS_CONST) {
5311     storage_set_keys_in_use();
5312   }
5313 
5314   if (flag & HA_STATUS_VARIABLE) {
5315     storage_info_variable();
5316   }
5317 
5318   DBUG_RETURN(0);
5319 }
5320 
storage_info_variable()5321 void ha_mroonga::storage_info_variable()
5322 {
5323   MRN_DBUG_ENTER_METHOD();
5324 
5325   storage_info_variable_records();
5326   storage_info_variable_data_file_length();
5327 
5328   DBUG_VOID_RETURN;
5329 }
5330 
storage_info_variable_records()5331 void ha_mroonga::storage_info_variable_records()
5332 {
5333   MRN_DBUG_ENTER_METHOD();
5334 
5335   stats.records = grn_table_size(ctx, grn_table);
5336 
5337   DBUG_VOID_RETURN;
5338 }
5339 
storage_info_variable_data_file_length()5340 void ha_mroonga::storage_info_variable_data_file_length()
5341 {
5342   MRN_DBUG_ENTER_METHOD();
5343 
5344   stats.data_file_length = 0;
5345   stats.data_file_length += file_size(grn_obj_path(ctx, grn_table));
5346   grn_hash *columns = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
5347                                       GRN_OBJ_TABLE_HASH_KEY);
5348   grn_table_columns(ctx, grn_table, NULL, 0, (grn_obj *)columns);
5349   /* grn_id id __attribute__((unused)); */
5350   grn_id *column_id;
5351   GRN_HASH_EACH(ctx, columns, id, &column_id, NULL, NULL, {
5352     grn_obj *column = grn_ctx_at(ctx, *column_id);
5353     stats.data_file_length += file_size(grn_obj_path(ctx, column));
5354     grn_obj_unlink(ctx, column);
5355   });
5356   grn_hash_close(ctx, columns);
5357 
5358   DBUG_VOID_RETURN;
5359 }
5360 
info(uint flag)5361 int ha_mroonga::info(uint flag)
5362 {
5363   MRN_DBUG_ENTER_METHOD();
5364 
5365   int error = 0;
5366   if (share->wrapper_mode)
5367   {
5368     error = wrapper_info(flag);
5369   } else {
5370     error = storage_info(flag);
5371   }
5372   DBUG_RETURN(error);
5373 }
5374 
wrapper_lock_count() const5375 uint ha_mroonga::wrapper_lock_count() const
5376 {
5377   uint lock_count;
5378   MRN_DBUG_ENTER_METHOD();
5379   MRN_SET_WRAP_SHARE_KEY(share, table->s);
5380   MRN_SET_WRAP_TABLE_KEY(this, table);
5381   lock_count = wrap_handler->lock_count();
5382   MRN_SET_BASE_SHARE_KEY(share, table->s);
5383   MRN_SET_BASE_TABLE_KEY(this, table);
5384   DBUG_RETURN(lock_count);
5385 }
5386 
storage_lock_count() const5387 uint ha_mroonga::storage_lock_count() const
5388 {
5389   MRN_DBUG_ENTER_METHOD();
5390   DBUG_RETURN(1);
5391 }
5392 
lock_count() const5393 uint ha_mroonga::lock_count() const
5394 {
5395   MRN_DBUG_ENTER_METHOD();
5396   int error = 0;
5397   if (share->wrapper_mode)
5398   {
5399     error = wrapper_lock_count();
5400   } else {
5401     error = storage_lock_count();
5402   }
5403   DBUG_RETURN(error);
5404 }
5405 
wrapper_store_lock(THD * thd,THR_LOCK_DATA ** to,enum thr_lock_type lock_type)5406 THR_LOCK_DATA **ha_mroonga::wrapper_store_lock(THD *thd, THR_LOCK_DATA **to,
5407                                                enum thr_lock_type lock_type)
5408 {
5409   MRN_DBUG_ENTER_METHOD();
5410   MRN_SET_WRAP_SHARE_KEY(share, table->s);
5411   MRN_SET_WRAP_TABLE_KEY(this, table);
5412   to = wrap_handler->store_lock(thd, to, lock_type);
5413   MRN_SET_BASE_SHARE_KEY(share, table->s);
5414   MRN_SET_BASE_TABLE_KEY(this, table);
5415   DBUG_RETURN(to);
5416 }
5417 
storage_store_lock(THD * thd,THR_LOCK_DATA ** to,enum thr_lock_type lock_type)5418 THR_LOCK_DATA **ha_mroonga::storage_store_lock(THD *thd, THR_LOCK_DATA **to,
5419                                                enum thr_lock_type lock_type)
5420 {
5421   MRN_DBUG_ENTER_METHOD();
5422   if (lock_type != TL_IGNORE && thr_lock_data.type == TL_UNLOCK) {
5423     if (!thd_in_lock_tables(thd)) {
5424       if (lock_type == TL_READ_NO_INSERT) {
5425         lock_type = TL_READ;
5426       } else if (lock_type >= TL_WRITE_CONCURRENT_INSERT &&
5427                  lock_type <= TL_WRITE && !thd_tablespace_op(thd)) {
5428         lock_type = TL_WRITE_ALLOW_WRITE;
5429       }
5430     }
5431 
5432     thr_lock_data.type = lock_type;
5433   }
5434   *to++ = &thr_lock_data;
5435   DBUG_RETURN(to);
5436 }
5437 
store_lock(THD * thd,THR_LOCK_DATA ** to,enum thr_lock_type lock_type)5438 THR_LOCK_DATA **ha_mroonga::store_lock(THD *thd, THR_LOCK_DATA **to,
5439                                        enum thr_lock_type lock_type)
5440 {
5441   MRN_DBUG_ENTER_METHOD();
5442   DBUG_PRINT("info", ("mroonga: lock_type=%s",
5443                       mrn_inspect_thr_lock_type(lock_type)));
5444   if (share->wrapper_mode)
5445     to = wrapper_store_lock(thd, to, lock_type);
5446   else
5447     to = storage_store_lock(thd, to, lock_type);
5448   DBUG_RETURN(to);
5449 }
5450 
wrapper_external_lock(THD * thd,int lock_type)5451 int ha_mroonga::wrapper_external_lock(THD *thd, int lock_type)
5452 {
5453   int error = 0;
5454   MRN_DBUG_ENTER_METHOD();
5455   MRN_SET_WRAP_SHARE_KEY(share, table->s);
5456   MRN_SET_WRAP_TABLE_KEY(this, table);
5457   error = wrap_handler->ha_external_lock(thd, lock_type);
5458   MRN_SET_BASE_SHARE_KEY(share, table->s);
5459   MRN_SET_BASE_TABLE_KEY(this, table);
5460   DBUG_RETURN(error);
5461 }
5462 
storage_external_lock(THD * thd,int lock_type)5463 int ha_mroonga::storage_external_lock(THD *thd, int lock_type)
5464 {
5465   MRN_DBUG_ENTER_METHOD();
5466   DBUG_RETURN(0);
5467 }
5468 
external_lock(THD * thd,int lock_type)5469 int ha_mroonga::external_lock(THD *thd, int lock_type)
5470 {
5471   MRN_DBUG_ENTER_METHOD();
5472   int error = 0;
5473   mrn_lock_type = lock_type;
5474   if (share->wrapper_mode)
5475   {
5476     error = wrapper_external_lock(thd, lock_type);
5477   } else {
5478     error = storage_external_lock(thd, lock_type);
5479   }
5480   DBUG_RETURN(error);
5481 }
5482 
wrapper_rnd_init(bool scan)5483 int ha_mroonga::wrapper_rnd_init(bool scan)
5484 {
5485   int error = 0;
5486   MRN_DBUG_ENTER_METHOD();
5487   MRN_SET_WRAP_SHARE_KEY(share, table->s);
5488   MRN_SET_WRAP_TABLE_KEY(this, table);
5489   error = wrap_handler->ha_rnd_init(scan);
5490   MRN_SET_BASE_SHARE_KEY(share, table->s);
5491   MRN_SET_BASE_TABLE_KEY(this, table);
5492   DBUG_RETURN(error);
5493 }
5494 
storage_rnd_init(bool scan)5495 int ha_mroonga::storage_rnd_init(bool scan)
5496 {
5497   MRN_DBUG_ENTER_METHOD();
5498   mrn_change_encoding(ctx, NULL);
5499   cursor = grn_table_cursor_open(ctx, grn_table, NULL, 0, NULL, 0, 0, -1, 0);
5500   if (ctx->rc) {
5501     my_message(ER_ERROR_ON_READ, ctx->errbuf, MYF(0));
5502     DBUG_RETURN(ER_ERROR_ON_READ);
5503   }
5504   DBUG_RETURN(0);
5505 }
5506 
rnd_init(bool scan)5507 int ha_mroonga::rnd_init(bool scan)
5508 {
5509   MRN_DBUG_ENTER_METHOD();
5510   int error = 0;
5511   if (share->wrapper_mode)
5512   {
5513     error = wrapper_rnd_init(scan);
5514   } else {
5515     error = storage_rnd_init(scan);
5516   }
5517   DBUG_RETURN(error);
5518 }
5519 
wrapper_rnd_end()5520 int ha_mroonga::wrapper_rnd_end()
5521 {
5522   int error = 0;
5523   MRN_DBUG_ENTER_METHOD();
5524   MRN_SET_WRAP_SHARE_KEY(share, table->s);
5525   MRN_SET_WRAP_TABLE_KEY(this, table);
5526   error = wrap_handler->ha_rnd_end();
5527   MRN_SET_BASE_SHARE_KEY(share, table->s);
5528   MRN_SET_BASE_TABLE_KEY(this, table);
5529   DBUG_RETURN(error);
5530 }
5531 
storage_rnd_end()5532 int ha_mroonga::storage_rnd_end()
5533 {
5534   MRN_DBUG_ENTER_METHOD();
5535   clear_cursor();
5536   DBUG_RETURN(0);
5537 }
5538 
rnd_end()5539 int ha_mroonga::rnd_end()
5540 {
5541   MRN_DBUG_ENTER_METHOD();
5542   int error = 0;
5543   if (share->wrapper_mode)
5544   {
5545     error = wrapper_rnd_end();
5546   } else {
5547     error = storage_rnd_end();
5548   }
5549   DBUG_RETURN(error);
5550 }
5551 
5552 #ifdef MRN_HANDLER_RECORDS_RETURN_ERROR
wrapper_records(ha_rows * num_rows)5553 int ha_mroonga::wrapper_records(ha_rows *num_rows)
5554 {
5555   int error = 0;
5556   MRN_DBUG_ENTER_METHOD();
5557   MRN_SET_WRAP_SHARE_KEY(share, table->s);
5558   MRN_SET_WRAP_TABLE_KEY(this, table);
5559   error = wrap_handler->ha_records(num_rows);
5560   MRN_SET_BASE_SHARE_KEY(share, table->s);
5561   MRN_SET_BASE_TABLE_KEY(this, table);
5562   DBUG_RETURN(error);
5563 }
5564 
storage_records(ha_rows * num_rows)5565 int ha_mroonga::storage_records(ha_rows *num_rows)
5566 {
5567   MRN_DBUG_ENTER_METHOD();
5568   int error = handler::records(num_rows);
5569   DBUG_RETURN(error);
5570 }
5571 
records(ha_rows * num_rows)5572 int ha_mroonga::records(ha_rows *num_rows)
5573 {
5574   MRN_DBUG_ENTER_METHOD();
5575   int error = 0;
5576   if (share->wrapper_mode) {
5577     error = wrapper_records(num_rows);
5578   } else {
5579     error = storage_records(num_rows);
5580   }
5581   DBUG_RETURN(error);
5582 }
5583 #else
wrapper_records()5584 ha_rows ha_mroonga::wrapper_records()
5585 {
5586   ha_rows num_rows;
5587   MRN_DBUG_ENTER_METHOD();
5588   MRN_SET_WRAP_SHARE_KEY(share, table->s);
5589   MRN_SET_WRAP_TABLE_KEY(this, table);
5590   num_rows = wrap_handler->records();
5591   MRN_SET_BASE_SHARE_KEY(share, table->s);
5592   MRN_SET_BASE_TABLE_KEY(this, table);
5593   DBUG_RETURN(num_rows);
5594 }
5595 
storage_records()5596 ha_rows ha_mroonga::storage_records()
5597 {
5598   MRN_DBUG_ENTER_METHOD();
5599   ha_rows num_rows = handler::records();
5600   DBUG_RETURN(num_rows);
5601 }
5602 
records()5603 ha_rows ha_mroonga::records()
5604 {
5605   MRN_DBUG_ENTER_METHOD();
5606   ha_rows num_rows;
5607   if (share->wrapper_mode) {
5608     num_rows = wrapper_records();
5609   } else {
5610     num_rows = storage_records();
5611   }
5612   DBUG_RETURN(num_rows);
5613 }
5614 #endif
5615 
wrapper_rnd_next(uchar * buf)5616 int ha_mroonga::wrapper_rnd_next(uchar *buf)
5617 {
5618   int error = 0;
5619   MRN_DBUG_ENTER_METHOD();
5620   MRN_SET_WRAP_SHARE_KEY(share, table->s);
5621   MRN_SET_WRAP_TABLE_KEY(this, table);
5622   if (fulltext_searching)
5623     set_pk_bitmap();
5624 #ifdef MRN_HANDLER_HAVE_HA_RND_NEXT
5625   error = wrap_handler->ha_rnd_next(buf);
5626 #else
5627   error = wrap_handler->rnd_next(buf);
5628 #endif
5629   MRN_SET_BASE_SHARE_KEY(share, table->s);
5630   MRN_SET_BASE_TABLE_KEY(this, table);
5631   DBUG_RETURN(error);
5632 }
5633 
storage_rnd_next(uchar * buf)5634 int ha_mroonga::storage_rnd_next(uchar *buf)
5635 {
5636   MRN_DBUG_ENTER_METHOD();
5637   int error = storage_get_next_record(buf);
5638   DBUG_RETURN(error);
5639 }
5640 
rnd_next(uchar * buf)5641 int ha_mroonga::rnd_next(uchar *buf)
5642 {
5643   MRN_DBUG_ENTER_METHOD();
5644   int error = 0;
5645   if (share->wrapper_mode)
5646   {
5647     error = wrapper_rnd_next(buf);
5648   } else {
5649     error = storage_rnd_next(buf);
5650   }
5651   DBUG_RETURN(error);
5652 }
5653 
wrapper_rnd_pos(uchar * buf,uchar * pos)5654 int ha_mroonga::wrapper_rnd_pos(uchar *buf, uchar *pos)
5655 {
5656   int error = 0;
5657   MRN_DBUG_ENTER_METHOD();
5658   MRN_SET_WRAP_SHARE_KEY(share, table->s);
5659   MRN_SET_WRAP_TABLE_KEY(this, table);
5660 #ifdef MRN_HANDLER_HAVE_HA_RND_POS
5661   error = wrap_handler->ha_rnd_pos(buf, pos);
5662 #else
5663   error = wrap_handler->rnd_pos(buf, pos);
5664 #endif
5665   MRN_SET_BASE_SHARE_KEY(share, table->s);
5666   MRN_SET_BASE_TABLE_KEY(this, table);
5667   DBUG_RETURN(error);
5668 }
5669 
storage_rnd_pos(uchar * buf,uchar * pos)5670 int ha_mroonga::storage_rnd_pos(uchar *buf, uchar *pos)
5671 {
5672   MRN_DBUG_ENTER_METHOD();
5673   record_id = *((grn_id*) pos);
5674   storage_store_fields(buf, record_id);
5675   DBUG_RETURN(0);
5676 }
5677 
rnd_pos(uchar * buf,uchar * pos)5678 int ha_mroonga::rnd_pos(uchar *buf, uchar *pos)
5679 {
5680   MRN_DBUG_ENTER_METHOD();
5681   int error = 0;
5682   if (share->wrapper_mode)
5683   {
5684     error = wrapper_rnd_pos(buf, pos);
5685   } else {
5686     error = storage_rnd_pos(buf, pos);
5687   }
5688   DBUG_RETURN(error);
5689 }
5690 
wrapper_position(const uchar * record)5691 void ha_mroonga::wrapper_position(const uchar *record)
5692 {
5693   MRN_DBUG_ENTER_METHOD();
5694   MRN_SET_WRAP_SHARE_KEY(share, table->s);
5695   MRN_SET_WRAP_TABLE_KEY(this, table);
5696   wrap_handler->ref = ref;
5697   wrap_handler->position(record);
5698   MRN_SET_BASE_SHARE_KEY(share, table->s);
5699   MRN_SET_BASE_TABLE_KEY(this, table);
5700   DBUG_VOID_RETURN;
5701 }
5702 
storage_position(const uchar * record)5703 void ha_mroonga::storage_position(const uchar *record)
5704 {
5705   MRN_DBUG_ENTER_METHOD();
5706   memcpy(ref, &record_id, sizeof(grn_id));
5707   DBUG_VOID_RETURN;
5708 }
5709 
position(const uchar * record)5710 void ha_mroonga::position(const uchar *record)
5711 {
5712   MRN_DBUG_ENTER_METHOD();
5713   if (share->wrapper_mode)
5714     wrapper_position(record);
5715   else
5716     storage_position(record);
5717   DBUG_VOID_RETURN;
5718 }
5719 
generic_extra(enum ha_extra_function operation)5720 int ha_mroonga::generic_extra(enum ha_extra_function operation)
5721 {
5722   MRN_DBUG_ENTER_METHOD();
5723   switch (operation) {
5724   case HA_EXTRA_IGNORE_DUP_KEY:
5725     ignoring_duplicated_key = true;
5726     break;
5727   case HA_EXTRA_NO_IGNORE_DUP_KEY:
5728     ignoring_duplicated_key = false;
5729     break;
5730   case HA_EXTRA_WRITE_CAN_REPLACE:
5731     replacing_ = true;
5732     break;
5733   case HA_EXTRA_WRITE_CANNOT_REPLACE:
5734     replacing_ = false;
5735     break;
5736   case HA_EXTRA_INSERT_WITH_UPDATE:
5737     inserting_with_update = true;
5738     break;
5739   case HA_EXTRA_KEYREAD:
5740     ignoring_no_key_columns = true;
5741     break;
5742   case HA_EXTRA_NO_KEYREAD:
5743     ignoring_no_key_columns = false;
5744     break;
5745   default:
5746     break;
5747   }
5748   DBUG_RETURN(0);
5749 }
5750 
wrapper_extra(enum ha_extra_function operation)5751 int ha_mroonga::wrapper_extra(enum ha_extra_function operation)
5752 {
5753   int error = 0;
5754   MRN_DBUG_ENTER_METHOD();
5755   MRN_SET_WRAP_SHARE_KEY(share, table->s);
5756   MRN_SET_WRAP_TABLE_KEY(this, table);
5757   error = wrap_handler->extra(operation);
5758   MRN_SET_BASE_SHARE_KEY(share, table->s);
5759   MRN_SET_BASE_TABLE_KEY(this, table);
5760   DBUG_RETURN(error);
5761 }
5762 
storage_extra(enum ha_extra_function operation)5763 int ha_mroonga::storage_extra(enum ha_extra_function operation)
5764 {
5765   MRN_DBUG_ENTER_METHOD();
5766   DBUG_RETURN(0);
5767 }
5768 
extra(enum ha_extra_function operation)5769 int ha_mroonga::extra(enum ha_extra_function operation)
5770 {
5771   int error = 0;
5772   MRN_DBUG_ENTER_METHOD();
5773   DBUG_PRINT("info",
5774              ("mroonga: this=%p; extra-operation=%s",
5775               this, mrn_inspect_extra_function(operation)));
5776   if (share->wrapper_mode) {
5777     if ((error = wrapper_extra(operation)))
5778       DBUG_RETURN(error);
5779   } else {
5780     if ((error = storage_extra(operation)))
5781       DBUG_RETURN(error);
5782   }
5783   error = generic_extra(operation);
5784   DBUG_RETURN(error);
5785 }
5786 
wrapper_extra_opt(enum ha_extra_function operation,ulong cache_size)5787 int ha_mroonga::wrapper_extra_opt(enum ha_extra_function operation,
5788                                   ulong cache_size)
5789 {
5790   int error = 0;
5791   MRN_DBUG_ENTER_METHOD();
5792   MRN_SET_WRAP_SHARE_KEY(share, table->s);
5793   MRN_SET_WRAP_TABLE_KEY(this, table);
5794   error = wrap_handler->extra_opt(operation, cache_size);
5795   MRN_SET_BASE_SHARE_KEY(share, table->s);
5796   MRN_SET_BASE_TABLE_KEY(this, table);
5797   DBUG_RETURN(error);
5798 }
5799 
storage_extra_opt(enum ha_extra_function operation,ulong cache_size)5800 int ha_mroonga::storage_extra_opt(enum ha_extra_function operation,
5801                                   ulong cache_size)
5802 {
5803   MRN_DBUG_ENTER_METHOD();
5804   DBUG_RETURN(0);
5805 }
5806 
extra_opt(enum ha_extra_function operation,ulong cache_size)5807 int ha_mroonga::extra_opt(enum ha_extra_function operation, ulong cache_size)
5808 {
5809   int error = 0;
5810   MRN_DBUG_ENTER_METHOD();
5811   if (share->wrapper_mode)
5812   {
5813     if ((error = wrapper_extra_opt(operation, cache_size)))
5814       DBUG_RETURN(error);
5815   } else {
5816     if ((error = storage_extra_opt(operation, cache_size)))
5817       DBUG_RETURN(error);
5818   }
5819   error = generic_extra(operation);
5820   DBUG_RETURN(error);
5821 }
5822 
wrapper_is_target_index(KEY * key_info)5823 bool ha_mroonga::wrapper_is_target_index(KEY *key_info)
5824 {
5825   MRN_DBUG_ENTER_METHOD();
5826   bool target_index =
5827     (key_info->algorithm == HA_KEY_ALG_FULLTEXT) || mrn_is_geo_key(key_info);
5828   DBUG_PRINT("info", ("mroonga: %s", target_index ? "true" : "false"));
5829   DBUG_RETURN(target_index);
5830 }
5831 
wrapper_have_target_index()5832 bool ha_mroonga::wrapper_have_target_index()
5833 {
5834   MRN_DBUG_ENTER_METHOD();
5835 
5836   bool have_target_index = false;
5837 
5838   uint i;
5839   uint n_keys = table->s->keys;
5840   for (i = 0; i < n_keys; i++) {
5841     KEY *key_info = &(table->key_info[i]);
5842 
5843     if (wrapper_is_target_index(key_info)) {
5844       have_target_index = true;
5845       break;
5846     }
5847   }
5848 
5849   DBUG_PRINT("info", ("mroonga: %s", have_target_index ? "true" : "false"));
5850   DBUG_RETURN(have_target_index);
5851 }
5852 
wrapper_write_row(uchar * buf)5853 int ha_mroonga::wrapper_write_row(uchar *buf)
5854 {
5855   int error = 0;
5856   THD *thd = ha_thd();
5857 
5858   MRN_DBUG_ENTER_METHOD();
5859 
5860   mrn::Operation operation(operations_,
5861                            "write",
5862                            table->s->table_name.str,
5863                            table->s->table_name.length);
5864 
5865   operation.record_target(record_id);
5866   MRN_SET_WRAP_SHARE_KEY(share, table->s);
5867   MRN_SET_WRAP_TABLE_KEY(this, table);
5868   tmp_disable_binlog(thd);
5869   error = wrap_handler->ha_write_row(buf);
5870   insert_id_for_cur_row = wrap_handler->insert_id_for_cur_row;
5871   reenable_binlog(thd);
5872   MRN_SET_BASE_SHARE_KEY(share, table->s);
5873   MRN_SET_BASE_TABLE_KEY(this, table);
5874 
5875   if (!error && wrapper_have_target_index()) {
5876     error = wrapper_write_row_index(buf);
5877   }
5878 
5879   DBUG_RETURN(error);
5880 }
5881 
wrapper_write_row_index(uchar * buf)5882 int ha_mroonga::wrapper_write_row_index(uchar *buf)
5883 {
5884   MRN_DBUG_ENTER_METHOD();
5885 
5886   int error = 0;
5887 
5888   if (is_dry_write()) {
5889     DBUG_PRINT("info", ("mroonga: dry write: ha_mroonga::%s", __FUNCTION__));
5890     DBUG_RETURN(error);
5891   }
5892 
5893   mrn_change_encoding(ctx, NULL);
5894   GRN_BULK_REWIND(&key_buffer);
5895   grn_bulk_space(ctx, &key_buffer, table->key_info->key_length);
5896   key_copy((uchar *)(GRN_TEXT_VALUE(&key_buffer)),
5897            buf,
5898            &(table->key_info[table_share->primary_key]),
5899            table->key_info[table_share->primary_key].key_length);
5900 
5901   int added;
5902   grn_id record_id;
5903   record_id = grn_table_add(ctx, grn_table,
5904                             GRN_TEXT_VALUE(&key_buffer),
5905                             GRN_TEXT_LEN(&key_buffer),
5906                             &added);
5907   if (record_id == GRN_ID_NIL) {
5908     DBUG_PRINT("info", ("mroonga: failed to add a new record into groonga"));
5909     char error_message[MRN_MESSAGE_BUFFER_SIZE];
5910     snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
5911              "failed to add a new record into groonga: key=<%.*s>",
5912              (int)GRN_TEXT_LEN(&key_buffer),
5913              GRN_TEXT_VALUE(&key_buffer));
5914     error = ER_ERROR_ON_WRITE;
5915     push_warning(ha_thd(), MRN_SEVERITY_WARNING, error,
5916                  error_message);
5917     DBUG_RETURN(0);
5918   }
5919 
5920   mrn::DebugColumnAccess debug_column_access(table, &table->read_set);
5921   uint i;
5922   uint n_keys = table->s->keys;
5923   for (i = 0; i < n_keys; i++) {
5924     KEY *key_info = &(table->key_info[i]);
5925 
5926     if (!(wrapper_is_target_index(key_info))) {
5927       continue;
5928     }
5929 
5930     grn_obj *index_column = grn_index_columns[i];
5931     if (!index_column) {
5932       continue;
5933     }
5934 
5935     uint j;
5936     for (j = 0; j < KEY_N_KEY_PARTS(key_info); j++) {
5937       Field *field = key_info->key_part[j].field;
5938 
5939       if (field->is_null())
5940         continue;
5941 
5942       error = mrn_change_encoding(ctx, field->charset());
5943       if (error)
5944         goto err;
5945       error = generic_store_bulk(field, &new_value_buffer);
5946       if (error) {
5947         my_message(error,
5948                    "mroonga: wrapper: "
5949                    "failed to get new value for updating index.",
5950                    MYF(0));
5951         goto err;
5952       }
5953 
5954       grn_rc rc;
5955       rc = grn_column_index_update(ctx, index_column, record_id, j + 1,
5956                                    NULL, &new_value_buffer);
5957       if (rc) {
5958         error = ER_ERROR_ON_WRITE;
5959         my_message(error, ctx->errbuf, MYF(0));
5960         goto err;
5961       }
5962     }
5963   }
5964 err:
5965 
5966   DBUG_RETURN(error);
5967 }
5968 
storage_write_row(uchar * buf)5969 int ha_mroonga::storage_write_row(uchar *buf)
5970 {
5971   MRN_DBUG_ENTER_METHOD();
5972   int error = 0;
5973   bool unique_indexes_are_processed = false;
5974 
5975   if (is_dry_write()) {
5976     DBUG_PRINT("info", ("mroonga: dry write: ha_mroonga::%s", __FUNCTION__));
5977     DBUG_RETURN(error);
5978   }
5979 
5980   mrn::Operation operation(operations_,
5981                            "write",
5982                            table->s->table_name.str,
5983                            table->s->table_name.length);
5984 
5985   THD *thd = ha_thd();
5986   int i;
5987   int n_columns = table->s->fields;
5988 
5989   if (table->next_number_field && buf == table->record[0])
5990   {
5991     if ((error = update_auto_increment()))
5992       DBUG_RETURN(error);
5993   }
5994 
5995   mrn::DebugColumnAccess debug_column_access(table, &table->read_set);
5996   for (i = 0; i < n_columns; i++) {
5997     Field *field = table->field[i];
5998 
5999 #ifdef MRN_SUPPORT_GENERATED_COLUMNS
6000     if (MRN_GENERATED_COLUMNS_FIELD_IS_VIRTUAL(field)) {
6001       continue;
6002     }
6003 #endif
6004 
6005     if (field->is_null()) continue;
6006 
6007     mrn::ColumnName column_name(field->field_name);
6008     if (strcmp(MRN_COLUMN_NAME_ID, column_name.c_str()) == 0) {
6009       push_warning_printf(thd, MRN_SEVERITY_WARNING,
6010                           WARN_DATA_TRUNCATED,
6011                           MRN_GET_ERR_MSG(WARN_DATA_TRUNCATED),
6012                           MRN_COLUMN_NAME_ID,
6013                           MRN_GET_CURRENT_ROW_FOR_WARNING(thd));
6014       if (MRN_ABORT_ON_WARNING(thd)) {
6015         DBUG_RETURN(ER_DATA_TOO_LONG);
6016       }
6017     }
6018   }
6019 
6020   uint pkey_nr = table->s->primary_key;
6021 
6022   int added = 0;
6023   {
6024     mrn::Lock lock(&(share->record_mutex), have_unique_index());
6025     if ((error = storage_write_row_unique_indexes(buf)))
6026     {
6027       DBUG_RETURN(error);
6028     }
6029     unique_indexes_are_processed = true;
6030 
6031     char *pkey;
6032     int pkey_size;
6033     GRN_BULK_REWIND(&key_buffer);
6034     if (pkey_nr == MAX_INDEXES) {
6035       pkey = NULL;
6036       pkey_size = 0;
6037     } else {
6038       KEY *key_info = &(table->key_info[pkey_nr]);
6039       if (KEY_N_KEY_PARTS(key_info) == 1) {
6040         Field *pkey_field = key_info->key_part[0].field;
6041         error = mrn_change_encoding(ctx, pkey_field->charset());
6042         if (error) {
6043           DBUG_RETURN(error);
6044         }
6045         generic_store_bulk(pkey_field, &key_buffer);
6046         pkey = GRN_TEXT_VALUE(&key_buffer);
6047         pkey_size = GRN_TEXT_LEN(&key_buffer);
6048       } else {
6049         mrn_change_encoding(ctx, NULL);
6050         uchar key[MRN_MAX_KEY_SIZE];
6051         key_copy(key, buf, key_info, key_info->key_length);
6052         grn_bulk_reserve(ctx, &key_buffer, MRN_MAX_KEY_SIZE);
6053         pkey = GRN_TEXT_VALUE(&key_buffer);
6054         storage_encode_multiple_column_key(key_info,
6055                                            key, key_info->key_length,
6056                                            (uchar *)pkey, (uint *)&pkey_size);
6057       }
6058     }
6059 
6060     if (grn_table->header.type != GRN_TABLE_NO_KEY && pkey_size == 0) {
6061       my_message(ER_ERROR_ON_WRITE, "primary key is empty", MYF(0));
6062       DBUG_RETURN(ER_ERROR_ON_WRITE);
6063     }
6064 
6065     record_id = grn_table_add(ctx, grn_table, pkey, pkey_size, &added);
6066     if (ctx->rc) {
6067       my_message(ER_ERROR_ON_WRITE, ctx->errbuf, MYF(0));
6068       DBUG_RETURN(ER_ERROR_ON_WRITE);
6069     }
6070     if (!added) {
6071       // duplicated error
6072       error = HA_ERR_FOUND_DUPP_KEY;
6073       memcpy(dup_ref, &record_id, sizeof(grn_id));
6074       dup_key = pkey_nr;
6075       if (!ignoring_duplicated_key) {
6076         GRN_LOG(ctx, GRN_LOG_ERROR,
6077                 "duplicated id on insert: update primary key: <%.*s>",
6078                 pkey_size, pkey);
6079       }
6080       uint j;
6081       for (j = 0; j < table->s->keys; j++) {
6082         if (j == pkey_nr) {
6083           continue;
6084         }
6085         KEY *key_info = &table->key_info[j];
6086         if (key_info->flags & HA_NOSAME) {
6087           grn_table_delete_by_id(ctx, grn_index_tables[j], key_id[j]);
6088         }
6089       }
6090       DBUG_RETURN(error);
6091     }
6092     operation.record_target(record_id);
6093   }
6094 
6095   grn_obj colbuf;
6096   GRN_VOID_INIT(&colbuf);
6097   for (i = 0; i < n_columns; i++) {
6098     Field *field = table->field[i];
6099 
6100     if (field->is_null())
6101       continue;
6102 
6103 #ifdef MRN_SUPPORT_GENERATED_COLUMNS
6104     if (MRN_GENERATED_COLUMNS_FIELD_IS_VIRTUAL(field)) {
6105       continue;
6106     }
6107 #endif
6108 
6109     mrn::ColumnName column_name(field->field_name);
6110 
6111 #ifdef MRN_HAVE_SPATIAL
6112     bool is_null_geometry_value =
6113       field->real_type() == MYSQL_TYPE_GEOMETRY &&
6114       static_cast<Field_geom *>(field)->get_length() == 0;
6115     if (is_null_geometry_value) {
6116       continue;
6117     }
6118 #endif
6119 
6120     if (strcmp(MRN_COLUMN_NAME_ID, column_name.c_str()) == 0) {
6121       continue;
6122     }
6123 
6124     error = mrn_change_encoding(ctx, field->charset());
6125     if (error) {
6126       GRN_OBJ_FIN(ctx, &colbuf);
6127       goto err;
6128     }
6129     error = generic_store_bulk(field, &colbuf);
6130     if (error) {
6131       GRN_OBJ_FIN(ctx, &colbuf);
6132       goto err;
6133     }
6134 
6135     grn_obj *column = grn_columns[i];
6136     if (is_foreign_key_field(table->s->table_name.str, field->field_name.str)) {
6137       grn_obj value;
6138       GRN_RECORD_INIT(&value, 0, grn_obj_get_range(ctx, column));
6139       grn_rc cast_rc = grn_obj_cast(ctx, &colbuf, &value, GRN_FALSE);
6140       if (cast_rc != GRN_SUCCESS) {
6141         grn_obj inspected;
6142         GRN_TEXT_INIT(&inspected, 0);
6143         grn_inspect(ctx, &inspected, &colbuf);
6144         error = HA_ERR_NO_REFERENCED_ROW;
6145         GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
6146                          "foreign record doesn't exist: <%s>:<%.*s>",
6147                          field->field_name.str,
6148                          static_cast<int>(GRN_TEXT_LEN(&inspected)),
6149                          GRN_TEXT_VALUE(&inspected));
6150         GRN_OBJ_FIN(ctx, &value);
6151         GRN_OBJ_FIN(ctx, &colbuf);
6152         GRN_OBJ_FIN(ctx, &inspected);
6153         goto err;
6154       }
6155       grn_obj_set_value(ctx, column, record_id, &value, GRN_OBJ_SET);
6156     } else {
6157       if (added && is_grn_zero_column_value(column, &colbuf)) {
6158         // WORKAROUND: groonga can't index newly added '0' value for
6159         // fix size column. So we add non-'0' value first then add
6160         // real '0' value again. It will be removed when groonga
6161         // supports 'null' value.
6162         char *bytes = GRN_BULK_HEAD(&colbuf);
6163         bytes[0] = '\1';
6164         grn_obj_set_value(ctx, column, record_id, &colbuf, GRN_OBJ_SET);
6165         bytes[0] = '\0';
6166       }
6167       grn_obj_set_value(ctx, column, record_id, &colbuf, GRN_OBJ_SET);
6168     }
6169     if (ctx->rc) {
6170       GRN_OBJ_FIN(ctx, &colbuf);
6171       my_message(ER_ERROR_ON_WRITE, ctx->errbuf, MYF(0));
6172       error = ER_ERROR_ON_WRITE;
6173       goto err;
6174     }
6175   }
6176   GRN_OBJ_FIN(ctx, &colbuf);
6177 
6178   error = storage_write_row_multiple_column_indexes(buf, record_id);
6179   if (error) {
6180     goto err;
6181   }
6182 
6183   // for UDF last_insert_grn_id()
6184   st_mrn_slot_data *slot_data;
6185   slot_data = mrn_get_slot_data(thd, true);
6186   if (slot_data == NULL) {
6187     error = HA_ERR_OUT_OF_MEM;
6188     goto err;
6189   }
6190   slot_data->last_insert_record_id = record_id;
6191 
6192   grn_db_touch(ctx, grn_ctx_db(ctx));
6193 
6194   if (table->found_next_number_field &&
6195       !table->s->next_number_keypart) {
6196     Field_num *field = (Field_num *) table->found_next_number_field;
6197     if (field->unsigned_flag || field->val_int() > 0) {
6198       MRN_LONG_TERM_SHARE *long_term_share = share->long_term_share;
6199       ulonglong nr = (ulonglong) field->val_int();
6200       if (!long_term_share->auto_inc_inited) {
6201         storage_info(HA_STATUS_AUTO);
6202       }
6203       {
6204         mrn::Lock lock(&long_term_share->auto_inc_mutex);
6205         if (long_term_share->auto_inc_value <= nr) {
6206           long_term_share->auto_inc_value = nr + 1;
6207           DBUG_PRINT("info", ("mroonga: auto_inc_value=%llu",
6208             long_term_share->auto_inc_value));
6209         }
6210       }
6211     }
6212   }
6213   DBUG_RETURN(0);
6214 
6215 err:
6216   if (unique_indexes_are_processed) {
6217     uint j;
6218     for (j = 0; j < table->s->keys; j++) {
6219       if (j == pkey_nr) {
6220         continue;
6221       }
6222       KEY *key_info = &table->key_info[j];
6223       if (key_info->flags & HA_NOSAME) {
6224         grn_table_delete_by_id(ctx, grn_index_tables[j], key_id[j]);
6225       }
6226     }
6227   }
6228   grn_table_delete_by_id(ctx, grn_table, record_id);
6229   DBUG_RETURN(error);
6230 }
6231 
storage_write_row_multiple_column_index(uchar * buf,grn_id record_id,KEY * key_info,grn_obj * index_column)6232 int ha_mroonga::storage_write_row_multiple_column_index(uchar *buf,
6233                                                         grn_id record_id,
6234                                                         KEY *key_info,
6235                                                         grn_obj *index_column)
6236 {
6237   MRN_DBUG_ENTER_METHOD();
6238   int error = 0;
6239 
6240   mrn_change_encoding(ctx, NULL);
6241   GRN_BULK_REWIND(&key_buffer);
6242   grn_bulk_space(ctx, &key_buffer, key_info->key_length);
6243   key_copy((uchar *)(GRN_TEXT_VALUE(&key_buffer)),
6244            buf,
6245            key_info,
6246            key_info->key_length);
6247   GRN_BULK_REWIND(&encoded_key_buffer);
6248   grn_bulk_reserve(ctx, &encoded_key_buffer, MRN_MAX_KEY_SIZE);
6249   uint encoded_key_length;
6250   storage_encode_multiple_column_key(key_info,
6251                                      (uchar *)(GRN_TEXT_VALUE(&key_buffer)),
6252                                      key_info->key_length,
6253                                      (uchar *)(GRN_TEXT_VALUE(&encoded_key_buffer)),
6254                                      &encoded_key_length);
6255   grn_bulk_space(ctx, &encoded_key_buffer, encoded_key_length);
6256   DBUG_PRINT("info", ("mroonga: key_length=%u", key_info->key_length));
6257   DBUG_PRINT("info", ("mroonga: encoded_key_length=%u", encoded_key_length));
6258 
6259   grn_rc rc;
6260   rc = grn_column_index_update(ctx, index_column, record_id, 1, NULL,
6261                                &encoded_key_buffer);
6262   if (rc) {
6263     error = ER_ERROR_ON_WRITE;
6264     my_message(error, ctx->errbuf, MYF(0));
6265   }
6266   DBUG_RETURN(error);
6267 }
6268 
storage_write_row_multiple_column_indexes(uchar * buf,grn_id record_id)6269 int ha_mroonga::storage_write_row_multiple_column_indexes(uchar *buf,
6270                                                           grn_id record_id)
6271 {
6272   MRN_DBUG_ENTER_METHOD();
6273 
6274   int error = 0;
6275 
6276   mrn::DebugColumnAccess debug_column_access(table, &table->read_set);
6277   uint i;
6278   uint n_keys = table->s->keys;
6279   for (i = 0; i < n_keys; i++) {
6280     if (i == table->s->primary_key) {
6281       continue;
6282     }
6283 
6284     KEY *key_info = &(table->key_info[i]);
6285 
6286     if (KEY_N_KEY_PARTS(key_info) == 1 || (key_info->flags & HA_FULLTEXT)) {
6287       continue;
6288     }
6289 
6290     grn_obj *index_column = grn_index_columns[i];
6291     if (!index_column) {
6292       continue;
6293     }
6294 
6295     if ((error = storage_write_row_multiple_column_index(buf,
6296                                                          record_id,
6297                                                          key_info,
6298                                                          index_column)))
6299     {
6300       goto err;
6301     }
6302   }
6303 
6304 err:
6305 
6306   DBUG_RETURN(error);
6307 }
6308 
storage_write_row_unique_index(const uchar * buf,KEY * key_info,grn_obj * index_table,grn_obj * index_column,grn_id * key_id)6309 int ha_mroonga::storage_write_row_unique_index(const uchar *buf,
6310                                                KEY *key_info,
6311                                                grn_obj *index_table,
6312                                                grn_obj *index_column,
6313                                                grn_id *key_id)
6314 {
6315   char *ukey = NULL;
6316   int error, ukey_size = 0;
6317   MRN_DBUG_ENTER_METHOD();
6318   GRN_BULK_REWIND(&key_buffer);
6319   if (KEY_N_KEY_PARTS(key_info) == 1) {
6320     Field *ukey_field = key_info->key_part[0].field;
6321     error = mrn_change_encoding(ctx, ukey_field->charset());
6322     if (error) {
6323       DBUG_RETURN(error);
6324     }
6325     generic_store_bulk(ukey_field, &key_buffer);
6326     ukey = GRN_TEXT_VALUE(&key_buffer);
6327     ukey_size = GRN_TEXT_LEN(&key_buffer);
6328   } else {
6329     mrn_change_encoding(ctx, NULL);
6330     uchar key[MRN_MAX_KEY_SIZE];
6331     key_copy(key, buf, key_info, key_info->key_length);
6332     grn_bulk_reserve(ctx, &key_buffer, MRN_MAX_KEY_SIZE);
6333     ukey = GRN_TEXT_VALUE(&key_buffer);
6334     storage_encode_multiple_column_key(key_info,
6335                                        key, key_info->key_length,
6336                                        (uchar *)(ukey), (uint *)&ukey_size);
6337   }
6338 
6339   int added;
6340   *key_id = grn_table_add(ctx, index_table, ukey, ukey_size, &added);
6341   if (ctx->rc) {
6342     my_message(ER_ERROR_ON_WRITE, ctx->errbuf, MYF(0));
6343     DBUG_RETURN(ER_ERROR_ON_WRITE);
6344   }
6345   if (!added) {
6346     // duplicated error
6347     error = HA_ERR_FOUND_DUPP_KEY;
6348     grn_id duplicated_record_id = GRN_ID_NIL;
6349     {
6350       grn_table_cursor *table_cursor;
6351       table_cursor = grn_table_cursor_open(ctx, index_table,
6352                                            ukey, ukey_size,
6353                                            ukey, ukey_size,
6354                                            0, -1, 0);
6355       if (table_cursor) {
6356         grn_obj *index_cursor;
6357         index_cursor = grn_index_cursor_open(ctx, table_cursor, index_column,
6358                                              GRN_ID_NIL, GRN_ID_MAX, 0);
6359         if (index_cursor) {
6360           grn_posting *posting;
6361           posting = grn_index_cursor_next(ctx, index_cursor, NULL);
6362           if (posting) {
6363             duplicated_record_id = posting->rid;
6364           }
6365         }
6366         grn_obj_unlink(ctx, index_cursor);
6367       }
6368       grn_table_cursor_close(ctx, table_cursor);
6369     }
6370     memcpy(dup_ref, &duplicated_record_id, sizeof(grn_id));
6371     if (!ignoring_duplicated_key) {
6372       GRN_LOG(ctx, GRN_LOG_ERROR,
6373               "duplicated id on insert: update unique index: <%.*s>",
6374               ukey_size, ukey);
6375     }
6376     DBUG_RETURN(error);
6377   }
6378   DBUG_RETURN(0);
6379 }
6380 
storage_write_row_unique_indexes(uchar * buf)6381 int ha_mroonga::storage_write_row_unique_indexes(uchar *buf)
6382 {
6383   int error = 0;
6384   uint i;
6385   uint n_keys = table->s->keys;
6386   MRN_DBUG_ENTER_METHOD();
6387 
6388   for (i = 0; i < n_keys; i++) {
6389     if (i == table->s->primary_key) {
6390       continue;
6391     }
6392 
6393     KEY *key_info = &table->key_info[i];
6394 
6395     if (!(key_info->flags & HA_NOSAME)) {
6396       continue;
6397     }
6398 
6399     grn_obj *index_table = grn_index_tables[i];
6400     if (!index_table) {
6401       continue;
6402     }
6403     grn_obj *index_column = grn_index_columns[i];
6404     if (!index_column) {
6405       continue;
6406     }
6407 
6408     if ((error = storage_write_row_unique_index(buf, key_info,
6409                                                 index_table, index_column,
6410                                                 &key_id[i])))
6411     {
6412       if (error == HA_ERR_FOUND_DUPP_KEY)
6413       {
6414         dup_key = i;
6415       }
6416       goto err;
6417     }
6418   }
6419   DBUG_RETURN(0);
6420 
6421 err:
6422   if (i) {
6423     mrn_change_encoding(ctx, NULL);
6424     do {
6425       i--;
6426 
6427       if (i == table->s->primary_key) {
6428         continue;
6429       }
6430 
6431       KEY *key_info = &table->key_info[i];
6432       if (!(key_info->flags & HA_NOSAME)) {
6433         continue;
6434       }
6435 
6436       if (key_info->flags & HA_NOSAME) {
6437         grn_table_delete_by_id(ctx, grn_index_tables[i], key_id[i]);
6438       }
6439     } while (i);
6440   }
6441   DBUG_RETURN(error);
6442 }
6443 
write_row(uchar * buf)6444 int ha_mroonga::write_row(uchar *buf)
6445 {
6446   MRN_DBUG_ENTER_METHOD();
6447   int error = 0;
6448   if (share->wrapper_mode)
6449   {
6450     error = wrapper_write_row(buf);
6451   } else {
6452     error = storage_write_row(buf);
6453   }
6454   DBUG_RETURN(error);
6455 }
6456 
wrapper_get_record_id(uchar * data,grn_id * record_id,const char * context)6457 int ha_mroonga::wrapper_get_record_id(uchar *data, grn_id *record_id,
6458                                       const char *context)
6459 {
6460   MRN_DBUG_ENTER_METHOD();
6461 
6462   int error = 0;
6463 
6464   grn_obj key;
6465   GRN_TEXT_INIT(&key, 0);
6466 
6467   mrn_change_encoding(ctx, NULL);
6468   grn_bulk_space(ctx, &key, table->key_info->key_length);
6469   key_copy((uchar *)(GRN_TEXT_VALUE(&key)),
6470            data,
6471            &(table->key_info[table_share->primary_key]),
6472            table->key_info[table_share->primary_key].key_length);
6473 
6474   *record_id = grn_table_get(ctx, grn_table,
6475                              GRN_TEXT_VALUE(&key), GRN_TEXT_LEN(&key));
6476   if (*record_id == GRN_ID_NIL) {
6477     DBUG_PRINT("info", ("mroonga: %s", context));
6478     char error_message[MRN_MESSAGE_BUFFER_SIZE];
6479     snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
6480              "%s: key=<%.*s>",
6481              context, (int)GRN_TEXT_LEN(&key), GRN_TEXT_VALUE(&key));
6482     error = ER_ERROR_ON_WRITE;
6483     push_warning(ha_thd(), MRN_SEVERITY_WARNING, error,
6484                  error_message);
6485   }
6486   grn_obj_unlink(ctx, &key);
6487 
6488   DBUG_RETURN(error);
6489 }
6490 
wrapper_update_row(const uchar * old_data,const uchar * new_data)6491 int ha_mroonga::wrapper_update_row(const uchar *old_data,
6492                                    const uchar *new_data)
6493 {
6494   MRN_DBUG_ENTER_METHOD();
6495 
6496   int error = 0;
6497   THD *thd = ha_thd();
6498 
6499   mrn::Operation operation(operations_,
6500                            "update",
6501                            table->s->table_name.str,
6502                            table->s->table_name.length);
6503 
6504   MRN_SET_WRAP_SHARE_KEY(share, table->s);
6505   MRN_SET_WRAP_TABLE_KEY(this, table);
6506   tmp_disable_binlog(thd);
6507   error = wrap_handler->ha_update_row(old_data, new_data);
6508   reenable_binlog(thd);
6509   MRN_SET_BASE_SHARE_KEY(share, table->s);
6510   MRN_SET_BASE_TABLE_KEY(this, table);
6511 
6512   if (!error && wrapper_have_target_index()) {
6513     error = wrapper_update_row_index(old_data, new_data);
6514   }
6515 
6516   DBUG_RETURN(error);
6517 }
6518 
wrapper_update_row_index(const uchar * old_data,const uchar * new_data)6519 int ha_mroonga::wrapper_update_row_index(const uchar *old_data,
6520                                          const uchar *new_data)
6521 {
6522   MRN_DBUG_ENTER_METHOD();
6523 
6524   int error = 0;
6525 
6526   if (is_dry_write()) {
6527     DBUG_PRINT("info", ("mroonga: dry write: ha_mroonga::%s", __FUNCTION__));
6528     DBUG_RETURN(error);
6529   }
6530 
6531   mrn_change_encoding(ctx, NULL);
6532   KEY *key_info = &(table->key_info[table_share->primary_key]);
6533   GRN_BULK_REWIND(&key_buffer);
6534   key_copy((uchar *)(GRN_TEXT_VALUE(&key_buffer)),
6535            new_data,
6536            key_info, key_info->key_length);
6537   int added;
6538   grn_id new_record_id;
6539   new_record_id = grn_table_add(ctx, grn_table,
6540                                 GRN_TEXT_VALUE(&key_buffer),
6541                                 table->key_info->key_length,
6542                                 &added);
6543   if (new_record_id == GRN_ID_NIL) {
6544     char error_message[MRN_MESSAGE_BUFFER_SIZE];
6545     snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
6546              "failed to get new record ID for updating from groonga: key=<%.*s>",
6547              (int)GRN_TEXT_LEN(&key_buffer), GRN_TEXT_VALUE(&key_buffer));
6548     error = ER_ERROR_ON_WRITE;
6549     my_message(error, error_message, MYF(0));
6550     DBUG_RETURN(error);
6551   }
6552 
6553   grn_id old_record_id;
6554   my_ptrdiff_t ptr_diff = PTR_BYTE_DIFF(old_data, table->record[0]);
6555   for (uint j = 0; j < KEY_N_KEY_PARTS(key_info); j++) {
6556     Field *field = key_info->key_part[j].field;
6557     field->move_field_offset(ptr_diff);
6558   }
6559   error = wrapper_get_record_id((uchar *)old_data, &old_record_id,
6560                                 "failed to get old record ID "
6561                                 "for updating from groonga");
6562   for (uint j = 0; j < KEY_N_KEY_PARTS(key_info); j++) {
6563     Field *field = key_info->key_part[j].field;
6564     field->move_field_offset(-ptr_diff);
6565   }
6566   if (error) {
6567     DBUG_RETURN(0);
6568   }
6569 
6570   mrn::DebugColumnAccess debug_column_access(table, &table->read_set);
6571   uint i;
6572   uint n_keys = table->s->keys;
6573   for (i = 0; i < n_keys; i++) {
6574     KEY *key_info = &(table->key_info[i]);
6575 
6576     if (!(wrapper_is_target_index(key_info))) {
6577       continue;
6578     }
6579 
6580     grn_obj *index_column = grn_index_columns[i];
6581     if (!index_column) {
6582       /* disable keys */
6583       continue;
6584     }
6585 
6586     uint j;
6587     for (j = 0; j < KEY_N_KEY_PARTS(key_info); j++) {
6588       Field *field = key_info->key_part[j].field;
6589 
6590       generic_store_bulk(field, &new_value_buffer);
6591 
6592       field->move_field_offset(ptr_diff);
6593       generic_store_bulk(field, &old_value_buffer);
6594       field->move_field_offset(-ptr_diff);
6595 
6596       grn_rc rc;
6597       if (old_record_id == new_record_id) {
6598         if (added) {
6599           rc = grn_column_index_update(ctx, index_column, old_record_id, j + 1,
6600                                        &old_value_buffer, NULL);
6601           if (!rc) {
6602             rc = grn_column_index_update(ctx, index_column, new_record_id, j + 1,
6603                                          NULL, &new_value_buffer);
6604           }
6605         } else {
6606           rc = grn_column_index_update(ctx, index_column, old_record_id, j + 1,
6607                                        &old_value_buffer, &new_value_buffer);
6608         }
6609       } else {
6610         rc = grn_column_index_update(ctx, index_column, old_record_id, j + 1,
6611                                      &old_value_buffer, NULL);
6612         if (!rc) {
6613           rc = grn_column_index_update(ctx, index_column, new_record_id, j + 1,
6614                                        NULL, &new_value_buffer);
6615         }
6616         if (!rc) {
6617           rc = grn_table_delete_by_id(ctx, grn_table, old_record_id);
6618         }
6619       }
6620       if (rc) {
6621         error = ER_ERROR_ON_WRITE;
6622         my_message(error, ctx->errbuf, MYF(0));
6623         goto err;
6624       }
6625     }
6626   }
6627 err:
6628 
6629   DBUG_RETURN(error);
6630 }
6631 
storage_update_row(const uchar * old_data,const uchar * new_data)6632 int ha_mroonga::storage_update_row(const uchar *old_data,
6633                                    const uchar *new_data)
6634 {
6635   MRN_DBUG_ENTER_METHOD();
6636   int error = 0;
6637 
6638   if (is_dry_write()) {
6639     DBUG_PRINT("info", ("mroonga: dry write: ha_mroonga::%s", __FUNCTION__));
6640     DBUG_RETURN(error);
6641   }
6642 
6643   mrn::Operation operation(operations_,
6644                            "update",
6645                            table->s->table_name.str,
6646                            table->s->table_name.length);
6647   operation.record_target(record_id);
6648 
6649   grn_obj colbuf;
6650   int i;
6651   uint j;
6652   int n_columns = table->s->fields;
6653   THD *thd = ha_thd();
6654 
6655   for (i = 0; i < n_columns; i++) {
6656     Field *field = table->field[i];
6657 
6658 #ifdef MRN_SUPPORT_GENERATED_COLUMNS
6659     if (MRN_GENERATED_COLUMNS_FIELD_IS_VIRTUAL(field)) {
6660       continue;
6661     }
6662 #endif
6663 
6664     if (!bitmap_is_set(table->write_set, field->field_index))
6665       continue;
6666 
6667     if (field->is_null())
6668       continue;
6669 
6670     {
6671       mrn::ColumnName column_name(field->field_name);
6672       if (strcmp(MRN_COLUMN_NAME_ID, column_name.c_str()) == 0) {
6673         push_warning_printf(thd, MRN_SEVERITY_WARNING,
6674                             WARN_DATA_TRUNCATED, MRN_GET_ERR_MSG(WARN_DATA_TRUNCATED),
6675                             MRN_COLUMN_NAME_ID,
6676                             MRN_GET_CURRENT_ROW_FOR_WARNING(thd));
6677         if (MRN_ABORT_ON_WARNING(thd)) {
6678           DBUG_RETURN(ER_DATA_TOO_LONG);
6679         }
6680       }
6681     }
6682 
6683     if (!is_foreign_key_field(table->s->table_name.str, field->field_name.str))
6684       continue;
6685 
6686     {
6687       grn_obj *column = grn_columns[i];
6688       grn_obj new_value;
6689       GRN_VOID_INIT(&new_value);
6690       {
6691         mrn::DebugColumnAccess debug_column_access(table, &table->read_set);
6692         generic_store_bulk(field, &new_value);
6693       }
6694       grn_obj casted_value;
6695       GRN_RECORD_INIT(&casted_value, 0, grn_obj_get_range(ctx, column));
6696       grn_rc cast_rc = grn_obj_cast(ctx, &new_value, &casted_value, GRN_FALSE);
6697       GRN_OBJ_FIN(ctx, &casted_value);
6698       if (cast_rc != GRN_SUCCESS) {
6699         grn_obj inspected;
6700         GRN_TEXT_INIT(&inspected, 0);
6701         grn_inspect(ctx, &inspected, &new_value);
6702         GRN_OBJ_FIN(ctx, &new_value);
6703         error = HA_ERR_NO_REFERENCED_ROW;
6704         GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
6705                          "foreign record doesn't exist: <%s>:<%.*s>",
6706                          field->field_name.str,
6707                          static_cast<int>(GRN_TEXT_LEN(&inspected)),
6708                          GRN_TEXT_VALUE(&inspected));
6709         GRN_OBJ_FIN(ctx, &inspected);
6710         DBUG_RETURN(error);
6711       }
6712       GRN_OBJ_FIN(ctx, &new_value);
6713     }
6714   }
6715 
6716   KEY *pkey_info = NULL;
6717   storage_store_fields_for_prep_update(old_data, new_data, record_id);
6718   {
6719     mrn::Lock lock(&(share->record_mutex), have_unique_index());
6720     mrn::DebugColumnAccess debug_column_access(table, &table->read_set);
6721     if ((error = storage_prepare_delete_row_unique_indexes(old_data,
6722                                                            record_id))) {
6723       DBUG_RETURN(error);
6724     }
6725     if ((error = storage_update_row_unique_indexes(new_data)))
6726     {
6727       DBUG_RETURN(error);
6728     }
6729   }
6730 
6731   if (table->s->primary_key != MAX_INDEXES) {
6732     pkey_info = &(table->key_info[table->s->primary_key]);
6733   }
6734   GRN_VOID_INIT(&colbuf);
6735   for (i = 0; i < n_columns; i++) {
6736     Field *field = table->field[i];
6737 
6738 #ifdef MRN_SUPPORT_GENERATED_COLUMNS
6739     if (MRN_GENERATED_COLUMNS_FIELD_IS_VIRTUAL(field)) {
6740       continue;
6741     }
6742 #endif
6743 
6744     if (bitmap_is_set(table->write_set, field->field_index)) {
6745       mrn::DebugColumnAccess debug_column_access(table, &table->read_set);
6746       DBUG_PRINT("info", ("mroonga: update column %d(%d)",i,field->field_index));
6747 
6748       if (field->is_null()) continue;
6749 
6750       mrn::ColumnName column_name(field->field_name);
6751       if (strcmp(MRN_COLUMN_NAME_ID, column_name.c_str()) == 0) {
6752         continue;
6753       }
6754 
6755       error = mrn_change_encoding(ctx, field->charset());
6756       if (error)
6757         goto err;
6758 
6759       bool is_pkey = false;
6760       bool on_duplicate_key_update =
6761         (inserting_with_update && ignoring_duplicated_key);
6762       if (pkey_info && !on_duplicate_key_update) {
6763         for (j = 0; j < KEY_N_KEY_PARTS(pkey_info); j++) {
6764           Field *pkey_field = pkey_info->key_part[j].field;
6765           if (strcmp(pkey_field->field_name.str, column_name.c_str()) == 0) {
6766             is_pkey = true;
6767             break;
6768           }
6769         }
6770       }
6771 
6772       generic_store_bulk(field, &colbuf);
6773       if (is_pkey) {
6774         bool is_multiple_column_index = KEY_N_KEY_PARTS(pkey_info) > 1;
6775         bool is_same_value;
6776         if (is_multiple_column_index) {
6777           is_same_value = false;
6778         } else {
6779           grn_id found_record_id = grn_table_get(ctx,
6780                                                  grn_table,
6781                                                  GRN_BULK_HEAD(&colbuf),
6782                                                  GRN_BULK_VSIZE(&colbuf));
6783           is_same_value = (record_id == found_record_id);
6784         }
6785         if (!is_same_value && !replacing_) {
6786           char message[MRN_BUFFER_SIZE];
6787           snprintf(message, MRN_BUFFER_SIZE,
6788                    "data truncated for primary key column: <%s>",
6789                    column_name.c_str());
6790           push_warning(thd, MRN_SEVERITY_WARNING,
6791                        WARN_DATA_TRUNCATED, message);
6792         }
6793         continue;
6794       }
6795 
6796       grn_obj_set_value(ctx, grn_columns[i], record_id, &colbuf, GRN_OBJ_SET);
6797       if (ctx->rc) {
6798         grn_obj_unlink(ctx, &colbuf);
6799         my_message(ER_ERROR_ON_WRITE, ctx->errbuf, MYF(0));
6800         error = ER_ERROR_ON_WRITE;
6801         goto err;
6802       }
6803     }
6804   }
6805   grn_obj_unlink(ctx, &colbuf);
6806 
6807   if ((error = storage_update_row_index(old_data, new_data)))
6808   {
6809     goto err;
6810   }
6811 
6812   if ((error = storage_delete_row_unique_indexes()))
6813   {
6814     DBUG_RETURN(error);
6815   }
6816 
6817   grn_db_touch(ctx, grn_ctx_db(ctx));
6818 
6819   if (table->found_next_number_field &&
6820       !table->s->next_number_keypart &&
6821       new_data == table->record[0]) {
6822     mrn::DebugColumnAccess debug_column_access(table, &table->read_set);
6823     Field_num *field = (Field_num *) table->found_next_number_field;
6824     if (field->unsigned_flag || field->val_int() > 0) {
6825       MRN_LONG_TERM_SHARE *long_term_share = share->long_term_share;
6826       ulonglong nr = (ulonglong) field->val_int();
6827       if (!long_term_share->auto_inc_inited) {
6828         storage_info(HA_STATUS_AUTO);
6829       }
6830       {
6831         mrn::Lock lock(&long_term_share->auto_inc_mutex);
6832         if (long_term_share->auto_inc_value <= nr) {
6833           long_term_share->auto_inc_value = nr + 1;
6834           DBUG_PRINT("info", ("mroonga: auto_inc_value=%llu",
6835             long_term_share->auto_inc_value));
6836         }
6837       }
6838     }
6839   }
6840   DBUG_RETURN(0);
6841 
6842 err:
6843   for (j = 0; j < table->s->keys; j++) {
6844     if (j == table->s->primary_key) {
6845       continue;
6846     }
6847     KEY *key_info = &table->key_info[j];
6848     if ((key_info->flags & HA_NOSAME) && key_id[j] != GRN_ID_NIL) {
6849       grn_table_delete_by_id(ctx, grn_index_tables[j], key_id[j]);
6850     }
6851   }
6852 
6853   if (!error && thd_sql_command(ha_thd()) == SQLCOM_TRUNCATE) {
6854     MRN_LONG_TERM_SHARE *long_term_share = share->long_term_share;
6855     mrn::Lock lock(&long_term_share->auto_inc_mutex);
6856     long_term_share->auto_inc_value = 0;
6857     DBUG_PRINT("info", ("mroonga: auto_inc_value=%llu",
6858       long_term_share->auto_inc_value));
6859     long_term_share->auto_inc_inited = false;
6860   }
6861 
6862   DBUG_RETURN(error);
6863 }
6864 
storage_update_row_index(const uchar * old_data,const uchar * new_data)6865 int ha_mroonga::storage_update_row_index(const uchar *old_data,
6866                                          const uchar *new_data)
6867 {
6868   MRN_DBUG_ENTER_METHOD();
6869   int error = 0;
6870 
6871   grn_obj old_key, old_encoded_key, new_key, new_encoded_key;
6872   GRN_TEXT_INIT(&old_key, 0);
6873   GRN_TEXT_INIT(&old_encoded_key, 0);
6874   GRN_TEXT_INIT(&new_key, 0);
6875   GRN_TEXT_INIT(&new_encoded_key, 0);
6876 
6877   my_ptrdiff_t ptr_diff = PTR_BYTE_DIFF(old_data, table->record[0]);
6878 
6879   mrn::DebugColumnAccess debug_column_access(table, &table->read_set);
6880   uint i;
6881   uint n_keys = table->s->keys;
6882   mrn_change_encoding(ctx, NULL);
6883   for (i = 0; i < n_keys; i++) {
6884     if (i == table->s->primary_key) {
6885       continue;
6886     }
6887 
6888     KEY *key_info = &(table->key_info[i]);
6889 
6890     if (KEY_N_KEY_PARTS(key_info) == 1 || (key_info->flags & HA_FULLTEXT)) {
6891       continue;
6892     }
6893 
6894     grn_obj *index_column = grn_index_columns[i];
6895     if (!index_column) {
6896       /* disable keys */
6897       continue;
6898     }
6899 
6900     GRN_BULK_REWIND(&old_key);
6901     grn_bulk_space(ctx, &old_key, key_info->key_length);
6902     for (uint j = 0; j < KEY_N_KEY_PARTS(key_info); j++) {
6903       Field *field = key_info->key_part[j].field;
6904       field->move_field_offset(ptr_diff);
6905     }
6906     key_copy((uchar *)(GRN_TEXT_VALUE(&old_key)),
6907              (uchar *)old_data,
6908              key_info,
6909              key_info->key_length);
6910     for (uint j = 0; j < KEY_N_KEY_PARTS(key_info); j++) {
6911       Field *field = key_info->key_part[j].field;
6912       field->move_field_offset(-ptr_diff);
6913     }
6914     GRN_BULK_REWIND(&old_encoded_key);
6915     grn_bulk_reserve(ctx, &old_encoded_key, MRN_MAX_KEY_SIZE);
6916     uint old_encoded_key_length;
6917     storage_encode_multiple_column_key(key_info,
6918                                        (uchar *)(GRN_TEXT_VALUE(&old_key)),
6919                                        key_info->key_length,
6920                                        (uchar *)(GRN_TEXT_VALUE(&old_encoded_key)),
6921                                        &old_encoded_key_length);
6922     grn_bulk_space(ctx, &old_encoded_key, old_encoded_key_length);
6923 
6924     GRN_BULK_REWIND(&new_key);
6925     grn_bulk_space(ctx, &new_key, key_info->key_length);
6926     key_copy((uchar *)(GRN_TEXT_VALUE(&new_key)),
6927              (uchar *)new_data,
6928              key_info,
6929              key_info->key_length);
6930     GRN_BULK_REWIND(&new_encoded_key);
6931     grn_bulk_reserve(ctx, &new_encoded_key, MRN_MAX_KEY_SIZE);
6932     uint new_encoded_key_length;
6933     storage_encode_multiple_column_key(key_info,
6934                                        (uchar *)(GRN_TEXT_VALUE(&new_key)),
6935                                        key_info->key_length,
6936                                        (uchar *)(GRN_TEXT_VALUE(&new_encoded_key)),
6937                                        &new_encoded_key_length);
6938     grn_bulk_space(ctx, &new_encoded_key, new_encoded_key_length);
6939 
6940     grn_rc rc;
6941     rc = grn_column_index_update(ctx, index_column, record_id, 1,
6942                                  &old_encoded_key, &new_encoded_key);
6943     if (rc) {
6944       error = ER_ERROR_ON_WRITE;
6945       my_message(error, ctx->errbuf, MYF(0));
6946       goto err;
6947     }
6948   }
6949 err:
6950   grn_obj_unlink(ctx, &old_key);
6951   grn_obj_unlink(ctx, &old_encoded_key);
6952   grn_obj_unlink(ctx, &new_key);
6953   grn_obj_unlink(ctx, &new_encoded_key);
6954 
6955   DBUG_RETURN(error);
6956 }
6957 
storage_update_row_unique_indexes(const uchar * new_data)6958 int ha_mroonga::storage_update_row_unique_indexes(const uchar *new_data)
6959 {
6960   int error;
6961   uint i;
6962   uint n_keys = table->s->keys;
6963   MRN_DBUG_ENTER_METHOD();
6964 
6965   for (i = 0; i < n_keys; i++) {
6966     if (i == table->s->primary_key) {
6967       continue;
6968     }
6969 
6970     KEY *key_info = &table->key_info[i];
6971     if (!(key_info->flags & HA_NOSAME)) {
6972       continue;
6973     }
6974 
6975     grn_obj *index_table = grn_index_tables[i];
6976     if (!index_table) {
6977       key_id[i] = GRN_ID_NIL;
6978       del_key_id[i] = GRN_ID_NIL;
6979       continue;
6980     }
6981 
6982     grn_obj *index_column = grn_index_columns[i];
6983     if (!index_column) {
6984       key_id[i] = GRN_ID_NIL;
6985       del_key_id[i] = GRN_ID_NIL;
6986       continue;
6987     }
6988 
6989     if (
6990       KEY_N_KEY_PARTS(key_info) == 1 &&
6991       !bitmap_is_set(table->write_set,
6992                      key_info->key_part[0].field->field_index)
6993     ) {
6994       /* no change */
6995       key_id[i] = GRN_ID_NIL;
6996       del_key_id[i] = GRN_ID_NIL;
6997       continue;
6998     }
6999 
7000     if ((error = storage_write_row_unique_index(new_data, key_info,
7001                                                 index_table, index_column,
7002                                                 &key_id[i])))
7003     {
7004       if (error == HA_ERR_FOUND_DUPP_KEY)
7005       {
7006         if (key_id[i] == del_key_id[i]) {
7007           /* no change */
7008           key_id[i] = GRN_ID_NIL;
7009           del_key_id[i] = GRN_ID_NIL;
7010           continue;
7011         }
7012         dup_key = i;
7013         DBUG_PRINT("info", ("mroonga: different key ID: %d record ID: %d,%d",
7014           i, key_id[i], del_key_id[i]));
7015       }
7016       goto err;
7017     }
7018   }
7019   DBUG_RETURN(0);
7020 
7021 err:
7022   if (i) {
7023     mrn_change_encoding(ctx, NULL);
7024     do {
7025       i--;
7026       KEY *key_info = &table->key_info[i];
7027       if ((key_info->flags & HA_NOSAME) && key_id[i] != GRN_ID_NIL) {
7028         grn_table_delete_by_id(ctx, grn_index_tables[i], key_id[i]);
7029       }
7030     } while (i);
7031   }
7032   DBUG_RETURN(error);
7033 }
7034 
update_row(const uchar * old_data,const uchar * new_data)7035 int ha_mroonga::update_row(const uchar *old_data, const uchar *new_data)
7036 {
7037   MRN_DBUG_ENTER_METHOD();
7038   int error = 0;
7039   if (share->wrapper_mode)
7040   {
7041     error = wrapper_update_row(old_data, new_data);
7042   } else {
7043     error = storage_update_row(old_data, new_data);
7044   }
7045   DBUG_RETURN(error);
7046 }
7047 
wrapper_delete_row(const uchar * buf)7048 int ha_mroonga::wrapper_delete_row(const uchar *buf)
7049 {
7050   MRN_DBUG_ENTER_METHOD();
7051 
7052   int error = 0;
7053   THD *thd= ha_thd();
7054 
7055   mrn::Operation operation(operations_,
7056                            "delete",
7057                            table->s->table_name.str,
7058                            table->s->table_name.length);
7059 
7060   MRN_SET_WRAP_SHARE_KEY(share, table->s);
7061   MRN_SET_WRAP_TABLE_KEY(this, table);
7062   tmp_disable_binlog(thd);
7063   error = wrap_handler->ha_delete_row(buf);
7064   reenable_binlog(thd);
7065   MRN_SET_BASE_SHARE_KEY(share, table->s);
7066   MRN_SET_BASE_TABLE_KEY(this, table);
7067 
7068   if (!error && wrapper_have_target_index()) {
7069     error = wrapper_delete_row_index(buf);
7070   }
7071 
7072   DBUG_RETURN(error);
7073 }
7074 
wrapper_delete_row_index(const uchar * buf)7075 int ha_mroonga::wrapper_delete_row_index(const uchar *buf)
7076 {
7077   MRN_DBUG_ENTER_METHOD();
7078 
7079   int error = 0;
7080 
7081   if (is_dry_write()) {
7082     DBUG_PRINT("info", ("mroonga: dry write: ha_mroonga::%s", __FUNCTION__));
7083     DBUG_RETURN(error);
7084   }
7085 
7086   mrn_change_encoding(ctx, NULL);
7087   grn_id record_id;
7088   error = wrapper_get_record_id((uchar *)buf, &record_id,
7089                                 "failed to get record ID "
7090                                 "for deleting from groonga");
7091   if (error) {
7092     DBUG_RETURN(0);
7093   }
7094 
7095   mrn::DebugColumnAccess debug_column_access(table, &table->read_set);
7096   uint i;
7097   uint n_keys = table->s->keys;
7098   for (i = 0; i < n_keys; i++) {
7099     KEY *key_info = &(table->key_info[i]);
7100 
7101     if (!(wrapper_is_target_index(key_info))) {
7102       continue;
7103     }
7104 
7105     grn_obj *index_column = grn_index_columns[i];
7106     if (!index_column) {
7107       /* disable keys */
7108       continue;
7109     }
7110 
7111     uint j;
7112     for (j = 0; j < KEY_N_KEY_PARTS(key_info); j++) {
7113       Field *field = key_info->key_part[j].field;
7114 
7115       if (field->is_null())
7116         continue;
7117 
7118       generic_store_bulk(field, &old_value_buffer);
7119       grn_rc rc;
7120       rc = grn_column_index_update(ctx, index_column, record_id, j + 1,
7121                                    &old_value_buffer, NULL);
7122       if (rc) {
7123         error = ER_ERROR_ON_WRITE;
7124         my_message(error, ctx->errbuf, MYF(0));
7125         goto err;
7126       }
7127     }
7128   }
7129 err:
7130   grn_table_delete_by_id(ctx, grn_table, record_id);
7131   if (ctx->rc) {
7132     error = ER_ERROR_ON_WRITE;
7133     my_message(error, ctx->errbuf, MYF(0));
7134   }
7135 
7136   DBUG_RETURN(error);
7137 }
7138 
storage_delete_row(const uchar * buf)7139 int ha_mroonga::storage_delete_row(const uchar *buf)
7140 {
7141   MRN_DBUG_ENTER_METHOD();
7142   int error;
7143 
7144   if (is_dry_write()) {
7145     DBUG_PRINT("info", ("mroonga: dry write: ha_mroonga::%s", __FUNCTION__));
7146     DBUG_RETURN(0);
7147   }
7148 
7149   mrn::Operation operation(operations_,
7150                            "delete",
7151                            table->s->table_name.str,
7152                            table->s->table_name.length);
7153   operation.record_target(record_id);
7154 
7155   {
7156     grn_id referencing_child_table_id = GRN_ID_NIL;
7157     grn_hash *columns = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
7158                                         GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY);
7159     grn_table_columns(ctx, grn_table, "", 0,
7160                       reinterpret_cast<grn_obj *>(columns));
7161     GRN_HASH_EACH_BEGIN(ctx, columns, cursor, id) {
7162       void *key;
7163       grn_hash_cursor_get_key(ctx, cursor, &key);
7164       grn_id column_id = *static_cast<grn_id *>(key);
7165       grn_obj *column = grn_ctx_at(ctx, column_id);
7166       if (!column)
7167         continue;
7168 
7169       if (column->header.type != GRN_COLUMN_INDEX)
7170         continue;
7171 
7172       grn_ii_cursor *ii_cursor =
7173         grn_ii_cursor_open(ctx,
7174                            reinterpret_cast<grn_ii *>(column),
7175                            record_id,
7176                            GRN_ID_NIL,
7177                            GRN_ID_MAX,
7178                            0,
7179                            0);
7180       if (!ii_cursor)
7181         continue;
7182 
7183       if (grn_ii_cursor_next(ctx, ii_cursor)) {
7184         referencing_child_table_id = grn_obj_get_range(ctx, column);
7185       }
7186 
7187       grn_ii_cursor_close(ctx, ii_cursor);
7188 
7189       if (referencing_child_table_id != GRN_ID_NIL)
7190         break;
7191     } GRN_HASH_EACH_END(ctx, cursor);
7192     grn_hash_close(ctx, columns);
7193 
7194     if (referencing_child_table_id != GRN_ID_NIL) {
7195       grn_obj *referencing_child_table =
7196         grn_ctx_at(ctx, referencing_child_table_id);
7197       char name[GRN_TABLE_MAX_KEY_SIZE];
7198       int name_size;
7199       name_size = grn_obj_name(ctx,
7200                                referencing_child_table,
7201                                name,
7202                                GRN_TABLE_MAX_KEY_SIZE);
7203       error = HA_ERR_ROW_IS_REFERENCED;
7204       GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
7205                        "one or more child rows exist in <%.*s>",
7206                        name_size,
7207                        name);
7208       DBUG_RETURN(error);
7209     }
7210   }
7211 
7212   storage_store_fields_for_prep_update(buf, NULL, record_id);
7213   {
7214     mrn::Lock lock(&(share->record_mutex), have_unique_index());
7215     if ((error = storage_prepare_delete_row_unique_indexes(buf, record_id))) {
7216       DBUG_RETURN(error);
7217     }
7218     mrn_change_encoding(ctx, NULL);
7219     grn_table_delete_by_id(ctx, grn_table, record_id);
7220     if (ctx->rc) {
7221       my_message(ER_ERROR_ON_WRITE, ctx->errbuf, MYF(0));
7222       DBUG_RETURN(ER_ERROR_ON_WRITE);
7223     }
7224     if (
7225       (error = storage_delete_row_index(buf)) ||
7226       (error = storage_delete_row_unique_indexes())
7227       ) {
7228       DBUG_RETURN(error);
7229     }
7230   }
7231 
7232   grn_db_touch(ctx, grn_ctx_db(ctx));
7233 
7234   DBUG_RETURN(0);
7235 }
7236 
storage_delete_row_index(const uchar * buf)7237 int ha_mroonga::storage_delete_row_index(const uchar *buf)
7238 {
7239   MRN_DBUG_ENTER_METHOD();
7240   int error = 0;
7241 
7242   grn_obj key, encoded_key;
7243   GRN_TEXT_INIT(&key, 0);
7244   GRN_TEXT_INIT(&encoded_key, 0);
7245 
7246   mrn::DebugColumnAccess debug_column_access(table, &table->read_set);
7247   uint i;
7248   uint n_keys = table->s->keys;
7249   mrn_change_encoding(ctx, NULL);
7250   for (i = 0; i < n_keys; i++) {
7251     if (i == table->s->primary_key) {
7252       continue;
7253     }
7254 
7255     KEY *key_info = &(table->key_info[i]);
7256 
7257     if (KEY_N_KEY_PARTS(key_info) == 1 || (key_info->flags & HA_FULLTEXT)) {
7258       continue;
7259     }
7260 
7261     grn_obj *index_column = grn_index_columns[i];
7262     if (!index_column) {
7263       /* disable keys */
7264       continue;
7265     }
7266 
7267     GRN_BULK_REWIND(&key);
7268     grn_bulk_space(ctx, &key, key_info->key_length);
7269     key_copy((uchar *)(GRN_TEXT_VALUE(&key)),
7270              (uchar *)buf,
7271              key_info,
7272              key_info->key_length);
7273     GRN_BULK_REWIND(&encoded_key);
7274     grn_bulk_reserve(ctx, &encoded_key, MRN_MAX_KEY_SIZE);
7275     uint encoded_key_length;
7276     storage_encode_multiple_column_key(key_info,
7277                                        (uchar *)(GRN_TEXT_VALUE(&key)),
7278                                        key_info->key_length,
7279                                        (uchar *)(GRN_TEXT_VALUE(&encoded_key)),
7280                                        &encoded_key_length);
7281     grn_bulk_space(ctx, &encoded_key, encoded_key_length);
7282 
7283     grn_rc rc;
7284     rc = grn_column_index_update(ctx, index_column, record_id, 1,
7285                                  &encoded_key, NULL);
7286     if (rc) {
7287       error = ER_ERROR_ON_WRITE;
7288       my_message(error, ctx->errbuf, MYF(0));
7289       goto err;
7290     }
7291   }
7292 err:
7293   grn_obj_unlink(ctx, &encoded_key);
7294   grn_obj_unlink(ctx, &key);
7295 
7296   DBUG_RETURN(error);
7297 }
7298 
storage_delete_row_unique_index(grn_obj * index_table,grn_id del_key_id)7299 int ha_mroonga::storage_delete_row_unique_index(grn_obj *index_table,
7300                                                 grn_id del_key_id)
7301 {
7302   MRN_DBUG_ENTER_METHOD();
7303   grn_rc rc = grn_table_delete_by_id(ctx, index_table, del_key_id);
7304   if (rc) {
7305     my_message(ER_ERROR_ON_WRITE, ctx->errbuf, MYF(0));
7306     DBUG_RETURN(ER_ERROR_ON_WRITE);
7307   }
7308   DBUG_RETURN(0);
7309 }
7310 
storage_delete_row_unique_indexes()7311 int ha_mroonga::storage_delete_row_unique_indexes()
7312 {
7313   int error = 0, tmp_error;
7314   uint i;
7315   uint n_keys = table->s->keys;
7316   MRN_DBUG_ENTER_METHOD();
7317 
7318   for (i = 0; i < n_keys; i++) {
7319     if (i == table->s->primary_key) {
7320       continue;
7321     }
7322 
7323     KEY *key_info = &table->key_info[i];
7324     if ((!(key_info->flags & HA_NOSAME)) || del_key_id[i] == GRN_ID_NIL) {
7325       continue;
7326     }
7327 
7328     grn_obj *index_table = grn_index_tables[i];
7329     if ((tmp_error = storage_delete_row_unique_index(index_table,
7330                                                      del_key_id[i])))
7331     {
7332       error = tmp_error;
7333     }
7334   }
7335   DBUG_RETURN(error);
7336 }
7337 
storage_prepare_delete_row_unique_index(const uchar * buf,grn_id record_id,KEY * key_info,grn_obj * index_table,grn_obj * index_column,grn_id * del_key_id)7338 int ha_mroonga::storage_prepare_delete_row_unique_index(const uchar *buf,
7339                                                         grn_id record_id,
7340                                                         KEY *key_info,
7341                                                         grn_obj *index_table,
7342                                                         grn_obj *index_column,
7343                                                         grn_id *del_key_id)
7344 {
7345   const void *ukey = NULL;
7346   uint32 ukey_size = 0;
7347   MRN_DBUG_ENTER_METHOD();
7348   if (KEY_N_KEY_PARTS(key_info) == 1) {
7349     GRN_BULK_REWIND(&key_buffer);
7350     grn_obj_get_value(ctx, index_column, record_id, &key_buffer);
7351     ukey = GRN_TEXT_VALUE(&key_buffer);
7352     ukey_size = GRN_TEXT_LEN(&key_buffer);
7353   } else {
7354     mrn_change_encoding(ctx, NULL);
7355     uchar key[MRN_MAX_KEY_SIZE];
7356     key_copy(key, (uchar *) buf, key_info, key_info->key_length);
7357     grn_bulk_reserve(ctx, &key_buffer, MRN_MAX_KEY_SIZE);
7358     ukey = GRN_TEXT_VALUE(&key_buffer);
7359     storage_encode_multiple_column_key(key_info,
7360                                        key, key_info->key_length,
7361                                        (uchar *)ukey, (uint *)&ukey_size);
7362   }
7363   *del_key_id = grn_table_get(ctx, index_table, ukey, ukey_size);
7364   DBUG_RETURN(0);
7365 }
7366 
storage_prepare_delete_row_unique_indexes(const uchar * buf,grn_id record_id)7367 int ha_mroonga::storage_prepare_delete_row_unique_indexes(const uchar *buf,
7368                                                           grn_id record_id)
7369 {
7370   int error = 0, tmp_error;
7371   uint i;
7372   uint n_keys = table->s->keys;
7373   MRN_DBUG_ENTER_METHOD();
7374 
7375   for (i = 0; i < n_keys; i++) {
7376     if (i == table->s->primary_key) {
7377       continue;
7378     }
7379 
7380     KEY *key_info = &table->key_info[i];
7381     if (!(key_info->flags & HA_NOSAME)) {
7382       continue;
7383     }
7384 
7385     grn_obj *index_table = grn_index_tables[i];
7386     if (!index_table) {
7387       del_key_id[i] = GRN_ID_NIL;
7388       continue;
7389     }
7390 
7391     grn_obj *index_column;
7392     if (KEY_N_KEY_PARTS(key_info) == 1) {
7393       Field *field = key_info->key_part[0].field;
7394       mrn_change_encoding(ctx, field->charset());
7395       index_column = grn_columns[field->field_index];
7396     } else {
7397       mrn_change_encoding(ctx, NULL);
7398       index_column = grn_index_columns[i];
7399     }
7400     if ((tmp_error = storage_prepare_delete_row_unique_index(buf, record_id,
7401                                                              key_info,
7402                                                              index_table,
7403                                                              index_column,
7404                                                              &del_key_id[i])))
7405     {
7406       error = tmp_error;
7407     }
7408   }
7409   DBUG_RETURN(error);
7410 }
7411 
delete_row(const uchar * buf)7412 int ha_mroonga::delete_row(const uchar *buf)
7413 {
7414   MRN_DBUG_ENTER_METHOD();
7415   int error = 0;
7416   if (share->wrapper_mode)
7417   {
7418     error = wrapper_delete_row(buf);
7419   } else {
7420     error = storage_delete_row(buf);
7421   }
7422   DBUG_RETURN(error);
7423 }
7424 
wrapper_max_supported_key_parts() const7425 uint ha_mroonga::wrapper_max_supported_key_parts() const
7426 {
7427   MRN_DBUG_ENTER_METHOD();
7428   DBUG_RETURN(MAX_REF_PARTS);
7429 }
7430 
storage_max_supported_key_parts() const7431 uint ha_mroonga::storage_max_supported_key_parts() const
7432 {
7433   MRN_DBUG_ENTER_METHOD();
7434   DBUG_RETURN(MAX_REF_PARTS);
7435 }
7436 
max_supported_key_parts() const7437 uint ha_mroonga::max_supported_key_parts() const
7438 {
7439   MRN_DBUG_ENTER_METHOD();
7440 
7441   uint parts;
7442   if (!share && !analyzed_for_create &&
7443     (
7444       thd_sql_command(ha_thd()) == SQLCOM_CREATE_TABLE ||
7445       thd_sql_command(ha_thd()) == SQLCOM_CREATE_INDEX ||
7446       thd_sql_command(ha_thd()) == SQLCOM_ALTER_TABLE
7447     )
7448   ) {
7449     create_share_for_create();
7450   }
7451   if (analyzed_for_create && share_for_create.wrapper_mode) {
7452     parts = wrapper_max_supported_key_parts();
7453   } else if (wrap_handler && share && share->wrapper_mode) {
7454     parts = wrapper_max_supported_key_parts();
7455   } else {
7456     parts = storage_max_supported_key_parts();
7457   }
7458 
7459   DBUG_RETURN(parts);
7460 }
7461 
wrapper_records_in_range(uint key_nr,key_range * range_min,key_range * range_max)7462 ha_rows ha_mroonga::wrapper_records_in_range(uint key_nr, key_range *range_min,
7463                                              key_range *range_max)
7464 {
7465   ha_rows row_count;
7466   MRN_DBUG_ENTER_METHOD();
7467   KEY *key_info = &(table->s->key_info[key_nr]);
7468   if (mrn_is_geo_key(key_info)) {
7469     row_count = generic_records_in_range_geo(key_nr, range_min, range_max);
7470   } else {
7471     MRN_SET_WRAP_SHARE_KEY(share, table->s);
7472     MRN_SET_WRAP_TABLE_KEY(this, table);
7473     row_count = wrap_handler->records_in_range(key_nr, range_min, range_max);
7474     MRN_SET_BASE_SHARE_KEY(share, table->s);
7475     MRN_SET_BASE_TABLE_KEY(this, table);
7476   }
7477   DBUG_RETURN(row_count);
7478 }
7479 
storage_records_in_range(uint key_nr,key_range * range_min,key_range * range_max)7480 ha_rows ha_mroonga::storage_records_in_range(uint key_nr, key_range *range_min,
7481                                              key_range *range_max)
7482 {
7483   MRN_DBUG_ENTER_METHOD();
7484   int flags = 0;
7485   uint size_min = 0, size_max = 0;
7486   ha_rows row_count = 0;
7487   uchar *key_min = NULL, *key_max = NULL;
7488   uchar key_min_entity[MRN_MAX_KEY_SIZE];
7489   uchar key_max_entity[MRN_MAX_KEY_SIZE];
7490   KEY *key_info = &(table->s->key_info[key_nr]);
7491   bool is_multiple_column_index = KEY_N_KEY_PARTS(key_info) > 1;
7492 
7493   if (is_multiple_column_index) {
7494     mrn_change_encoding(ctx, NULL);
7495     if (range_min && range_max &&
7496         range_min->length == range_max->length &&
7497         memcmp(range_min->key, range_max->key, range_min->length) == 0) {
7498       flags |= GRN_CURSOR_PREFIX;
7499       key_min = key_min_entity;
7500       storage_encode_multiple_column_key(key_info,
7501                                          range_min->key, range_min->length,
7502                                          key_min, &size_min);
7503     } else {
7504       key_min = key_min_entity;
7505       key_max = key_max_entity;
7506       storage_encode_multiple_column_key_range(key_info,
7507                                                range_min, range_max,
7508                                                key_min, &size_min,
7509                                                key_max, &size_max);
7510     }
7511   } else if (mrn_is_geo_key(key_info)) {
7512     mrn_change_encoding(ctx, key_info->key_part->field->charset());
7513     row_count = generic_records_in_range_geo(key_nr, range_min, range_max);
7514     DBUG_RETURN(row_count);
7515   } else {
7516     Field *field = key_info->key_part[0].field;
7517     const char *column_name = field->field_name.str;
7518     mrn_change_encoding(ctx, field->charset());
7519 
7520     if (strcmp(MRN_COLUMN_NAME_ID, column_name) == 0) {
7521       DBUG_RETURN((ha_rows)1);
7522     }
7523 
7524     if (range_min) {
7525       key_min = key_min_entity;
7526       storage_encode_key(field, range_min->key, key_min, &size_min);
7527       if (size_min == 0) {
7528         DBUG_RETURN(HA_POS_ERROR);
7529       }
7530     }
7531     if (range_max) {
7532       key_max = key_max_entity;
7533       storage_encode_key(field, range_max->key, key_max, &size_max);
7534       if (size_max == 0) {
7535         DBUG_RETURN(HA_POS_ERROR);
7536       }
7537     }
7538   }
7539 
7540   if (range_min) {
7541     DBUG_PRINT("info", ("mroonga: range_min->flag=%u", range_min->flag));
7542     if (range_min->flag == HA_READ_AFTER_KEY) {
7543       flags |= GRN_CURSOR_GT;
7544     }
7545   }
7546   if (range_max) {
7547     DBUG_PRINT("info", ("mroonga: range_min->flag=%u", range_max->flag));
7548     if (range_max->flag == HA_READ_BEFORE_KEY) {
7549       flags |= GRN_CURSOR_LT;
7550     }
7551   }
7552 
7553   int cursor_limit = THDVAR(ha_thd(), max_n_records_for_estimate);
7554   uint pkey_nr = table->s->primary_key;
7555   if (key_nr == pkey_nr) {
7556     DBUG_PRINT("info", ("mroonga: use primary key"));
7557     grn_table_cursor *cursor;
7558     cursor = grn_table_cursor_open(ctx, grn_table,
7559                                    key_min, size_min,
7560                                    key_max, size_max,
7561                                    0, cursor_limit, flags);
7562     while (grn_table_cursor_next(ctx, cursor) != GRN_ID_NIL) {
7563       row_count++;
7564     }
7565     grn_table_cursor_close(ctx, cursor);
7566   } else {
7567     if (is_multiple_column_index) {
7568       DBUG_PRINT("info", ("mroonga: use multiple column key%u", key_nr));
7569     } else {
7570       DBUG_PRINT("info", ("mroonga: use key%u", key_nr));
7571     }
7572 
7573     grn_table_cursor *cursor;
7574     cursor = grn_table_cursor_open(ctx, grn_index_tables[key_nr],
7575                                    key_min, size_min,
7576                                    key_max, size_max,
7577                                    0, cursor_limit, flags);
7578     grn_obj *index_column = grn_index_columns[key_nr];
7579     grn_ii *ii = reinterpret_cast<grn_ii *>(index_column);
7580     row_count = grn_ii_estimate_size_for_lexicon_cursor(ctx, ii, cursor);
7581     grn_table_cursor_close(ctx, cursor);
7582 
7583     unsigned int max_n_lexicon_records =
7584       grn_table_size(ctx, grn_index_tables[key_nr]);
7585     if (cursor_limit >= 0 &&
7586         static_cast<unsigned int>(cursor_limit) < max_n_lexicon_records) {
7587       row_count++;
7588     }
7589   }
7590   DBUG_RETURN(row_count);
7591 }
7592 
generic_records_in_range_geo(uint key_nr,key_range * range_min,key_range * range_max)7593 ha_rows ha_mroonga::generic_records_in_range_geo(uint key_nr,
7594                                                  key_range *range_min,
7595                                                  key_range *range_max)
7596 {
7597   MRN_DBUG_ENTER_METHOD();
7598   ha_rows row_count;
7599   int error;
7600 
7601   if (!range_min) {
7602     DBUG_PRINT("info",
7603                ("mroonga: range min is missing for geometry range search"));
7604     DBUG_RETURN(HA_POS_ERROR);
7605   }
7606   if (range_max) {
7607     DBUG_PRINT("info",
7608                ("mroonga: range max is specified for geometry range search"));
7609     DBUG_RETURN(HA_POS_ERROR);
7610   }
7611   error = mrn_change_encoding(ctx,
7612     table->key_info[key_nr].key_part->field->charset());
7613   if (error)
7614     DBUG_RETURN(error);
7615   if (!(range_min->flag & HA_READ_MBR_CONTAIN)) {
7616     push_warning_unsupported_spatial_index_search(range_min->flag);
7617     row_count = grn_table_size(ctx, grn_table);
7618     DBUG_RETURN(row_count);
7619   }
7620 
7621   geo_store_rectangle(range_min->key);
7622   row_count = grn_geo_estimate_in_rectangle(ctx,
7623                                             grn_index_columns[key_nr],
7624                                             &top_left_point,
7625                                             &bottom_right_point);
7626   DBUG_RETURN(row_count);
7627 }
7628 
records_in_range(uint key_nr,key_range * range_min,key_range * range_max)7629 ha_rows ha_mroonga::records_in_range(uint key_nr, key_range *range_min, key_range *range_max)
7630 {
7631   MRN_DBUG_ENTER_METHOD();
7632   ha_rows row_count = 0;
7633   if (share->wrapper_mode)
7634   {
7635     row_count = wrapper_records_in_range(key_nr, range_min, range_max);
7636   } else {
7637     row_count = storage_records_in_range(key_nr, range_min, range_max);
7638   }
7639   DBUG_PRINT("info", ("mroonga: row_count=%" MRN_HA_ROWS_FORMAT, row_count));
7640   DBUG_RETURN(row_count);
7641 }
7642 
wrapper_index_init(uint idx,bool sorted)7643 int ha_mroonga::wrapper_index_init(uint idx, bool sorted)
7644 {
7645   MRN_DBUG_ENTER_METHOD();
7646   int error = 0;
7647   KEY *key_info = &(table->s->key_info[idx]);
7648   MRN_SET_WRAP_SHARE_KEY(share, table->s);
7649   MRN_SET_WRAP_TABLE_KEY(this, table);
7650   if (!mrn_is_geo_key(key_info) && key_info->algorithm != HA_KEY_ALG_FULLTEXT)
7651   {
7652     error = wrap_handler->ha_index_init(share->wrap_key_nr[idx], sorted);
7653   } else {
7654     error = wrap_handler->ha_index_init(share->wrap_primary_key, sorted);
7655   }
7656   MRN_SET_BASE_SHARE_KEY(share, table->s);
7657   MRN_SET_BASE_TABLE_KEY(this, table);
7658   DBUG_RETURN(error);
7659 }
7660 
storage_index_init(uint idx,bool sorted)7661 int ha_mroonga::storage_index_init(uint idx, bool sorted)
7662 {
7663   MRN_DBUG_ENTER_METHOD();
7664   DBUG_RETURN(0);
7665 }
7666 
index_init(uint idx,bool sorted)7667 int ha_mroonga::index_init(uint idx, bool sorted)
7668 {
7669   MRN_DBUG_ENTER_METHOD();
7670   DBUG_PRINT("info", ("mroonga: idx=%u", idx));
7671   active_index = idx;
7672   int error = 0;
7673   if (share->wrapper_mode)
7674   {
7675     error = wrapper_index_init(idx, sorted);
7676   } else {
7677     error = storage_index_init(idx, sorted);
7678   }
7679   DBUG_RETURN(error);
7680 }
7681 
wrapper_index_end()7682 int ha_mroonga::wrapper_index_end()
7683 {
7684   int error = 0;
7685   MRN_DBUG_ENTER_METHOD();
7686   MRN_SET_WRAP_SHARE_KEY(share, table->s);
7687   MRN_SET_WRAP_TABLE_KEY(this, table);
7688   error = wrap_handler->ha_index_or_rnd_end();
7689   MRN_SET_BASE_SHARE_KEY(share, table->s);
7690   MRN_SET_BASE_TABLE_KEY(this, table);
7691   DBUG_RETURN(error);
7692 }
7693 
storage_index_end()7694 int ha_mroonga::storage_index_end()
7695 {
7696   MRN_DBUG_ENTER_METHOD();
7697   clear_cursor();
7698   clear_cursor_geo();
7699   DBUG_RETURN(0);
7700 }
7701 
index_end()7702 int ha_mroonga::index_end()
7703 {
7704   MRN_DBUG_ENTER_METHOD();
7705   int error = 0;
7706   if (share->wrapper_mode)
7707   {
7708     error = wrapper_index_end();
7709   } else {
7710     error = storage_index_end();
7711   }
7712   DBUG_RETURN(error);
7713 }
7714 
wrapper_index_read_map(uchar * buf,const uchar * key,key_part_map keypart_map,enum ha_rkey_function find_flag)7715 int ha_mroonga::wrapper_index_read_map(uchar *buf, const uchar *key,
7716                                        key_part_map keypart_map,
7717                                        enum ha_rkey_function find_flag)
7718 {
7719   int error = 0;
7720   MRN_DBUG_ENTER_METHOD();
7721   KEY *key_info = &(table->key_info[active_index]);
7722   if (mrn_is_geo_key(key_info)) {
7723     clear_cursor_geo();
7724     error = generic_geo_open_cursor(key, find_flag);
7725     if (!error) {
7726       error = wrapper_get_next_geo_record(buf);
7727     }
7728     DBUG_RETURN(error);
7729   } else {
7730     MRN_SET_WRAP_SHARE_KEY(share, table->s);
7731     MRN_SET_WRAP_TABLE_KEY(this, table);
7732     if (fulltext_searching)
7733       set_pk_bitmap();
7734 #ifdef MRN_HANDLER_HAVE_HA_INDEX_READ_MAP
7735     error = wrap_handler->ha_index_read_map(buf, key, keypart_map, find_flag);
7736 #else
7737     error = wrap_handler->index_read_map(buf, key, keypart_map, find_flag);
7738 #endif
7739     MRN_SET_BASE_SHARE_KEY(share, table->s);
7740     MRN_SET_BASE_TABLE_KEY(this, table);
7741   }
7742   DBUG_RETURN(error);
7743 }
7744 
storage_index_read_map(uchar * buf,const uchar * key,key_part_map keypart_map,enum ha_rkey_function find_flag)7745 int ha_mroonga::storage_index_read_map(uchar *buf, const uchar *key,
7746                                        key_part_map keypart_map,
7747                                        enum ha_rkey_function find_flag)
7748 {
7749   MRN_DBUG_ENTER_METHOD();
7750   check_count_skip(keypart_map);
7751 
7752   int error = 0;
7753 
7754   uint key_nr = active_index;
7755   KEY *key_info = &(table->key_info[key_nr]);
7756   int flags = 0;
7757   uint size_min = 0, size_max = 0;
7758   uchar *key_min = NULL, *key_max = NULL;
7759   uchar key_min_entity[MRN_MAX_KEY_SIZE];
7760   uchar key_max_entity[MRN_MAX_KEY_SIZE];
7761 
7762   clear_cursor();
7763   clear_cursor_geo();
7764   clear_empty_value_records();
7765 
7766   switch (find_flag) {
7767   case HA_READ_BEFORE_KEY:
7768     flags |= GRN_CURSOR_LT | GRN_CURSOR_DESCENDING;
7769     break;
7770   case HA_READ_PREFIX_LAST:
7771     flags |= GRN_CURSOR_PREFIX | GRN_CURSOR_DESCENDING;
7772     break;
7773   case HA_READ_PREFIX_LAST_OR_PREV:
7774     flags |= GRN_CURSOR_LE | GRN_CURSOR_DESCENDING;
7775     break;
7776   case HA_READ_AFTER_KEY:
7777     flags |= GRN_CURSOR_GT | GRN_CURSOR_ASCENDING;
7778     break;
7779   case HA_READ_KEY_OR_NEXT:
7780     flags |= GRN_CURSOR_GE | GRN_CURSOR_ASCENDING;
7781     break;
7782   case HA_READ_KEY_EXACT:
7783     flags |= GRN_CURSOR_LE | GRN_CURSOR_GE;
7784     break;
7785   default:
7786     break;
7787   }
7788 
7789   bool is_multiple_column_index = KEY_N_KEY_PARTS(key_info) > 1;
7790   if (is_multiple_column_index) {
7791     mrn_change_encoding(ctx, NULL);
7792     uint key_length =
7793       mrn_calculate_key_len(table, active_index, key, keypart_map);
7794     DBUG_PRINT("info",
7795                ("mroonga: multiple column index: "
7796                 "search key length=<%u>, "
7797                 "multiple column index key length=<%u>",
7798                 key_length, key_info->key_length));
7799     if (key_length == key_info->key_length) {
7800       switch (find_flag) {
7801       case HA_READ_BEFORE_KEY:
7802       case HA_READ_PREFIX_LAST_OR_PREV:
7803         key_max = key_max_entity;
7804         storage_encode_multiple_column_key(key_info,
7805                                            key, key_length,
7806                                            key_max, &size_max);
7807         break;
7808       case HA_READ_PREFIX_LAST:
7809         key_min = key_min_entity;
7810         storage_encode_multiple_column_key(key_info,
7811                                            key, key_length,
7812                                            key_min, &size_min);
7813         break;
7814       default:
7815         key_min = key_min_entity;
7816         storage_encode_multiple_column_key(key_info,
7817                                            key, key_length,
7818                                            key_min, &size_min);
7819         if (find_flag == HA_READ_KEY_EXACT) {
7820           key_max = key_min;
7821           size_max = size_min;
7822         }
7823         break;
7824       }
7825     } else {
7826       const uchar *prev_key = NULL;
7827       uint prev_key_length = 0;
7828       if ((keypart_map >> 1) > 0) {
7829         prev_key = key;
7830         prev_key_length =
7831           mrn_calculate_key_len(table, active_index, key, keypart_map >> 1);
7832       }
7833       switch (find_flag) {
7834       case HA_READ_BEFORE_KEY:
7835         if (prev_key) {
7836           flags |= GRN_CURSOR_GE;
7837           key_min = key_min_entity;
7838           storage_encode_multiple_column_key_range(key_info,
7839                                                    prev_key, prev_key_length,
7840                                                    NULL, 0,
7841                                                    key_min, &size_min,
7842                                                    NULL, NULL);
7843         }
7844         key_max = key_max_entity;
7845         storage_encode_multiple_column_key_range(key_info,
7846                                                  key, key_length,
7847                                                  NULL, 0,
7848                                                  key_max, &size_max,
7849                                                  NULL, NULL);
7850         break;
7851       case HA_READ_PREFIX_LAST:
7852         key_min = key_min_entity;
7853         storage_encode_multiple_column_key(key_info,
7854                                            key, key_length,
7855                                            key_min, &size_min);
7856         break;
7857       case HA_READ_PREFIX_LAST_OR_PREV:
7858         if (prev_key) {
7859           flags |= GRN_CURSOR_GE;
7860           key_min = key_min_entity;
7861           storage_encode_multiple_column_key_range(key_info,
7862                                                    prev_key, prev_key_length,
7863                                                    NULL, 0,
7864                                                    key_min, &size_min,
7865                                                    NULL, NULL);
7866         }
7867         key_max = key_max_entity;
7868         storage_encode_multiple_column_key_range(key_info,
7869                                                  NULL, 0,
7870                                                  key, key_length,
7871                                                  NULL, NULL,
7872                                                  key_max, &size_max);
7873         break;
7874       case HA_READ_AFTER_KEY:
7875         key_min = key_min_entity;
7876         storage_encode_multiple_column_key_range(key_info,
7877                                                  NULL, 0,
7878                                                  key, key_length,
7879                                                  NULL, NULL,
7880                                                  key_min, &size_min);
7881         if (prev_key) {
7882           flags |= GRN_CURSOR_LE;
7883           key_max = key_max_entity;
7884           storage_encode_multiple_column_key_range(key_info,
7885                                                    NULL, 0,
7886                                                    prev_key, prev_key_length,
7887                                                    NULL, NULL,
7888                                                    key_max, &size_max);
7889         }
7890         break;
7891       case HA_READ_KEY_OR_NEXT:
7892         key_min = key_min_entity;
7893         storage_encode_multiple_column_key_range(key_info,
7894                                                  key, key_length,
7895                                                  NULL, 0,
7896                                                  key_min, &size_min,
7897                                                  NULL, NULL);
7898         if (prev_key) {
7899           flags |= GRN_CURSOR_LE;
7900           key_max = key_max_entity;
7901           storage_encode_multiple_column_key_range(key_info,
7902                                                    NULL, 0,
7903                                                    prev_key, prev_key_length,
7904                                                    NULL, NULL,
7905                                                    key_max, &size_max);
7906         }
7907         break;
7908       case HA_READ_KEY_EXACT:
7909         key_min = key_min_entity;
7910         key_max = key_max_entity;
7911         storage_encode_multiple_column_key_range(key_info,
7912                                                  key, key_length,
7913                                                  key, key_length,
7914                                                  key_min, &size_min,
7915                                                  key_max, &size_max);
7916       default:
7917         break;
7918       }
7919     }
7920   } else if (mrn_is_geo_key(key_info)) {
7921     error = mrn_change_encoding(ctx, key_info->key_part->field->charset());
7922     if (error)
7923       DBUG_RETURN(error);
7924     error = generic_geo_open_cursor(key, find_flag);
7925     if (!error) {
7926       error = storage_get_next_record(buf);
7927     }
7928     DBUG_RETURN(error);
7929   } else {
7930     Field *field = key_info->key_part[0].field;
7931     error = mrn_change_encoding(ctx, field->charset());
7932     if (error)
7933       DBUG_RETURN(error);
7934 
7935     if (find_flag == HA_READ_KEY_EXACT) {
7936       const char *column_name = field->field_name.str;
7937 
7938       key_min = key_min_entity;
7939       key_max = key_min_entity;
7940       storage_encode_key(field, key, key_min, &size_min);
7941       size_max = size_min;
7942       // for _id
7943       if (strcmp(MRN_COLUMN_NAME_ID, column_name) == 0) {
7944         grn_id found_record_id = *((grn_id *)key_min);
7945         if (grn_table_at(ctx, grn_table, found_record_id) != GRN_ID_NIL) { // found
7946           storage_store_fields(buf, found_record_id);
7947           table->status = 0;
7948           record_id = found_record_id;
7949           DBUG_RETURN(0);
7950         } else {
7951           table->status = STATUS_NOT_FOUND;
7952           DBUG_RETURN(HA_ERR_END_OF_FILE);
7953         }
7954       }
7955     } else if (find_flag == HA_READ_BEFORE_KEY ||
7956                find_flag == HA_READ_PREFIX_LAST_OR_PREV) {
7957       key_max = key_max_entity;
7958       storage_encode_key(field, key, key_max_entity, &size_max);
7959     } else {
7960       key_min = key_min_entity;
7961       storage_encode_key(field, key, key_min_entity, &size_min);
7962     }
7963   }
7964 
7965   uint pkey_nr = table->s->primary_key;
7966   if (key_nr == pkey_nr) {
7967     DBUG_PRINT("info", ("mroonga: use primary key"));
7968     cursor = grn_table_cursor_open(ctx, grn_table,
7969                                    key_min, size_min,
7970                                    key_max, size_max,
7971                                    0, -1, flags);
7972   } else {
7973     bool is_empty_value_records_search = false;
7974     if (is_multiple_column_index) {
7975       DBUG_PRINT("info", ("mroonga: use multiple column key%u", key_nr));
7976     } else if (flags == 0 && size_min == 0 && size_max == 0) {
7977       is_empty_value_records_search = true;
7978       DBUG_PRINT("info",
7979                  ("mroonga: use table scan for searching empty value records"));
7980     } else {
7981       DBUG_PRINT("info", ("mroonga: use key%u", key_nr));
7982     }
7983     if (is_empty_value_records_search) {
7984       grn_obj *expression, *expression_variable;
7985       GRN_EXPR_CREATE_FOR_QUERY(ctx, grn_table,
7986                                 expression, expression_variable);
7987       grn_obj *target_column =
7988         grn_columns[key_info->key_part->field->field_index];
7989       grn_expr_append_const(ctx, expression, target_column, GRN_OP_GET_VALUE, 1);
7990       grn_obj empty_value;
7991       GRN_TEXT_INIT(&empty_value, 0);
7992       grn_expr_append_obj(ctx, expression, &empty_value, GRN_OP_PUSH, 1);
7993       grn_expr_append_op(ctx, expression, GRN_OP_EQUAL, 2);
7994 
7995       empty_value_records =
7996         grn_table_create(ctx, NULL, 0, NULL,
7997                          GRN_OBJ_TABLE_HASH_KEY | GRN_OBJ_WITH_SUBREC,
7998                          grn_table, 0);
7999       grn_table_select(ctx, grn_table, expression, empty_value_records,
8000                        GRN_OP_OR);
8001       grn_obj_unlink(ctx, expression);
8002       grn_obj_unlink(ctx, &empty_value);
8003 
8004       empty_value_records_cursor =
8005         grn_table_cursor_open(ctx, empty_value_records,
8006                               NULL, 0, NULL, 0,
8007                               0, -1, flags);
8008     } else {
8009       index_table_cursor = grn_table_cursor_open(ctx, grn_index_tables[key_nr],
8010                                                  key_min, size_min,
8011                                                  key_max, size_max,
8012                                                  0, -1, flags);
8013       cursor = grn_index_cursor_open(ctx, index_table_cursor,
8014                                      grn_index_columns[key_nr],
8015                                      0, GRN_ID_MAX, 0);
8016     }
8017   }
8018   if (ctx->rc) {
8019     my_message(ER_ERROR_ON_READ, ctx->errbuf, MYF(0));
8020     DBUG_RETURN(ER_ERROR_ON_READ);
8021   }
8022   error = storage_get_next_record(buf);
8023   DBUG_RETURN(error);
8024 }
8025 
index_read_map(uchar * buf,const uchar * key,key_part_map keypart_map,enum ha_rkey_function find_flag)8026 int ha_mroonga::index_read_map(uchar *buf, const uchar *key,
8027                                key_part_map keypart_map,
8028                                enum ha_rkey_function find_flag)
8029 {
8030   MRN_DBUG_ENTER_METHOD();
8031   int error = 0;
8032   if (share->wrapper_mode)
8033   {
8034     error = wrapper_index_read_map(buf, key, keypart_map, find_flag);
8035   } else {
8036     error = storage_index_read_map(buf, key, keypart_map, find_flag);
8037   }
8038   DBUG_PRINT("info", ("mroonga: error=%d", error));
8039   DBUG_RETURN(error);
8040 }
8041 
8042 #ifdef MRN_HANDLER_HAVE_INDEX_READ_LAST_MAP
wrapper_index_read_last_map(uchar * buf,const uchar * key,key_part_map keypart_map)8043 int ha_mroonga::wrapper_index_read_last_map(uchar *buf, const uchar *key,
8044                                             key_part_map keypart_map)
8045 {
8046   int error = 0;
8047   MRN_DBUG_ENTER_METHOD();
8048   MRN_SET_WRAP_SHARE_KEY(share, table->s);
8049   MRN_SET_WRAP_TABLE_KEY(this, table);
8050   if (fulltext_searching)
8051     set_pk_bitmap();
8052 #  ifdef MRN_HANDLER_HAVE_HA_INDEX_READ_LAST_MAP
8053   error = wrap_handler->ha_index_read_last_map(buf, key, keypart_map);
8054 #  else
8055   error = wrap_handler->index_read_last_map(buf, key, keypart_map);
8056 #  endif
8057   MRN_SET_BASE_SHARE_KEY(share, table->s);
8058   MRN_SET_BASE_TABLE_KEY(this, table);
8059   DBUG_RETURN(error);
8060 }
8061 
storage_index_read_last_map(uchar * buf,const uchar * key,key_part_map keypart_map)8062 int ha_mroonga::storage_index_read_last_map(uchar *buf, const uchar *key,
8063                                             key_part_map keypart_map)
8064 {
8065   MRN_DBUG_ENTER_METHOD();
8066   uint key_nr = active_index;
8067   KEY *key_info = &(table->key_info[key_nr]);
8068 
8069   int flags = GRN_CURSOR_DESCENDING, error;
8070   uint size_min = 0, size_max = 0;
8071   uchar *key_min = NULL, *key_max = NULL;
8072   uchar key_min_entity[MRN_MAX_KEY_SIZE];
8073 
8074   clear_cursor();
8075 
8076   bool is_multiple_column_index = KEY_N_KEY_PARTS(key_info) > 1;
8077   if (is_multiple_column_index) {
8078     mrn_change_encoding(ctx, NULL);
8079     flags |= GRN_CURSOR_PREFIX;
8080     uint key_length =
8081       mrn_calculate_key_len(table, active_index, key, keypart_map);
8082     key_min = key_min_entity;
8083     storage_encode_multiple_column_key(key_info,
8084                                        key, key_length,
8085                                        key_min, &size_min);
8086   } else {
8087     Field *field = key_info->key_part[0].field;
8088     error = mrn_change_encoding(ctx, field->charset());
8089     if (error)
8090       DBUG_RETURN(error);
8091 
8092     key_min = key_min_entity;
8093     key_max = key_min_entity;
8094     storage_encode_key(field, key, key_min, &size_min);
8095     size_max = size_min;
8096   }
8097 
8098   uint pkey_nr = table->s->primary_key;
8099   if (key_nr == pkey_nr) {
8100     DBUG_PRINT("info", ("mroonga: use primary key"));
8101     cursor = grn_table_cursor_open(ctx, grn_table,
8102                                    key_min, size_min, key_max, size_max,
8103                                    0, -1, flags);
8104   } else {
8105     if (is_multiple_column_index) {
8106       DBUG_PRINT("info", ("mroonga: use multiple column key%u", key_nr));
8107     } else {
8108       DBUG_PRINT("info", ("mroonga: use key%u", key_nr));
8109     }
8110     index_table_cursor = grn_table_cursor_open(ctx, grn_index_tables[key_nr],
8111                                                key_min, size_min,
8112                                                key_max, size_max,
8113                                                0, -1, flags);
8114     cursor = grn_index_cursor_open(ctx, index_table_cursor,
8115                                    grn_index_columns[key_nr],
8116                                    0, GRN_ID_MAX, 0);
8117   }
8118   if (ctx->rc) {
8119     my_message(ER_ERROR_ON_READ, ctx->errbuf, MYF(0));
8120     DBUG_RETURN(ER_ERROR_ON_READ);
8121   }
8122   error = storage_get_next_record(buf);
8123   DBUG_RETURN(error);
8124 }
8125 
index_read_last_map(uchar * buf,const uchar * key,key_part_map keypart_map)8126 int ha_mroonga::index_read_last_map(uchar *buf, const uchar *key,
8127                                     key_part_map keypart_map)
8128 {
8129   MRN_DBUG_ENTER_METHOD();
8130   int error = 0;
8131   if (share->wrapper_mode)
8132   {
8133     error = wrapper_index_read_last_map(buf, key, keypart_map);
8134   } else {
8135     error = storage_index_read_last_map(buf, key, keypart_map);
8136   }
8137   DBUG_RETURN(error);
8138 }
8139 #endif
8140 
wrapper_index_next(uchar * buf)8141 int ha_mroonga::wrapper_index_next(uchar *buf)
8142 {
8143   int error = 0;
8144   MRN_DBUG_ENTER_METHOD();
8145   KEY *key_info = &(table->key_info[active_index]);
8146   if (mrn_is_geo_key(key_info)) {
8147     error = wrapper_get_next_geo_record(buf);
8148   } else {
8149     MRN_SET_WRAP_SHARE_KEY(share, table->s);
8150     MRN_SET_WRAP_TABLE_KEY(this, table);
8151     if (fulltext_searching)
8152       set_pk_bitmap();
8153 #ifdef MRN_HANDLER_HAVE_HA_INDEX_NEXT
8154     error = wrap_handler->ha_index_next(buf);
8155 #else
8156     error = wrap_handler->index_next(buf);
8157 #endif
8158     MRN_SET_BASE_SHARE_KEY(share, table->s);
8159     MRN_SET_BASE_TABLE_KEY(this, table);
8160   }
8161   DBUG_RETURN(error);
8162 }
8163 
storage_index_next(uchar * buf)8164 int ha_mroonga::storage_index_next(uchar *buf)
8165 {
8166   MRN_DBUG_ENTER_METHOD();
8167   int error = storage_get_next_record(buf);
8168   DBUG_RETURN(error);
8169 }
8170 
index_next(uchar * buf)8171 int ha_mroonga::index_next(uchar *buf)
8172 {
8173   MRN_DBUG_ENTER_METHOD();
8174   int error = 0;
8175   if (share->wrapper_mode)
8176   {
8177     error = wrapper_index_next(buf);
8178   } else {
8179     error = storage_index_next(buf);
8180   }
8181   DBUG_RETURN(error);
8182 }
8183 
wrapper_index_prev(uchar * buf)8184 int ha_mroonga::wrapper_index_prev(uchar *buf)
8185 {
8186   int error = 0;
8187   MRN_DBUG_ENTER_METHOD();
8188   KEY *key_info = &(table->key_info[active_index]);
8189   if (mrn_is_geo_key(key_info)) {
8190     error = wrapper_get_next_geo_record(buf);
8191   } else {
8192     MRN_SET_WRAP_SHARE_KEY(share, table->s);
8193     MRN_SET_WRAP_TABLE_KEY(this, table);
8194     if (fulltext_searching)
8195       set_pk_bitmap();
8196 #ifdef MRN_HANDLER_HAVE_HA_INDEX_NEXT
8197     error = wrap_handler->ha_index_prev(buf);
8198 #else
8199     error = wrap_handler->index_prev(buf);
8200 #endif
8201     MRN_SET_BASE_SHARE_KEY(share, table->s);
8202     MRN_SET_BASE_TABLE_KEY(this, table);
8203   }
8204   DBUG_RETURN(error);
8205 }
8206 
storage_index_prev(uchar * buf)8207 int ha_mroonga::storage_index_prev(uchar *buf)
8208 {
8209   MRN_DBUG_ENTER_METHOD();
8210   int error = storage_get_next_record(buf);
8211   DBUG_RETURN(error);
8212 }
8213 
index_prev(uchar * buf)8214 int ha_mroonga::index_prev(uchar *buf)
8215 {
8216   MRN_DBUG_ENTER_METHOD();
8217   int error = 0;
8218   if (share->wrapper_mode)
8219   {
8220     error = wrapper_index_prev(buf);
8221   } else {
8222     error = storage_index_prev(buf);
8223   }
8224   DBUG_RETURN(error);
8225 }
8226 
wrapper_index_first(uchar * buf)8227 int ha_mroonga::wrapper_index_first(uchar *buf)
8228 {
8229   int error = 0;
8230   MRN_DBUG_ENTER_METHOD();
8231   MRN_SET_WRAP_SHARE_KEY(share, table->s);
8232   MRN_SET_WRAP_TABLE_KEY(this, table);
8233   if (fulltext_searching)
8234     set_pk_bitmap();
8235 #ifdef MRN_HANDLER_HAVE_HA_INDEX_FIRST
8236   error = wrap_handler->ha_index_first(buf);
8237 #else
8238   error = wrap_handler->index_first(buf);
8239 #endif
8240   MRN_SET_BASE_SHARE_KEY(share, table->s);
8241   MRN_SET_BASE_TABLE_KEY(this, table);
8242   DBUG_RETURN(error);
8243 }
8244 
storage_index_first(uchar * buf)8245 int ha_mroonga::storage_index_first(uchar *buf)
8246 {
8247   MRN_DBUG_ENTER_METHOD();
8248   clear_cursor();
8249   int flags = GRN_CURSOR_ASCENDING;
8250   uint pkey_nr = table->s->primary_key;
8251   mrn_change_encoding(ctx, NULL);
8252   if (active_index == pkey_nr) {
8253     DBUG_PRINT("info", ("mroonga: use primary key"));
8254     cursor = grn_table_cursor_open(ctx, grn_table, NULL, 0, NULL, 0,
8255                                    0, -1, flags);
8256   } else {
8257     if (KEY_N_KEY_PARTS(&(table->key_info[active_index])) > 1) {
8258       DBUG_PRINT("info", ("mroonga: use multiple column key%u", active_index));
8259     } else {
8260       DBUG_PRINT("info", ("mroonga: use key%u", active_index));
8261     }
8262     index_table_cursor = grn_table_cursor_open(ctx,
8263                                                grn_index_tables[active_index],
8264                                                NULL, 0,
8265                                                NULL, 0,
8266                                                0, -1, flags);
8267     cursor = grn_index_cursor_open(ctx, index_table_cursor,
8268                                    grn_index_columns[active_index],
8269                                    0, GRN_ID_MAX, 0);
8270   }
8271   if (ctx->rc) {
8272     my_message(ER_ERROR_ON_READ, ctx->errbuf, MYF(0));
8273     DBUG_RETURN(ER_ERROR_ON_READ);
8274   }
8275   int error = storage_get_next_record(buf);
8276   DBUG_RETURN(error);
8277 }
8278 
index_first(uchar * buf)8279 int ha_mroonga::index_first(uchar *buf)
8280 {
8281   MRN_DBUG_ENTER_METHOD();
8282   int error = 0;
8283   if (share->wrapper_mode)
8284   {
8285     error = wrapper_index_first(buf);
8286   } else {
8287     error = storage_index_first(buf);
8288   }
8289   DBUG_RETURN(error);
8290 }
8291 
wrapper_index_last(uchar * buf)8292 int ha_mroonga::wrapper_index_last(uchar *buf)
8293 {
8294   int error = 0;
8295   MRN_DBUG_ENTER_METHOD();
8296   MRN_SET_WRAP_SHARE_KEY(share, table->s);
8297   MRN_SET_WRAP_TABLE_KEY(this, table);
8298   if (fulltext_searching)
8299     set_pk_bitmap();
8300 #ifdef MRN_HANDLER_HAVE_HA_INDEX_LAST
8301   error = wrap_handler->ha_index_last(buf);
8302 #else
8303   error = wrap_handler->index_last(buf);
8304 #endif
8305   MRN_SET_BASE_SHARE_KEY(share, table->s);
8306   MRN_SET_BASE_TABLE_KEY(this, table);
8307   DBUG_RETURN(error);
8308 }
8309 
storage_index_last(uchar * buf)8310 int ha_mroonga::storage_index_last(uchar *buf)
8311 {
8312   MRN_DBUG_ENTER_METHOD();
8313   clear_cursor();
8314   int flags = GRN_CURSOR_DESCENDING;
8315   uint pkey_nr = table->s->primary_key;
8316   mrn_change_encoding(ctx, NULL);
8317   if (active_index == pkey_nr) {
8318     DBUG_PRINT("info", ("mroonga: use primary key"));
8319     cursor = grn_table_cursor_open(ctx, grn_table, NULL, 0, NULL, 0,
8320                                    0, -1, flags);
8321   } else {
8322     if (KEY_N_KEY_PARTS(&(table->key_info[active_index])) > 1) {
8323       DBUG_PRINT("info", ("mroonga: use multiple column key%u", active_index));
8324     } else {
8325       DBUG_PRINT("info", ("mroonga: use key%u", active_index));
8326     }
8327     index_table_cursor = grn_table_cursor_open(ctx,
8328                                                grn_index_tables[active_index],
8329                                                NULL, 0,
8330                                                NULL, 0,
8331                                                0, -1, flags);
8332     cursor = grn_index_cursor_open(ctx, index_table_cursor,
8333                                    grn_index_columns[active_index],
8334                                    0, GRN_ID_MAX, 0);
8335   }
8336   if (ctx->rc) {
8337     my_message(ER_ERROR_ON_READ, ctx->errbuf, MYF(0));
8338     DBUG_RETURN(ER_ERROR_ON_READ);
8339   }
8340   int error = storage_get_next_record(buf);
8341   DBUG_RETURN(error);
8342 }
8343 
index_last(uchar * buf)8344 int ha_mroonga::index_last(uchar *buf)
8345 {
8346   MRN_DBUG_ENTER_METHOD();
8347   int error = 0;
8348   if (share->wrapper_mode)
8349   {
8350     error = wrapper_index_last(buf);
8351   } else {
8352     error = storage_index_last(buf);
8353   }
8354   DBUG_RETURN(error);
8355 }
8356 
wrapper_index_next_same(uchar * buf,const uchar * key,uint keylen)8357 int ha_mroonga::wrapper_index_next_same(uchar *buf, const uchar *key,
8358                                         uint keylen)
8359 {
8360   MRN_DBUG_ENTER_METHOD();
8361   int error = 0;
8362   KEY *key_info = &(table->s->key_info[active_index]);
8363   if (mrn_is_geo_key(key_info)) {
8364     error = wrapper_get_next_geo_record(buf);
8365   } else {
8366     MRN_SET_WRAP_SHARE_KEY(share, table->s);
8367     MRN_SET_WRAP_TABLE_KEY(this, table);
8368     if (fulltext_searching)
8369       set_pk_bitmap();
8370 #ifdef MRN_HANDLER_HAVE_HA_INDEX_NEXT_SAME
8371     error = wrap_handler->ha_index_next_same(buf, key, keylen);
8372 #else
8373     error = wrap_handler->index_next_same(buf, key, keylen);
8374 #endif
8375     MRN_SET_BASE_SHARE_KEY(share, table->s);
8376     MRN_SET_BASE_TABLE_KEY(this, table);
8377   }
8378   DBUG_RETURN(error);
8379 }
8380 
storage_index_next_same(uchar * buf,const uchar * key,uint keylen)8381 int ha_mroonga::storage_index_next_same(uchar *buf, const uchar *key,
8382                                         uint keylen)
8383 {
8384   MRN_DBUG_ENTER_METHOD();
8385   int error = storage_get_next_record(count_skip ? NULL : buf);
8386   DBUG_RETURN(error);
8387 }
8388 
index_next_same(uchar * buf,const uchar * key,uint keylen)8389 int ha_mroonga::index_next_same(uchar *buf, const uchar *key, uint keylen)
8390 {
8391   MRN_DBUG_ENTER_METHOD();
8392   int error = 0;
8393   if (share->wrapper_mode)
8394   {
8395     error = wrapper_index_next_same(buf, key, keylen);
8396   } else {
8397     error = storage_index_next_same(buf, key, keylen);
8398   }
8399   DBUG_RETURN(error);
8400 }
8401 
generic_ft_init()8402 int ha_mroonga::generic_ft_init()
8403 {
8404   MRN_DBUG_ENTER_METHOD();
8405   struct st_mrn_ft_info *mrn_ft_info =
8406     reinterpret_cast<struct st_mrn_ft_info *>(ft_handler);
8407   GRN_CTX_SET_ENCODING(ctx, mrn_ft_info->encoding);
8408 
8409   int error = 0;
8410   if (sorted_result) {
8411     mrn_ft_info->cursor = grn_table_cursor_open(ctx, sorted_result,
8412                                                 NULL, 0, NULL, 0,
8413                                                 0, -1, 0);
8414   } else {
8415     mrn_ft_info->cursor = grn_table_cursor_open(ctx, mrn_ft_info->result,
8416                                                 NULL, 0, NULL, 0,
8417                                                 0, -1, 0);
8418   }
8419   if (ctx->rc) {
8420     error = ER_ERROR_ON_READ;
8421     my_message(error, ctx->errbuf, MYF(0));
8422   } else {
8423     if (sorted_result) {
8424       if (grn_table->header.type == GRN_TABLE_NO_KEY) {
8425         mrn_ft_info->id_accessor = grn_obj_column(ctx, sorted_result,
8426                                                   MRN_COLUMN_NAME_ID,
8427                                                   strlen(MRN_COLUMN_NAME_ID));
8428       } else {
8429         mrn_ft_info->key_accessor = grn_obj_column(ctx, sorted_result,
8430                                                    MRN_COLUMN_NAME_KEY,
8431                                                    strlen(MRN_COLUMN_NAME_KEY));
8432       }
8433     } else {
8434       mrn_ft_info->key_accessor = grn_obj_column(ctx, mrn_ft_info->result,
8435                                                  MRN_COLUMN_NAME_KEY,
8436                                                  strlen(MRN_COLUMN_NAME_KEY));
8437     }
8438   }
8439   DBUG_RETURN(error);
8440 }
8441 
wrapper_ft_init()8442 int ha_mroonga::wrapper_ft_init()
8443 {
8444   MRN_DBUG_ENTER_METHOD();
8445   int error = generic_ft_init();
8446   DBUG_RETURN(error);
8447 }
8448 
storage_ft_init()8449 int ha_mroonga::storage_ft_init()
8450 {
8451   MRN_DBUG_ENTER_METHOD();
8452   int error = generic_ft_init();
8453   record_id = GRN_ID_NIL;
8454   DBUG_RETURN(error);
8455 }
8456 
ft_init()8457 int ha_mroonga::ft_init()
8458 {
8459   MRN_DBUG_ENTER_METHOD();
8460   int error = 0;
8461   if (share->wrapper_mode)
8462   {
8463     error = wrapper_ft_init();
8464   } else {
8465     error = storage_ft_init();
8466   }
8467   DBUG_RETURN(error);
8468 }
8469 
generic_ft_init_ext_add_conditions_fast_order_limit(struct st_mrn_ft_info * info,grn_obj * expression)8470 void ha_mroonga::generic_ft_init_ext_add_conditions_fast_order_limit(
8471   struct st_mrn_ft_info *info, grn_obj *expression)
8472 {
8473   MRN_DBUG_ENTER_METHOD();
8474 
8475   Item *where =
8476     MRN_SELECT_LEX_GET_WHERE_COND(table->pos_in_table_list->select_lex);
8477 
8478   bool is_storage_mode = !(share->wrapper_mode);
8479   mrn::ConditionConverter converter(info->ctx, grn_table, is_storage_mode);
8480   converter.convert(where, expression);
8481 
8482   DBUG_VOID_RETURN;
8483 }
8484 
generic_ft_init_ext_prepare_expression_in_boolean_mode(struct st_mrn_ft_info * info,String * key,grn_obj * index_column,grn_obj * match_columns,grn_obj * expression)8485 grn_rc ha_mroonga::generic_ft_init_ext_prepare_expression_in_boolean_mode(
8486   struct st_mrn_ft_info *info,
8487   String *key,
8488   grn_obj *index_column,
8489   grn_obj *match_columns,
8490   grn_obj *expression)
8491 {
8492   MRN_DBUG_ENTER_METHOD();
8493 
8494   mrn::QueryParser query_parser(info->ctx,
8495                                 ha_thd(),
8496                                 expression,
8497                                 index_column,
8498                                 KEY_N_KEY_PARTS(info->key_info),
8499                                 match_columns);
8500   grn_rc rc = query_parser.parse(key->ptr(), key->length());
8501 
8502   DBUG_RETURN(rc);
8503 }
8504 
generic_ft_init_ext_prepare_expression_in_normal_mode(struct st_mrn_ft_info * info,String * key,grn_obj * index_column,grn_obj * match_columns,grn_obj * expression)8505 grn_rc ha_mroonga::generic_ft_init_ext_prepare_expression_in_normal_mode(
8506   struct st_mrn_ft_info *info,
8507   String *key,
8508   grn_obj *index_column,
8509   grn_obj *match_columns,
8510   grn_obj *expression)
8511 {
8512   MRN_DBUG_ENTER_METHOD();
8513 
8514   grn_rc rc = GRN_SUCCESS;
8515 
8516   grn_obj query;
8517   GRN_TEXT_INIT(&query, GRN_OBJ_DO_SHALLOW_COPY);
8518   GRN_TEXT_SET(info->ctx, &query, key->ptr(), key->length());
8519   grn_expr_append_obj(info->ctx, match_columns, index_column, GRN_OP_PUSH, 1);
8520   grn_expr_append_obj(info->ctx, expression, match_columns, GRN_OP_PUSH, 1);
8521   grn_expr_append_const(info->ctx, expression, &query, GRN_OP_PUSH, 1);
8522   grn_expr_append_op(info->ctx, expression, GRN_OP_SIMILAR, 2);
8523   grn_obj_unlink(info->ctx, &query);
8524 
8525   DBUG_RETURN(rc);
8526 }
8527 
generic_ft_init_ext_select(uint flags,uint key_nr,String * key)8528 struct st_mrn_ft_info *ha_mroonga::generic_ft_init_ext_select(uint flags,
8529                                                               uint key_nr,
8530                                                               String *key)
8531 {
8532   MRN_DBUG_ENTER_METHOD();
8533 
8534   struct st_mrn_ft_info *info = new st_mrn_ft_info();
8535   info->mroonga = this;
8536   info->ctx = ctx;
8537   mrn_change_encoding(info->ctx,
8538                       table->key_info[key_nr].key_part->field->charset());
8539   info->encoding = GRN_CTX_GET_ENCODING(info->ctx);
8540   info->table = grn_table;
8541   info->result = grn_table_create(info->ctx, NULL, 0, NULL,
8542                                   GRN_OBJ_TABLE_HASH_KEY | GRN_OBJ_WITH_SUBREC,
8543                                   grn_table, 0);
8544   if (!info->result) {
8545     char error_message[MRN_MESSAGE_BUFFER_SIZE];
8546     snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
8547              "[mroonga][ft-init] failed to create a table "
8548              "to store matched records for one search: <%s>",
8549              ctx->errbuf);
8550     my_message(ER_ERROR_ON_READ, error_message, MYF(0));
8551     GRN_LOG(ctx, GRN_LOG_ERROR, "%s", error_message);
8552     delete info;
8553     DBUG_RETURN(NULL);
8554   }
8555 
8556   info->score_column = grn_obj_column(info->ctx, info->result,
8557                                       MRN_COLUMN_NAME_SCORE,
8558                                       strlen(MRN_COLUMN_NAME_SCORE));
8559   GRN_TEXT_INIT(&(info->key), 0);
8560   grn_bulk_space(info->ctx, &(info->key), table->key_info->key_length);
8561   GRN_INT32_INIT(&(info->score), 0);
8562   info->active_index = key_nr;
8563   info->key_info = &(table->key_info[key_nr]);
8564   info->primary_key_info = &(table->key_info[table_share->primary_key]);
8565   info->cursor = NULL;
8566   info->id_accessor = NULL;
8567   info->key_accessor = NULL;
8568 
8569   if (key->length() == 0) {
8570     DBUG_RETURN(info);
8571   }
8572 
8573   grn_obj *index_column = grn_index_columns[key_nr];
8574   grn_obj *match_columns, *match_columns_variable;
8575   GRN_EXPR_CREATE_FOR_QUERY(info->ctx, info->table, match_columns,
8576                             match_columns_variable);
8577 
8578   grn_obj *expression, *expression_variable;
8579   GRN_EXPR_CREATE_FOR_QUERY(info->ctx, info->table,
8580                             expression, expression_variable);
8581 
8582   grn_rc rc = GRN_SUCCESS;
8583   if (flags & FT_BOOL) {
8584     rc = generic_ft_init_ext_prepare_expression_in_boolean_mode(info,
8585                                                                 key,
8586                                                                 index_column,
8587                                                                 match_columns,
8588                                                                 expression);
8589   } else {
8590     rc = generic_ft_init_ext_prepare_expression_in_normal_mode(info,
8591                                                                key,
8592                                                                index_column,
8593                                                                match_columns,
8594                                                                expression);
8595   }
8596 
8597   if (rc == GRN_SUCCESS) {
8598     if (fast_order_limit) {
8599       generic_ft_init_ext_add_conditions_fast_order_limit(info, expression);
8600     }
8601     longlong escalation_threshold = THDVAR(ha_thd(), match_escalation_threshold);
8602     mrn::MatchEscalationThresholdScope scope(info->ctx, escalation_threshold);
8603     grn_table_select(info->ctx, info->table, expression,
8604                      info->result, GRN_OP_OR);
8605   }
8606 
8607   grn_obj_unlink(info->ctx, expression);
8608   grn_obj_unlink(info->ctx, match_columns);
8609 
8610   DBUG_RETURN(info);
8611 }
8612 
generic_ft_init_ext(uint flags,uint key_nr,String * key)8613 FT_INFO *ha_mroonga::generic_ft_init_ext(uint flags, uint key_nr, String *key)
8614 {
8615   MRN_DBUG_ENTER_METHOD();
8616 
8617   check_count_skip(0);
8618 
8619   mrn_change_encoding(ctx, system_charset_info);
8620   grn_operator operation = GRN_OP_OR;
8621   if (!matched_record_keys) {
8622     matched_record_keys = grn_table_create(ctx, NULL, 0, NULL,
8623                                            GRN_OBJ_TABLE_HASH_KEY | GRN_OBJ_WITH_SUBREC,
8624                                            grn_table, 0);
8625     if (!matched_record_keys) {
8626       char error_message[MRN_MESSAGE_BUFFER_SIZE];
8627       snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
8628                "[mroonga][ft-init] "
8629                "failed to create a table to store all matched records: <%s>",
8630                ctx->errbuf);
8631       my_message(ER_ERROR_ON_READ, error_message, MYF(0));
8632       GRN_LOG(ctx, GRN_LOG_ERROR, "%s", error_message);
8633       DBUG_RETURN(NULL);
8634     }
8635   }
8636 
8637   grn_table_sort_key *sort_keys = NULL;
8638   int n_sort_keys = 0;
8639   longlong limit = -1;
8640   check_fast_order_limit(&sort_keys, &n_sort_keys, &limit);
8641 
8642   struct st_mrn_ft_info *info = generic_ft_init_ext_select(flags, key_nr, key);
8643   if (!info) {
8644     DBUG_RETURN(NULL);
8645   }
8646 
8647   grn_rc rc;
8648   rc = grn_table_setoperation(ctx, matched_record_keys, info->result,
8649                               matched_record_keys, operation);
8650   if (rc) {
8651     char error_message[MRN_MESSAGE_BUFFER_SIZE];
8652     snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
8653              "failed to merge matched record keys: <%s>",
8654              ctx->errbuf);
8655     my_message(ER_ERROR_ON_READ, error_message, MYF(0));
8656     GRN_LOG(ctx, GRN_LOG_ERROR, "%s", error_message);
8657   }
8658   if (fast_order_limit) {
8659     if (sorted_result) {
8660       grn_obj_close(ctx, sorted_result);
8661     }
8662     sorted_result = grn_table_create(ctx, NULL,
8663                                      0, NULL,
8664                                      GRN_OBJ_TABLE_NO_KEY, NULL,
8665                                      matched_record_keys);
8666     grn_table_sort(ctx, matched_record_keys, 0, static_cast<int>(limit),
8667                    sorted_result, sort_keys, n_sort_keys);
8668   } else if (flags & FT_SORTED) {
8669     grn_table_sort_key score_sort_key;
8670     score_sort_key.key = grn_obj_column(ctx,
8671                                         matched_record_keys,
8672                                         MRN_COLUMN_NAME_SCORE,
8673                                         strlen(MRN_COLUMN_NAME_SCORE));
8674     score_sort_key.offset = 0;
8675     score_sort_key.flags = GRN_TABLE_SORT_DESC;
8676     if (sorted_result) {
8677       grn_obj_unlink(ctx, sorted_result);
8678     }
8679     sorted_result = grn_table_create(ctx, NULL,
8680                                      0, NULL,
8681                                      GRN_OBJ_TABLE_NO_KEY, NULL,
8682                                      matched_record_keys);
8683     grn_table_sort(ctx, matched_record_keys, 0, -1,
8684                    sorted_result, &score_sort_key, 1);
8685     grn_obj_unlink(ctx, score_sort_key.key);
8686   }
8687   if (sort_keys) {
8688     for (int i = 0; i < n_sort_keys; i++) {
8689       grn_obj_unlink(info->ctx, sort_keys[i].key);
8690     }
8691     my_free(sort_keys);
8692   }
8693 
8694   DBUG_RETURN((FT_INFO *)info);
8695 }
8696 
wrapper_ft_init_ext(uint flags,uint key_nr,String * key)8697 FT_INFO *ha_mroonga::wrapper_ft_init_ext(uint flags, uint key_nr, String *key)
8698 {
8699   MRN_DBUG_ENTER_METHOD();
8700 
8701   FT_INFO *info = generic_ft_init_ext(flags, key_nr, key);
8702   if (!info) {
8703     DBUG_RETURN(NULL);
8704   }
8705 
8706   struct st_mrn_ft_info *mrn_ft_info = (struct st_mrn_ft_info *)info;
8707   mrn_ft_info->please = &mrn_wrapper_ft_vft;
8708 #ifdef HA_CAN_FULLTEXT_EXT
8709   mrn_ft_info->could_you = &mrn_wrapper_ft_vft_ext;
8710 #endif
8711   ++wrap_ft_init_count;
8712 
8713   DBUG_RETURN(info);
8714 }
8715 
storage_ft_init_ext(uint flags,uint key_nr,String * key)8716 FT_INFO *ha_mroonga::storage_ft_init_ext(uint flags, uint key_nr, String *key)
8717 {
8718   MRN_DBUG_ENTER_METHOD();
8719 
8720   FT_INFO *info = generic_ft_init_ext(flags, key_nr, key);
8721   if (!info) {
8722     DBUG_RETURN(NULL);
8723   }
8724 
8725   struct st_mrn_ft_info *mrn_ft_info = (struct st_mrn_ft_info *)info;
8726   mrn_ft_info->please = &mrn_storage_ft_vft;
8727 #ifdef HA_CAN_FULLTEXT_EXT
8728   mrn_ft_info->could_you = &mrn_storage_ft_vft_ext;
8729 #endif
8730   DBUG_RETURN(info);
8731 }
8732 
ft_init_ext(uint flags,uint key_nr,String * key)8733 FT_INFO *ha_mroonga::ft_init_ext(uint flags, uint key_nr, String *key)
8734 {
8735   MRN_DBUG_ENTER_METHOD();
8736   fulltext_searching = true;
8737   FT_INFO *info;
8738   if (key_nr == NO_SUCH_KEY) {
8739     struct st_mrn_ft_info *mrn_ft_info = new st_mrn_ft_info();
8740     mrn_ft_info->please = &mrn_no_such_key_ft_vft;
8741 #ifdef HA_CAN_FULLTEXT_EXT
8742     mrn_ft_info->could_you = &mrn_no_such_key_ft_vft_ext;
8743 #endif
8744     info = (FT_INFO *)mrn_ft_info;
8745   } else {
8746     if (share->wrapper_mode)
8747     {
8748       info = wrapper_ft_init_ext(flags, key_nr, key);
8749     } else {
8750       info = storage_ft_init_ext(flags, key_nr, key);
8751     }
8752   }
8753   DBUG_RETURN(info);
8754 }
8755 
wrapper_ft_read(uchar * buf)8756 int ha_mroonga::wrapper_ft_read(uchar *buf)
8757 {
8758   MRN_DBUG_ENTER_METHOD();
8759   if (wrap_ft_init_count)
8760     set_pk_bitmap();
8761 
8762   struct st_mrn_ft_info *mrn_ft_info =
8763     reinterpret_cast<struct st_mrn_ft_info *>(ft_handler);
8764   GRN_CTX_SET_ENCODING(ctx, mrn_ft_info->encoding);
8765 
8766   int error = 0;
8767   do {
8768     grn_id found_record_id;
8769     found_record_id = grn_table_cursor_next(ctx, mrn_ft_info->cursor);
8770     if (found_record_id == GRN_ID_NIL) {
8771       error = HA_ERR_END_OF_FILE;
8772       break;
8773     }
8774 
8775     GRN_BULK_REWIND(&key_buffer);
8776     if (mrn_ft_info->key_accessor) {
8777       grn_obj_get_value(ctx, mrn_ft_info->key_accessor,
8778                         found_record_id, &key_buffer);
8779     } else {
8780       void *key;
8781       int key_length;
8782       key_length = grn_table_cursor_get_key(ctx, mrn_ft_info->cursor, &key);
8783       GRN_TEXT_SET(ctx, &key_buffer, key, key_length);
8784     }
8785     error = wrapper_get_record(buf, (const uchar *)GRN_TEXT_VALUE(&key_buffer));
8786   } while (error == HA_ERR_END_OF_FILE || error == HA_ERR_KEY_NOT_FOUND);
8787   DBUG_RETURN(error);
8788 }
8789 
storage_ft_read(uchar * buf)8790 int ha_mroonga::storage_ft_read(uchar *buf)
8791 {
8792   MRN_DBUG_ENTER_METHOD();
8793   struct st_mrn_ft_info *mrn_ft_info =
8794     reinterpret_cast<struct st_mrn_ft_info *>(ft_handler);
8795   GRN_CTX_SET_ENCODING(ctx, mrn_ft_info->encoding);
8796 
8797   grn_id found_record_id;
8798   found_record_id = grn_table_cursor_next(ctx, mrn_ft_info->cursor);
8799   if (ctx->rc) {
8800     my_message(ER_ERROR_ON_READ, ctx->errbuf, MYF(0));
8801     DBUG_RETURN(ER_ERROR_ON_READ);
8802   }
8803 
8804   if (found_record_id == GRN_ID_NIL) {
8805     table->status = STATUS_NOT_FOUND;
8806     DBUG_RETURN(HA_ERR_END_OF_FILE);
8807   }
8808   table->status = 0;
8809 
8810   if (count_skip && record_id != GRN_ID_NIL) {
8811     DBUG_RETURN(0);
8812   }
8813 
8814   GRN_BULK_REWIND(&key_buffer);
8815   if (mrn_ft_info->id_accessor) {
8816     grn_obj id_buffer;
8817     GRN_RECORD_INIT(&id_buffer, 0, grn_obj_id(ctx, grn_table));
8818     grn_obj_get_value(ctx, mrn_ft_info->id_accessor,
8819                       found_record_id, &id_buffer);
8820     record_id = GRN_RECORD_VALUE(&id_buffer);
8821   } else if (mrn_ft_info->key_accessor) {
8822     grn_obj_get_value(ctx, mrn_ft_info->key_accessor,
8823                       found_record_id, &key_buffer);
8824     record_id = grn_table_get(ctx, grn_table,
8825                               GRN_TEXT_VALUE(&key_buffer),
8826                               GRN_TEXT_LEN(&key_buffer));
8827   } else {
8828     void *key;
8829     grn_table_cursor_get_key(ctx, mrn_ft_info->cursor, &key);
8830     if (ctx->rc) {
8831       record_id = GRN_ID_NIL;
8832       my_message(ER_ERROR_ON_READ, ctx->errbuf, MYF(0));
8833       DBUG_RETURN(ER_ERROR_ON_READ);
8834     } else {
8835       record_id = *((grn_id *)key);
8836     }
8837   }
8838   storage_store_fields(buf, record_id);
8839   DBUG_RETURN(0);
8840 }
8841 
ft_read(uchar * buf)8842 int ha_mroonga::ft_read(uchar *buf)
8843 {
8844   MRN_DBUG_ENTER_METHOD();
8845   int error = 0;
8846   if (share->wrapper_mode)
8847   {
8848     error = wrapper_ft_read(buf);
8849   } else {
8850     error = storage_ft_read(buf);
8851   }
8852   DBUG_RETURN(error);
8853 }
8854 
wrapper_cond_push(const Item * cond)8855 const Item *ha_mroonga::wrapper_cond_push(const Item *cond)
8856 {
8857   const Item *reminder_cond;
8858   MRN_DBUG_ENTER_METHOD();
8859   MRN_SET_WRAP_SHARE_KEY(share, table->s);
8860   MRN_SET_WRAP_TABLE_KEY(this, table);
8861   reminder_cond = wrap_handler->cond_push(cond);
8862   MRN_SET_BASE_SHARE_KEY(share, table->s);
8863   MRN_SET_BASE_TABLE_KEY(this, table);
8864   DBUG_RETURN(reminder_cond);
8865 }
8866 
storage_cond_push(const Item * cond)8867 const Item *ha_mroonga::storage_cond_push(const Item *cond)
8868 {
8869   MRN_DBUG_ENTER_METHOD();
8870   const Item *reminder_cond = cond;
8871   if (!pushed_cond) {
8872     mrn::ConditionConverter converter(ctx, grn_table, true);
8873     if (converter.count_match_against(cond) == 1 &&
8874         converter.is_convertable(cond)) {
8875       reminder_cond = NULL;
8876     }
8877   }
8878   DBUG_RETURN(reminder_cond);
8879 }
8880 
cond_push(const Item * cond)8881 const Item *ha_mroonga::cond_push(const Item *cond)
8882 {
8883   MRN_DBUG_ENTER_METHOD();
8884   const Item *reminder_cond;
8885   if (share->wrapper_mode)
8886   {
8887     reminder_cond = wrapper_cond_push(cond);
8888   } else {
8889     reminder_cond = storage_cond_push(cond);
8890   }
8891   DBUG_RETURN(reminder_cond);
8892 }
8893 
wrapper_cond_pop()8894 void ha_mroonga::wrapper_cond_pop()
8895 {
8896   MRN_DBUG_ENTER_METHOD();
8897   MRN_SET_WRAP_SHARE_KEY(share, table->s);
8898   MRN_SET_WRAP_TABLE_KEY(this, table);
8899   wrap_handler->cond_pop();
8900   MRN_SET_BASE_SHARE_KEY(share, table->s);
8901   MRN_SET_BASE_TABLE_KEY(this, table);
8902   DBUG_VOID_RETURN;
8903 }
8904 
storage_cond_pop()8905 void ha_mroonga::storage_cond_pop()
8906 {
8907   MRN_DBUG_ENTER_METHOD();
8908   DBUG_VOID_RETURN;
8909 }
8910 
cond_pop()8911 void ha_mroonga::cond_pop()
8912 {
8913   MRN_DBUG_ENTER_METHOD();
8914   if (share->wrapper_mode)
8915     wrapper_cond_pop();
8916   else
8917     storage_cond_pop();
8918   DBUG_VOID_RETURN;
8919 }
8920 
wrapper_get_error_message(int error,String * buf)8921 bool ha_mroonga::wrapper_get_error_message(int error, String *buf)
8922 {
8923   bool temporary_error;
8924   MRN_DBUG_ENTER_METHOD();
8925   MRN_SET_WRAP_SHARE_KEY(share, table->s);
8926   MRN_SET_WRAP_TABLE_KEY(this, table);
8927   temporary_error = wrap_handler->get_error_message(error, buf);
8928   MRN_SET_BASE_SHARE_KEY(share, table->s);
8929   MRN_SET_BASE_TABLE_KEY(this, table);
8930   DBUG_RETURN(temporary_error);
8931 }
8932 
storage_get_error_message(int error,String * buf)8933 bool ha_mroonga::storage_get_error_message(int error, String *buf)
8934 {
8935   MRN_DBUG_ENTER_METHOD();
8936   bool temporary_error = false;
8937   // latest error message
8938   buf->copy(ctx->errbuf, (uint) strlen(ctx->errbuf), system_charset_info);
8939   DBUG_RETURN(temporary_error);
8940 }
8941 
get_error_message(int error,String * buf)8942 bool ha_mroonga::get_error_message(int error, String *buf)
8943 {
8944   MRN_DBUG_ENTER_METHOD();
8945   bool temporary_error;
8946   if (share && share->wrapper_mode)
8947   {
8948     temporary_error = wrapper_get_error_message(error, buf);
8949   } else {
8950     temporary_error = storage_get_error_message(error, buf);
8951   }
8952   DBUG_RETURN(temporary_error);
8953 }
8954 
file_size(const char * path)8955 ulonglong ha_mroonga::file_size(const char *path)
8956 {
8957   MRN_DBUG_ENTER_METHOD();
8958 
8959   struct stat file_status;
8960   if (stat(path, &file_status) == 0) {
8961     DBUG_RETURN(file_status.st_size);
8962   } else {
8963     DBUG_RETURN(0);
8964   }
8965 }
8966 
have_unique_index()8967 bool ha_mroonga::have_unique_index()
8968 {
8969   MRN_DBUG_ENTER_METHOD();
8970 
8971   uint n_keys = table->s->keys;
8972 
8973   for (uint i = 0; i < n_keys; i++) {
8974     if (i == table->s->primary_key) {
8975       continue;
8976     }
8977 
8978     KEY *key_info = &(table->key_info[i]);
8979     if (key_info->flags & HA_NOSAME) {
8980       DBUG_RETURN(true);
8981     }
8982   }
8983 
8984   DBUG_RETURN(false);
8985 }
8986 
is_foreign_key_field(const char * table_name,const char * field_name)8987 bool ha_mroonga::is_foreign_key_field(const char *table_name,
8988                                       const char *field_name)
8989 {
8990   MRN_DBUG_ENTER_METHOD();
8991 
8992   grn_obj *table = grn_ctx_get(ctx, table_name, -1);
8993   if (!table) {
8994     DBUG_RETURN(false);
8995   }
8996 
8997   mrn::ColumnName column_name(field_name);
8998   grn_obj *column = grn_obj_column(ctx,
8999                                    table,
9000                                    column_name.c_str(),
9001                                    column_name.length());
9002   if (!column) {
9003     DBUG_RETURN(false);
9004   }
9005 
9006   grn_obj *range = grn_ctx_at(ctx, grn_obj_get_range(ctx, column));
9007   if (!range) {
9008     grn_obj_unlink(ctx, column);
9009     DBUG_RETURN(false);
9010   }
9011 
9012   if (!mrn::grn::is_table(range)) {
9013     grn_obj_unlink(ctx, column);
9014     DBUG_RETURN(false);
9015   }
9016 
9017   grn_obj *foreign_index_column;
9018   mrn::IndexColumnName index_column_name(table_name, field_name);
9019   foreign_index_column = grn_obj_column(ctx, range,
9020                                         index_column_name.c_str(),
9021                                         index_column_name.length());
9022   if (foreign_index_column) {
9023     grn_obj_unlink(ctx, foreign_index_column);
9024     DBUG_RETURN(true);
9025   }
9026 
9027   grn_obj_unlink(ctx, column);
9028   DBUG_RETURN(false);
9029 }
9030 
push_warning_unsupported_spatial_index_search(enum ha_rkey_function flag)9031 void ha_mroonga::push_warning_unsupported_spatial_index_search(enum ha_rkey_function flag)
9032 {
9033   char search_name[MRN_BUFFER_SIZE];
9034   if (flag == HA_READ_MBR_INTERSECT) {
9035     strcpy(search_name, "intersect");
9036   } else if (flag == HA_READ_MBR_WITHIN) {
9037     strcpy(search_name, "within");
9038   } else if (flag & HA_READ_MBR_DISJOINT) {
9039     strcpy(search_name, "disjoint");
9040   } else if (flag & HA_READ_MBR_EQUAL) {
9041     strcpy(search_name, "equal");
9042   } else {
9043     sprintf(search_name, "unknown: %d", flag);
9044   }
9045   push_warning_printf(ha_thd(),
9046                       MRN_SEVERITY_WARNING,
9047                       ER_UNSUPPORTED_EXTENSION,
9048                       "spatial index search "
9049                       "except MBRContains aren't supported: <%s>",
9050                       search_name);
9051 }
9052 
clear_cursor()9053 void ha_mroonga::clear_cursor()
9054 {
9055   MRN_DBUG_ENTER_METHOD();
9056   if (cursor) {
9057     grn_obj_unlink(ctx, cursor);
9058     cursor = NULL;
9059   }
9060   if (index_table_cursor) {
9061     grn_table_cursor_close(ctx, index_table_cursor);
9062     index_table_cursor = NULL;
9063   }
9064   DBUG_VOID_RETURN;
9065 }
9066 
clear_cursor_geo()9067 void ha_mroonga::clear_cursor_geo()
9068 {
9069   MRN_DBUG_ENTER_METHOD();
9070   if (cursor_geo) {
9071     grn_obj_unlink(ctx, cursor_geo);
9072     cursor_geo = NULL;
9073   }
9074   DBUG_VOID_RETURN;
9075 }
9076 
clear_empty_value_records()9077 void ha_mroonga::clear_empty_value_records()
9078 {
9079   MRN_DBUG_ENTER_METHOD();
9080   if (empty_value_records_cursor) {
9081     grn_table_cursor_close(ctx, empty_value_records_cursor);
9082     empty_value_records_cursor = NULL;
9083   }
9084   if (empty_value_records) {
9085     grn_obj_unlink(ctx, empty_value_records);
9086     empty_value_records = NULL;
9087   }
9088   DBUG_VOID_RETURN;
9089 }
9090 
clear_search_result()9091 void ha_mroonga::clear_search_result()
9092 {
9093   MRN_DBUG_ENTER_METHOD();
9094   clear_cursor();
9095   if (sorted_result) {
9096     grn_obj_unlink(ctx, sorted_result);
9097     sorted_result = NULL;
9098   }
9099   if (matched_record_keys) {
9100     grn_obj_unlink(ctx, matched_record_keys);
9101     matched_record_keys = NULL;
9102   }
9103   DBUG_VOID_RETURN;
9104 }
9105 
clear_search_result_geo()9106 void ha_mroonga::clear_search_result_geo()
9107 {
9108   MRN_DBUG_ENTER_METHOD();
9109   clear_cursor_geo();
9110   if (grn_source_column_geo) {
9111     grn_obj_unlink(ctx, grn_source_column_geo);
9112     grn_source_column_geo = NULL;
9113   }
9114   DBUG_VOID_RETURN;
9115 }
9116 
clear_indexes()9117 void ha_mroonga::clear_indexes()
9118 {
9119   MRN_DBUG_ENTER_METHOD();
9120   uint n_keys = table->s->keys;
9121   uint pkey_nr = table->s->primary_key;
9122 
9123   for (uint i = 0; i < n_keys; i++) {
9124     if (i != pkey_nr) {
9125       if (grn_index_tables) {
9126         grn_obj_unlink(ctx, grn_index_tables[i]);
9127       }
9128       if (grn_index_columns) {
9129         grn_obj_unlink(ctx, grn_index_columns[i]);
9130       }
9131     }
9132   }
9133 
9134   if (grn_index_tables) {
9135     free(grn_index_tables);
9136     grn_index_tables = NULL;
9137   }
9138 
9139   if (grn_index_columns) {
9140     free(grn_index_columns);
9141     grn_index_columns = NULL;
9142   }
9143 
9144   if (key_id) {
9145     free(key_id);
9146     key_id = NULL;
9147   }
9148 
9149   if (del_key_id) {
9150     free(del_key_id);
9151     del_key_id = NULL;
9152   }
9153 
9154   DBUG_VOID_RETURN;
9155 }
9156 
add_wrap_hton(const char * path,handlerton * wrap_handlerton)9157 int ha_mroonga::add_wrap_hton(const char *path, handlerton *wrap_handlerton)
9158 {
9159   MRN_DBUG_ENTER_METHOD();
9160   st_mrn_slot_data *slot_data = mrn_get_slot_data(ha_thd(), true);
9161   if (!slot_data)
9162     DBUG_RETURN(HA_ERR_OUT_OF_MEM);
9163   st_mrn_wrap_hton *wrap_hton =
9164     (st_mrn_wrap_hton *)malloc(sizeof(st_mrn_wrap_hton));
9165   if (!wrap_hton)
9166     DBUG_RETURN(HA_ERR_OUT_OF_MEM);
9167   wrap_hton->next = NULL;
9168   strcpy(wrap_hton->path, path);
9169   wrap_hton->hton = wrap_handlerton;
9170   if (slot_data->first_wrap_hton)
9171   {
9172     st_mrn_wrap_hton *tmp_wrap_hton = slot_data->first_wrap_hton;
9173     while (tmp_wrap_hton->next)
9174       tmp_wrap_hton = tmp_wrap_hton->next;
9175     tmp_wrap_hton->next = wrap_hton;
9176   } else {
9177     slot_data->first_wrap_hton = wrap_hton;
9178   }
9179   DBUG_RETURN(0);
9180 }
9181 
remove_related_files(const char * base_path)9182 void ha_mroonga::remove_related_files(const char *base_path)
9183 {
9184   MRN_DBUG_ENTER_METHOD();
9185 
9186   const char *base_directory_name = ".";
9187   size_t base_path_length = strlen(base_path);
9188 #ifdef WIN32
9189   WIN32_FIND_DATA data;
9190   HANDLE finder = FindFirstFile(base_directory_name, &data);
9191   if (finder != INVALID_HANDLE_VALUE) {
9192     do {
9193       if (!(data.dwFileAttributes & FILE_ATTRIBUTE_NORMAL)) {
9194         continue;
9195       }
9196       if (strncmp(data.cFileName, base_path, base_path_length) == 0) {
9197         unlink(data.cFileName);
9198       }
9199     } while (FindNextFile(finder, &data) != 0);
9200     FindClose(finder);
9201   }
9202 #else
9203   DIR *dir = opendir(base_directory_name);
9204   if (dir) {
9205     while (struct dirent *entry = readdir(dir)) {
9206       struct stat file_status;
9207       if (stat(entry->d_name, &file_status) != 0) {
9208         continue;
9209       }
9210       if (!((file_status.st_mode & S_IFMT) == S_IFREG)) {
9211         continue;
9212       }
9213       if (strncmp(entry->d_name, base_path, base_path_length) == 0) {
9214         unlink(entry->d_name);
9215       }
9216     }
9217     closedir(dir);
9218   }
9219 #endif
9220 
9221   DBUG_VOID_RETURN;
9222 }
9223 
remove_grn_obj_force(const char * name)9224 void ha_mroonga::remove_grn_obj_force(const char *name)
9225 {
9226   MRN_DBUG_ENTER_METHOD();
9227 
9228   grn_obj *obj = grn_ctx_get(ctx, name, strlen(name));
9229   if (obj) {
9230     grn_obj_remove(ctx, obj);
9231   } else {
9232     grn_obj *db = grn_ctx_db(ctx);
9233     grn_id id = grn_table_get(ctx, db, name, strlen(name));
9234     if (id) {
9235       char path[MRN_MAX_PATH_SIZE];
9236       grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
9237       if (grn_obj_path_by_id(ctx, db, id, path) == GRN_SUCCESS) {
9238         remove_related_files(path);
9239       }
9240     }
9241   }
9242 
9243   DBUG_VOID_RETURN;
9244 }
9245 
drop_index(MRN_SHARE * target_share,uint key_index)9246 int ha_mroonga::drop_index(MRN_SHARE *target_share, uint key_index)
9247 {
9248   MRN_DBUG_ENTER_METHOD();
9249   int error = 0;
9250   grn_rc rc = GRN_SUCCESS;
9251   char target_name[GRN_TABLE_MAX_KEY_SIZE];
9252   int target_name_length;
9253 
9254   KEY *key_info = target_share->table_share->key_info;
9255   if (!target_share->wrapper_mode && target_share->index_table[key_index]) {
9256     const char *table_name = target_share->index_table[key_index];
9257     snprintf(target_name, GRN_TABLE_MAX_KEY_SIZE,
9258              "%s.%s", table_name, key_info[key_index].name.str);
9259     target_name_length = strlen(target_name);
9260     grn_obj *index_column = grn_ctx_get(ctx, target_name, target_name_length);
9261     if (index_column) {
9262       rc = grn_obj_remove(ctx, index_column);
9263     }
9264   } else {
9265     mrn::PathMapper mapper(target_share->table_name);
9266     mrn::IndexTableName index_table_name(mapper.table_name(),
9267                                          key_info[key_index].name.str);
9268     grn_obj *index_table = grn_ctx_get(ctx,
9269                                        index_table_name.c_str(),
9270                                        index_table_name.length());
9271     if (!index_table) {
9272       index_table = grn_ctx_get(ctx,
9273                                 index_table_name.old_c_str(),
9274                                 index_table_name.old_length());
9275     }
9276     if (index_table) {
9277       target_name_length = grn_obj_name(ctx, index_table,
9278                                         target_name, GRN_TABLE_MAX_KEY_SIZE);
9279       rc = grn_obj_remove(ctx, index_table);
9280     } else {
9281       target_name_length = 0;
9282     }
9283   }
9284 
9285   if (rc != GRN_SUCCESS) {
9286     char error_message[MRN_MESSAGE_BUFFER_SIZE];
9287     snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
9288              "failed to drop index: <%.*s>: <%s>",
9289              target_name_length, target_name,
9290              ctx->errbuf);
9291     my_message(ER_ERROR_ON_WRITE, error_message, MYF(0));
9292     GRN_LOG(ctx, GRN_LOG_ERROR, "%s", error_message);
9293   }
9294 
9295   DBUG_RETURN(error);
9296 }
9297 
drop_indexes_normal(const char * table_name,grn_obj * table)9298 int ha_mroonga::drop_indexes_normal(const char *table_name, grn_obj *table)
9299 {
9300   MRN_DBUG_ENTER_METHOD();
9301 
9302   int error = 0;
9303 
9304   grn_hash *columns_raw = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
9305                                           GRN_OBJ_TABLE_HASH_KEY);
9306   mrn::SmartGrnObj columns(ctx, reinterpret_cast<grn_obj *>(columns_raw));
9307   if (!columns.get()) {
9308     char error_message[MRN_MESSAGE_BUFFER_SIZE];
9309     snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
9310              "failed to allocate columns buffer: <%s>: <%s>",
9311              table_name, ctx->errbuf);
9312     error = HA_ERR_OUT_OF_MEM;
9313     my_message(ER_ERROR_ON_WRITE, error_message, MYF(0));
9314     GRN_LOG(ctx, GRN_LOG_ERROR, "%s", error_message);
9315     DBUG_RETURN(error);
9316   }
9317 
9318   grn_table_columns(ctx, table, "", 0, columns.get());
9319   grn_table_cursor *cursor = grn_table_cursor_open(ctx,
9320                                                    columns.get(),
9321                                                    NULL, 0,
9322                                                    NULL, 0,
9323                                                    0, -1,
9324                                                    0);
9325   if (!cursor) {
9326     char error_message[MRN_MESSAGE_BUFFER_SIZE];
9327     snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
9328              "failed to allocate columns cursor: <%s>: <%s>",
9329              table_name, ctx->errbuf);
9330     error = HA_ERR_OUT_OF_MEM;
9331     my_message(ER_ERROR_ON_WRITE, error_message, MYF(0));
9332     GRN_LOG(ctx, GRN_LOG_ERROR, "%s", error_message);
9333     DBUG_RETURN(error);
9334   }
9335 
9336   while (grn_table_cursor_next(ctx, cursor) != GRN_ID_NIL) {
9337     void *key;
9338     grn_table_cursor_get_key(ctx, cursor, &key);
9339     grn_id *id = reinterpret_cast<grn_id *>(key);
9340     mrn::SmartGrnObj column(ctx, grn_ctx_at(ctx, *id));
9341     if (!column.get()) {
9342       continue;
9343     }
9344 
9345     grn_operator index_operators[] = {
9346       GRN_OP_EQUAL,
9347       GRN_OP_MATCH,
9348       GRN_OP_LESS,
9349       GRN_OP_REGEXP
9350     };
9351     size_t n_index_operators = sizeof(index_operators) / sizeof(grn_operator);
9352     for (size_t i = 0; i < n_index_operators; i++) {
9353       grn_index_datum index_datum;
9354       while (grn_column_find_index_data(ctx,
9355                                         column.get(),
9356                                         index_operators[i],
9357                                         &index_datum,
9358                                         1) > 0) {
9359         grn_id index_table_id = index_datum.index->header.domain;
9360         mrn::SmartGrnObj index_table(ctx, grn_ctx_at(ctx, index_table_id));
9361         char index_table_name[GRN_TABLE_MAX_KEY_SIZE];
9362         int index_table_name_length;
9363         index_table_name_length = grn_obj_name(ctx, index_table.get(),
9364                                                index_table_name,
9365                                                GRN_TABLE_MAX_KEY_SIZE);
9366         if (mrn::IndexTableName::is_custom_name(table_name,
9367                                                 strlen(table_name),
9368                                                 index_table_name,
9369                                                 index_table_name_length)) {
9370           char index_column_name[GRN_TABLE_MAX_KEY_SIZE];
9371           int index_column_name_length;
9372           index_column_name_length = grn_obj_name(ctx,
9373                                                   index_datum.index,
9374                                                   index_column_name,
9375                                                   GRN_TABLE_MAX_KEY_SIZE);
9376           grn_rc rc = grn_obj_remove(ctx, index_datum.index);
9377           if (rc != GRN_SUCCESS) {
9378             char error_message[MRN_MESSAGE_BUFFER_SIZE];
9379             snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
9380                      "failed to drop index column: <%.*s>: <%s>",
9381                      index_column_name_length, index_column_name,
9382                      ctx->errbuf);
9383             error = ER_ERROR_ON_WRITE;
9384             my_message(error, error_message, MYF(0));
9385             GRN_LOG(ctx, GRN_LOG_ERROR, "%s", error_message);
9386           }
9387         } else {
9388           grn_rc rc = grn_obj_remove(ctx, index_table.get());
9389           if (rc == GRN_SUCCESS) {
9390             index_table.release();
9391           } else {
9392             char error_message[MRN_MESSAGE_BUFFER_SIZE];
9393             snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
9394                      "failed to drop index table: <%.*s>: <%s>",
9395                      index_table_name_length, index_table_name,
9396                      ctx->errbuf);
9397             error = ER_ERROR_ON_WRITE;
9398             my_message(error, error_message, MYF(0));
9399             GRN_LOG(ctx, GRN_LOG_ERROR, "%s", error_message);
9400           }
9401         }
9402 
9403         if (error != 0) {
9404           break;
9405         }
9406       }
9407 
9408       if (error != 0) {
9409         break;
9410       }
9411     }
9412 
9413     if (error != 0) {
9414       break;
9415     }
9416   }
9417 
9418   grn_table_cursor_close(ctx, cursor);
9419 
9420   DBUG_RETURN(error);
9421 }
9422 
drop_indexes_multiple(const char * table_name,grn_obj * table,const char * index_table_name_separator)9423 int ha_mroonga::drop_indexes_multiple(const char *table_name,
9424                                       grn_obj *table,
9425                                       const char *index_table_name_separator)
9426 {
9427   MRN_DBUG_ENTER_METHOD();
9428 
9429   int error = 0;
9430 
9431   char index_table_name_prefix[GRN_TABLE_MAX_KEY_SIZE];
9432   snprintf(index_table_name_prefix, GRN_TABLE_MAX_KEY_SIZE,
9433            "%s%s", table_name, index_table_name_separator);
9434   grn_table_cursor *cursor =
9435     grn_table_cursor_open(ctx,
9436                           grn_ctx_db(ctx),
9437                           index_table_name_prefix,
9438                           strlen(index_table_name_prefix),
9439                           NULL, 0,
9440                           0, -1,
9441                           GRN_CURSOR_PREFIX);
9442   if (!cursor) {
9443     char error_message[MRN_MESSAGE_BUFFER_SIZE];
9444     snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
9445              "failed to allocate index tables cursor: <%s>: <%s>",
9446              table_name, ctx->errbuf);
9447     error = HA_ERR_OUT_OF_MEM;
9448     my_message(ER_ERROR_ON_WRITE, error_message, MYF(0));
9449     GRN_LOG(ctx, GRN_LOG_ERROR, "%s", error_message);
9450     DBUG_RETURN(error);
9451   }
9452 
9453   grn_id table_id = grn_obj_id(ctx, table);
9454   grn_id id;
9455   while ((id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
9456     mrn::SmartGrnObj object(ctx, grn_ctx_at(ctx, id));
9457     if (!object.get()) {
9458       continue;
9459     }
9460     if (!grn_obj_is_table(ctx, object.get())) {
9461       continue;
9462     }
9463 
9464     char multiple_column_index_table_name[GRN_TABLE_MAX_KEY_SIZE];
9465     int multiple_column_index_table_name_length;
9466     multiple_column_index_table_name_length =
9467       grn_obj_name(ctx,
9468                    object.get(),
9469                    multiple_column_index_table_name,
9470                    GRN_TABLE_MAX_KEY_SIZE);
9471 
9472     char multiple_column_index_name[GRN_TABLE_MAX_KEY_SIZE];
9473     snprintf(multiple_column_index_name, GRN_TABLE_MAX_KEY_SIZE,
9474              "%.*s.%s",
9475              multiple_column_index_table_name_length,
9476              multiple_column_index_table_name,
9477              INDEX_COLUMN_NAME);
9478     mrn::SmartGrnObj index_column(ctx, multiple_column_index_name);
9479     if (!index_column.get()) {
9480       continue;
9481     }
9482 
9483     if (grn_obj_get_range(ctx, index_column.get()) != table_id) {
9484       continue;
9485     }
9486 
9487     grn_rc rc = grn_obj_remove(ctx, object.get());
9488     if (rc == GRN_SUCCESS) {
9489       object.release();
9490       index_column.release();
9491     } else {
9492       char error_message[MRN_MESSAGE_BUFFER_SIZE];
9493       snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
9494                "failed to drop multiple column index table: <%.*s>: <%s>",
9495                multiple_column_index_table_name_length,
9496                multiple_column_index_table_name,
9497                ctx->errbuf);
9498       error = ER_ERROR_ON_WRITE;
9499       my_message(error, error_message, MYF(0));
9500       GRN_LOG(ctx, GRN_LOG_ERROR, "%s", error_message);
9501       break;
9502     }
9503   }
9504 
9505   grn_table_cursor_close(ctx, cursor);
9506 
9507   DBUG_RETURN(error);
9508 }
9509 
drop_indexes(const char * table_name)9510 int ha_mroonga::drop_indexes(const char *table_name)
9511 {
9512   MRN_DBUG_ENTER_METHOD();
9513   int error = 0;
9514 
9515   mrn::SmartGrnObj table(ctx, table_name);
9516   if (!table.get()) {
9517     DBUG_RETURN(0);
9518   }
9519 
9520   error = drop_indexes_normal(table_name, table.get());
9521   if (error == 0) {
9522     error = drop_indexes_multiple(table_name, table.get(),
9523                                   mrn::IndexTableName::SEPARATOR);
9524   }
9525   if (error == 0) {
9526     error = drop_indexes_multiple(table_name, table.get(),
9527                                   mrn::IndexTableName::OLD_SEPARATOR);
9528   }
9529 
9530   DBUG_RETURN(error);
9531 }
9532 
find_column_flags(Field * field,MRN_SHARE * mrn_share,int i,grn_obj_flags * column_flags)9533 bool ha_mroonga::find_column_flags(Field *field, MRN_SHARE *mrn_share, int i,
9534                                    grn_obj_flags *column_flags)
9535 {
9536   MRN_DBUG_ENTER_METHOD();
9537   bool found = false;
9538 
9539 #ifdef MRN_SUPPORT_CUSTOM_OPTIONS
9540   {
9541     const char *names = field->option_struct->flags;
9542     if (names) {
9543       found = mrn_parse_grn_column_create_flags(ha_thd(),
9544                                                 ctx,
9545                                                 names,
9546                                                 strlen(names),
9547                                                 column_flags);
9548       DBUG_RETURN(found);
9549     }
9550   }
9551 #endif
9552 
9553   if (mrn_share->col_flags[i]) {
9554     found = mrn_parse_grn_column_create_flags(ha_thd(),
9555                                               ctx,
9556                                               mrn_share->col_flags[i],
9557                                               mrn_share->col_flags_length[i],
9558                                               column_flags);
9559     DBUG_RETURN(found);
9560   }
9561 
9562   DBUG_RETURN(found);
9563 }
9564 
find_column_type(Field * field,MRN_SHARE * mrn_share,int i,int error_code)9565 grn_obj *ha_mroonga::find_column_type(Field *field, MRN_SHARE *mrn_share, int i,
9566                                       int error_code)
9567 {
9568   MRN_DBUG_ENTER_METHOD();
9569 
9570   const char *grn_type_name = NULL;
9571 #ifdef MRN_SUPPORT_CUSTOM_OPTIONS
9572   grn_type_name = field->option_struct->groonga_type;
9573 #endif
9574   if (!grn_type_name) {
9575     grn_type_name = mrn_share->col_type[i];
9576   }
9577 
9578   grn_obj *type = NULL;
9579   if (grn_type_name) {
9580     type = grn_ctx_get(ctx, grn_type_name, -1);
9581     if (!type) {
9582       char error_message[MRN_BUFFER_SIZE];
9583       snprintf(error_message, MRN_BUFFER_SIZE,
9584                "unknown custom Groonga type name for <%s> column: <%s>",
9585                field->field_name.str, grn_type_name);
9586       GRN_LOG(ctx, GRN_LOG_ERROR, "%s", error_message);
9587       my_message(error_code, error_message, MYF(0));
9588 
9589       DBUG_RETURN(NULL);
9590     }
9591   } else {
9592     grn_builtin_type grn_type_id = mrn_grn_type_from_field(ctx, field, false);
9593     type = grn_ctx_at(ctx, grn_type_id);
9594   }
9595 
9596   DBUG_RETURN(type);
9597 }
9598 
find_tokenizer(KEY * key,MRN_SHARE * mrn_share,int i)9599 grn_obj *ha_mroonga::find_tokenizer(KEY *key, MRN_SHARE *mrn_share, int i)
9600 {
9601   MRN_DBUG_ENTER_METHOD();
9602   grn_obj *tokenizer;
9603   const char *tokenizer_name = NULL;
9604   uint tokenizer_name_length = 0;
9605 #ifdef MRN_SUPPORT_CUSTOM_OPTIONS
9606   if (key->option_struct->tokenizer) {
9607     tokenizer_name = key->option_struct->tokenizer;
9608     tokenizer_name_length = strlen(tokenizer_name);
9609   }
9610 #endif
9611   if (!tokenizer_name) {
9612     tokenizer_name = mrn_share->key_tokenizer[i];
9613     tokenizer_name_length = mrn_share->key_tokenizer_length[i];
9614   }
9615   tokenizer = find_tokenizer(tokenizer_name, tokenizer_name_length);
9616   DBUG_RETURN(tokenizer);
9617 }
9618 
find_tokenizer(const char * name,int name_length)9619 grn_obj *ha_mroonga::find_tokenizer(const char *name, int name_length)
9620 {
9621   MRN_DBUG_ENTER_METHOD();
9622 
9623   if (strncasecmp("off", name, name_length) == 0) {
9624     DBUG_RETURN(NULL);
9625   }
9626 
9627   grn_obj *tokenizer;
9628   mrn_change_encoding(ctx, system_charset_info);
9629   tokenizer = grn_ctx_get(ctx, name, name_length);
9630   if (!tokenizer) {
9631     char message[MRN_BUFFER_SIZE];
9632     sprintf(message,
9633             "specified tokenizer for fulltext index <%.*s> doesn't exist. "
9634             "The default tokenizer for fulltext index <%s> is used instead.",
9635             name_length, name,
9636             MRN_DEFAULT_TOKENIZER);
9637     push_warning(ha_thd(),
9638                  MRN_SEVERITY_WARNING, ER_UNSUPPORTED_EXTENSION,
9639                  message);
9640     tokenizer = grn_ctx_get(ctx,
9641                             MRN_DEFAULT_TOKENIZER,
9642                             strlen(MRN_DEFAULT_TOKENIZER));
9643   }
9644   if (!tokenizer) {
9645     push_warning(ha_thd(),
9646                  MRN_SEVERITY_WARNING, ER_UNSUPPORTED_EXTENSION,
9647                  "couldn't find tokenizer for fulltext index. "
9648                  "Bigram tokenizer is used instead.");
9649     tokenizer = grn_ctx_at(ctx, GRN_DB_BIGRAM);
9650   }
9651   DBUG_RETURN(tokenizer);
9652 }
9653 
have_custom_normalizer(KEY * key) const9654 bool ha_mroonga::have_custom_normalizer(KEY *key) const
9655 {
9656   MRN_DBUG_ENTER_METHOD();
9657 
9658 #ifdef MRN_SUPPORT_CUSTOM_OPTIONS
9659   if (key->option_struct && key->option_struct->normalizer) {
9660     DBUG_RETURN(true);
9661   }
9662 #endif
9663 
9664   if (key->comment.length > 0) {
9665     mrn::ParametersParser parser(key->comment.str,
9666                                  key->comment.length);
9667     parser.parse();
9668     DBUG_RETURN(parser["normalizer"] != NULL);
9669   }
9670 
9671   DBUG_RETURN(false);
9672 }
9673 
find_normalizer(KEY * key)9674 grn_obj *ha_mroonga::find_normalizer(KEY *key)
9675 {
9676   MRN_DBUG_ENTER_METHOD();
9677 
9678 #ifdef MRN_SUPPORT_CUSTOM_OPTIONS
9679   if (key->option_struct->normalizer) {
9680     grn_obj *normalizer = find_normalizer(key,
9681                                           key->option_struct->normalizer);
9682     DBUG_RETURN(normalizer);
9683   }
9684 #endif
9685 
9686   if (key->comment.length > 0) {
9687     mrn::ParametersParser parser(key->comment.str,
9688                                  key->comment.length);
9689     parser.parse();
9690     grn_obj *normalizer = find_normalizer(key, parser["normalizer"]);
9691     DBUG_RETURN(normalizer);
9692   }
9693 
9694   grn_obj *normalizer = find_normalizer(key, NULL);
9695   DBUG_RETURN(normalizer);
9696 }
9697 
find_normalizer(KEY * key,const char * name)9698 grn_obj *ha_mroonga::find_normalizer(KEY *key, const char *name)
9699 {
9700   MRN_DBUG_ENTER_METHOD();
9701 
9702   grn_obj *normalizer = NULL;
9703   bool use_normalizer = true;
9704   if (name) {
9705     if (strcmp(name, "none") == 0) {
9706       use_normalizer = false;
9707     } else {
9708       normalizer = grn_ctx_get(ctx, name, -1);
9709     }
9710   }
9711   if (use_normalizer && !normalizer) {
9712     Field *field = key->key_part[0].field;
9713     mrn::FieldNormalizer field_normalizer(ctx, ha_thd(), field);
9714     normalizer = field_normalizer.find_grn_normalizer();
9715   }
9716 
9717   DBUG_RETURN(normalizer);
9718 }
9719 
find_index_column_flags(KEY * key,grn_column_flags * index_column_flags)9720 bool ha_mroonga::find_index_column_flags(KEY *key, grn_column_flags *index_column_flags)
9721 {
9722   MRN_DBUG_ENTER_METHOD();
9723   bool found = false;
9724 
9725 #ifdef MRN_SUPPORT_CUSTOM_OPTIONS
9726   {
9727     const char *names = key->option_struct->flags;
9728     if (names) {
9729       found = mrn_parse_grn_index_column_flags(ha_thd(),
9730                                                ctx,
9731                                                names,
9732                                                strlen(names),
9733                                                index_column_flags);
9734       DBUG_RETURN(found);
9735     }
9736   }
9737 #endif
9738 
9739   if (key->comment.length > 0) {
9740     mrn::ParametersParser parser(key->comment.str,
9741                                  key->comment.length);
9742     parser.parse();
9743     const char *names = parser["flags"];
9744     if (!names) {
9745       // Deprecated. It's for backward compatibility.
9746       names = parser["index_flags"];
9747     }
9748     if (names) {
9749       found = mrn_parse_grn_index_column_flags(ha_thd(),
9750                                                ctx,
9751                                                names,
9752                                                strlen(names),
9753                                                index_column_flags);
9754     }
9755   }
9756 
9757   DBUG_RETURN(found);
9758 }
9759 
find_token_filters(KEY * key,grn_obj * token_filters)9760 bool ha_mroonga::find_token_filters(KEY *key, grn_obj *token_filters)
9761 {
9762   MRN_DBUG_ENTER_METHOD();
9763   bool found = false;
9764 
9765 #ifdef MRN_SUPPORT_CUSTOM_OPTIONS
9766   if (key->option_struct->token_filters) {
9767     found = find_token_filters_fill(token_filters,
9768                                     key->option_struct->token_filters,
9769                                     strlen(key->option_struct->token_filters));
9770     DBUG_RETURN(found);
9771   }
9772 #endif
9773 
9774   if (key->comment.length > 0) {
9775     mrn::ParametersParser parser(key->comment.str,
9776                                  key->comment.length);
9777     parser.parse();
9778     const char *names = parser["token_filters"];
9779     if (names) {
9780       found = find_token_filters_fill(token_filters, names, strlen(names));
9781     }
9782   }
9783 
9784   DBUG_RETURN(found);
9785 }
9786 
find_token_filters_put(grn_obj * token_filters,const char * token_filter_name,int token_filter_name_length)9787 bool ha_mroonga::find_token_filters_put(grn_obj *token_filters,
9788                                         const char *token_filter_name,
9789                                         int token_filter_name_length)
9790 {
9791   grn_obj *token_filter;
9792 
9793   token_filter = grn_ctx_get(ctx,
9794                              token_filter_name,
9795                              token_filter_name_length);
9796   if (token_filter) {
9797     GRN_PTR_PUT(ctx, token_filters, token_filter);
9798     return true;
9799   } else {
9800     char message[MRN_BUFFER_SIZE];
9801     sprintf(message,
9802             "nonexistent token filter: <%.*s>",
9803             token_filter_name_length, token_filter_name);
9804     push_warning(ha_thd(),
9805                  MRN_SEVERITY_WARNING, ER_UNSUPPORTED_EXTENSION,
9806                  message);
9807     return false;
9808   }
9809 }
9810 
find_token_filters_fill(grn_obj * token_filters,const char * token_filter_names,int token_filter_names_length)9811 bool ha_mroonga::find_token_filters_fill(grn_obj *token_filters,
9812                                          const char *token_filter_names,
9813                                          int token_filter_names_length)
9814 {
9815   const char *start, *current, *end;
9816   const char *name_start, *name_end;
9817   const char *last_name_end;
9818 
9819   start = token_filter_names;
9820   end = start + token_filter_names_length;
9821   current = start;
9822   name_start = NULL;
9823   name_end = NULL;
9824   last_name_end = start;
9825   while (current < end) {
9826     switch (current[0]) {
9827     case ' ' :
9828       if (name_start && !name_end) {
9829         name_end = current;
9830       }
9831       break;
9832     case ',' :
9833       if (!name_start) {
9834         goto break_loop;
9835       }
9836       if (!name_end) {
9837         name_end = current;
9838       }
9839       find_token_filters_put(token_filters,
9840                              name_start,
9841                              name_end - name_start);
9842       last_name_end = name_end + 1;
9843       name_start = NULL;
9844       name_end = NULL;
9845       break;
9846     default :
9847       if (!name_start) {
9848         name_start = current;
9849       }
9850       break;
9851     }
9852     current++;
9853   }
9854 
9855 break_loop:
9856   if (!name_start) {
9857     char message[MRN_BUFFER_SIZE];
9858     sprintf(message,
9859             "empty token filter name: "
9860             "<%.*s|%.*s|%.*s>",
9861             (int)(last_name_end - start), start,
9862             (int)(current - last_name_end), last_name_end,
9863             (int)(end - current), current);
9864     push_warning(ha_thd(),
9865                  MRN_SEVERITY_WARNING, ER_UNSUPPORTED_EXTENSION,
9866                  message);
9867     return false;
9868   }
9869 
9870   if (!name_end) {
9871     name_end = current;
9872   }
9873   find_token_filters_put(token_filters,
9874                          name_start,
9875                          name_end - name_start);
9876 
9877   return true;
9878 }
9879 
wrapper_get_record(uchar * buf,const uchar * key)9880 int ha_mroonga::wrapper_get_record(uchar *buf, const uchar *key)
9881 {
9882   MRN_DBUG_ENTER_METHOD();
9883 
9884   int error = 0;
9885   MRN_SET_WRAP_SHARE_KEY(share, table->s);
9886   MRN_SET_WRAP_TABLE_KEY(this, table);
9887   if (wrap_handler->inited == NONE) {
9888 #ifdef MRN_HANDLER_HAVE_HA_INDEX_READ_IDX_MAP
9889     error = wrap_handler->ha_index_read_idx_map(buf,
9890                                                 share->wrap_primary_key,
9891                                                 key,
9892                                                 pk_keypart_map,
9893                                                 HA_READ_KEY_EXACT);
9894 #else
9895     error = wrap_handler->index_read_idx_map(buf,
9896                                              share->wrap_primary_key,
9897                                              key,
9898                                              pk_keypart_map,
9899                                              HA_READ_KEY_EXACT);
9900 #endif
9901   } else {
9902 #ifdef MRN_HANDLER_HAVE_HA_INDEX_READ_MAP
9903     error = wrap_handler->ha_index_read_map(buf,
9904                                             key,
9905                                             pk_keypart_map,
9906                                             HA_READ_KEY_EXACT);
9907 #else
9908     error = wrap_handler->index_read_map(buf,
9909                                          key,
9910                                          pk_keypart_map,
9911                                          HA_READ_KEY_EXACT);
9912 #endif
9913   }
9914   MRN_SET_BASE_SHARE_KEY(share, table->s);
9915   MRN_SET_BASE_TABLE_KEY(this, table);
9916 
9917   DBUG_RETURN(error);
9918 }
9919 
wrapper_get_next_geo_record(uchar * buf)9920 int ha_mroonga::wrapper_get_next_geo_record(uchar *buf)
9921 {
9922   MRN_DBUG_ENTER_METHOD();
9923   int error = 0;
9924   mrn_change_encoding(ctx, NULL);
9925   do {
9926     GRN_BULK_REWIND(&key_buffer);
9927     grn_id found_record_id;
9928     grn_posting *posting;
9929     posting = grn_geo_cursor_next(ctx, cursor_geo);
9930     if (!posting) {
9931       error = HA_ERR_END_OF_FILE;
9932       clear_cursor_geo();
9933       break;
9934     }
9935     found_record_id = posting->rid;
9936     grn_table_get_key(ctx, grn_table, found_record_id,
9937                       GRN_TEXT_VALUE(&key_buffer),
9938                       table->key_info->key_length);
9939     error = wrapper_get_record(buf, (const uchar *)GRN_TEXT_VALUE(&key_buffer));
9940   } while (error == HA_ERR_END_OF_FILE || error == HA_ERR_KEY_NOT_FOUND);
9941   DBUG_RETURN(error);
9942 }
9943 
storage_get_next_record(uchar * buf)9944 int ha_mroonga::storage_get_next_record(uchar *buf)
9945 {
9946   MRN_DBUG_ENTER_METHOD();
9947   if (cursor_geo) {
9948     grn_posting *posting;
9949     posting = grn_geo_cursor_next(ctx, cursor_geo);
9950     if (posting) {
9951       record_id = posting->rid;
9952     } else {
9953       record_id = GRN_ID_NIL;
9954     }
9955   } else if (cursor) {
9956     record_id = grn_table_cursor_next(ctx, cursor);
9957   } else if (empty_value_records_cursor) {
9958     grn_id empty_value_record_id;
9959     empty_value_record_id =
9960       grn_table_cursor_next(ctx, empty_value_records_cursor);
9961     if (empty_value_record_id == GRN_ID_NIL) {
9962       record_id = GRN_ID_NIL;
9963     } else {
9964       grn_table_get_key(ctx, empty_value_records, empty_value_record_id,
9965                         &record_id, sizeof(grn_id));
9966     }
9967   } else {
9968     record_id = GRN_ID_NIL;
9969   }
9970   if (ctx->rc) {
9971     int error = ER_ERROR_ON_READ;
9972     my_message(error, ctx->errbuf, MYF(0));
9973     DBUG_RETURN(error);
9974   }
9975   if (record_id == GRN_ID_NIL) {
9976     DBUG_PRINT("info", ("mroonga: storage_get_next_record: end-of-file"));
9977     table->status = STATUS_NOT_FOUND;
9978     DBUG_RETURN(HA_ERR_END_OF_FILE);
9979   }
9980   if (buf) {
9981     if (ignoring_no_key_columns)
9982       storage_store_fields_by_index(buf);
9983     else
9984       storage_store_fields(buf, record_id);
9985     if (cursor_geo && grn_source_column_geo) {
9986       int latitude, longitude;
9987       GRN_GEO_POINT_VALUE(&source_point, latitude, longitude);
9988       double latitude_in_degree = GRN_GEO_MSEC2DEGREE(latitude);
9989       double longitude_in_degree = GRN_GEO_MSEC2DEGREE(longitude);
9990       if (!((bottom_right_latitude_in_degree <= latitude_in_degree &&
9991              latitude_in_degree <= top_left_latitude_in_degree) &&
9992             (top_left_longitude_in_degree <= longitude_in_degree &&
9993              longitude_in_degree <= bottom_right_longitude_in_degree))) {
9994         DBUG_PRINT("info",
9995                    ("mroonga: remove not contained geo point: "
9996                     "<%g,%g>(<%d,%d>); key: <%g,%g>(<%d,%d>), <%g,%g>(<%d,%d>)",
9997                     latitude_in_degree, longitude_in_degree,
9998                     latitude, longitude,
9999                     top_left_latitude_in_degree, top_left_longitude_in_degree,
10000                     GRN_GEO_DEGREE2MSEC(top_left_latitude_in_degree),
10001                     GRN_GEO_DEGREE2MSEC(top_left_longitude_in_degree),
10002                     bottom_right_latitude_in_degree,
10003                     bottom_right_longitude_in_degree,
10004                     GRN_GEO_DEGREE2MSEC(bottom_right_latitude_in_degree),
10005                     GRN_GEO_DEGREE2MSEC(bottom_right_longitude_in_degree)));
10006         int error = storage_get_next_record(buf);
10007         DBUG_RETURN(error);
10008       }
10009     }
10010   }
10011   table->status = 0;
10012   DBUG_RETURN(0);
10013 }
10014 
geo_store_rectangle(const uchar * rectangle)10015 void ha_mroonga::geo_store_rectangle(const uchar *rectangle)
10016 {
10017   MRN_DBUG_ENTER_METHOD();
10018 
10019   double locations[4];
10020   for (int i = 0; i < 4; i++) {
10021     uchar reversed_value[8];
10022     for (int j = 0; j < 8; j++) {
10023       reversed_value[j] = (rectangle + (8 * i))[7 - j];
10024     }
10025     mi_float8get(locations[i], reversed_value);
10026   }
10027   top_left_longitude_in_degree = locations[0];
10028   bottom_right_longitude_in_degree = locations[1];
10029   bottom_right_latitude_in_degree = locations[2];
10030   top_left_latitude_in_degree = locations[3];
10031   int top_left_latitude = GRN_GEO_DEGREE2MSEC(top_left_latitude_in_degree);
10032   int top_left_longitude = GRN_GEO_DEGREE2MSEC(top_left_longitude_in_degree);
10033   int bottom_right_latitude = GRN_GEO_DEGREE2MSEC(bottom_right_latitude_in_degree);
10034   int bottom_right_longitude = GRN_GEO_DEGREE2MSEC(bottom_right_longitude_in_degree);
10035   GRN_GEO_POINT_SET(ctx, &top_left_point,
10036                     top_left_latitude, top_left_longitude);
10037   GRN_GEO_POINT_SET(ctx, &bottom_right_point,
10038                     bottom_right_latitude, bottom_right_longitude);
10039 
10040   DBUG_VOID_RETURN;
10041 }
10042 
generic_geo_open_cursor(const uchar * key,enum ha_rkey_function find_flag)10043 int ha_mroonga::generic_geo_open_cursor(const uchar *key,
10044                                         enum ha_rkey_function find_flag)
10045 {
10046   MRN_DBUG_ENTER_METHOD();
10047   int error = 0;
10048   int flags = 0;
10049   if (find_flag & HA_READ_MBR_CONTAIN) {
10050     grn_obj *index = grn_index_columns[active_index];
10051     geo_store_rectangle(key);
10052     cursor_geo = grn_geo_cursor_open_in_rectangle(ctx,
10053                                                   index,
10054                                                   &top_left_point,
10055                                                   &bottom_right_point,
10056                                                   0, -1);
10057     if (cursor_geo) {
10058       if (grn_source_column_geo) {
10059         grn_obj_unlink(ctx, grn_source_column_geo);
10060       }
10061       grn_obj sources;
10062       GRN_OBJ_INIT(&sources, GRN_BULK, 0, GRN_ID_NIL);
10063       grn_obj_get_info(ctx, index, GRN_INFO_SOURCE, &sources);
10064       grn_source_column_geo = grn_ctx_at(ctx, GRN_RECORD_VALUE(&sources));
10065       grn_obj_unlink(ctx, &sources);
10066     }
10067   } else {
10068     push_warning_unsupported_spatial_index_search(find_flag);
10069     cursor = grn_table_cursor_open(ctx, grn_table, NULL, 0, NULL, 0,
10070                                    0, -1, flags);
10071   }
10072   if (ctx->rc) {
10073     error = ER_ERROR_ON_READ;
10074     my_message(error, ctx->errbuf, MYF(0));
10075   }
10076   DBUG_RETURN(error);
10077 }
10078 
is_dry_write()10079 bool ha_mroonga::is_dry_write()
10080 {
10081   MRN_DBUG_ENTER_METHOD();
10082   bool dry_write_p = THDVAR(ha_thd(), dry_write);
10083   DBUG_RETURN(dry_write_p);
10084 }
10085 
is_enable_optimization()10086 bool ha_mroonga::is_enable_optimization()
10087 {
10088   MRN_DBUG_ENTER_METHOD();
10089   bool enable_optimization_p = THDVAR(ha_thd(), enable_optimization);
10090   DBUG_RETURN(enable_optimization_p);
10091 }
10092 
should_normalize(Field * field) const10093 bool ha_mroonga::should_normalize(Field *field) const
10094 {
10095   MRN_DBUG_ENTER_METHOD();
10096   mrn::FieldNormalizer field_normalizer(ctx, ha_thd(), field);
10097   bool need_normalize_p = field_normalizer.should_normalize();
10098   DBUG_RETURN(need_normalize_p);
10099 }
10100 
check_count_skip(key_part_map target_key_part_map)10101 void ha_mroonga::check_count_skip(key_part_map target_key_part_map)
10102 {
10103   MRN_DBUG_ENTER_METHOD();
10104 
10105   if (!is_enable_optimization()) {
10106     GRN_LOG(ctx, GRN_LOG_DEBUG,
10107             "[mroonga][count-skip][false] optimization is disabled");
10108     count_skip = false;
10109     DBUG_VOID_RETURN;
10110   }
10111 
10112   if (thd_sql_command(ha_thd()) != SQLCOM_SELECT) {
10113     GRN_LOG(ctx, GRN_LOG_DEBUG,
10114             "[mroonga][count-skip][false] not SELECT");
10115     count_skip = false;
10116     DBUG_VOID_RETURN;
10117   }
10118 
10119   if (share->wrapper_mode &&
10120       !(wrap_handler->ha_table_flags() & HA_NO_TRANSACTIONS)) {
10121     GRN_LOG(ctx, GRN_LOG_DEBUG,
10122             "[mroonga][count-skip][false] wrapped engine is transactional");
10123     count_skip = false;
10124     DBUG_VOID_RETURN;
10125   }
10126 
10127   st_select_lex *select_lex = table->pos_in_table_list->select_lex;
10128   KEY *key_info = NULL;
10129   if (active_index != MAX_KEY) {
10130     key_info = &(table->key_info[active_index]);
10131   }
10132   mrn::CountSkipChecker checker(ctx,
10133                                 table,
10134                                 select_lex,
10135                                 key_info,
10136                                 target_key_part_map,
10137                                 !share->wrapper_mode);
10138   if (checker.check()) {
10139     count_skip = true;
10140     mrn_count_skip++;
10141     DBUG_VOID_RETURN;
10142   } else {
10143     count_skip = false;
10144     DBUG_VOID_RETURN;
10145   }
10146 }
10147 
is_grn_zero_column_value(grn_obj * column,grn_obj * value)10148 bool ha_mroonga::is_grn_zero_column_value(grn_obj *column, grn_obj *value)
10149 {
10150   MRN_DBUG_ENTER_METHOD();
10151 
10152   if (column->header.type != GRN_COLUMN_FIX_SIZE) {
10153     DBUG_RETURN(false);
10154   }
10155 
10156   char *bytes = GRN_BULK_HEAD(value);
10157   unsigned int size = GRN_BULK_VSIZE(value);
10158   for (unsigned int i = 0; i < size; ++i) {
10159     if (bytes[i] != '\0') {
10160       DBUG_RETURN(false);
10161     }
10162   }
10163 
10164   DBUG_RETURN(true);
10165 }
10166 
is_primary_key_field(Field * field) const10167 bool ha_mroonga::is_primary_key_field(Field *field) const
10168 {
10169   MRN_DBUG_ENTER_METHOD();
10170 
10171   if (table->s->primary_key == MAX_INDEXES) {
10172     DBUG_RETURN(false);
10173   }
10174 
10175   KEY *key_info = &(table->s->key_info[table->s->primary_key]);
10176   if (KEY_N_KEY_PARTS(key_info) != 1) {
10177     DBUG_RETURN(false);
10178   }
10179 
10180   if (strcmp(field->field_name.str,
10181              key_info->key_part[0].field->field_name.str) == 0) {
10182     DBUG_RETURN(true);
10183   } else {
10184     DBUG_RETURN(false);
10185   }
10186 }
10187 
check_fast_order_limit(grn_table_sort_key ** sort_keys,int * n_sort_keys,longlong * limit)10188 void ha_mroonga::check_fast_order_limit(grn_table_sort_key **sort_keys,
10189                                         int *n_sort_keys,
10190                                         longlong *limit)
10191 {
10192   MRN_DBUG_ENTER_METHOD();
10193 
10194   if (!is_enable_optimization()) {
10195     DBUG_PRINT("info", ("mroonga: fast order limit: optimization is disabled"));
10196     fast_order_limit = false;
10197     DBUG_VOID_RETURN;
10198   }
10199 
10200   TABLE_LIST *table_list = table->pos_in_table_list;
10201   st_select_lex *select_lex = table_list->select_lex;
10202   SELECT_LEX_UNIT *unit = MRN_TABLE_LIST_GET_DERIVED(table_list);
10203   st_select_lex *first_select_lex;
10204   if (unit)
10205   {
10206     first_select_lex = unit->first_select();
10207   } else {
10208     first_select_lex = select_lex;
10209   }
10210   DBUG_PRINT("info",
10211     ("mroonga: first_select_lex->options=%llu",
10212      first_select_lex ? MRN_SELECT_LEX_GET_ACTIVE_OPTIONS(first_select_lex) : 0));
10213 
10214   if (
10215     thd_sql_command(ha_thd()) == SQLCOM_SELECT &&
10216     !select_lex->with_sum_func &&
10217     !select_lex->group_list.elements &&
10218     !MRN_SELECT_LEX_GET_HAVING_COND(select_lex) &&
10219     select_lex->table_list.elements == 1 &&
10220     select_lex->order_list.elements &&
10221     select_lex->explicit_limit &&
10222     select_lex->select_limit &&
10223     select_lex->select_limit->val_int() > 0
10224   ) {
10225     if (select_lex->offset_limit) {
10226       *limit = select_lex->offset_limit->val_int();
10227     } else {
10228       *limit = 0;
10229     }
10230     *limit += select_lex->select_limit->val_int();
10231     if (*limit > (longlong)INT_MAX) {
10232       DBUG_PRINT("info",
10233                  ("mroonga: fast_order_limit = false: "
10234                   "too long limit: %lld <= %d is required",
10235                   *limit, INT_MAX));
10236       fast_order_limit = false;
10237       DBUG_VOID_RETURN;
10238     }
10239     if (first_select_lex &&
10240         (MRN_SELECT_LEX_GET_ACTIVE_OPTIONS(first_select_lex) & OPTION_FOUND_ROWS)) {
10241       DBUG_PRINT("info",
10242                  ("mroonga: fast_order_limit = false: "
10243                   "SQL_CALC_FOUND_ROWS is specified"));
10244       fast_order_limit = false;
10245       DBUG_VOID_RETURN;
10246     }
10247     bool is_storage_mode = !(share->wrapper_mode);
10248     Item *where = MRN_SELECT_LEX_GET_WHERE_COND(select_lex);
10249     const Item_func *match_against = NULL;
10250     if (where) {
10251       mrn::ConditionConverter converter(ctx, grn_table, is_storage_mode);
10252       if (!converter.is_convertable(where)) {
10253         DBUG_PRINT("info",
10254                    ("mroonga: fast_order_limit = false: "
10255                     "not Groonga layer condition search"));
10256         fast_order_limit = false;
10257         DBUG_VOID_RETURN;
10258       }
10259       unsigned int n_match_againsts = converter.count_match_against(where);
10260       if (n_match_againsts == 0) {
10261         DBUG_PRINT("info",
10262                    ("mroonga: fast_order_limit = false: "
10263                     "Groonga layer condition but not fulltext search"));
10264         fast_order_limit = false;
10265         DBUG_VOID_RETURN;
10266       }
10267       if (n_match_againsts > 1) {
10268         DBUG_PRINT("info",
10269                    ("mroonga: fast_order_limit = false: "
10270                     "MATCH AGAINST must be only one"));
10271         fast_order_limit = false;
10272         DBUG_VOID_RETURN;
10273       }
10274     }
10275     int n_max_sort_keys = select_lex->order_list.elements;
10276     *n_sort_keys = 0;
10277     size_t sort_keys_size = sizeof(grn_table_sort_key) * n_max_sort_keys;
10278     *sort_keys = (grn_table_sort_key *)mrn_my_malloc(sort_keys_size,
10279                                                      MYF(MY_WME));
10280     memset(*sort_keys, 0, sort_keys_size);
10281     ORDER *order;
10282     int i;
10283     mrn_change_encoding(ctx, system_charset_info);
10284     for (order = (ORDER *) select_lex->order_list.first, i = 0;
10285          order;
10286          order = order->next, i++) {
10287       Item *item = *order->item;
10288       if (item->type() == Item::FIELD_ITEM)
10289       {
10290         Field *field = static_cast<Item_field *>(item)->field;
10291         mrn::ColumnName column_name(field->field_name);
10292 
10293         if (should_normalize(field))
10294         {
10295           DBUG_PRINT("info", ("mroonga: fast_order_limit = false: "
10296                               "sort by collated value isn't supported yet."));
10297           fast_order_limit = false;
10298           my_free(*sort_keys);
10299           *sort_keys = NULL;
10300           *n_sort_keys = 0;
10301           DBUG_VOID_RETURN;
10302         }
10303 
10304         if (is_storage_mode) {
10305           (*sort_keys)[i].key = grn_obj_column(ctx, matched_record_keys,
10306                                                column_name.c_str(),
10307                                                column_name.length());
10308         } else {
10309           if (is_primary_key_field(field)) {
10310             (*sort_keys)[i].key = grn_obj_column(ctx, matched_record_keys,
10311                                                  MRN_COLUMN_NAME_KEY,
10312                                                  strlen(MRN_COLUMN_NAME_KEY));
10313           } else {
10314             DBUG_PRINT("info", ("mroonga: fast_order_limit = false: "
10315                                 "sort by not primary key value "
10316                                 "isn't supported in wrapper mode."));
10317             fast_order_limit = false;
10318             my_free(*sort_keys);
10319             *sort_keys = NULL;
10320             *n_sort_keys = 0;
10321             DBUG_VOID_RETURN;
10322           }
10323         }
10324       } else if (!match_against || match_against->eq(item, true)) {
10325         (*sort_keys)[i].key = grn_obj_column(ctx, matched_record_keys,
10326                                              MRN_COLUMN_NAME_SCORE,
10327                                              strlen(MRN_COLUMN_NAME_SCORE));
10328       } else {
10329         DBUG_PRINT("info", ("mroonga: fast_order_limit = false: "
10330                             "sort by computed value isn't supported."));
10331         fast_order_limit = false;
10332         my_free(*sort_keys);
10333         *sort_keys = NULL;
10334         *n_sort_keys = 0;
10335         DBUG_VOID_RETURN;
10336       }
10337       (*sort_keys)[i].offset = 0;
10338       if (MRN_ORDER_IS_ASC(order))
10339       {
10340         (*sort_keys)[i].flags = GRN_TABLE_SORT_ASC;
10341       } else {
10342         (*sort_keys)[i].flags = GRN_TABLE_SORT_DESC;
10343       }
10344       (*n_sort_keys)++;
10345     }
10346     DBUG_PRINT("info", ("mroonga: fast_order_limit = true"));
10347     fast_order_limit = true;
10348     mrn_fast_order_limit++;
10349     DBUG_VOID_RETURN;
10350   }
10351   DBUG_PRINT("info", ("mroonga: fast_order_limit = false"));
10352   fast_order_limit = false;
10353   DBUG_VOID_RETURN;
10354 }
10355 
generic_store_bulk_fixed_size_string(Field * field,grn_obj * buf)10356 int ha_mroonga::generic_store_bulk_fixed_size_string(Field *field, grn_obj *buf)
10357 {
10358   MRN_DBUG_ENTER_METHOD();
10359   int error = 0;
10360   grn_obj_reinit(ctx, buf, GRN_DB_SHORT_TEXT, 0);
10361   GRN_TEXT_SET(ctx, buf, field->ptr, field->field_length);
10362   DBUG_RETURN(error);
10363 }
10364 
generic_store_bulk_variable_size_string(Field * field,grn_obj * buf)10365 int ha_mroonga::generic_store_bulk_variable_size_string(Field *field,
10366                                                         grn_obj *buf)
10367 {
10368   MRN_DBUG_ENTER_METHOD();
10369   int error = 0;
10370   String value;
10371   field->val_str(NULL, &value);
10372   grn_obj_reinit(ctx, buf, GRN_DB_SHORT_TEXT, 0);
10373   DBUG_PRINT("info", ("mroonga: length=%" MRN_FORMAT_STRING_LENGTH,
10374                       value.length()));
10375   DBUG_PRINT("info", ("mroonga: value=%s", value.c_ptr_safe()));
10376   GRN_TEXT_SET(ctx, buf, value.ptr(), value.length());
10377   DBUG_RETURN(error);
10378 }
10379 
generic_store_bulk_integer(Field * field,grn_obj * buf)10380 int ha_mroonga::generic_store_bulk_integer(Field *field, grn_obj *buf)
10381 {
10382   MRN_DBUG_ENTER_METHOD();
10383   int error = 0;
10384   long long value = field->val_int();
10385   DBUG_PRINT("info", ("mroonga: value=%lld", value));
10386   uint32 size = field->pack_length();
10387   DBUG_PRINT("info", ("mroonga: size=%u", size));
10388   Field_num *field_num = static_cast<Field_num *>(field);
10389   bool is_unsigned = field_num->unsigned_flag;
10390   DBUG_PRINT("info", ("mroonga: is_unsigned=%s", is_unsigned ? "true" : "false"));
10391   switch (size) {
10392   case 1:
10393     if (is_unsigned) {
10394       grn_obj_reinit(ctx, buf, GRN_DB_UINT8, 0);
10395       GRN_UINT8_SET(ctx, buf, value);
10396     } else {
10397       grn_obj_reinit(ctx, buf, GRN_DB_INT8, 0);
10398       GRN_INT8_SET(ctx, buf, value);
10399     }
10400     break;
10401   case 2:
10402     if (is_unsigned) {
10403       grn_obj_reinit(ctx, buf, GRN_DB_UINT16, 0);
10404       GRN_UINT16_SET(ctx, buf, value);
10405     } else {
10406       grn_obj_reinit(ctx, buf, GRN_DB_INT16, 0);
10407       GRN_INT16_SET(ctx, buf, value);
10408     }
10409     break;
10410   case 3:
10411   case 4:
10412     if (is_unsigned) {
10413       grn_obj_reinit(ctx, buf, GRN_DB_UINT32, 0);
10414       GRN_UINT32_SET(ctx, buf, value);
10415     } else {
10416       grn_obj_reinit(ctx, buf, GRN_DB_INT32, 0);
10417       GRN_INT32_SET(ctx, buf, value);
10418     }
10419     break;
10420   case 8:
10421     if (is_unsigned) {
10422       grn_obj_reinit(ctx, buf, GRN_DB_UINT64, 0);
10423       GRN_UINT64_SET(ctx, buf, value);
10424     } else {
10425       grn_obj_reinit(ctx, buf, GRN_DB_INT64, 0);
10426       GRN_INT64_SET(ctx, buf, value);
10427     }
10428     break;
10429   default:
10430     // Why!?
10431     error = HA_ERR_UNSUPPORTED;
10432     char error_message[MRN_MESSAGE_BUFFER_SIZE];
10433     snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
10434              "unknown integer value size: <%u>: "
10435              "available sizes: [1, 2, 3, 4, 8]",
10436              size);
10437     push_warning(ha_thd(), MRN_SEVERITY_WARNING,
10438                  error, error_message);
10439     break;
10440   }
10441   DBUG_RETURN(error);
10442 }
10443 
generic_store_bulk_unsigned_integer(Field * field,grn_obj * buf)10444 int ha_mroonga::generic_store_bulk_unsigned_integer(Field *field, grn_obj *buf)
10445 {
10446   MRN_DBUG_ENTER_METHOD();
10447   int error = 0;
10448   long long signed_value = field->val_int();
10449   unsigned long long unsigned_value = *((unsigned long long *)(&signed_value));
10450   uint32 size = field->pack_length();
10451   switch (size) {
10452   case 1:
10453     grn_obj_reinit(ctx, buf, GRN_DB_UINT8, 0);
10454     GRN_UINT8_SET(ctx, buf, unsigned_value);
10455     break;
10456   case 2:
10457     grn_obj_reinit(ctx, buf, GRN_DB_UINT16, 0);
10458     GRN_UINT16_SET(ctx, buf, unsigned_value);
10459     break;
10460   case 3:
10461   case 4:
10462     grn_obj_reinit(ctx, buf, GRN_DB_UINT32, 0);
10463     GRN_UINT32_SET(ctx, buf, unsigned_value);
10464     break;
10465   case 8:
10466     grn_obj_reinit(ctx, buf, GRN_DB_UINT64, 0);
10467     GRN_UINT64_SET(ctx, buf, unsigned_value);
10468     break;
10469   default:
10470     // Why!?
10471     error = HA_ERR_UNSUPPORTED;
10472     char error_message[MRN_MESSAGE_BUFFER_SIZE];
10473     snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
10474              "unknown unsigned integer value size: <%u>: "
10475              "available sizes: [1, 2, 3, 4, 8]",
10476              size);
10477     push_warning(ha_thd(), MRN_SEVERITY_WARNING,
10478                  error, error_message);
10479     break;
10480   }
10481   DBUG_RETURN(error);
10482 }
10483 
generic_store_bulk_float(Field * field,grn_obj * buf)10484 int ha_mroonga::generic_store_bulk_float(Field *field, grn_obj *buf)
10485 {
10486   MRN_DBUG_ENTER_METHOD();
10487   int error = 0;
10488   double value = field->val_real();
10489   uint32 size = field->pack_length();
10490   switch (size) {
10491   case 4:
10492   case 8:
10493     grn_obj_reinit(ctx, buf, GRN_DB_FLOAT, 0);
10494     GRN_FLOAT_SET(ctx, buf, value);
10495     break;
10496   default:
10497     // Why!?
10498     error = HA_ERR_UNSUPPORTED;
10499     char error_message[MRN_MESSAGE_BUFFER_SIZE];
10500     snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
10501              "unknown float value size: <%u>: "
10502              "available sizes: [4, 8]",
10503              size);
10504     push_warning(ha_thd(), MRN_SEVERITY_WARNING,
10505                  error, error_message);
10506     break;
10507   }
10508   DBUG_RETURN(error);
10509 }
10510 
get_grn_time_from_timestamp_field(Field_timestamp * field)10511 long long int ha_mroonga::get_grn_time_from_timestamp_field(Field_timestamp *field)
10512 {
10513   MRN_DBUG_ENTER_METHOD();
10514   long long int grn_time = 0;
10515 #ifdef MRN_TIMESTAMP_USE_TIMEVAL
10516   int warnings = 0;
10517   struct timeval time_value;
10518   if (field->get_timestamp(&time_value, &warnings)) {
10519     // XXX: Should we report warnings or MySQL does?
10520   } else {
10521     DBUG_PRINT("info", ("mroonga: timeval tv_sec=%ld", time_value.tv_sec));
10522     grn_time = GRN_TIME_PACK(time_value.tv_sec, time_value.tv_usec);
10523   }
10524 #elif defined(MRN_TIMESTAMP_USE_MY_TIME_T)
10525   unsigned long int micro_seconds;
10526   my_time_t seconds = field->get_timestamp(&micro_seconds);
10527   DBUG_PRINT("info", ("mroonga: my_time_t seconds=%ld", seconds));
10528   grn_time = GRN_TIME_PACK(seconds, micro_seconds);
10529 #else
10530   my_bool is_null_value;
10531   long seconds = field->get_timestamp(&is_null_value);
10532   DBUG_PRINT("info", ("mroonga: long seconds=%ld", seconds));
10533   grn_time = GRN_TIME_PACK(seconds, 0);
10534 #endif
10535   DBUG_RETURN(grn_time);
10536 }
10537 
generic_store_bulk_timestamp(Field * field,grn_obj * buf)10538 int ha_mroonga::generic_store_bulk_timestamp(Field *field, grn_obj *buf)
10539 {
10540   MRN_DBUG_ENTER_METHOD();
10541   int error = 0;
10542   Field_timestamp *timestamp_field = (Field_timestamp *)field;
10543   long long int time = get_grn_time_from_timestamp_field(timestamp_field);
10544   grn_obj_reinit(ctx, buf, GRN_DB_TIME, 0);
10545   GRN_TIME_SET(ctx, buf, time);
10546   DBUG_RETURN(error);
10547 }
10548 
generic_store_bulk_date(Field * field,grn_obj * buf)10549 int ha_mroonga::generic_store_bulk_date(Field *field, grn_obj *buf)
10550 {
10551   MRN_DBUG_ENTER_METHOD();
10552   int error = 0;
10553   bool truncated = false;
10554   long long int date_value = field->val_int();
10555   struct tm date;
10556   memset(&date, 0, sizeof(struct tm));
10557   date.tm_year = date_value / 10000 % 10000 - mrn::TimeConverter::TM_YEAR_BASE;
10558   date.tm_mon = date_value / 100 % 100 - 1;
10559   date.tm_mday = date_value % 100;
10560   int usec = 0;
10561   mrn::TimeConverter time_converter;
10562   long long int time = time_converter.tm_to_grn_time(&date, usec, &truncated);
10563   if (truncated) {
10564     field->set_warning(MRN_SEVERITY_WARNING,
10565                        WARN_DATA_TRUNCATED, 1);
10566   }
10567   grn_obj_reinit(ctx, buf, GRN_DB_TIME, 0);
10568   GRN_TIME_SET(ctx, buf, time);
10569   DBUG_RETURN(error);
10570 }
10571 
generic_store_bulk_time(Field * field,grn_obj * buf)10572 int ha_mroonga::generic_store_bulk_time(Field *field, grn_obj *buf)
10573 {
10574   MRN_DBUG_ENTER_METHOD();
10575   int error = 0;
10576   bool truncated = false;
10577   Field_time *time_field = (Field_time *)field;
10578   MYSQL_TIME mysql_time;
10579   time_field->get_time(&mysql_time);
10580   mrn::TimeConverter time_converter;
10581   long long int time = time_converter.mysql_time_to_grn_time(&mysql_time,
10582                                                              &truncated);
10583   if (truncated) {
10584     field->set_warning(MRN_SEVERITY_WARNING,
10585                        WARN_DATA_TRUNCATED, 1);
10586   }
10587   grn_obj_reinit(ctx, buf, GRN_DB_TIME, 0);
10588   GRN_TIME_SET(ctx, buf, time);
10589   DBUG_RETURN(error);
10590 }
10591 
generic_store_bulk_datetime(Field * field,grn_obj * buf)10592 int ha_mroonga::generic_store_bulk_datetime(Field *field, grn_obj *buf)
10593 {
10594   MRN_DBUG_ENTER_METHOD();
10595   int error = 0;
10596   bool truncated = false;
10597   Field_datetime *datetime_field = (Field_datetime *)field;
10598   MYSQL_TIME mysql_time;
10599   datetime_field->get_time(&mysql_time);
10600   mrn::TimeConverter time_converter;
10601   long long int time = time_converter.mysql_time_to_grn_time(&mysql_time,
10602                                                              &truncated);
10603   if (truncated) {
10604     if (MRN_ABORT_ON_WARNING(ha_thd())) {
10605       error = MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd());
10606     }
10607     field->set_warning(MRN_SEVERITY_WARNING,
10608                        MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd()),
10609                        1);
10610   }
10611   grn_obj_reinit(ctx, buf, GRN_DB_TIME, 0);
10612   GRN_TIME_SET(ctx, buf, time);
10613   DBUG_RETURN(error);
10614 }
10615 
generic_store_bulk_year(Field * field,grn_obj * buf)10616 int ha_mroonga::generic_store_bulk_year(Field *field, grn_obj *buf)
10617 {
10618   MRN_DBUG_ENTER_METHOD();
10619   int error = 0;
10620   bool truncated = false;
10621 
10622   int year;
10623   if (field->field_length == 2) {
10624     year = static_cast<int>(field->val_int() + 2000);
10625   } else {
10626     year = static_cast<int>(field->val_int());
10627   }
10628 
10629   DBUG_PRINT("info", ("mroonga: year=%d", year));
10630   struct tm date;
10631   memset(&date, 0, sizeof(struct tm));
10632   date.tm_year = year - mrn::TimeConverter::TM_YEAR_BASE;
10633   date.tm_mon = 0;
10634   date.tm_mday = 1;
10635 
10636   int usec = 0;
10637   mrn::TimeConverter time_converter;
10638   long long int time = time_converter.tm_to_grn_time(&date, usec, &truncated);
10639   if (truncated) {
10640     if (MRN_ABORT_ON_WARNING(ha_thd())) {
10641       error = MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd());
10642     }
10643     field->set_warning(MRN_SEVERITY_WARNING,
10644                        MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd()),
10645                        1);
10646   }
10647   grn_obj_reinit(ctx, buf, GRN_DB_TIME, 0);
10648   GRN_TIME_SET(ctx, buf, time);
10649   DBUG_RETURN(error);
10650 }
10651 
10652 #ifdef MRN_HAVE_MYSQL_TYPE_DATETIME2
generic_store_bulk_datetime2(Field * field,grn_obj * buf)10653 int ha_mroonga::generic_store_bulk_datetime2(Field *field, grn_obj *buf)
10654 {
10655   MRN_DBUG_ENTER_METHOD();
10656   int error = 0;
10657   bool truncated = false;
10658   Field_datetimef *datetimef_field = (Field_datetimef *)field;
10659   MYSQL_TIME mysql_time;
10660   datetimef_field->get_time(&mysql_time);
10661   mrn::TimeConverter time_converter;
10662   long long int time = time_converter.mysql_time_to_grn_time(&mysql_time,
10663                                                              &truncated);
10664   if (truncated) {
10665     if (MRN_ABORT_ON_WARNING(ha_thd())) {
10666       error = MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd());
10667     }
10668     field->set_warning(MRN_SEVERITY_WARNING,
10669                        MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd()),
10670                        1);
10671   }
10672   grn_obj_reinit(ctx, buf, GRN_DB_TIME, 0);
10673   GRN_TIME_SET(ctx, buf, time);
10674   DBUG_RETURN(error);
10675 }
10676 #endif
10677 
10678 #ifdef MRN_HAVE_MYSQL_TYPE_TIME2
generic_store_bulk_time2(Field * field,grn_obj * buf)10679 int ha_mroonga::generic_store_bulk_time2(Field *field, grn_obj *buf)
10680 {
10681   MRN_DBUG_ENTER_METHOD();
10682   int error = 0;
10683   bool truncated = false;
10684   MYSQL_TIME mysql_time;
10685   field->get_time(&mysql_time);
10686   mrn::TimeConverter time_converter;
10687   long long int time = time_converter.mysql_time_to_grn_time(&mysql_time,
10688                                                              &truncated);
10689   if (truncated) {
10690     if (MRN_ABORT_ON_WARNING(ha_thd())) {
10691       error = MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd());
10692     }
10693     field->set_warning(MRN_SEVERITY_WARNING,
10694                        MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd()),
10695                        1);
10696   }
10697   grn_obj_reinit(ctx, buf, GRN_DB_TIME, 0);
10698   GRN_TIME_SET(ctx, buf, time);
10699   DBUG_RETURN(error);
10700 }
10701 #endif
10702 
generic_store_bulk_new_date(Field * field,grn_obj * buf)10703 int ha_mroonga::generic_store_bulk_new_date(Field *field, grn_obj *buf)
10704 {
10705   MRN_DBUG_ENTER_METHOD();
10706   int error = 0;
10707   bool truncated = false;
10708   Field_newdate *newdate_field = (Field_newdate *)field;
10709   MYSQL_TIME mysql_date;
10710   newdate_field->get_time(&mysql_date);
10711   mrn::TimeConverter time_converter;
10712   long long int time = time_converter.mysql_time_to_grn_time(&mysql_date,
10713                                                              &truncated);
10714   if (truncated) {
10715     if (MRN_ABORT_ON_WARNING(ha_thd())) {
10716       error = MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd());
10717     }
10718     field->set_warning(MRN_SEVERITY_WARNING,
10719                        MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd()),
10720                        1);
10721   }
10722   grn_obj_reinit(ctx, buf, GRN_DB_TIME, 0);
10723   GRN_TIME_SET(ctx, buf, time);
10724   DBUG_RETURN(error);
10725 }
10726 
generic_store_bulk_new_decimal(Field * field,grn_obj * buf)10727 int ha_mroonga::generic_store_bulk_new_decimal(Field *field, grn_obj *buf)
10728 {
10729   MRN_DBUG_ENTER_METHOD();
10730   int error = 0;
10731   String value;
10732   Field_new_decimal *new_decimal_field = (Field_new_decimal *)field;
10733   new_decimal_field->val_str(&value, NULL);
10734   grn_obj_reinit(ctx, buf, GRN_DB_SHORT_TEXT, 0);
10735   GRN_TEXT_SET(ctx, buf, value.ptr(), value.length());
10736   DBUG_RETURN(error);
10737 }
10738 
generic_store_bulk_blob(Field * field,grn_obj * buf)10739 int ha_mroonga::generic_store_bulk_blob(Field *field, grn_obj *buf)
10740 {
10741   MRN_DBUG_ENTER_METHOD();
10742   int error = 0;
10743   String buffer;
10744   Field_blob *blob = (Field_blob *)field;
10745   String *value = blob->val_str(0, &buffer);
10746   grn_obj_reinit(ctx, buf, GRN_DB_TEXT, 0);
10747   GRN_TEXT_SET(ctx, buf, value->ptr(), value->length());
10748   DBUG_RETURN(error);
10749 }
10750 
generic_store_bulk_geometry(Field * field,grn_obj * buf)10751 int ha_mroonga::generic_store_bulk_geometry(Field *field, grn_obj *buf)
10752 {
10753   MRN_DBUG_ENTER_METHOD();
10754   int error = 0;
10755 #ifdef MRN_HAVE_SPATIAL
10756   String buffer;
10757   Field_geom *geometry = (Field_geom *)field;
10758   String *value = geometry->val_str(0, &buffer);
10759   const char *wkb = value->ptr();
10760   int len = value->length();
10761   error = mrn_set_geometry(ctx, buf, wkb, len);
10762 #endif
10763   DBUG_RETURN(error);
10764 }
10765 
10766 #ifdef MRN_HAVE_MYSQL_TYPE_JSON
generic_store_bulk_json(Field * field,grn_obj * buf)10767 int ha_mroonga::generic_store_bulk_json(Field *field, grn_obj *buf)
10768 {
10769   MRN_DBUG_ENTER_METHOD();
10770   int error = 0;
10771   String buffer;
10772   Field_json *json = static_cast<Field_json *>(field);
10773   String *value = json->val_str(&buffer, NULL);
10774   grn_obj_reinit(ctx, buf, GRN_DB_TEXT, 0);
10775   GRN_TEXT_SET(ctx, buf, value->ptr(), value->length());
10776   DBUG_RETURN(error);
10777 }
10778 #endif
10779 
generic_store_bulk(Field * field,grn_obj * buf)10780 int ha_mroonga::generic_store_bulk(Field *field, grn_obj *buf)
10781 {
10782   MRN_DBUG_ENTER_METHOD();
10783   int error;
10784   error = mrn_change_encoding(ctx, field->charset());
10785   if (error)
10786     return error;
10787   switch (field->real_type()) {
10788   case MYSQL_TYPE_DECIMAL:
10789     error = generic_store_bulk_variable_size_string(field, buf);
10790     break;
10791   case MYSQL_TYPE_TINY:
10792   case MYSQL_TYPE_SHORT:
10793   case MYSQL_TYPE_LONG:
10794     error = generic_store_bulk_integer(field, buf);
10795     break;
10796   case MYSQL_TYPE_FLOAT:
10797   case MYSQL_TYPE_DOUBLE:
10798     error = generic_store_bulk_float(field, buf);
10799     break;
10800   case MYSQL_TYPE_NULL:
10801     error = generic_store_bulk_unsigned_integer(field, buf);
10802     break;
10803   case MYSQL_TYPE_TIMESTAMP:
10804     error = generic_store_bulk_timestamp(field, buf);
10805     break;
10806   case MYSQL_TYPE_LONGLONG:
10807   case MYSQL_TYPE_INT24:
10808     error = generic_store_bulk_integer(field, buf);
10809     break;
10810   case MYSQL_TYPE_DATE:
10811     error = generic_store_bulk_date(field, buf);
10812     break;
10813   case MYSQL_TYPE_TIME:
10814     error = generic_store_bulk_time(field, buf);
10815     break;
10816   case MYSQL_TYPE_DATETIME:
10817     error = generic_store_bulk_datetime(field, buf);
10818     break;
10819   case MYSQL_TYPE_YEAR:
10820     error = generic_store_bulk_year(field, buf);
10821     break;
10822   case MYSQL_TYPE_NEWDATE:
10823     error = generic_store_bulk_new_date(field, buf);
10824     break;
10825   case MYSQL_TYPE_VARCHAR:
10826     error = generic_store_bulk_variable_size_string(field, buf);
10827     break;
10828   case MYSQL_TYPE_BIT:
10829     error = generic_store_bulk_unsigned_integer(field, buf);
10830     break;
10831 #ifdef MRN_HAVE_MYSQL_TYPE_TIMESTAMP2
10832   case MYSQL_TYPE_TIMESTAMP2:
10833     error = generic_store_bulk_timestamp(field, buf);
10834     break;
10835 #endif
10836 #ifdef MRN_HAVE_MYSQL_TYPE_DATETIME2
10837   case MYSQL_TYPE_DATETIME2:
10838     error = generic_store_bulk_datetime2(field, buf);
10839     break;
10840 #endif
10841 #ifdef MRN_HAVE_MYSQL_TYPE_TIME2
10842   case MYSQL_TYPE_TIME2:
10843     error = generic_store_bulk_time2(field, buf);
10844     break;
10845 #endif
10846   case MYSQL_TYPE_NEWDECIMAL:
10847     error = generic_store_bulk_new_decimal(field, buf);
10848     break;
10849   case MYSQL_TYPE_ENUM:
10850     error = generic_store_bulk_unsigned_integer(field, buf);
10851     break;
10852   case MYSQL_TYPE_SET:
10853     error = generic_store_bulk_unsigned_integer(field, buf);
10854     break;
10855   case MYSQL_TYPE_TINY_BLOB:
10856   case MYSQL_TYPE_MEDIUM_BLOB:
10857   case MYSQL_TYPE_LONG_BLOB:
10858   case MYSQL_TYPE_BLOB:
10859     error = generic_store_bulk_blob(field, buf);
10860     break;
10861   case MYSQL_TYPE_VAR_STRING:
10862     error = generic_store_bulk_variable_size_string(field, buf);
10863     break;
10864   case MYSQL_TYPE_STRING:
10865     error = generic_store_bulk_fixed_size_string(field, buf);
10866     break;
10867   case MYSQL_TYPE_GEOMETRY:
10868     error = generic_store_bulk_geometry(field, buf);
10869     break;
10870 #ifdef MRN_HAVE_MYSQL_TYPE_JSON
10871   case MYSQL_TYPE_JSON:
10872     error = generic_store_bulk_json(field, buf);
10873     break;
10874 #endif
10875   default:
10876     error = HA_ERR_UNSUPPORTED;
10877     break;
10878   }
10879   DBUG_RETURN(error);
10880 }
10881 
storage_store_field_string(Field * field,const char * value,uint value_length)10882 void ha_mroonga::storage_store_field_string(Field *field,
10883                                             const char *value,
10884                                             uint value_length)
10885 {
10886   MRN_DBUG_ENTER_METHOD();
10887   field->store(value, value_length, field->charset());
10888   DBUG_VOID_RETURN;
10889 }
10890 
storage_store_field_integer(Field * field,const char * value,uint value_length)10891 void ha_mroonga::storage_store_field_integer(Field *field,
10892                                              const char *value,
10893                                              uint value_length)
10894 {
10895   MRN_DBUG_ENTER_METHOD();
10896   Field_num *field_num = static_cast<Field_num *>(field);
10897   bool is_unsigned = field_num->unsigned_flag;
10898   switch (value_length) {
10899   case 1:
10900     {
10901       if (is_unsigned) {
10902         unsigned char field_value;
10903         field_value = *((unsigned char *)value);
10904         field->store(field_value, is_unsigned);
10905       } else {
10906         signed char field_value;
10907         field_value = *((signed char *)value);
10908         field->store(field_value, is_unsigned);
10909       }
10910       break;
10911     }
10912   case 2:
10913     {
10914       if (is_unsigned) {
10915         unsigned short field_value;
10916         field_value = *((unsigned short *)value);
10917         field->store(field_value, is_unsigned);
10918       } else {
10919         short field_value;
10920         field_value = *((short *)value);
10921         field->store(field_value, is_unsigned);
10922       }
10923       break;
10924     }
10925   case 4:
10926     {
10927       if (is_unsigned) {
10928         unsigned int field_value;
10929         field_value = *((unsigned int *)value);
10930         field->store(field_value, is_unsigned);
10931       } else {
10932         int field_value;
10933         field_value = *((int *)value);
10934         field->store(field_value, is_unsigned);
10935       }
10936       break;
10937     }
10938   case 8:
10939     {
10940       if (is_unsigned) {
10941         unsigned long long int field_value;
10942         field_value = *((unsigned long long int *)value);
10943         DBUG_PRINT("info", ("mroonga: field_value=%llu", field_value));
10944         field->store(field_value, is_unsigned);
10945       } else {
10946         long long int field_value;
10947         field_value = *((long long int *)value);
10948         field->store(field_value, is_unsigned);
10949       }
10950       break;
10951     }
10952   default:
10953     {
10954       // Why!?
10955       char error_message[MRN_MESSAGE_BUFFER_SIZE];
10956       snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
10957                "unknown integer value size: <%d>: "
10958                "available sizes: [1, 2, 4, 8]",
10959                value_length);
10960       push_warning(ha_thd(), MRN_SEVERITY_WARNING,
10961                    HA_ERR_UNSUPPORTED, error_message);
10962       storage_store_field_string(field, value, value_length);
10963       break;
10964     }
10965   }
10966   DBUG_VOID_RETURN;
10967 }
10968 
storage_store_field_unsigned_integer(Field * field,const char * value,uint value_length)10969 void ha_mroonga::storage_store_field_unsigned_integer(Field *field,
10970                                                       const char *value,
10971                                                       uint value_length)
10972 {
10973   MRN_DBUG_ENTER_METHOD();
10974   switch (value_length) {
10975   case 1:
10976     {
10977       unsigned char field_value;
10978       field_value = *((unsigned char *)value);
10979       field->store(field_value, true);
10980       break;
10981     }
10982   case 2:
10983     {
10984       unsigned short field_value;
10985       field_value = *((unsigned short *)value);
10986       field->store(field_value, true);
10987       break;
10988     }
10989   case 4:
10990     {
10991       unsigned int field_value;
10992       field_value = *((unsigned int *)value);
10993       field->store(field_value, true);
10994       break;
10995     }
10996   case 8:
10997     {
10998       unsigned long long int field_value;
10999       field_value = *((unsigned long long int *)value);
11000       DBUG_PRINT("info", ("mroonga: field_value=%llu", field_value));
11001       field->store(field_value, true);
11002       break;
11003     }
11004   default:
11005     {
11006       // Why!?
11007       char error_message[MRN_MESSAGE_BUFFER_SIZE];
11008       snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
11009                "unknown integer value size: <%d>: "
11010                "available sizes: [1, 2, 4, 8]",
11011                value_length);
11012       push_warning(ha_thd(), MRN_SEVERITY_WARNING,
11013                    HA_ERR_UNSUPPORTED, error_message);
11014       storage_store_field_string(field, value, value_length);
11015       break;
11016     }
11017   }
11018   DBUG_VOID_RETURN;
11019 }
11020 
storage_store_field_float(Field * field,const char * value,uint value_length)11021 void ha_mroonga::storage_store_field_float(Field *field,
11022                                            const char *value,
11023                                            uint value_length)
11024 {
11025   MRN_DBUG_ENTER_METHOD();
11026   double field_value;
11027   field_value = *((double *)value);
11028   field->store(field_value);
11029   DBUG_VOID_RETURN;
11030 }
11031 
storage_store_field_timestamp(Field * field,const char * value,uint value_length)11032 void ha_mroonga::storage_store_field_timestamp(Field *field,
11033                                                const char *value,
11034                                                uint value_length)
11035 {
11036   MRN_DBUG_ENTER_METHOD();
11037   long long int time = *((long long int *)value);
11038   Field_timestamp *timestamp_field = (Field_timestamp *)field;
11039 #ifdef MRN_TIMESTAMP_USE_TIMEVAL
11040   struct timeval time_value;
11041   GRN_TIME_UNPACK(time, time_value.tv_sec, time_value.tv_usec);
11042   timestamp_field->store_timestamp(&time_value);
11043 #elif defined(MRN_TIMESTAMP_USE_MY_TIME_T)
11044   long long int sec, usec;
11045   GRN_TIME_UNPACK(time, sec, usec);
11046   timestamp_field->store_TIME(static_cast<int32>(sec),
11047                               static_cast<int32>(usec));
11048 #else
11049   int32 sec, usec __attribute__((unused));
11050   GRN_TIME_UNPACK(time, sec, usec);
11051   timestamp_field->store_timestamp(sec);
11052 #endif
11053   DBUG_VOID_RETURN;
11054 }
11055 
storage_store_field_date(Field * field,const char * value,uint value_length)11056 void ha_mroonga::storage_store_field_date(Field *field,
11057                                           const char *value,
11058                                           uint value_length)
11059 {
11060   MRN_DBUG_ENTER_METHOD();
11061   long long int time = *((long long int *)value);
11062   long long int sec, usec __attribute__((unused));
11063   GRN_TIME_UNPACK(time, sec, usec);
11064   struct tm date;
11065   time_t sec_t = static_cast<int32>(sec);
11066   gmtime_r(&sec_t, &date);
11067   long long int date_in_mysql =
11068     (date.tm_year + mrn::TimeConverter::TM_YEAR_BASE) * 10000 +
11069     (date.tm_mon + 1) * 100 +
11070     date.tm_mday;
11071   field->store(date_in_mysql, false);
11072   DBUG_VOID_RETURN;
11073 }
11074 
storage_store_field_time(Field * field,const char * value,uint value_length)11075 void ha_mroonga::storage_store_field_time(Field *field,
11076                                           const char *value,
11077                                           uint value_length)
11078 {
11079   MRN_DBUG_ENTER_METHOD();
11080   long long int time = *((long long int *)value);
11081   MYSQL_TIME mysql_time;
11082   memset(&mysql_time, 0, sizeof(MYSQL_TIME));
11083   mysql_time.time_type = MYSQL_TIMESTAMP_TIME;
11084   mrn::TimeConverter time_converter;
11085   time_converter.grn_time_to_mysql_time(time, &mysql_time);
11086 #ifdef MRN_FIELD_STORE_TIME_NEED_TYPE
11087   Field_time *time_field = (Field_time *)field;
11088   time_field->store_time(&mysql_time, mysql_time.time_type);
11089 #else
11090   field->store_time(&mysql_time);
11091 #endif
11092   DBUG_VOID_RETURN;
11093 }
11094 
storage_store_field_datetime(Field * field,const char * value,uint value_length)11095 void ha_mroonga::storage_store_field_datetime(Field *field,
11096                                               const char *value,
11097                                               uint value_length)
11098 {
11099   MRN_DBUG_ENTER_METHOD();
11100   long long int time = *((long long int *)value);
11101   MYSQL_TIME mysql_datetime;
11102   memset(&mysql_datetime, 0, sizeof(MYSQL_TIME));
11103   mysql_datetime.time_type = MYSQL_TIMESTAMP_DATETIME;
11104   mrn::TimeConverter time_converter;
11105   time_converter.grn_time_to_mysql_time(time, &mysql_datetime);
11106 #ifdef MRN_FIELD_STORE_TIME_NEED_TYPE
11107   Field_datetime *datetime_field = (Field_datetime *)field;
11108   datetime_field->store_time(&mysql_datetime, mysql_datetime.time_type);
11109 #else
11110   field->store_time(&mysql_datetime);
11111 #endif
11112   DBUG_VOID_RETURN;
11113 }
11114 
storage_store_field_year(Field * field,const char * value,uint value_length)11115 void ha_mroonga::storage_store_field_year(Field *field,
11116                                           const char *value,
11117                                           uint value_length)
11118 {
11119   MRN_DBUG_ENTER_METHOD();
11120   long long int time = *((long long int *)value);
11121   MYSQL_TIME mysql_time;
11122   memset(&mysql_time, 0, sizeof(MYSQL_TIME));
11123   mysql_time.time_type = MYSQL_TIMESTAMP_DATE;
11124   mrn::TimeConverter time_converter;
11125   time_converter.grn_time_to_mysql_time(time, &mysql_time);
11126   DBUG_PRINT("info", ("mroonga: stored %d", mysql_time.year));
11127   field->store(mysql_time.year, false);
11128   DBUG_VOID_RETURN;
11129 }
11130 
storage_store_field_new_date(Field * field,const char * value,uint value_length)11131 void ha_mroonga::storage_store_field_new_date(Field *field,
11132                                               const char *value,
11133                                               uint value_length)
11134 {
11135   MRN_DBUG_ENTER_METHOD();
11136   long long int time = *((long long int *)value);
11137   MYSQL_TIME mysql_date;
11138   memset(&mysql_date, 0, sizeof(MYSQL_TIME));
11139   mysql_date.time_type = MYSQL_TIMESTAMP_DATE;
11140   mrn::TimeConverter time_converter;
11141   time_converter.grn_time_to_mysql_time(time, &mysql_date);
11142 #ifdef MRN_FIELD_STORE_TIME_NEED_TYPE
11143   Field_newdate *newdate_field = (Field_newdate *)field;
11144   newdate_field->store_time(&mysql_date, MYSQL_TIMESTAMP_DATE);
11145 #else
11146   field->store_time(&mysql_date);
11147 #endif
11148   DBUG_VOID_RETURN;
11149 }
11150 
11151 #ifdef MRN_HAVE_MYSQL_TYPE_DATETIME2
storage_store_field_datetime2(Field * field,const char * value,uint value_length)11152 void ha_mroonga::storage_store_field_datetime2(Field *field,
11153                                                const char *value,
11154                                                uint value_length)
11155 {
11156   MRN_DBUG_ENTER_METHOD();
11157   long long int time = *((long long int *)value);
11158   MYSQL_TIME mysql_datetime;
11159   memset(&mysql_datetime, 0, sizeof(MYSQL_TIME));
11160   mysql_datetime.time_type = MYSQL_TIMESTAMP_DATETIME;
11161   mrn::TimeConverter time_converter;
11162   time_converter.grn_time_to_mysql_time(time, &mysql_datetime);
11163   field->store_time(&mysql_datetime);
11164   DBUG_VOID_RETURN;
11165 }
11166 #endif
11167 
11168 #ifdef MRN_HAVE_MYSQL_TYPE_TIME2
storage_store_field_time2(Field * field,const char * value,uint value_length)11169 void ha_mroonga::storage_store_field_time2(Field *field,
11170                                            const char *value,
11171                                            uint value_length)
11172 {
11173   MRN_DBUG_ENTER_METHOD();
11174   long long int time = *((long long int *)value);
11175 
11176   MYSQL_TIME mysql_time;
11177   memset(&mysql_time, 0, sizeof(MYSQL_TIME));
11178   mysql_time.time_type = MYSQL_TIMESTAMP_TIME;
11179   mrn::TimeConverter time_converter;
11180   time_converter.grn_time_to_mysql_time(time, &mysql_time);
11181   field->store_time(&mysql_time);
11182   DBUG_VOID_RETURN;
11183 }
11184 #endif
11185 
storage_store_field_blob(Field * field,const char * value,uint value_length)11186 void ha_mroonga::storage_store_field_blob(Field *field,
11187                                           const char *value,
11188                                           uint value_length)
11189 {
11190   MRN_DBUG_ENTER_METHOD();
11191   Field_blob *blob = (Field_blob *)field;
11192   String *blob_buffer = &blob_buffers[field->field_index];
11193   blob_buffer->length(0);
11194   blob_buffer->reserve(value_length);
11195   blob_buffer->q_append(value, value_length);
11196   blob->set_ptr((uint32) value_length, (uchar *) blob_buffer->ptr());
11197   DBUG_VOID_RETURN;
11198 }
11199 
storage_store_field_geometry(Field * field,const char * value,uint value_length)11200 void ha_mroonga::storage_store_field_geometry(Field *field,
11201                                               const char *value,
11202                                               uint value_length)
11203 {
11204   MRN_DBUG_ENTER_METHOD();
11205 #ifdef MRN_HAVE_SPATIAL
11206   uchar wkb[SRID_SIZE + WKB_HEADER_SIZE + POINT_DATA_SIZE];
11207   grn_geo_point *field_value = (grn_geo_point *)value;
11208   int latitude, longitude;
11209   latitude = field_value->latitude;
11210   longitude = field_value->longitude;
11211   if (grn_source_column_geo) {
11212     GRN_GEO_POINT_SET(ctx, &source_point, latitude, longitude);
11213   }
11214   memset(wkb, 0, SRID_SIZE);
11215   memset(wkb + SRID_SIZE, Geometry::wkb_ndr, 1); // wkb_ndr is meaningless.
11216   int4store(wkb + SRID_SIZE + 1, Geometry::wkb_point);
11217   double latitude_in_degree, longitude_in_degree;
11218   latitude_in_degree = GRN_GEO_MSEC2DEGREE(latitude);
11219   longitude_in_degree = GRN_GEO_MSEC2DEGREE(longitude);
11220   float8store(wkb + SRID_SIZE + WKB_HEADER_SIZE,
11221               longitude_in_degree);
11222   float8store(wkb + SRID_SIZE + WKB_HEADER_SIZE + SIZEOF_STORED_DOUBLE,
11223               latitude_in_degree);
11224   String *geometry_buffer = &blob_buffers[field->field_index];
11225   geometry_buffer->length(0);
11226   uint wkb_length = sizeof(wkb) / sizeof(*wkb);
11227   Field_geom *geometry = (Field_geom *)field;
11228   geometry_buffer->reserve(wkb_length);
11229   geometry_buffer->q_append((const char *) wkb, wkb_length);
11230   geometry->set_ptr((uint32) wkb_length, (uchar *) geometry_buffer->ptr());
11231 #endif
11232   DBUG_VOID_RETURN;
11233 }
11234 
11235 #ifdef MRN_HAVE_MYSQL_TYPE_JSON
storage_store_field_json(Field * field,const char * value,uint value_length)11236 void ha_mroonga::storage_store_field_json(Field *field,
11237                                           const char *value,
11238                                           uint value_length)
11239 {
11240   MRN_DBUG_ENTER_METHOD();
11241   Field_json *json = static_cast<Field_json *>(field);
11242   json->store(value, value_length, field->charset());
11243   DBUG_VOID_RETURN;
11244 }
11245 #endif
11246 
storage_store_field(Field * field,const char * value,uint value_length)11247 void ha_mroonga::storage_store_field(Field *field,
11248                                      const char *value, uint value_length)
11249 {
11250   field->set_notnull();
11251   switch (field->real_type()) {
11252   case MYSQL_TYPE_DECIMAL:
11253     storage_store_field_string(field, value, value_length);
11254     break;
11255   case MYSQL_TYPE_TINY:
11256   case MYSQL_TYPE_SHORT:
11257   case MYSQL_TYPE_LONG:
11258     storage_store_field_integer(field, value, value_length);
11259     break;
11260   case MYSQL_TYPE_FLOAT:
11261   case MYSQL_TYPE_DOUBLE:
11262     storage_store_field_float(field, value, value_length);
11263     break;
11264   case MYSQL_TYPE_NULL:
11265     storage_store_field_unsigned_integer(field, value, value_length);
11266     break;
11267   case MYSQL_TYPE_TIMESTAMP:
11268     storage_store_field_timestamp(field, value, value_length);
11269     break;
11270   case MYSQL_TYPE_LONGLONG:
11271   case MYSQL_TYPE_INT24:
11272     storage_store_field_integer(field, value, value_length);
11273     break;
11274   case MYSQL_TYPE_DATE:
11275     storage_store_field_date(field, value, value_length);
11276     break;
11277   case MYSQL_TYPE_TIME:
11278     storage_store_field_time(field, value, value_length);
11279     break;
11280   case MYSQL_TYPE_DATETIME:
11281     storage_store_field_datetime(field, value, value_length);
11282     break;
11283   case MYSQL_TYPE_YEAR:
11284     storage_store_field_year(field, value, value_length);
11285     break;
11286   case MYSQL_TYPE_NEWDATE:
11287     storage_store_field_new_date(field, value, value_length);
11288     break;
11289   case MYSQL_TYPE_VARCHAR:
11290     storage_store_field_string(field, value, value_length);
11291     break;
11292   case MYSQL_TYPE_BIT:
11293     storage_store_field_unsigned_integer(field, value, value_length);
11294     break;
11295 #ifdef MRN_HAVE_MYSQL_TYPE_TIMESTAMP2
11296   case MYSQL_TYPE_TIMESTAMP2:
11297     storage_store_field_timestamp(field, value, value_length);
11298     break;
11299 #endif
11300 #ifdef MRN_HAVE_MYSQL_TYPE_DATETIME2
11301   case MYSQL_TYPE_DATETIME2:
11302     storage_store_field_datetime2(field, value, value_length);
11303     break;
11304 #endif
11305 #ifdef MRN_HAVE_MYSQL_TYPE_TIME2
11306   case MYSQL_TYPE_TIME2:
11307     storage_store_field_time2(field, value, value_length);
11308     break;
11309 #endif
11310   case MYSQL_TYPE_NEWDECIMAL:
11311     storage_store_field_string(field, value, value_length);
11312     break;
11313   case MYSQL_TYPE_ENUM:
11314   case MYSQL_TYPE_SET:
11315     storage_store_field_unsigned_integer(field, value, value_length);
11316     break;
11317   case MYSQL_TYPE_TINY_BLOB:
11318   case MYSQL_TYPE_MEDIUM_BLOB:
11319   case MYSQL_TYPE_LONG_BLOB:
11320   case MYSQL_TYPE_BLOB:
11321     storage_store_field_blob(field, value, value_length);
11322     break;
11323   case MYSQL_TYPE_VAR_STRING:
11324   case MYSQL_TYPE_STRING:
11325     storage_store_field_string(field, value, value_length);
11326     break;
11327   case MYSQL_TYPE_GEOMETRY:
11328     storage_store_field_geometry(field, value, value_length);
11329     break;
11330   case MYSQL_TYPE_VARCHAR_COMPRESSED:
11331   case MYSQL_TYPE_BLOB_COMPRESSED:
11332     DBUG_ASSERT(0);
11333 #ifdef MRN_HAVE_MYSQL_TYPE_JSON
11334   case MYSQL_TYPE_JSON:
11335     storage_store_field_json(field, value, value_length);
11336     break;
11337 #endif
11338   }
11339 }
11340 
storage_store_field_column(Field * field,bool is_primary_key,int nth_column,grn_id record_id)11341 void ha_mroonga::storage_store_field_column(Field *field, bool is_primary_key,
11342                                             int nth_column, grn_id record_id)
11343 {
11344   MRN_DBUG_ENTER_METHOD();
11345 
11346   if (!grn_columns[nth_column]) {
11347     DBUG_VOID_RETURN;
11348   }
11349 
11350   grn_obj *column = grn_columns[nth_column];
11351   grn_id range_id = grn_obj_get_range(ctx, column);
11352   grn_obj *range = grn_column_ranges[nth_column];
11353   grn_obj *value = &new_value_buffer;
11354 
11355   if (mrn::grn::is_table(range)) {
11356     if (mrn::grn::is_vector_column(column)) {
11357       grn_obj_reinit(ctx, value, range_id, GRN_OBJ_VECTOR);
11358       grn_obj_get_value(ctx, column, record_id, value);
11359 
11360       grn_obj unvectored_value;
11361       GRN_TEXT_INIT(&unvectored_value, 0);
11362       int n_ids = GRN_BULK_VSIZE(value) / sizeof(grn_id);
11363       for (int i = 0; i < n_ids; i++) {
11364         grn_id id = GRN_RECORD_VALUE_AT(value, i);
11365         if (i > 0) {
11366           GRN_TEXT_PUTS(ctx, &unvectored_value, mrn_vector_column_delimiter);
11367         }
11368         char key[GRN_TABLE_MAX_KEY_SIZE];
11369         int key_length;
11370         key_length = grn_table_get_key(ctx, range, id,
11371                                        &key, GRN_TABLE_MAX_KEY_SIZE);
11372         GRN_TEXT_PUT(ctx, &unvectored_value, key, key_length);
11373       }
11374       storage_store_field(field,
11375                           GRN_TEXT_VALUE(&unvectored_value),
11376                           GRN_TEXT_LEN(&unvectored_value));
11377       GRN_OBJ_FIN(ctx, &unvectored_value);
11378     } else {
11379       grn_obj_reinit(ctx, value, range_id, 0);
11380       grn_obj_get_value(ctx, column, record_id, value);
11381 
11382       grn_id id = GRN_RECORD_VALUE(value);
11383       char key[GRN_TABLE_MAX_KEY_SIZE];
11384       int key_length;
11385       key_length = grn_table_get_key(ctx, range, id,
11386                                      &key, GRN_TABLE_MAX_KEY_SIZE);
11387       storage_store_field(field, key, key_length);
11388     }
11389   } else {
11390     grn_obj_reinit(ctx, value, range_id, 0);
11391     grn_obj_get_value(ctx, column, record_id, value);
11392     if (is_primary_key && GRN_BULK_VSIZE(value) == 0) {
11393       char key[GRN_TABLE_MAX_KEY_SIZE];
11394       int key_length;
11395       key_length = grn_table_get_key(ctx, grn_table, record_id,
11396                                      &key, GRN_TABLE_MAX_KEY_SIZE);
11397       storage_store_field(field, key, key_length);
11398     } else {
11399       storage_store_field(field, GRN_BULK_HEAD(value), GRN_BULK_VSIZE(value));
11400     }
11401   }
11402 
11403   DBUG_VOID_RETURN;
11404 }
11405 
storage_store_fields(uchar * buf,grn_id record_id)11406 void ha_mroonga::storage_store_fields(uchar *buf, grn_id record_id)
11407 {
11408   MRN_DBUG_ENTER_METHOD();
11409   DBUG_PRINT("info", ("mroonga: stored record ID: %d", record_id));
11410 
11411   my_ptrdiff_t ptr_diff = PTR_BYTE_DIFF(buf, table->record[0]);
11412 
11413   Field *primary_key_field = NULL;
11414   if (table->s->primary_key != MAX_INDEXES) {
11415     KEY *key_info = &(table->s->key_info[table->s->primary_key]);
11416     if (KEY_N_KEY_PARTS(key_info) == 1) {
11417       primary_key_field = key_info->key_part[0].field;
11418     }
11419   }
11420 
11421   int i;
11422   int n_columns = table->s->fields;
11423   for (i = 0; i < n_columns; i++) {
11424     Field *field = table->field[i];
11425 
11426     if (bitmap_is_set(table->read_set, field->field_index) ||
11427         bitmap_is_set(table->write_set, field->field_index)) {
11428       const char *column_name = field->field_name.str;
11429 
11430       if (ignoring_no_key_columns) {
11431         KEY *key_info = &(table->s->key_info[active_index]);
11432         if (strcmp(key_info->key_part[0].field->field_name.str, column_name)) {
11433           continue;
11434         }
11435       }
11436 
11437       mrn::DebugColumnAccess debug_column_access(table, &table->write_set);
11438       DBUG_PRINT("info", ("mroonga: store column %d(%d)",i,field->field_index));
11439       field->move_field_offset(ptr_diff);
11440       if (strcmp(MRN_COLUMN_NAME_ID, column_name) == 0) {
11441         // for _id column
11442         field->set_notnull();
11443         field->store((int)record_id);
11444       } else if (primary_key_field &&
11445                  strcmp(primary_key_field->field_name.str, column_name) == 0) {
11446         // for primary key column
11447         storage_store_field_column(field, true, i, record_id);
11448       } else {
11449         storage_store_field_column(field, false, i, record_id);
11450       }
11451       field->move_field_offset(-ptr_diff);
11452     }
11453   }
11454 
11455   DBUG_VOID_RETURN;
11456 }
11457 
storage_store_fields_for_prep_update(const uchar * old_data,const uchar * new_data,grn_id record_id)11458 void ha_mroonga::storage_store_fields_for_prep_update(const uchar *old_data,
11459                                                       const uchar *new_data,
11460                                                       grn_id record_id)
11461 {
11462   MRN_DBUG_ENTER_METHOD();
11463   DBUG_PRINT("info", ("mroonga: stored record ID: %d", record_id));
11464   my_ptrdiff_t ptr_diff_old = PTR_BYTE_DIFF(old_data, table->record[0]);
11465   my_ptrdiff_t ptr_diff_new = 0;
11466 #ifdef MRN_RBR_UPDATE_NEED_ALL_COLUMNS
11467   if (!written_by_row_based_binlog) {
11468     if (check_written_by_row_based_binlog()) {
11469       written_by_row_based_binlog = 2;
11470     } else {
11471       written_by_row_based_binlog = 1;
11472     }
11473   }
11474   bool need_all_columns =
11475     (new_data && written_by_row_based_binlog == 2);
11476 #endif
11477   if (new_data) {
11478     ptr_diff_new = PTR_BYTE_DIFF(new_data, table->record[0]);
11479   }
11480   int i;
11481   int n_columns = table->s->fields;
11482   for (i = 0; i < n_columns; i++) {
11483     Field *field = table->field[i];
11484 
11485 #ifdef MRN_SUPPORT_GENERATED_COLUMNS
11486     if (MRN_GENERATED_COLUMNS_FIELD_IS_VIRTUAL(field)) {
11487       continue;
11488     }
11489 #endif
11490     if (
11491       !bitmap_is_set(table->read_set, field->field_index) &&
11492       !bitmap_is_set(table->write_set, field->field_index) &&
11493 #ifdef MRN_RBR_UPDATE_NEED_ALL_COLUMNS
11494       (
11495         need_all_columns ||
11496 #endif
11497         bitmap_is_set(&multiple_column_key_bitmap, field->field_index)
11498 #ifdef MRN_RBR_UPDATE_NEED_ALL_COLUMNS
11499       )
11500 #endif
11501     ) {
11502       mrn::DebugColumnAccess debug_column_access(table, &table->write_set);
11503       DBUG_PRINT("info", ("mroonga: store column %d(%d)",i,field->field_index));
11504       grn_obj value;
11505       GRN_OBJ_INIT(&value, GRN_BULK, 0, grn_obj_get_range(ctx, grn_columns[i]));
11506       grn_obj_get_value(ctx, grn_columns[i], record_id, &value);
11507       // old column
11508       field->move_field_offset(ptr_diff_old);
11509       storage_store_field(field, GRN_BULK_HEAD(&value), GRN_BULK_VSIZE(&value));
11510       field->move_field_offset(-ptr_diff_old);
11511       if (new_data) {
11512         // new column
11513         field->move_field_offset(ptr_diff_new);
11514         storage_store_field(field, GRN_BULK_HEAD(&value), GRN_BULK_VSIZE(&value));
11515         field->move_field_offset(-ptr_diff_new);
11516       }
11517       GRN_OBJ_FIN(ctx, &value);
11518     }
11519   }
11520 
11521   DBUG_VOID_RETURN;
11522 }
11523 
storage_store_fields_by_index(uchar * buf)11524 void ha_mroonga::storage_store_fields_by_index(uchar *buf)
11525 {
11526   MRN_DBUG_ENTER_METHOD();
11527   uint key_length;
11528   void *key;
11529   KEY *key_info = &table->key_info[active_index];
11530   if (table->s->primary_key == active_index)
11531     key_length = grn_table_cursor_get_key(ctx, cursor, &key);
11532   else
11533     key_length = grn_table_cursor_get_key(ctx, index_table_cursor, &key);
11534 
11535   if (KEY_N_KEY_PARTS(key_info) == 1) {
11536     my_ptrdiff_t ptr_diff = PTR_BYTE_DIFF(buf, table->record[0]);
11537     Field *field = key_info->key_part->field;
11538     mrn::DebugColumnAccess debug_column_access(table, &table->write_set);
11539     field->move_field_offset(ptr_diff);
11540     storage_store_field(field, (const char *)key, key_length);
11541     field->move_field_offset(-ptr_diff);
11542   } else {
11543     uchar enc_buf[MAX_KEY_LENGTH];
11544     uint enc_len;
11545     mrn::MultipleColumnKeyCodec codec(ctx, ha_thd(), key_info);
11546     codec.decode(static_cast<uchar *>(key), key_length, enc_buf, &enc_len);
11547     key_restore(buf, enc_buf, key_info, enc_len);
11548   }
11549   DBUG_VOID_RETURN;
11550 }
11551 
storage_encode_key_normalize_min_sort_chars(Field * field,uchar * buf,uint size)11552 int ha_mroonga::storage_encode_key_normalize_min_sort_chars(Field *field,
11553                                                             uchar *buf,
11554                                                             uint size)
11555 {
11556   MRN_DBUG_ENTER_METHOD();
11557   int error = 0;
11558 
11559   if (size == 0) {
11560     DBUG_RETURN(0);
11561   }
11562   if (!field->has_charset()) {
11563     DBUG_RETURN(0);
11564   }
11565 
11566   uint16 raw_min_sort_char =
11567     static_cast<uint16>(field->sort_charset()->min_sort_char);
11568   if (raw_min_sort_char <= UINT_MAX8) {
11569     uchar min_sort_char = static_cast<uchar>(raw_min_sort_char);
11570     for (uint i = size - 1; i > 0; --i) {
11571       if (buf[i] != min_sort_char) {
11572         break;
11573       }
11574       buf[i] = '\0';
11575     }
11576   }
11577 
11578   DBUG_RETURN(error);
11579 }
11580 
storage_encode_key_fixed_size_string(Field * field,const uchar * key,uchar * buf,uint * size)11581 int ha_mroonga::storage_encode_key_fixed_size_string(Field *field,
11582                                                      const uchar *key,
11583                                                      uchar *buf, uint *size)
11584 {
11585   MRN_DBUG_ENTER_METHOD();
11586   int error = 0;
11587   memcpy(buf, key, field->field_length);
11588   *size = field->field_length;
11589   DBUG_RETURN(error);
11590 }
11591 
storage_encode_key_variable_size_string(Field * field,const uchar * key,uchar * buf,uint * size)11592 int ha_mroonga::storage_encode_key_variable_size_string(Field *field,
11593                                                         const uchar *key,
11594                                                         uchar *buf, uint *size)
11595 {
11596   MRN_DBUG_ENTER_METHOD();
11597   int error = 0;
11598   *size = uint2korr(key);
11599   memcpy(buf, key + HA_KEY_BLOB_LENGTH, *size);
11600   storage_encode_key_normalize_min_sort_chars(field, buf, *size);
11601   DBUG_RETURN(error);
11602 }
11603 
storage_encode_key_timestamp(Field * field,const uchar * key,uchar * buf,uint * size)11604 int ha_mroonga::storage_encode_key_timestamp(Field *field, const uchar *key,
11605                                              uchar *buf, uint *size)
11606 {
11607   MRN_DBUG_ENTER_METHOD();
11608   int error = 0;
11609   bool truncated = false;
11610   long long int time;
11611   MYSQL_TIME mysql_time;
11612 #ifdef MRN_MARIADB_P
11613   if (field->decimals() == 0) {
11614     my_time_t my_time = sint4korr(key);
11615     mrn_my_tz_UTC->gmt_sec_to_TIME(&mysql_time, my_time);
11616     mysql_time.second_part = 0;
11617   } else {
11618     Field_timestamp_hires *timestamp_hires_field =
11619       (Field_timestamp_hires *)field;
11620     uint fuzzy_date = 0;
11621     uchar *ptr_backup = field->ptr;
11622     uchar *null_ptr_backup = field->null_ptr;
11623     TABLE *table_backup = field->table;
11624     field->ptr = (uchar *)key;
11625     field->null_ptr = (uchar *)(key - 1);
11626     field->table = table;
11627     timestamp_hires_field->get_date(&mysql_time, fuzzy_date);
11628     field->ptr = ptr_backup;
11629     field->null_ptr = null_ptr_backup;
11630     field->table = table_backup;
11631   }
11632 #else
11633   my_time_t my_time = uint4korr(key);
11634   mrn_my_tz_UTC->gmt_sec_to_TIME(&mysql_time, my_time);
11635 #endif
11636   mrn::TimeConverter time_converter;
11637   time = time_converter.mysql_time_to_grn_time(&mysql_time, &truncated);
11638   if (truncated) {
11639     if (MRN_ABORT_ON_WARNING(ha_thd())) {
11640       error = MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd());
11641     }
11642     field->set_warning(MRN_SEVERITY_WARNING,
11643                        MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd()),
11644                        1);
11645   }
11646   memcpy(buf, &time, 8);
11647   *size = 8;
11648   DBUG_RETURN(error);
11649 }
11650 
storage_encode_key_time(Field * field,const uchar * key,uchar * buf,uint * size)11651 int ha_mroonga::storage_encode_key_time(Field *field, const uchar *key,
11652                                         uchar *buf, uint *size)
11653 {
11654   MRN_DBUG_ENTER_METHOD();
11655   int error = 0;
11656   long long int time;
11657 #ifdef MRN_MARIADB_P
11658   MYSQL_TIME mysql_time;
11659   bool truncated = false;
11660   if (field->decimals() == 0) {
11661     long long int packed_time = sint3korr(key);
11662     mysql_time.neg = false;
11663     if (packed_time < 0) {
11664       mysql_time.neg = true;
11665       packed_time = -packed_time;
11666     }
11667     mysql_time.year = 0;
11668     mysql_time.month = 0;
11669     mysql_time.day = 0;
11670     mysql_time.hour = (int)(packed_time / 10000);
11671     long long int minute_part = packed_time - mysql_time.hour * 10000;
11672     mysql_time.minute = (int)(minute_part / 100);
11673     mysql_time.second = (int)(minute_part % 100);
11674     mysql_time.second_part = 0;
11675     mysql_time.time_type = MYSQL_TIMESTAMP_TIME;
11676   } else {
11677     Field_time_hires *time_hires_field = (Field_time_hires *)field;
11678     uint fuzzy_date = 0;
11679     uchar *ptr_backup = field->ptr;
11680     uchar *null_ptr_backup = field->null_ptr;
11681     field->ptr = (uchar *)key;
11682     field->null_ptr = (uchar *)(key - 1);
11683     time_hires_field->get_date(&mysql_time, fuzzy_date);
11684     field->ptr = ptr_backup;
11685     field->null_ptr = null_ptr_backup;
11686   }
11687   mrn::TimeConverter time_converter;
11688   time = time_converter.mysql_time_to_grn_time(&mysql_time, &truncated);
11689   if (truncated) {
11690     if (MRN_ABORT_ON_WARNING(ha_thd())) {
11691       error = MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd());
11692     }
11693     field->set_warning(MRN_SEVERITY_WARNING,
11694                        MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd()),
11695                        1);
11696   }
11697 #else
11698   int mysql_time = (int)sint3korr(key);
11699   int sec =
11700     mysql_time / 10000 * 60 * 60 +
11701     mysql_time / 100 % 100 * 60 +
11702     mysql_time % 60;
11703   int usec = 0;
11704   time = GRN_TIME_PACK(sec, usec);
11705 #endif
11706   memcpy(buf, &time, 8);
11707   *size = 8;
11708   DBUG_RETURN(error);
11709 }
11710 
storage_encode_key_year(Field * field,const uchar * key,uchar * buf,uint * size)11711 int ha_mroonga::storage_encode_key_year(Field *field, const uchar *key,
11712                                         uchar *buf, uint *size)
11713 {
11714   MRN_DBUG_ENTER_METHOD();
11715   int error = 0;
11716   bool truncated = false;
11717   int year = (int)key[0];
11718 
11719   struct tm datetime;
11720   memset(&datetime, 0, sizeof(struct tm));
11721   datetime.tm_year = year;
11722   datetime.tm_mon = 0;
11723   datetime.tm_mday = 1;
11724   int usec = 0;
11725   mrn::TimeConverter time_converter;
11726   long long int time = time_converter.tm_to_grn_time(&datetime, usec,
11727                                                      &truncated);
11728   if (truncated) {
11729     if (MRN_ABORT_ON_WARNING(ha_thd())) {
11730       error = MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd());
11731     }
11732     field->set_warning(MRN_SEVERITY_WARNING,
11733                        MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd()),
11734                        1);
11735   }
11736   memcpy(buf, &time, 8);
11737   *size = 8;
11738   DBUG_RETURN(error);
11739 }
11740 
storage_encode_key_datetime(Field * field,const uchar * key,uchar * buf,uint * size)11741 int ha_mroonga::storage_encode_key_datetime(Field *field, const uchar *key,
11742                                             uchar *buf, uint *size)
11743 {
11744   MRN_DBUG_ENTER_METHOD();
11745   int error = 0;
11746   bool truncated = false;
11747   long long int time;
11748 #ifdef MRN_MARIADB_P
11749   if (field->decimals() > 0) {
11750     Field_datetime_hires *datetime_hires_field = (Field_datetime_hires *)field;
11751     MYSQL_TIME mysql_time;
11752     uint fuzzy_date = 0;
11753     uchar *ptr_backup = field->ptr;
11754     uchar *null_ptr_backup = field->null_ptr;
11755     field->ptr = (uchar *)key;
11756     field->null_ptr = (uchar *)(key - 1);
11757     datetime_hires_field->get_date(&mysql_time, fuzzy_date);
11758     field->ptr = ptr_backup;
11759     field->null_ptr = null_ptr_backup;
11760     mrn::TimeConverter time_converter;
11761     time = time_converter.mysql_time_to_grn_time(&mysql_time, &truncated);
11762   } else
11763 #endif
11764   {
11765     long long int encoded_datetime = sint8korr(key);
11766     uint32 part1 = (uint32)(encoded_datetime / 1000000LL);
11767     uint32 part2 = (uint32)(encoded_datetime -
11768                             (unsigned long long int)part1 * 1000000LL);
11769     struct tm date;
11770     memset(&date, 0, sizeof(struct tm));
11771     date.tm_year = part1 / 10000 - mrn::TimeConverter::TM_YEAR_BASE;
11772     date.tm_mon = part1 / 100 % 100 - 1;
11773     date.tm_mday = part1 % 100;
11774     date.tm_hour = part2 / 10000;
11775     date.tm_min = part2 / 100 % 100;
11776     date.tm_sec = part2 % 100;
11777     int usec = 0;
11778     mrn::TimeConverter time_converter;
11779     time = time_converter.tm_to_grn_time(&date, usec, &truncated);
11780   }
11781   if (truncated) {
11782     if (MRN_ABORT_ON_WARNING(ha_thd())) {
11783       error = MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd());
11784     }
11785     field->set_warning(MRN_SEVERITY_WARNING,
11786                        MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd()),
11787                        1);
11788   }
11789   memcpy(buf, &time, 8);
11790   *size = 8;
11791   DBUG_RETURN(error);
11792 }
11793 
11794 #ifdef MRN_HAVE_MYSQL_TYPE_TIMESTAMP2
storage_encode_key_timestamp2(Field * field,const uchar * key,uchar * buf,uint * size)11795 int ha_mroonga::storage_encode_key_timestamp2(Field *field, const uchar *key,
11796                                               uchar *buf, uint *size)
11797 {
11798   MRN_DBUG_ENTER_METHOD();
11799   int error = 0;
11800   bool truncated = false;
11801 
11802   Field_timestampf *timestamp2_field = (Field_timestampf *)field;
11803   struct timeval tm;
11804   my_timestamp_from_binary(&tm, key, timestamp2_field->decimals());
11805   MYSQL_TIME mysql_time;
11806   mrn_my_tz_UTC->gmt_sec_to_TIME(&mysql_time, (my_time_t)tm.tv_sec);
11807   mysql_time.second_part = tm.tv_usec;
11808   mrn::TimeConverter time_converter;
11809   long long int grn_time = time_converter.mysql_time_to_grn_time(&mysql_time,
11810                                                                  &truncated);
11811   if (truncated) {
11812     if (MRN_ABORT_ON_WARNING(ha_thd())) {
11813       error = MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd());
11814     }
11815     field->set_warning(MRN_SEVERITY_WARNING,
11816                        MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd()),
11817                        1);
11818   }
11819   memcpy(buf, &grn_time, 8);
11820   *size = 8;
11821 
11822   DBUG_RETURN(error);
11823 }
11824 #endif
11825 
11826 #ifdef MRN_HAVE_MYSQL_TYPE_DATETIME2
storage_encode_key_datetime2(Field * field,bool is_null,const uchar * key,uchar * buf,uint * size)11827 int ha_mroonga::storage_encode_key_datetime2(Field *field, bool is_null,
11828                                              const uchar *key,
11829                                              uchar *buf, uint *size)
11830 {
11831   MRN_DBUG_ENTER_METHOD();
11832   int error = 0;
11833   bool truncated = false;
11834 
11835   Field_datetimef *datetime2_field = (Field_datetimef *)field;
11836   longlong packed_time = is_null ? 0 :
11837     my_datetime_packed_from_binary(key, datetime2_field->decimals());
11838   MYSQL_TIME mysql_time;
11839   TIME_from_longlong_datetime_packed(&mysql_time, packed_time);
11840   mrn::TimeConverter time_converter;
11841   long long int grn_time = time_converter.mysql_time_to_grn_time(&mysql_time,
11842                                                                  &truncated);
11843   if (truncated) {
11844     if (MRN_ABORT_ON_WARNING(ha_thd())) {
11845       error = MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd());
11846     }
11847     field->set_warning(MRN_SEVERITY_WARNING,
11848                        MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd()),
11849                        1);
11850   }
11851   memcpy(buf, &grn_time, 8);
11852   *size = 8;
11853 
11854   DBUG_RETURN(error);
11855 }
11856 #endif
11857 
11858 #ifdef MRN_HAVE_MYSQL_TYPE_TIME2
storage_encode_key_time2(Field * field,const uchar * key,uchar * buf,uint * size)11859 int ha_mroonga::storage_encode_key_time2(Field *field, const uchar *key,
11860                                          uchar *buf, uint *size)
11861 {
11862   MRN_DBUG_ENTER_METHOD();
11863   int error = 0;
11864   bool truncated = false;
11865 
11866   Field_timef *time2_field = (Field_timef *)field;
11867   longlong packed_time =
11868     my_time_packed_from_binary(key, time2_field->decimals());
11869   MYSQL_TIME mysql_time;
11870   TIME_from_longlong_time_packed(&mysql_time, packed_time);
11871   mrn::TimeConverter time_converter;
11872   long long int grn_time = time_converter.mysql_time_to_grn_time(&mysql_time,
11873                                                                  &truncated);
11874   if (truncated) {
11875     if (MRN_ABORT_ON_WARNING(ha_thd())) {
11876       error = MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd());
11877     }
11878     field->set_warning(MRN_SEVERITY_WARNING,
11879                        MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd()),
11880                        1);
11881   }
11882   memcpy(buf, &grn_time, 8);
11883   *size = 8;
11884 
11885   DBUG_RETURN(error);
11886 }
11887 #endif
11888 
storage_encode_key_enum(Field * field,const uchar * key,uchar * buf,uint * size)11889 int ha_mroonga::storage_encode_key_enum(Field *field, const uchar *key,
11890                                         uchar *buf, uint *size)
11891 {
11892   MRN_DBUG_ENTER_METHOD();
11893   int error = 0;
11894   if (field->pack_length() == 1) {
11895     uchar value;
11896     value = key[0];
11897     *size = 1;
11898     memcpy(buf, &value, *size);
11899   } else {
11900     uint16 value;
11901     mrn::value_decoder::decode(&value, key);
11902     *size = 2;
11903     memcpy(buf, &value, *size);
11904   }
11905   DBUG_RETURN(error);
11906 }
11907 
storage_encode_key_set(Field * field,const uchar * key,uchar * buf,uint * size)11908 int ha_mroonga::storage_encode_key_set(Field *field, const uchar *key,
11909                                        uchar *buf, uint *size)
11910 {
11911   MRN_DBUG_ENTER_METHOD();
11912   int error = 0;
11913   Field_set unpacker((uchar *)key, field->field_length, (uchar *)(key - 1),
11914                      field->null_bit, field->unireg_check,
11915                      &field->field_name,
11916                      field->pack_length(),
11917                      static_cast<Field_set*>(field)->typelib,
11918                      static_cast<Field_set*>(field)->charset());
11919   switch (field->pack_length()) {
11920   case 1:
11921     {
11922       int8 signed_value = (int8)(unpacker.val_int());
11923       uint8 unsigned_value = *((uint8 *)&signed_value);
11924       *size = 1;
11925       memcpy(buf, &unsigned_value, *size);
11926     }
11927     break;
11928   case 2:
11929     {
11930       int16 signed_value = (int16)(unpacker.val_int());
11931       uint16 unsigned_value = *((uint16 *)&signed_value);
11932       *size = 2;
11933       memcpy(buf, &unsigned_value, *size);
11934     }
11935     break;
11936   case 3:
11937   case 4:
11938     {
11939       int32 signed_value = (int32)(unpacker.val_int());
11940       uint32 unsigned_value = *((uint32 *)&signed_value);
11941       *size = 4;
11942       memcpy(buf, &unsigned_value, *size);
11943     }
11944     break;
11945   case 8:
11946   default:
11947     {
11948       int64 signed_value = (int64)(unpacker.val_int());
11949       uint64 unsigned_value = *((uint64 *)&signed_value);
11950       *size = 8;
11951       memcpy(buf, &unsigned_value, *size);
11952     }
11953     break;
11954   }
11955   DBUG_RETURN(error);
11956 }
11957 
storage_encode_key(Field * field,const uchar * key,uchar * buf,uint * size)11958 int ha_mroonga::storage_encode_key(Field *field, const uchar *key,
11959                                    uchar *buf, uint *size)
11960 {
11961   MRN_DBUG_ENTER_METHOD();
11962   int error;
11963   bool truncated = false;
11964   bool is_null = false;
11965   const uchar *ptr = key;
11966 
11967   error = mrn_change_encoding(ctx, field->charset());
11968   if (error)
11969     DBUG_RETURN(error);
11970 
11971   if (field->null_bit) {
11972     is_null = *ptr;
11973     ptr += 1;
11974   }
11975 
11976   switch (field->real_type()) {
11977   case MYSQL_TYPE_BIT:
11978   case MYSQL_TYPE_TINY:
11979     {
11980       memcpy(buf, ptr, 1);
11981       *size = 1;
11982       break;
11983     }
11984   case MYSQL_TYPE_SHORT:
11985     {
11986       memcpy(buf, ptr, 2);
11987       *size = 2;
11988       break;
11989     }
11990   case MYSQL_TYPE_INT24:
11991     {
11992       memcpy(buf, ptr, 3);
11993       buf[3] = 0;
11994       *size = 4;
11995       break;
11996     }
11997   case MYSQL_TYPE_LONG:
11998     {
11999       memcpy(buf, ptr, 4);
12000       *size = 4;
12001       break;
12002     }
12003   case MYSQL_TYPE_TIMESTAMP:
12004     error = storage_encode_key_timestamp(field, ptr, buf, size);
12005     break;
12006   case MYSQL_TYPE_LONGLONG:
12007     {
12008       memcpy(buf, ptr, 8);
12009       *size = 8;
12010       break;
12011     }
12012   case MYSQL_TYPE_FLOAT:
12013     {
12014       float float_value;
12015       double double_value;
12016       mrn::value_decoder::decode(&float_value, ptr);
12017       double_value = float_value;
12018       memcpy(buf, &double_value, 8);
12019       *size = 8;
12020       break;
12021     }
12022   case MYSQL_TYPE_DOUBLE:
12023     {
12024       double val;
12025       mrn::value_decoder::decode(&val, ptr);
12026       memcpy(buf, &val, 8);
12027       *size = 8;
12028       break;
12029     }
12030   case MYSQL_TYPE_TIME:
12031     error = storage_encode_key_time(field, ptr, buf, size);
12032     break;
12033   case MYSQL_TYPE_YEAR:
12034     error = storage_encode_key_year(field, ptr, buf, size);
12035     break;
12036   case MYSQL_TYPE_DATETIME:
12037     error = storage_encode_key_datetime(field, ptr, buf, size);
12038     break;
12039   case MYSQL_TYPE_NEWDATE:
12040     {
12041       uint32 encoded_date = uint3korr(ptr);
12042       struct tm date;
12043       memset(&date, 0, sizeof(struct tm));
12044       date.tm_year = encoded_date / (16 * 32) - mrn::TimeConverter::TM_YEAR_BASE;
12045       date.tm_mon = encoded_date / 32 % 16 - 1;
12046       date.tm_mday = encoded_date % 32;
12047       int usec = 0;
12048       mrn::TimeConverter time_converter;
12049       long long int time = time_converter.tm_to_grn_time(&date, usec,
12050                                                          &truncated);
12051       if (truncated) {
12052         if (MRN_ABORT_ON_WARNING(ha_thd())) {
12053           error = MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd());
12054         }
12055         field->set_warning(MRN_SEVERITY_WARNING,
12056                            MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd()),
12057                            1);
12058       }
12059       memcpy(buf, &time, 8);
12060       *size = 8;
12061       break;
12062     }
12063 #ifdef MRN_HAVE_MYSQL_TYPE_TIMESTAMP2
12064   case MYSQL_TYPE_TIMESTAMP2:
12065     error = storage_encode_key_timestamp2(field, ptr, buf, size);
12066     break;
12067 #endif
12068 #ifdef MRN_HAVE_MYSQL_TYPE_DATETIME2
12069   case MYSQL_TYPE_DATETIME2:
12070     error = storage_encode_key_datetime2(field, is_null, ptr, buf, size);
12071     break;
12072 #endif
12073 #ifdef MRN_HAVE_MYSQL_TYPE_TIME2
12074   case MYSQL_TYPE_TIME2:
12075     error = storage_encode_key_time2(field, ptr, buf, size);
12076     break;
12077 #endif
12078   case MYSQL_TYPE_STRING:
12079     error = storage_encode_key_fixed_size_string(field, ptr, buf, size);
12080     break;
12081   case MYSQL_TYPE_VARCHAR:
12082   case MYSQL_TYPE_BLOB:
12083     error = storage_encode_key_variable_size_string(field, ptr, buf, size);
12084     break;
12085   case MYSQL_TYPE_ENUM:
12086     error = storage_encode_key_enum(field, ptr, buf, size);
12087     break;
12088   case MYSQL_TYPE_SET:
12089     error = storage_encode_key_set(field, ptr, buf, size);
12090     break;
12091   default:
12092     error = HA_ERR_UNSUPPORTED;
12093     break;
12094   }
12095   DBUG_RETURN(error);
12096 }
12097 
storage_encode_multiple_column_key(KEY * key_info,const uchar * key,uint key_length,uchar * buffer,uint * encoded_length)12098 int ha_mroonga::storage_encode_multiple_column_key(KEY *key_info,
12099                                                    const uchar *key,
12100                                                    uint key_length,
12101                                                    uchar *buffer,
12102                                                    uint *encoded_length)
12103 {
12104   MRN_DBUG_ENTER_METHOD();
12105   mrn::MultipleColumnKeyCodec codec(ctx, ha_thd(), key_info);
12106   int error = codec.encode(key, key_length, buffer, encoded_length);
12107   DBUG_RETURN(error);
12108 }
12109 
storage_encode_multiple_column_key_range(KEY * key_info,const uchar * start,uint start_size,const uchar * end,uint end_size,uchar * min_buffer,uint * min_encoded_size,uchar * max_buffer,uint * max_encoded_size)12110 int ha_mroonga::storage_encode_multiple_column_key_range(KEY *key_info,
12111                                                          const uchar *start,
12112                                                          uint start_size,
12113                                                          const uchar *end,
12114                                                          uint end_size,
12115                                                          uchar *min_buffer,
12116                                                          uint *min_encoded_size,
12117                                                          uchar *max_buffer,
12118                                                          uint *max_encoded_size)
12119 {
12120   MRN_DBUG_ENTER_METHOD();
12121   int error = 0;
12122   mrn::MultipleColumnKeyCodec codec(ctx, ha_thd(), key_info);
12123   uint encoded_key_size = codec.size();
12124   if (start) {
12125     memset(min_buffer, 0, encoded_key_size);
12126     error = codec.encode(start, start_size,
12127                          min_buffer, min_encoded_size);
12128     // TODO: handle error?
12129     *min_encoded_size = encoded_key_size;
12130   }
12131   if (end) {
12132     memset(max_buffer, 0xff, encoded_key_size);
12133     error = codec.encode(end, end_size,
12134                          max_buffer, max_encoded_size);
12135     // TODO: handle error?
12136     *max_encoded_size = encoded_key_size;
12137   }
12138   DBUG_RETURN(error);
12139 }
12140 
storage_encode_multiple_column_key_range(KEY * key_info,const key_range * start,const key_range * end,uchar * min_buffer,uint * min_encoded_size,uchar * max_buffer,uint * max_encoded_size)12141 int ha_mroonga::storage_encode_multiple_column_key_range(KEY *key_info,
12142                                                          const key_range *start,
12143                                                          const key_range *end,
12144                                                          uchar *min_buffer,
12145                                                          uint *min_encoded_size,
12146                                                          uchar *max_buffer,
12147                                                          uint *max_encoded_size)
12148 {
12149   MRN_DBUG_ENTER_METHOD();
12150 
12151   const uchar *start_data = NULL;
12152   uint start_size = 0;
12153   const uchar *end_data = NULL;
12154   uint end_size = 0;
12155   if (start) {
12156     start_data = start->key;
12157     start_size = start->length;
12158   }
12159   if (end) {
12160     end_data = end->key;
12161     end_size = end->length;
12162   }
12163 
12164   int error = storage_encode_multiple_column_key_range(key_info,
12165                                                        start_data, start_size,
12166                                                        end_data, end_size,
12167                                                        min_buffer,
12168                                                        min_encoded_size,
12169                                                        max_buffer,
12170                                                        max_encoded_size);
12171 
12172   DBUG_RETURN(error);
12173 }
12174 
generic_reset()12175 int ha_mroonga::generic_reset()
12176 {
12177   MRN_DBUG_ENTER_METHOD();
12178   int error = 0;
12179 
12180   if (thd_sql_command(ha_thd()) != SQLCOM_SELECT) {
12181     DBUG_RETURN(error);
12182   }
12183 
12184   TABLE_LIST *table_list = table->pos_in_table_list;
12185   if (!table_list) {
12186     DBUG_RETURN(error);
12187   }
12188 
12189   st_select_lex *select_lex = table_list->select_lex;
12190   if (!select_lex) {
12191     DBUG_RETURN(error);
12192   }
12193 
12194   List_iterator<Item_func_match> iterator(*(select_lex->ftfunc_list));
12195   Item_func_match *item;
12196   while ((item = iterator++)) {
12197     if (item->ft_handler) {
12198       mrn_generic_ft_clear(item->ft_handler);
12199     }
12200   }
12201 
12202   DBUG_RETURN(error);
12203 }
12204 
wrapper_reset()12205 int ha_mroonga::wrapper_reset()
12206 {
12207   MRN_DBUG_ENTER_METHOD();
12208   int error = 0;
12209   MRN_SET_WRAP_SHARE_KEY(share, table->s);
12210   MRN_SET_WRAP_TABLE_KEY(this, table);
12211   error = wrap_handler->ha_reset();
12212   MRN_SET_BASE_SHARE_KEY(share, table->s);
12213   MRN_SET_BASE_TABLE_KEY(this, table);
12214 #ifdef MRN_HANDLER_HAVE_CHECK_IF_SUPPORTED_INPLACE_ALTER
12215   if (alter_key_info_buffer) {
12216     my_free(alter_key_info_buffer);
12217     alter_key_info_buffer = NULL;
12218   }
12219 #else
12220   if (wrap_alter_key_info) {
12221     my_free(wrap_alter_key_info);
12222     wrap_alter_key_info = NULL;
12223   }
12224 #endif
12225   wrap_ft_init_count = 0;
12226   int generic_error = generic_reset();
12227   if (error == 0) {
12228     error = generic_error;
12229   }
12230   DBUG_RETURN(error);
12231 }
12232 
storage_reset()12233 int ha_mroonga::storage_reset()
12234 {
12235   MRN_DBUG_ENTER_METHOD();
12236   int error;
12237   error = generic_reset();
12238   DBUG_RETURN(error);
12239 }
12240 
reset()12241 int ha_mroonga::reset()
12242 {
12243   int error = 0;
12244   THD *thd = ha_thd();
12245   MRN_DBUG_ENTER_METHOD();
12246   DBUG_PRINT("info", ("mroonga: this=%p", this));
12247   clear_empty_value_records();
12248   clear_search_result();
12249   clear_search_result_geo();
12250   if (share->wrapper_mode)
12251     error = wrapper_reset();
12252   else
12253     error = storage_reset();
12254   ignoring_no_key_columns = false;
12255   inserting_with_update = false;
12256   ignoring_duplicated_key = false;
12257   fulltext_searching = false;
12258   replacing_ = false;
12259   written_by_row_based_binlog = 0;
12260   mrn_lock_type = F_UNLCK;
12261   mrn_clear_slot_data(thd);
12262   current_ft_item = NULL;
12263   DBUG_RETURN(error);
12264 }
12265 
wrapper_clone(const char * name,MEM_ROOT * mem_root)12266 handler *ha_mroonga::wrapper_clone(const char *name, MEM_ROOT *mem_root)
12267 {
12268   handler *cloned_handler;
12269   MRN_DBUG_ENTER_METHOD();
12270   if (!(cloned_handler = get_new_handler(table->s, mem_root,
12271                                          table->s->db_type())))
12272     DBUG_RETURN(NULL);
12273   ((ha_mroonga *) cloned_handler)->is_clone = true;
12274   ((ha_mroonga *) cloned_handler)->parent_for_clone = this;
12275   ((ha_mroonga *) cloned_handler)->mem_root_for_clone = mem_root;
12276   if (cloned_handler->ha_open(table, table->s->normalized_path.str,
12277                               table->db_stat, HA_OPEN_IGNORE_IF_LOCKED))
12278   {
12279     delete cloned_handler;
12280     DBUG_RETURN(NULL);
12281   }
12282   DBUG_RETURN(cloned_handler);
12283 }
12284 
storage_clone(const char * name,MEM_ROOT * mem_root)12285 handler *ha_mroonga::storage_clone(const char *name, MEM_ROOT *mem_root)
12286 {
12287   MRN_DBUG_ENTER_METHOD();
12288   handler *cloned_handler;
12289   cloned_handler = handler::clone(name, mem_root);
12290   DBUG_RETURN(cloned_handler);
12291 }
12292 
clone(const char * name,MEM_ROOT * mem_root)12293 handler *ha_mroonga::clone(const char *name, MEM_ROOT *mem_root)
12294 {
12295   MRN_DBUG_ENTER_METHOD();
12296   handler *cloned_handler;
12297   if (share->wrapper_mode)
12298   {
12299     cloned_handler = wrapper_clone(name, mem_root);
12300   } else {
12301     cloned_handler = storage_clone(name, mem_root);
12302   }
12303   DBUG_RETURN(cloned_handler);
12304 }
12305 
wrapper_table_cache_type()12306 uint8 ha_mroonga::wrapper_table_cache_type()
12307 {
12308   uint8 res;
12309   MRN_DBUG_ENTER_METHOD();
12310   MRN_SET_WRAP_SHARE_KEY(share, table->s);
12311   MRN_SET_WRAP_TABLE_KEY(this, table);
12312   res = wrap_handler->table_cache_type();
12313   MRN_SET_BASE_SHARE_KEY(share, table->s);
12314   MRN_SET_BASE_TABLE_KEY(this, table);
12315   DBUG_RETURN(res);
12316 }
12317 
storage_table_cache_type()12318 uint8 ha_mroonga::storage_table_cache_type()
12319 {
12320   MRN_DBUG_ENTER_METHOD();
12321   uint8 type = handler::table_cache_type();
12322   DBUG_RETURN(type);
12323 }
12324 
table_cache_type()12325 uint8 ha_mroonga::table_cache_type()
12326 {
12327   MRN_DBUG_ENTER_METHOD();
12328   uint8 type;
12329   if (share->wrapper_mode)
12330   {
12331     type = wrapper_table_cache_type();
12332   } else {
12333     type = storage_table_cache_type();
12334   }
12335   DBUG_RETURN(type);
12336 }
12337 
12338 #ifdef MRN_HANDLER_HAVE_MULTI_RANGE_READ
wrapper_multi_range_read_info_const(uint keyno,RANGE_SEQ_IF * seq,void * seq_init_param,uint n_ranges,uint * bufsz,uint * flags,Cost_estimate * cost)12339 ha_rows ha_mroonga::wrapper_multi_range_read_info_const(uint keyno,
12340                                                         RANGE_SEQ_IF *seq,
12341                                                         void *seq_init_param,
12342                                                         uint n_ranges,
12343                                                         uint *bufsz,
12344                                                         uint *flags,
12345                                                         Cost_estimate *cost)
12346 {
12347   MRN_DBUG_ENTER_METHOD();
12348   ha_rows rows;
12349   KEY *key_info = &(table->key_info[keyno]);
12350   if (mrn_is_geo_key(key_info)) {
12351     rows = handler::multi_range_read_info_const(keyno, seq, seq_init_param,
12352                                                 n_ranges, bufsz, flags, cost);
12353     DBUG_RETURN(rows);
12354   }
12355   MRN_SET_WRAP_SHARE_KEY(share, table->s);
12356   MRN_SET_WRAP_TABLE_KEY(this, table);
12357   if (fulltext_searching)
12358     set_pk_bitmap();
12359   rows = wrap_handler->multi_range_read_info_const(keyno, seq, seq_init_param,
12360                                                    n_ranges, bufsz, flags,
12361                                                    cost);
12362   MRN_SET_BASE_SHARE_KEY(share, table->s);
12363   MRN_SET_BASE_TABLE_KEY(this, table);
12364   DBUG_RETURN(rows);
12365 }
12366 
storage_multi_range_read_info_const(uint keyno,RANGE_SEQ_IF * seq,void * seq_init_param,uint n_ranges,uint * bufsz,uint * flags,Cost_estimate * cost)12367 ha_rows ha_mroonga::storage_multi_range_read_info_const(uint keyno,
12368                                                         RANGE_SEQ_IF *seq,
12369                                                         void *seq_init_param,
12370                                                         uint n_ranges,
12371                                                         uint *bufsz,
12372                                                         uint *flags,
12373                                                         Cost_estimate *cost)
12374 {
12375   MRN_DBUG_ENTER_METHOD();
12376   ha_rows rows = handler::multi_range_read_info_const(keyno, seq,
12377                                                       seq_init_param,
12378                                                       n_ranges, bufsz, flags,
12379                                                       cost);
12380   DBUG_RETURN(rows);
12381 }
12382 
multi_range_read_info_const(uint keyno,RANGE_SEQ_IF * seq,void * seq_init_param,uint n_ranges,uint * bufsz,uint * flags,Cost_estimate * cost)12383 ha_rows ha_mroonga::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
12384                                                 void *seq_init_param,
12385                                                 uint n_ranges, uint *bufsz,
12386                                                 uint *flags,
12387                                                 Cost_estimate *cost)
12388 {
12389   MRN_DBUG_ENTER_METHOD();
12390   ha_rows rows;
12391   if (share->wrapper_mode)
12392   {
12393     rows = wrapper_multi_range_read_info_const(keyno, seq, seq_init_param,
12394                                                n_ranges, bufsz,
12395                                                flags, cost);
12396   } else {
12397     rows = storage_multi_range_read_info_const(keyno, seq, seq_init_param,
12398                                                n_ranges, bufsz,
12399                                                flags, cost);
12400   }
12401   DBUG_RETURN(rows);
12402 }
12403 
wrapper_multi_range_read_info(uint keyno,uint n_ranges,uint keys,uint key_parts,uint * bufsz,uint * flags,Cost_estimate * cost)12404 ha_rows ha_mroonga::wrapper_multi_range_read_info(uint keyno, uint n_ranges,
12405                                                   uint keys,
12406 #ifdef MRN_HANDLER_HAVE_MULTI_RANGE_READ_INFO_KEY_PARTS
12407                                                   uint key_parts,
12408 #endif
12409                                                   uint *bufsz,
12410                                                   uint *flags,
12411                                                   Cost_estimate *cost)
12412 {
12413   MRN_DBUG_ENTER_METHOD();
12414   ha_rows rows;
12415   KEY *key_info = &(table->key_info[keyno]);
12416   if (mrn_is_geo_key(key_info)) {
12417     rows = handler::multi_range_read_info(keyno, n_ranges, keys,
12418 #ifdef MRN_HANDLER_HAVE_MULTI_RANGE_READ_INFO_KEY_PARTS
12419                                           key_parts,
12420 #endif
12421                                           bufsz, flags, cost);
12422     DBUG_RETURN(rows);
12423   }
12424   MRN_SET_WRAP_SHARE_KEY(share, table->s);
12425   MRN_SET_WRAP_TABLE_KEY(this, table);
12426   if (fulltext_searching)
12427     set_pk_bitmap();
12428   rows = wrap_handler->multi_range_read_info(keyno, n_ranges, keys,
12429 #ifdef MRN_HANDLER_HAVE_MULTI_RANGE_READ_INFO_KEY_PARTS
12430                                              key_parts,
12431 #endif
12432                                              bufsz, flags, cost);
12433   MRN_SET_BASE_SHARE_KEY(share, table->s);
12434   MRN_SET_BASE_TABLE_KEY(this, table);
12435   DBUG_RETURN(rows);
12436 }
12437 
storage_multi_range_read_info(uint keyno,uint n_ranges,uint keys,uint key_parts,uint * bufsz,uint * flags,Cost_estimate * cost)12438 ha_rows ha_mroonga::storage_multi_range_read_info(uint keyno, uint n_ranges,
12439                                                   uint keys,
12440 #ifdef MRN_HANDLER_HAVE_MULTI_RANGE_READ_INFO_KEY_PARTS
12441                                                   uint key_parts,
12442 #endif
12443                                                   uint *bufsz,
12444                                                   uint *flags,
12445                                                   Cost_estimate *cost)
12446 {
12447   MRN_DBUG_ENTER_METHOD();
12448   ha_rows rows = handler::multi_range_read_info(keyno, n_ranges, keys,
12449 #ifdef MRN_HANDLER_HAVE_MULTI_RANGE_READ_INFO_KEY_PARTS
12450                                                 key_parts,
12451 #endif
12452                                                 bufsz, flags, cost);
12453   DBUG_RETURN(rows);
12454 }
12455 
multi_range_read_info(uint keyno,uint n_ranges,uint keys,uint key_parts,uint * bufsz,uint * flags,Cost_estimate * cost)12456 ha_rows ha_mroonga::multi_range_read_info(uint keyno, uint n_ranges, uint keys,
12457 #ifdef MRN_HANDLER_HAVE_MULTI_RANGE_READ_INFO_KEY_PARTS
12458                                           uint key_parts,
12459 #endif
12460                                           uint *bufsz, uint *flags,
12461                                           Cost_estimate *cost)
12462 {
12463   MRN_DBUG_ENTER_METHOD();
12464   ha_rows rows;
12465   if (share->wrapper_mode)
12466   {
12467     rows = wrapper_multi_range_read_info(keyno, n_ranges, keys,
12468 #ifdef MRN_HANDLER_HAVE_MULTI_RANGE_READ_INFO_KEY_PARTS
12469                                          key_parts,
12470 #endif
12471                                          bufsz, flags, cost);
12472   } else {
12473     rows = storage_multi_range_read_info(keyno, n_ranges, keys,
12474 #ifdef MRN_HANDLER_HAVE_MULTI_RANGE_READ_INFO_KEY_PARTS
12475                                          key_parts,
12476 #endif
12477                                          bufsz, flags, cost);
12478   }
12479   DBUG_RETURN(rows);
12480 }
12481 
wrapper_multi_range_read_init(RANGE_SEQ_IF * seq,void * seq_init_param,uint n_ranges,uint mode,HANDLER_BUFFER * buf)12482 int ha_mroonga::wrapper_multi_range_read_init(RANGE_SEQ_IF *seq,
12483                                               void *seq_init_param,
12484                                               uint n_ranges, uint mode,
12485                                               HANDLER_BUFFER *buf)
12486 {
12487   MRN_DBUG_ENTER_METHOD();
12488   int error = 0;
12489   KEY *key_info = &(table->key_info[active_index]);
12490   if (mrn_is_geo_key(key_info)) {
12491     error = handler::multi_range_read_init(seq, seq_init_param,
12492                                            n_ranges, mode, buf);
12493     DBUG_RETURN(error);
12494   }
12495   MRN_SET_WRAP_SHARE_KEY(share, table->s);
12496   MRN_SET_WRAP_TABLE_KEY(this, table);
12497   if (fulltext_searching)
12498     set_pk_bitmap();
12499   error = wrap_handler->multi_range_read_init(seq, seq_init_param,
12500                                               n_ranges, mode, buf);
12501   MRN_SET_BASE_SHARE_KEY(share, table->s);
12502   MRN_SET_BASE_TABLE_KEY(this, table);
12503   DBUG_RETURN(error);
12504 }
12505 
storage_multi_range_read_init(RANGE_SEQ_IF * seq,void * seq_init_param,uint n_ranges,uint mode,HANDLER_BUFFER * buf)12506 int ha_mroonga::storage_multi_range_read_init(RANGE_SEQ_IF *seq,
12507                                               void *seq_init_param,
12508                                               uint n_ranges, uint mode,
12509                                               HANDLER_BUFFER *buf)
12510 {
12511   MRN_DBUG_ENTER_METHOD();
12512   int error = handler::multi_range_read_init(seq, seq_init_param,
12513                                              n_ranges, mode, buf);
12514   DBUG_RETURN(error);
12515 }
12516 
multi_range_read_init(RANGE_SEQ_IF * seq,void * seq_init_param,uint n_ranges,uint mode,HANDLER_BUFFER * buf)12517 int ha_mroonga::multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param,
12518                                       uint n_ranges, uint mode,
12519                                       HANDLER_BUFFER *buf)
12520 {
12521   MRN_DBUG_ENTER_METHOD();
12522   int error = 0;
12523   if (share->wrapper_mode)
12524   {
12525     error = wrapper_multi_range_read_init(seq, seq_init_param,
12526                                           n_ranges, mode, buf);
12527   } else {
12528     error = storage_multi_range_read_init(seq, seq_init_param,
12529                                           n_ranges, mode, buf);
12530   }
12531   DBUG_RETURN(error);
12532 }
12533 
wrapper_multi_range_read_next(range_id_t * range_info)12534 int ha_mroonga::wrapper_multi_range_read_next(range_id_t *range_info)
12535 {
12536   MRN_DBUG_ENTER_METHOD();
12537   int error = 0;
12538   KEY *key_info = &(table->key_info[active_index]);
12539   if (mrn_is_geo_key(key_info)) {
12540     error = handler::multi_range_read_next(range_info);
12541     DBUG_RETURN(error);
12542   }
12543   MRN_SET_WRAP_SHARE_KEY(share, table->s);
12544   MRN_SET_WRAP_TABLE_KEY(this, table);
12545   if (fulltext_searching)
12546     set_pk_bitmap();
12547   error = wrap_handler->multi_range_read_next(range_info);
12548   MRN_SET_BASE_SHARE_KEY(share, table->s);
12549   MRN_SET_BASE_TABLE_KEY(this, table);
12550   DBUG_RETURN(error);
12551 }
12552 
storage_multi_range_read_next(range_id_t * range_info)12553 int ha_mroonga::storage_multi_range_read_next(range_id_t *range_info)
12554 {
12555   MRN_DBUG_ENTER_METHOD();
12556   int error = handler::multi_range_read_next(range_info);
12557   DBUG_RETURN(error);
12558 }
12559 
multi_range_read_next(range_id_t * range_info)12560 int ha_mroonga::multi_range_read_next(range_id_t *range_info)
12561 {
12562   MRN_DBUG_ENTER_METHOD();
12563   int error = 0;
12564   if (share->wrapper_mode)
12565   {
12566     error = wrapper_multi_range_read_next(range_info);
12567   } else {
12568     error = storage_multi_range_read_next(range_info);
12569   }
12570   DBUG_RETURN(error);
12571 }
12572 #else // MRN_HANDLER_HAVE_MULTI_RANGE_READ
wrapper_read_multi_range_first(KEY_MULTI_RANGE ** found_range_p,KEY_MULTI_RANGE * ranges,uint range_count,bool sorted,HANDLER_BUFFER * buffer)12573 int ha_mroonga::wrapper_read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
12574                                                KEY_MULTI_RANGE *ranges,
12575                                                uint range_count,
12576                                                bool sorted,
12577                                                HANDLER_BUFFER *buffer)
12578 {
12579   int error = 0;
12580   MRN_DBUG_ENTER_METHOD();
12581   KEY *key_info = &(table->key_info[active_index]);
12582   if (mrn_is_geo_key(key_info)) {
12583     error = handler::read_multi_range_first(found_range_p, ranges,
12584                                             range_count, sorted, buffer);
12585     DBUG_RETURN(error);
12586   }
12587   MRN_SET_WRAP_SHARE_KEY(share, table->s);
12588   MRN_SET_WRAP_TABLE_KEY(this, table);
12589   if (fulltext_searching)
12590     set_pk_bitmap();
12591   error = wrap_handler->read_multi_range_first(found_range_p, ranges,
12592                                                   range_count, sorted, buffer);
12593   MRN_SET_BASE_SHARE_KEY(share, table->s);
12594   MRN_SET_BASE_TABLE_KEY(this, table);
12595   DBUG_RETURN(error);
12596 }
12597 
storage_read_multi_range_first(KEY_MULTI_RANGE ** found_range_p,KEY_MULTI_RANGE * ranges,uint range_count,bool sorted,HANDLER_BUFFER * buffer)12598 int ha_mroonga::storage_read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
12599                                                KEY_MULTI_RANGE *ranges,
12600                                                uint range_count,
12601                                                bool sorted,
12602                                                HANDLER_BUFFER *buffer)
12603 {
12604   MRN_DBUG_ENTER_METHOD();
12605   int error = handler::read_multi_range_first(found_range_p, ranges,
12606                                               range_count, sorted, buffer);
12607   DBUG_RETURN(error);
12608 }
12609 
read_multi_range_first(KEY_MULTI_RANGE ** found_range_p,KEY_MULTI_RANGE * ranges,uint range_count,bool sorted,HANDLER_BUFFER * buffer)12610 int ha_mroonga::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
12611                                        KEY_MULTI_RANGE *ranges,
12612                                        uint range_count,
12613                                        bool sorted,
12614                                        HANDLER_BUFFER *buffer)
12615 {
12616   MRN_DBUG_ENTER_METHOD();
12617   int error = 0;
12618   if (share->wrapper_mode)
12619   {
12620     error = wrapper_read_multi_range_first(found_range_p, ranges,
12621                                            range_count, sorted, buffer);
12622   } else {
12623     error = storage_read_multi_range_first(found_range_p, ranges,
12624                                            range_count, sorted, buffer);
12625   }
12626   DBUG_RETURN(error);
12627 }
12628 
wrapper_read_multi_range_next(KEY_MULTI_RANGE ** found_range_p)12629 int ha_mroonga::wrapper_read_multi_range_next(KEY_MULTI_RANGE **found_range_p)
12630 {
12631   int error = 0;
12632   MRN_DBUG_ENTER_METHOD();
12633   KEY *key_info = &(table->key_info[active_index]);
12634   if (mrn_is_geo_key(key_info)) {
12635     error = handler::read_multi_range_next(found_range_p);
12636     DBUG_RETURN(error);
12637   }
12638   MRN_SET_WRAP_SHARE_KEY(share, table->s);
12639   MRN_SET_WRAP_TABLE_KEY(this, table);
12640   if (fulltext_searching)
12641     set_pk_bitmap();
12642   error = wrap_handler->read_multi_range_next(found_range_p);
12643   MRN_SET_BASE_SHARE_KEY(share, table->s);
12644   MRN_SET_BASE_TABLE_KEY(this, table);
12645   DBUG_RETURN(error);
12646 }
12647 
storage_read_multi_range_next(KEY_MULTI_RANGE ** found_range_p)12648 int ha_mroonga::storage_read_multi_range_next(KEY_MULTI_RANGE **found_range_p)
12649 {
12650   MRN_DBUG_ENTER_METHOD();
12651   int error = handler::read_multi_range_next(found_range_p);
12652   DBUG_RETURN(error);
12653 }
12654 
read_multi_range_next(KEY_MULTI_RANGE ** found_range_p)12655 int ha_mroonga::read_multi_range_next(KEY_MULTI_RANGE **found_range_p)
12656 {
12657   MRN_DBUG_ENTER_METHOD();
12658   int error = 0;
12659   if (share->wrapper_mode)
12660   {
12661     error = wrapper_read_multi_range_next(found_range_p);
12662   } else {
12663     error = storage_read_multi_range_next(found_range_p);
12664   }
12665   DBUG_RETURN(error);
12666 }
12667 #endif // MRN_HANDLER_HAVE_MULTI_RANGE_READ
12668 
12669 #ifdef MRN_HANDLER_START_BULK_INSERT_HAS_FLAGS
wrapper_start_bulk_insert(ha_rows rows,uint flags)12670 void ha_mroonga::wrapper_start_bulk_insert(ha_rows rows, uint flags)
12671 #else
12672 void ha_mroonga::wrapper_start_bulk_insert(ha_rows rows)
12673 #endif
12674 {
12675   MRN_DBUG_ENTER_METHOD();
12676   MRN_SET_WRAP_SHARE_KEY(share, table->s);
12677   MRN_SET_WRAP_TABLE_KEY(this, table);
12678 #ifdef MRN_HANDLER_START_BULK_INSERT_HAS_FLAGS
12679   wrap_handler->ha_start_bulk_insert(rows, flags);
12680 #else
12681   wrap_handler->ha_start_bulk_insert(rows);
12682 #endif
12683   MRN_SET_BASE_SHARE_KEY(share, table->s);
12684   MRN_SET_BASE_TABLE_KEY(this, table);
12685   DBUG_VOID_RETURN;
12686 }
12687 
12688 #ifdef MRN_HANDLER_START_BULK_INSERT_HAS_FLAGS
storage_start_bulk_insert(ha_rows rows,uint flags)12689 void ha_mroonga::storage_start_bulk_insert(ha_rows rows, uint flags)
12690 #else
12691 void ha_mroonga::storage_start_bulk_insert(ha_rows rows)
12692 #endif
12693 {
12694   MRN_DBUG_ENTER_METHOD();
12695   DBUG_VOID_RETURN;
12696 }
12697 
12698 #ifdef MRN_HANDLER_START_BULK_INSERT_HAS_FLAGS
start_bulk_insert(ha_rows rows,uint flags)12699 void ha_mroonga::start_bulk_insert(ha_rows rows, uint flags)
12700 #else
12701 void ha_mroonga::start_bulk_insert(ha_rows rows)
12702 #endif
12703 {
12704   MRN_DBUG_ENTER_METHOD();
12705   if (share->wrapper_mode) {
12706 #ifdef MRN_HANDLER_START_BULK_INSERT_HAS_FLAGS
12707     wrapper_start_bulk_insert(rows, flags);
12708 #else
12709     wrapper_start_bulk_insert(rows);
12710 #endif
12711   } else {
12712 #ifdef MRN_HANDLER_START_BULK_INSERT_HAS_FLAGS
12713     storage_start_bulk_insert(rows, flags);
12714 #else
12715     storage_start_bulk_insert(rows);
12716 #endif
12717   }
12718   DBUG_VOID_RETURN;
12719 }
12720 
wrapper_end_bulk_insert()12721 int ha_mroonga::wrapper_end_bulk_insert()
12722 {
12723   int error = 0;
12724   MRN_DBUG_ENTER_METHOD();
12725   MRN_SET_WRAP_SHARE_KEY(share, table->s);
12726   MRN_SET_WRAP_TABLE_KEY(this, table);
12727   error = wrap_handler->ha_end_bulk_insert();
12728   MRN_SET_BASE_SHARE_KEY(share, table->s);
12729   MRN_SET_BASE_TABLE_KEY(this, table);
12730   DBUG_RETURN(error);
12731 }
12732 
storage_end_bulk_insert()12733 int ha_mroonga::storage_end_bulk_insert()
12734 {
12735   MRN_DBUG_ENTER_METHOD();
12736   DBUG_RETURN(0);
12737 }
12738 
end_bulk_insert()12739 int ha_mroonga::end_bulk_insert()
12740 {
12741   MRN_DBUG_ENTER_METHOD();
12742   int error = 0;
12743   if (share->wrapper_mode)
12744   {
12745     error = wrapper_end_bulk_insert();
12746   } else {
12747     error = storage_end_bulk_insert();
12748   }
12749   DBUG_RETURN(error);
12750 }
12751 
generic_delete_all_rows(grn_obj * target_grn_table,const char * function_name)12752 int ha_mroonga::generic_delete_all_rows(grn_obj *target_grn_table,
12753                                         const char *function_name)
12754 {
12755   MRN_DBUG_ENTER_METHOD();
12756 
12757   int error = 0;
12758 
12759   error = mrn_change_encoding(ctx, system_charset_info);
12760   if (error)
12761     DBUG_RETURN(error);
12762 
12763   if (is_dry_write()) {
12764     DBUG_PRINT("info",
12765                ("mroonga: dry write: %s::%s", MRN_CLASS_NAME, function_name));
12766     DBUG_RETURN(error);
12767   }
12768 
12769   grn_table_cursor *cursor;
12770   cursor = grn_table_cursor_open(ctx, target_grn_table,
12771                                  NULL, 0,
12772                                  NULL, 0,
12773                                  0, -1,
12774                                  0);
12775   if (cursor) {
12776     while (grn_table_cursor_next(ctx, cursor) != GRN_ID_NIL) {
12777       grn_table_cursor_delete(ctx, cursor);
12778     }
12779     grn_table_cursor_close(ctx, cursor);
12780   } else {
12781     error = ER_ERROR_ON_WRITE;
12782     my_message(error, ctx->errbuf, MYF(0));
12783   }
12784   DBUG_RETURN(error);
12785 }
12786 
wrapper_delete_all_rows()12787 int ha_mroonga::wrapper_delete_all_rows()
12788 {
12789   int error = 0;
12790   MRN_DBUG_ENTER_METHOD();
12791   MRN_SET_WRAP_SHARE_KEY(share, table->s);
12792   MRN_SET_WRAP_TABLE_KEY(this, table);
12793   error = wrap_handler->ha_delete_all_rows();
12794   MRN_SET_BASE_SHARE_KEY(share, table->s);
12795   MRN_SET_BASE_TABLE_KEY(this, table);
12796 
12797   if (error) {
12798     DBUG_RETURN(error);
12799   }
12800 
12801   if (!wrapper_have_target_index()) {
12802     DBUG_RETURN(error);
12803   }
12804 
12805   uint i;
12806   uint n_keys = table->s->keys;
12807   for (i = 0; i < n_keys; i++) {
12808     KEY *key_info = &(table->key_info[i]);
12809 
12810     if (!(wrapper_is_target_index(key_info))) {
12811       continue;
12812     }
12813 
12814     if (!grn_index_tables[i]) {
12815       /* disable keys */
12816       continue;
12817     }
12818 
12819     error = generic_delete_all_rows(grn_index_tables[i], __FUNCTION__);
12820     if (error) {
12821       break;
12822     }
12823   }
12824 
12825   int grn_table_error;
12826   grn_table_error = generic_delete_all_rows(grn_table, __FUNCTION__);
12827   if (!error) {
12828     error = grn_table_error;
12829   }
12830 
12831   DBUG_RETURN(error);
12832 }
12833 
storage_delete_all_rows()12834 int ha_mroonga::storage_delete_all_rows()
12835 {
12836   MRN_DBUG_ENTER_METHOD();
12837   int error = generic_delete_all_rows(grn_table, __FUNCTION__);
12838   if (!error) {
12839     uint n_keys = table->s->keys;
12840     for (uint i = 0; i < n_keys; i++) {
12841       if (i == table->s->primary_key) {
12842         continue;
12843       }
12844 
12845       KEY *key_info = &(table->key_info[i]);
12846       if (!(key_info->flags & HA_NOSAME)) {
12847         continue;
12848       }
12849 
12850       grn_obj *index_table = grn_index_tables[i];
12851       if (!index_table) {
12852         continue;
12853       }
12854 
12855       error = generic_delete_all_rows(index_table, __FUNCTION__);
12856       if (error) {
12857         break;
12858       }
12859     }
12860   }
12861   DBUG_RETURN(error);
12862 }
12863 
delete_all_rows()12864 int ha_mroonga::delete_all_rows()
12865 {
12866   MRN_DBUG_ENTER_METHOD();
12867   int error = 0;
12868   if (share->wrapper_mode)
12869   {
12870     error = wrapper_delete_all_rows();
12871   } else {
12872     error = storage_delete_all_rows();
12873   }
12874   DBUG_RETURN(error);
12875 }
12876 
wrapper_truncate()12877 int ha_mroonga::wrapper_truncate()
12878 {
12879   int error = 0;
12880   MRN_SHARE *tmp_share;
12881   MRN_DBUG_ENTER_METHOD();
12882 
12883   if (!(tmp_share = mrn_get_share(table->s->table_name.str, table, &error)))
12884     DBUG_RETURN(error);
12885 
12886   MRN_SET_WRAP_SHARE_KEY(share, table->s);
12887   MRN_SET_WRAP_TABLE_KEY(this, table);
12888   error = parse_engine_table_options(ha_thd(), tmp_share->hton, table->s)
12889     ? MRN_GET_ERROR_NUMBER
12890     : wrap_handler->ha_truncate();
12891   MRN_SET_BASE_SHARE_KEY(share, table->s);
12892   MRN_SET_BASE_TABLE_KEY(this, table);
12893 
12894   mrn_free_share(tmp_share);
12895 
12896   if (!error && wrapper_have_target_index()) {
12897     error = wrapper_truncate_index();
12898   }
12899 
12900   DBUG_RETURN(error);
12901 }
12902 
wrapper_truncate_index()12903 int ha_mroonga::wrapper_truncate_index()
12904 {
12905   MRN_DBUG_ENTER_METHOD();
12906 
12907   int error = 0;
12908 
12909   error = mrn_change_encoding(ctx, system_charset_info);
12910   if (error)
12911     DBUG_RETURN(error);
12912 
12913   if (is_dry_write()) {
12914     DBUG_PRINT("info",
12915                ("mroonga: dry write: %s::%s", MRN_CLASS_NAME, __FUNCTION__));
12916     DBUG_RETURN(error);
12917   }
12918 
12919   grn_rc rc;
12920   uint i;
12921   uint n_keys = table->s->keys;
12922   for (i = 0; i < n_keys; i++) {
12923     KEY *key_info = &(table->key_info[i]);
12924 
12925     if (!(wrapper_is_target_index(key_info))) {
12926       continue;
12927     }
12928 
12929     if (!grn_index_tables[i]) {
12930       /* disable keys */
12931       continue;
12932     }
12933 
12934     rc = grn_table_truncate(ctx, grn_index_tables[i]);
12935     if (rc) {
12936       error = ER_ERROR_ON_WRITE;
12937       my_message(error, ctx->errbuf, MYF(0));
12938       goto err;
12939     }
12940   }
12941 err:
12942   rc = grn_table_truncate(ctx, grn_table);
12943   if (rc) {
12944     error = ER_ERROR_ON_WRITE;
12945     my_message(error, ctx->errbuf, MYF(0));
12946   }
12947 
12948   DBUG_RETURN(error);
12949 }
12950 
storage_truncate()12951 int ha_mroonga::storage_truncate()
12952 {
12953   MRN_DBUG_ENTER_METHOD();
12954   int error = 0;
12955 
12956   if (is_dry_write()) {
12957     DBUG_PRINT("info", ("mroonga: dry write: ha_mroonga::%s", __FUNCTION__));
12958     DBUG_RETURN(error);
12959   }
12960 
12961   grn_rc rc;
12962   rc = grn_table_truncate(ctx, grn_table);
12963   if (rc) {
12964     my_message(ER_ERROR_ON_WRITE, ctx->errbuf, MYF(0));
12965     DBUG_RETURN(ER_ERROR_ON_WRITE);
12966   }
12967   error = storage_truncate_index();
12968 
12969   if (!error && thd_sql_command(ha_thd()) == SQLCOM_TRUNCATE) {
12970     MRN_LONG_TERM_SHARE *long_term_share = share->long_term_share;
12971     mrn::Lock lock(&long_term_share->auto_inc_mutex);
12972     long_term_share->auto_inc_value = 0;
12973     DBUG_PRINT("info", ("mroonga: auto_inc_value=%llu",
12974       long_term_share->auto_inc_value));
12975     long_term_share->auto_inc_inited = false;
12976   }
12977 
12978   DBUG_RETURN(error);
12979 }
12980 
storage_truncate_index()12981 int ha_mroonga::storage_truncate_index()
12982 {
12983   MRN_DBUG_ENTER_METHOD();
12984   int error = 0;
12985 
12986   error = mrn_change_encoding(ctx, system_charset_info);
12987   if (error)
12988     DBUG_RETURN(error);
12989 
12990   grn_rc rc;
12991   uint i;
12992   uint n_keys = table->s->keys;
12993   for (i = 0; i < n_keys; i++) {
12994     if (i == table->s->primary_key) {
12995       continue;
12996     }
12997 
12998     KEY *key_info = &(table->key_info[i]);
12999 
13000     if (
13001       !(key_info->flags & HA_NOSAME) &&
13002       (KEY_N_KEY_PARTS(key_info) == 1 || (key_info->flags & HA_FULLTEXT))
13003     ) {
13004       continue;
13005     }
13006 
13007     if (!grn_index_tables[i]) {
13008       /* disable keys */
13009       continue;
13010     }
13011 
13012     rc = grn_table_truncate(ctx, grn_index_tables[i]);
13013     if (rc) {
13014       error = ER_ERROR_ON_WRITE;
13015       my_message(error, ctx->errbuf, MYF(0));
13016       goto err;
13017     }
13018   }
13019 err:
13020   DBUG_RETURN(error);
13021 }
13022 
truncate()13023 int ha_mroonga::truncate()
13024 {
13025   MRN_DBUG_ENTER_METHOD();
13026   int error = 0;
13027   if (share->wrapper_mode)
13028   {
13029     error = wrapper_truncate();
13030   } else {
13031     error = storage_truncate();
13032   }
13033   if (!error) {
13034     operations_->clear(table->s->table_name.str,
13035                        table->s->table_name.length);
13036   }
13037   DBUG_RETURN(error);
13038 }
13039 
wrapper_scan_time()13040 double ha_mroonga::wrapper_scan_time()
13041 {
13042   double res;
13043   MRN_DBUG_ENTER_METHOD();
13044   MRN_SET_WRAP_SHARE_KEY(share, table->s);
13045   MRN_SET_WRAP_TABLE_KEY(this, table);
13046   res = wrap_handler->scan_time();
13047   MRN_SET_BASE_SHARE_KEY(share, table->s);
13048   MRN_SET_BASE_TABLE_KEY(this, table);
13049   DBUG_RETURN(res);
13050 }
13051 
storage_scan_time()13052 double ha_mroonga::storage_scan_time()
13053 {
13054   MRN_DBUG_ENTER_METHOD();
13055   double time = handler::scan_time();
13056   DBUG_RETURN(time);
13057 }
13058 
scan_time()13059 double ha_mroonga::scan_time()
13060 {
13061   MRN_DBUG_ENTER_METHOD();
13062   double time;
13063   if (share->wrapper_mode)
13064   {
13065     time = wrapper_scan_time();
13066   } else {
13067     time = storage_scan_time();
13068   }
13069   DBUG_RETURN(time);
13070 }
13071 
wrapper_read_time(uint index,uint ranges,ha_rows rows)13072 double ha_mroonga::wrapper_read_time(uint index, uint ranges, ha_rows rows)
13073 {
13074   double res;
13075   MRN_DBUG_ENTER_METHOD();
13076   if (index < MAX_KEY) {
13077     KEY *key_info = &(table->key_info[index]);
13078     if (mrn_is_geo_key(key_info)) {
13079       res = handler::read_time(index, ranges, rows);
13080       DBUG_RETURN(res);
13081     }
13082     MRN_SET_WRAP_SHARE_KEY(share, table->s);
13083     MRN_SET_WRAP_TABLE_KEY(this, table);
13084     res = wrap_handler->read_time(share->wrap_key_nr[index], ranges, rows);
13085     MRN_SET_BASE_SHARE_KEY(share, table->s);
13086     MRN_SET_BASE_TABLE_KEY(this, table);
13087   } else {
13088     MRN_SET_WRAP_SHARE_KEY(share, table->s);
13089     MRN_SET_WRAP_TABLE_KEY(this, table);
13090     res = wrap_handler->read_time(index, ranges, rows);
13091     MRN_SET_BASE_SHARE_KEY(share, table->s);
13092     MRN_SET_BASE_TABLE_KEY(this, table);
13093   }
13094   DBUG_RETURN(res);
13095 }
13096 
storage_read_time(uint index,uint ranges,ha_rows rows)13097 double ha_mroonga::storage_read_time(uint index, uint ranges, ha_rows rows)
13098 {
13099   MRN_DBUG_ENTER_METHOD();
13100   double time = handler::read_time(index, ranges, rows);
13101   DBUG_RETURN(time);
13102 }
13103 
read_time(uint index,uint ranges,ha_rows rows)13104 double ha_mroonga::read_time(uint index, uint ranges, ha_rows rows)
13105 {
13106   MRN_DBUG_ENTER_METHOD();
13107   double time;
13108   if (share->wrapper_mode)
13109   {
13110     time = wrapper_read_time(index, ranges, rows);
13111   } else {
13112     time = storage_read_time(index, ranges, rows);
13113   }
13114   DBUG_RETURN(time);
13115 }
13116 
13117 #ifdef MRN_HANDLER_HAVE_KEYS_TO_USE_FOR_SCANNING
wrapper_keys_to_use_for_scanning()13118 const key_map *ha_mroonga::wrapper_keys_to_use_for_scanning()
13119 {
13120   const key_map *res;
13121   MRN_DBUG_ENTER_METHOD();
13122   MRN_SET_WRAP_SHARE_KEY(share, table->s);
13123   MRN_SET_WRAP_TABLE_KEY(this, table);
13124   res = wrap_handler->keys_to_use_for_scanning();
13125   MRN_SET_BASE_SHARE_KEY(share, table->s);
13126   MRN_SET_BASE_TABLE_KEY(this, table);
13127   DBUG_RETURN(res);
13128 }
13129 
storage_keys_to_use_for_scanning()13130 const key_map *ha_mroonga::storage_keys_to_use_for_scanning()
13131 {
13132   MRN_DBUG_ENTER_METHOD();
13133   DBUG_RETURN(&key_map_full);
13134 }
13135 
keys_to_use_for_scanning()13136 const key_map *ha_mroonga::keys_to_use_for_scanning()
13137 {
13138   MRN_DBUG_ENTER_METHOD();
13139   const key_map *key_map;
13140   if (share->wrapper_mode)
13141   {
13142     key_map = wrapper_keys_to_use_for_scanning();
13143   } else {
13144     key_map = storage_keys_to_use_for_scanning();
13145   }
13146   DBUG_RETURN(key_map);
13147 }
13148 #endif
13149 
wrapper_estimate_rows_upper_bound()13150 ha_rows ha_mroonga::wrapper_estimate_rows_upper_bound()
13151 {
13152   ha_rows res;
13153   MRN_DBUG_ENTER_METHOD();
13154   MRN_SET_WRAP_SHARE_KEY(share, table->s);
13155   MRN_SET_WRAP_TABLE_KEY(this, table);
13156   res = wrap_handler->estimate_rows_upper_bound();
13157   MRN_SET_BASE_SHARE_KEY(share, table->s);
13158   MRN_SET_BASE_TABLE_KEY(this, table);
13159   DBUG_RETURN(res);
13160 }
13161 
storage_estimate_rows_upper_bound()13162 ha_rows ha_mroonga::storage_estimate_rows_upper_bound()
13163 {
13164   MRN_DBUG_ENTER_METHOD();
13165   ha_rows rows = handler::estimate_rows_upper_bound();
13166   DBUG_RETURN(rows);
13167 }
13168 
estimate_rows_upper_bound()13169 ha_rows ha_mroonga::estimate_rows_upper_bound()
13170 {
13171   MRN_DBUG_ENTER_METHOD();
13172   ha_rows rows;
13173   if (share->wrapper_mode)
13174   {
13175     rows = wrapper_estimate_rows_upper_bound();
13176   } else {
13177     rows = storage_estimate_rows_upper_bound();
13178   }
13179   DBUG_RETURN(rows);
13180 }
13181 
wrapper_update_create_info(HA_CREATE_INFO * create_info)13182 void ha_mroonga::wrapper_update_create_info(HA_CREATE_INFO* create_info)
13183 {
13184   MRN_DBUG_ENTER_METHOD();
13185   MRN_SET_WRAP_SHARE_KEY(share, table->s);
13186   MRN_SET_WRAP_TABLE_KEY(this, table);
13187   wrap_handler->update_create_info(create_info);
13188   MRN_SET_BASE_SHARE_KEY(share, table->s);
13189   MRN_SET_BASE_TABLE_KEY(this, table);
13190   DBUG_VOID_RETURN;
13191 }
13192 
storage_update_create_info(HA_CREATE_INFO * create_info)13193 void ha_mroonga::storage_update_create_info(HA_CREATE_INFO* create_info)
13194 {
13195   MRN_DBUG_ENTER_METHOD();
13196   handler::update_create_info(create_info);
13197   if (!(create_info->used_fields & HA_CREATE_USED_AUTO)) {
13198     MRN_LONG_TERM_SHARE *long_term_share = share->long_term_share;
13199     if (!long_term_share->auto_inc_inited) {
13200       storage_info(HA_STATUS_AUTO);
13201     }
13202     create_info->auto_increment_value = long_term_share->auto_inc_value;
13203     DBUG_PRINT("info", ("mroonga: auto_inc_value=%llu",
13204       long_term_share->auto_inc_value));
13205   }
13206   DBUG_VOID_RETURN;
13207 }
13208 
update_create_info(HA_CREATE_INFO * create_info)13209 void ha_mroonga::update_create_info(HA_CREATE_INFO* create_info)
13210 {
13211   MRN_DBUG_ENTER_METHOD();
13212   if (!create_info->connect_string.str)
13213   {
13214     create_info->connect_string.str = table->s->connect_string.str;
13215     create_info->connect_string.length = table->s->connect_string.length;
13216   }
13217   if (share->wrapper_mode)
13218     wrapper_update_create_info(create_info);
13219   else
13220     storage_update_create_info(create_info);
13221   st_mrn_slot_data *slot_data = mrn_get_slot_data(ha_thd(), true);
13222   if (slot_data) {
13223     slot_data->alter_create_info = create_info;
13224     if (slot_data->alter_connect_string) {
13225       my_free(slot_data->alter_connect_string);
13226       slot_data->alter_connect_string = NULL;
13227     }
13228     if (create_info->connect_string.str) {
13229       slot_data->alter_connect_string =
13230         mrn_my_strndup(create_info->connect_string.str,
13231                        create_info->connect_string.length,
13232                        MYF(MY_WME));
13233     }
13234     if (slot_data->alter_comment) {
13235       my_free(slot_data->alter_comment);
13236       slot_data->alter_comment = NULL;
13237     }
13238     if (create_info->comment.str) {
13239       slot_data->alter_comment =
13240         mrn_my_strndup(create_info->comment.str,
13241                        create_info->comment.length,
13242                        MYF(MY_WME));
13243     }
13244     if (share && share->disable_keys) {
13245       slot_data->disable_keys_create_info = create_info;
13246     }
13247   }
13248   DBUG_VOID_RETURN;
13249 }
13250 
wrapper_rename_table(const char * from,const char * to,MRN_SHARE * tmp_share,const char * from_table_name,const char * to_table_name)13251 int ha_mroonga::wrapper_rename_table(const char *from, const char *to,
13252                                      MRN_SHARE *tmp_share,
13253                                      const char *from_table_name,
13254                                      const char *to_table_name)
13255 {
13256   int error = 0;
13257   handler *hnd;
13258   MRN_DBUG_ENTER_METHOD();
13259 
13260   hnd = get_new_handler(tmp_share->table_share,
13261                         current_thd->mem_root,
13262                         tmp_share->hton);
13263   if (!hnd)
13264   {
13265     DBUG_RETURN(HA_ERR_OUT_OF_MEM);
13266   }
13267 
13268   if ((error = hnd->ha_rename_table(from, to)))
13269   {
13270     delete hnd;
13271     DBUG_RETURN(error);
13272   }
13273 
13274   error = wrapper_rename_index(from, to, tmp_share,
13275                                from_table_name, to_table_name);
13276 
13277   delete hnd;
13278   DBUG_RETURN(error);
13279 }
13280 
wrapper_rename_index(const char * from,const char * to,MRN_SHARE * tmp_share,const char * from_table_name,const char * to_table_name)13281 int ha_mroonga::wrapper_rename_index(const char *from, const char *to,
13282                                      MRN_SHARE *tmp_share,
13283                                      const char *from_table_name,
13284                                      const char *to_table_name)
13285 {
13286   int error;
13287   grn_rc rc;
13288   MRN_DBUG_ENTER_METHOD();
13289   error = mrn_change_encoding(ctx, system_charset_info);
13290   if (error)
13291     DBUG_RETURN(error);
13292 
13293   error = ensure_database_open(from);
13294   if (error)
13295     DBUG_RETURN(error);
13296 
13297   TABLE_SHARE *tmp_table_share = tmp_share->table_share;
13298 
13299   uint i;
13300   for (i = 0; i < tmp_table_share->keys; i++) {
13301     const char *mysql_index_name = tmp_table_share->key_info[i].name.str;
13302     mrn::IndexTableName from_index_table_name(from_table_name, mysql_index_name);
13303     mrn::IndexTableName to_index_table_name(to_table_name, mysql_index_name);
13304     grn_obj *index_table;
13305     index_table = grn_ctx_get(ctx,
13306                               from_index_table_name.c_str(),
13307                               from_index_table_name.length());
13308     if (!index_table) {
13309       index_table = grn_ctx_get(ctx,
13310                                 from_index_table_name.old_c_str(),
13311                                 from_index_table_name.old_length());
13312     }
13313     if (index_table) {
13314       rc = grn_table_rename(ctx, index_table,
13315                             to_index_table_name.c_str(),
13316                             to_index_table_name.length());
13317       if (rc != GRN_SUCCESS) {
13318         error = ER_CANT_OPEN_FILE;
13319         my_message(error, ctx->errbuf, MYF(0));
13320         DBUG_RETURN(error);
13321       }
13322     }
13323   }
13324 
13325   grn_obj *table = grn_ctx_get(ctx, from_table_name, strlen(from_table_name));
13326   if (ctx->rc != GRN_SUCCESS) {
13327     error = ER_CANT_OPEN_FILE;
13328     my_message(error, ctx->errbuf, MYF(0));
13329     DBUG_RETURN(error);
13330   }
13331   rc = grn_table_rename(ctx, table, to_table_name,
13332                         strlen(to_table_name));
13333   if (rc != GRN_SUCCESS) {
13334     error = ER_CANT_OPEN_FILE;
13335     my_message(error, ctx->errbuf, MYF(0));
13336     DBUG_RETURN(error);
13337   }
13338   DBUG_RETURN(0);
13339 }
13340 
storage_rename_table(const char * from,const char * to,MRN_SHARE * tmp_share,const char * from_table_name,const char * to_table_name)13341 int ha_mroonga::storage_rename_table(const char *from, const char *to,
13342                                      MRN_SHARE *tmp_share,
13343                                      const char *from_table_name,
13344                                      const char *to_table_name)
13345 {
13346   int error;
13347   grn_rc rc;
13348   TABLE_SHARE *tmp_table_share = tmp_share->table_share;
13349   MRN_LONG_TERM_SHARE *from_long_term_share = tmp_share->long_term_share,
13350                       *to_long_term_share;
13351   MRN_DBUG_ENTER_METHOD();
13352   error = mrn_change_encoding(ctx, system_charset_info);
13353   if (error)
13354     DBUG_RETURN(error);
13355 
13356   error = ensure_database_open(from);
13357   if (error)
13358     DBUG_RETURN(error);
13359 
13360   if (!(to_long_term_share = mrn_get_long_term_share(to, strlen(to), &error)))
13361     DBUG_RETURN(error);
13362   to_long_term_share->auto_inc_value = from_long_term_share->auto_inc_value;
13363   DBUG_PRINT("info", ("mroonga: to_auto_inc_value=%llu",
13364     to_long_term_share->auto_inc_value));
13365   to_long_term_share->auto_inc_inited = from_long_term_share->auto_inc_inited;
13366 
13367   uint i;
13368   for (i = 0; i < tmp_table_share->keys; i++) {
13369     const char *mysql_index_name = tmp_table_share->key_info[i].name.str;
13370     mrn::IndexTableName from_index_table_name(from_table_name,
13371                                               mysql_index_name);
13372     mrn::IndexTableName to_index_table_name(to_table_name,
13373                                             mysql_index_name);
13374     grn_obj *index_table;
13375     index_table = grn_ctx_get(ctx,
13376                               from_index_table_name.c_str(),
13377                               from_index_table_name.length());
13378     if (!index_table) {
13379       index_table = grn_ctx_get(ctx,
13380                                 from_index_table_name.old_c_str(),
13381                                 from_index_table_name.old_length());
13382     }
13383     if (index_table) {
13384       rc = grn_table_rename(ctx, index_table,
13385                             to_index_table_name.c_str(),
13386                             to_index_table_name.length());
13387       if (rc != GRN_SUCCESS) {
13388         error = ER_CANT_OPEN_FILE;
13389         my_message(error, ctx->errbuf, MYF(0));
13390         goto error_end;
13391       }
13392     }
13393   }
13394 #ifdef MRN_SUPPORT_FOREIGN_KEYS
13395   error = storage_rename_foreign_key(tmp_share, from_table_name, to_table_name);
13396   if (error) {
13397     goto error_end;
13398   }
13399 #endif
13400   {
13401     grn_obj *table_obj = grn_ctx_get(ctx, from_table_name, strlen(from_table_name));
13402     if (ctx->rc != GRN_SUCCESS) {
13403       error = ER_CANT_OPEN_FILE;
13404       my_message(error, ctx->errbuf, MYF(0));
13405       goto error_end;
13406     }
13407     rc = grn_table_rename(ctx, table_obj, to_table_name,
13408                           strlen(to_table_name));
13409     if (rc != GRN_SUCCESS) {
13410       error = ER_CANT_OPEN_FILE;
13411       my_message(error, ctx->errbuf, MYF(0));
13412       goto error_end;
13413     }
13414   }
13415   DBUG_RETURN(0);
13416 
13417 error_end:
13418   mrn_free_long_term_share(to_long_term_share);
13419   DBUG_RETURN(error);
13420 }
13421 
13422 #ifdef MRN_SUPPORT_FOREIGN_KEYS
storage_rename_foreign_key(MRN_SHARE * tmp_share,const char * from_table_name,const char * to_table_name)13423 int ha_mroonga::storage_rename_foreign_key(MRN_SHARE *tmp_share,
13424                                            const char *from_table_name,
13425                                            const char *to_table_name)
13426 {
13427   int error;
13428   uint i;
13429   grn_obj *column, *ref_column;
13430   grn_rc rc;
13431   TABLE_SHARE *tmp_table_share = tmp_share->table_share;
13432   uint n_columns = tmp_table_share->fields;
13433   MRN_DBUG_ENTER_METHOD();
13434   for (i = 0; i < n_columns; ++i) {
13435     Field *field = tmp_table_share->field[i];
13436 
13437     if (!is_foreign_key_field(from_table_name, field->field_name.str)) {
13438       continue;
13439     }
13440 
13441     grn_obj *grn_from_table = grn_ctx_get(ctx, from_table_name, -1);
13442     mrn::ColumnName column_name(field->field_name);
13443     column = grn_obj_column(ctx,
13444                             grn_from_table,
13445                             column_name.c_str(),
13446                             column_name.length());
13447     if (!column) {
13448       continue;
13449     }
13450     grn_id ref_table_id = grn_obj_get_range(ctx, column);
13451     grn_obj *ref_table = grn_ctx_at(ctx, ref_table_id);
13452     mrn::IndexColumnName from_index_column_name(from_table_name,
13453                                                 column_name.c_str());
13454     ref_column = grn_obj_column(ctx, ref_table,
13455                                 from_index_column_name.c_str(),
13456                                 from_index_column_name.length());
13457     if (!ref_column) {
13458       continue;
13459     }
13460     mrn::IndexColumnName to_index_column_name(to_table_name,
13461                                               column_name.c_str());
13462     rc = grn_column_rename(ctx, ref_column,
13463                            to_index_column_name.c_str(),
13464                            to_index_column_name.length());
13465     if (rc != GRN_SUCCESS) {
13466       error = ER_CANT_OPEN_FILE;
13467       my_message(error, ctx->errbuf, MYF(0));
13468       DBUG_RETURN(error);
13469     }
13470   }
13471   DBUG_RETURN(0);
13472 }
13473 #endif
13474 
rename_table(const char * from,const char * to)13475 int ha_mroonga::rename_table(const char *from, const char *to)
13476 {
13477   int error = 0;
13478   TABLE_LIST table_list;
13479   TABLE_SHARE *tmp_table_share;
13480   TABLE tmp_table;
13481   MRN_SHARE *tmp_share;
13482   MRN_DBUG_ENTER_METHOD();
13483   mrn::PathMapper to_mapper(to);
13484   mrn::PathMapper from_mapper(from);
13485   if (strcmp(from_mapper.db_name(), to_mapper.db_name()))
13486     DBUG_RETURN(HA_ERR_WRONG_COMMAND);
13487 
13488   LEX_CSTRING db_name=    { from_mapper.db_name(), strlen(from_mapper.db_name()) };
13489   LEX_CSTRING table_name= { from_mapper.mysql_table_name(),
13490                             strlen(from_mapper.mysql_table_name()) };
13491   table_list.init_one_table(&db_name, &table_name, 0,TL_WRITE);
13492   mrn_open_mutex_lock(NULL);
13493   tmp_table_share = mrn_create_tmp_table_share(&table_list, from, &error);
13494   mrn_open_mutex_unlock(NULL);
13495   if (!tmp_table_share) {
13496     DBUG_RETURN(error);
13497   }
13498   tmp_table.s = tmp_table_share;
13499 #ifdef WITH_PARTITION_STORAGE_ENGINE
13500   tmp_table.part_info = NULL;
13501 #endif
13502   if (!(tmp_share = mrn_get_share(from, &tmp_table, &error)))
13503   {
13504     mrn_open_mutex_lock(NULL);
13505     mrn_free_tmp_table_share(tmp_table_share);
13506     mrn_open_mutex_unlock(NULL);
13507     DBUG_RETURN(error);
13508   }
13509 
13510   if (tmp_share->wrapper_mode)
13511   {
13512     error = wrapper_rename_table(from, to, tmp_share,
13513                                  from_mapper.table_name(),
13514                                  to_mapper.table_name());
13515   } else {
13516     error = storage_rename_table(from, to, tmp_share,
13517                                  from_mapper.table_name(),
13518                                  to_mapper.table_name());
13519   }
13520 
13521   if (!error && to_mapper.table_name()[0] == '#') {
13522     error = add_wrap_hton(to, tmp_share->hton);
13523   } else if (error && from_mapper.table_name()[0] == '#') {
13524     add_wrap_hton(from, tmp_share->hton);
13525   }
13526   if (!error) {
13527     mrn_free_long_term_share(tmp_share->long_term_share);
13528     tmp_share->long_term_share = NULL;
13529   }
13530   mrn_free_share(tmp_share);
13531   mrn_open_mutex_lock(NULL);
13532   mrn_free_tmp_table_share(tmp_table_share);
13533   mrn_open_mutex_unlock(NULL);
13534 
13535   DBUG_RETURN(error);
13536 }
13537 
wrapper_is_crashed() const13538 bool ha_mroonga::wrapper_is_crashed() const
13539 {
13540   bool res;
13541   MRN_DBUG_ENTER_METHOD();
13542   MRN_SET_WRAP_SHARE_KEY(share, table->s);
13543   MRN_SET_WRAP_TABLE_KEY(this, table);
13544   res = wrap_handler->is_crashed();
13545   MRN_SET_BASE_SHARE_KEY(share, table->s);
13546   MRN_SET_BASE_TABLE_KEY(this, table);
13547   DBUG_RETURN(res);
13548 }
13549 
storage_is_crashed() const13550 bool ha_mroonga::storage_is_crashed() const
13551 {
13552   MRN_DBUG_ENTER_METHOD();
13553   mrn::DatabaseRepairer repairer(ctx, ha_thd());
13554   bool crashed = repairer.is_crashed();
13555   DBUG_RETURN(crashed);
13556 }
13557 
is_crashed() const13558 bool ha_mroonga::is_crashed() const
13559 {
13560   MRN_DBUG_ENTER_METHOD();
13561   bool crashed;
13562   if (share->wrapper_mode)
13563   {
13564     crashed = wrapper_is_crashed();
13565   } else {
13566     crashed = storage_is_crashed();
13567   }
13568   DBUG_RETURN(crashed);
13569 }
13570 
wrapper_auto_repair(int error) const13571 bool ha_mroonga::wrapper_auto_repair(int error) const
13572 {
13573   bool repaired;
13574   MRN_DBUG_ENTER_METHOD();
13575   MRN_SET_WRAP_SHARE_KEY(share, table->s);
13576   MRN_SET_WRAP_TABLE_KEY(this, table);
13577 #ifdef MRN_HANDLER_AUTO_REPAIR_HAVE_ERROR
13578   repaired = wrap_handler->auto_repair(error);
13579 #else
13580   repaired = wrap_handler->auto_repair();
13581 #endif
13582   MRN_SET_BASE_SHARE_KEY(share, table->s);
13583   MRN_SET_BASE_TABLE_KEY(this, table);
13584   DBUG_RETURN(repaired);
13585 }
13586 
storage_auto_repair(int error) const13587 bool ha_mroonga::storage_auto_repair(int error) const
13588 {
13589   MRN_DBUG_ENTER_METHOD();
13590   bool repaired;
13591 #ifdef MRN_HANDLER_AUTO_REPAIR_HAVE_ERROR
13592   repaired = handler::auto_repair(error);
13593 #else
13594   repaired = handler::auto_repair();
13595 #endif
13596   DBUG_RETURN(repaired);
13597 }
13598 
auto_repair(int error) const13599 bool ha_mroonga::auto_repair(int error) const
13600 {
13601   MRN_DBUG_ENTER_METHOD();
13602   bool repaired;
13603   // TODO: We should consider about creating share for error =
13604   // ER_CANT_OPEN_FILE. The following code just ignores the error.
13605   if (share && share->wrapper_mode)
13606   {
13607     repaired = wrapper_auto_repair(error);
13608   } else {
13609     repaired = storage_auto_repair(error);
13610   }
13611   DBUG_RETURN(repaired);
13612 }
13613 
auto_repair() const13614 bool ha_mroonga::auto_repair() const
13615 {
13616   MRN_DBUG_ENTER_METHOD();
13617   bool repaired = auto_repair(HA_ERR_CRASHED_ON_USAGE);
13618   DBUG_RETURN(repaired);
13619 }
13620 
generic_disable_index(int i,KEY * key_info)13621 int ha_mroonga::generic_disable_index(int i, KEY *key_info)
13622 {
13623   MRN_DBUG_ENTER_METHOD();
13624 
13625   int error = 0;
13626   if (share->index_table[i]) {
13627     char index_column_name[GRN_TABLE_MAX_KEY_SIZE];
13628     snprintf(index_column_name, GRN_TABLE_MAX_KEY_SIZE - 1,
13629              "%s.%s", share->index_table[i], key_info[i].name.str);
13630     grn_obj *index_column = grn_ctx_get(ctx,
13631                                         index_column_name,
13632                                         strlen(index_column_name));
13633     if (index_column) {
13634       grn_obj_remove(ctx, index_column);
13635     }
13636   } else {
13637     mrn::PathMapper mapper(share->table_name);
13638     mrn::IndexTableName index_table_name(mapper.table_name(),
13639                                          key_info[i].name.str);
13640     grn_obj *index_table = grn_ctx_get(ctx,
13641                                        index_table_name.c_str(),
13642                                        index_table_name.length());
13643     if (!index_table) {
13644       index_table = grn_ctx_get(ctx,
13645                                 index_table_name.old_c_str(),
13646                                 index_table_name.old_length());
13647     }
13648     if (index_table) {
13649       grn_obj_remove(ctx, index_table);
13650     }
13651   }
13652   if (ctx->rc == GRN_SUCCESS) {
13653     grn_index_tables[i] = NULL;
13654     grn_index_columns[i] = NULL;
13655   } else {
13656     // TODO: Implement ctx->rc to error converter and use it.
13657     error = ER_ERROR_ON_WRITE;
13658     my_message(error, ctx->errbuf, MYF(0));
13659   }
13660 
13661   DBUG_RETURN(error);
13662 }
13663 
wrapper_disable_indexes_mroonga(uint mode)13664 int ha_mroonga::wrapper_disable_indexes_mroonga(uint mode)
13665 {
13666   int error = 0;
13667   MRN_DBUG_ENTER_METHOD();
13668   if (mode == HA_KEY_SWITCH_NONUNIQ_SAVE || mode == HA_KEY_SWITCH_ALL) {
13669     uint i;
13670     for (i = 0; i < table_share->keys; i++) {
13671       if (i == table->s->primary_key) {
13672         continue;
13673       }
13674       if (share->wrap_key_nr[i] < MAX_KEY) {
13675         continue;
13676       }
13677       if (!grn_index_tables[i]) {
13678         DBUG_PRINT("info", ("mroonga: keys are disabled already %u", i));
13679         DBUG_RETURN(0);
13680       }
13681     }
13682     KEY *key_info = table_share->key_info;
13683     for (i = 0; i < table_share->keys; i++) {
13684       if (!(key_info[i].flags & HA_FULLTEXT) &&
13685           !mrn_is_geo_key(&key_info[i])) {
13686         continue;
13687       }
13688 
13689       int sub_error = generic_disable_index(i, key_info);
13690       if (error != 0 && sub_error != 0) {
13691         error = sub_error;
13692       }
13693     }
13694   } else {
13695     error = HA_ERR_WRONG_COMMAND;
13696   }
13697   DBUG_RETURN(error);
13698 }
13699 
wrapper_disable_indexes(uint mode)13700 int ha_mroonga::wrapper_disable_indexes(uint mode)
13701 {
13702   int error = 0;
13703   MRN_DBUG_ENTER_METHOD();
13704   MRN_SET_WRAP_SHARE_KEY(share, table->s);
13705   MRN_SET_WRAP_TABLE_KEY(this, table);
13706   error = wrap_handler->ha_disable_indexes(mode);
13707   MRN_SET_BASE_SHARE_KEY(share, table->s);
13708   MRN_SET_BASE_TABLE_KEY(this, table);
13709   if (error == HA_ERR_WRONG_COMMAND) {
13710     error = 0;
13711   }
13712   if (!error) {
13713     error = wrapper_disable_indexes_mroonga(mode);
13714   }
13715   DBUG_RETURN(error);
13716 }
13717 
storage_disable_indexes(uint mode)13718 int ha_mroonga::storage_disable_indexes(uint mode)
13719 {
13720   int error = 0;
13721   MRN_DBUG_ENTER_METHOD();
13722   if (mode == HA_KEY_SWITCH_NONUNIQ_SAVE || mode == HA_KEY_SWITCH_ALL) {
13723     uint i;
13724     for (i = 0; i < table_share->keys; i++) {
13725       if (i == table->s->primary_key) {
13726         continue;
13727       }
13728       if (!grn_index_tables[i]) {
13729         DBUG_PRINT("info", ("mroonga: keys are disabled already %u", i));
13730         DBUG_RETURN(0);
13731       }
13732     }
13733     KEY *key_info = table_share->key_info;
13734     for (i = 0; i < table_share->keys; i++) {
13735       if (i == table->s->primary_key) {
13736         continue;
13737       }
13738       if (mode == HA_KEY_SWITCH_NONUNIQ_SAVE &&
13739           (key_info[i].flags & HA_NOSAME)) {
13740         continue;
13741       }
13742 
13743       int sub_error = generic_disable_index(i, key_info);
13744       if (error != 0 && sub_error != 0) {
13745         error = sub_error;
13746       }
13747     }
13748   } else {
13749     DBUG_RETURN(HA_ERR_WRONG_COMMAND);
13750   }
13751   DBUG_RETURN(error);
13752 }
13753 
disable_indexes(uint mode)13754 int ha_mroonga::disable_indexes(uint mode)
13755 {
13756   int error = 0;
13757   MRN_DBUG_ENTER_METHOD();
13758   if (share->wrapper_mode)
13759   {
13760     error = wrapper_disable_indexes(mode);
13761   } else {
13762     error = storage_disable_indexes(mode);
13763   }
13764   DBUG_RETURN(error);
13765 }
13766 
wrapper_enable_indexes_mroonga(uint mode)13767 int ha_mroonga::wrapper_enable_indexes_mroonga(uint mode)
13768 {
13769   int error = 0;
13770   MRN_DBUG_ENTER_METHOD();
13771   if (mode == HA_KEY_SWITCH_NONUNIQ_SAVE || mode == HA_KEY_SWITCH_ALL) {
13772     uint i, j;
13773     for (i = 0; i < table_share->keys; i++) {
13774       if (i == table->s->primary_key) {
13775         continue;
13776       }
13777       if (share->wrap_key_nr[i] < MAX_KEY) {
13778         continue;
13779       }
13780       if (!grn_index_columns[i]) {
13781         break;
13782       }
13783     }
13784     if (i == table_share->keys) {
13785       DBUG_PRINT("info", ("mroonga: keys are enabled already"));
13786       DBUG_RETURN(0);
13787     }
13788     KEY *p_key_info = &table->key_info[table_share->primary_key];
13789     KEY *key_info = table_share->key_info;
13790     uint n_keys = table_share->keys;
13791     MRN_ALLOCATE_VARIABLE_LENGTH_ARRAYS(grn_obj *, index_tables, n_keys);
13792     MRN_ALLOCATE_VARIABLE_LENGTH_ARRAYS(grn_obj *, index_columns, n_keys);
13793     bitmap_clear_all(table->read_set);
13794     mrn_set_bitmap_by_key(table->read_set, p_key_info);
13795     mrn::PathMapper mapper(share->table_name);
13796     for (i = 0, j = 0; i < n_keys; i++) {
13797       if (!(key_info[i].flags & HA_FULLTEXT) &&
13798         !mrn_is_geo_key(&key_info[i])) {
13799         j++;
13800         continue;
13801       }
13802 
13803       if ((error = mrn_add_index_param(share, &key_info[i], i)))
13804       {
13805         break;
13806       }
13807       index_tables[i] = NULL;
13808       index_columns[i] = NULL;
13809       if (!grn_index_columns[i]) {
13810         if (
13811           (key_info[i].flags & HA_FULLTEXT) &&
13812           (error = wrapper_create_index_fulltext(mapper.table_name(),
13813                                                  i, &key_info[i],
13814                                                  index_tables, index_columns,
13815                                                  share))
13816         ) {
13817           break;
13818         } else if (
13819           mrn_is_geo_key(&key_info[i]) &&
13820           (error = wrapper_create_index_geo(mapper.table_name(),
13821                                             i, &key_info[i],
13822                                             index_tables, index_columns,
13823                                             share))
13824         ) {
13825           break;
13826         }
13827         grn_index_columns[i] = index_columns[i];
13828       }
13829       mrn_set_bitmap_by_key(table->read_set, &key_info[i]);
13830     }
13831     if (!error && i > j)
13832     {
13833       error = wrapper_fill_indexes(ha_thd(), table->key_info, index_columns,
13834                                    n_keys);
13835     }
13836     bitmap_set_all(table->read_set);
13837     MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_tables);
13838     MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_columns);
13839   } else {
13840     error = HA_ERR_WRONG_COMMAND;
13841   }
13842   DBUG_RETURN(error);
13843 }
13844 
wrapper_enable_indexes(uint mode)13845 int ha_mroonga::wrapper_enable_indexes(uint mode)
13846 {
13847   int error = 0;
13848   MRN_DBUG_ENTER_METHOD();
13849 
13850   int mroonga_error = wrapper_enable_indexes_mroonga(mode);
13851 
13852   MRN_SET_WRAP_SHARE_KEY(share, table->s);
13853   MRN_SET_WRAP_TABLE_KEY(this, table);
13854   error = wrap_handler->ha_enable_indexes(mode);
13855   MRN_SET_BASE_SHARE_KEY(share, table->s);
13856   MRN_SET_BASE_TABLE_KEY(this, table);
13857   if (error == HA_ERR_WRONG_COMMAND) {
13858     error = mroonga_error;
13859   }
13860   DBUG_RETURN(error);
13861 }
13862 
storage_enable_indexes(uint mode)13863 int ha_mroonga::storage_enable_indexes(uint mode)
13864 {
13865   int error = 0;
13866   uint n_keys = table_share->keys;
13867   MRN_ALLOCATE_VARIABLE_LENGTH_ARRAYS(grn_obj *, index_tables, n_keys);
13868   MRN_ALLOCATE_VARIABLE_LENGTH_ARRAYS(grn_obj *, index_columns, n_keys);
13869   bool have_multiple_column_index = false;
13870   bool skip_unique_key = (mode == HA_KEY_SWITCH_NONUNIQ_SAVE);
13871   MRN_DBUG_ENTER_METHOD();
13872   if (mode == HA_KEY_SWITCH_NONUNIQ_SAVE || mode == HA_KEY_SWITCH_ALL) {
13873     uint i;
13874     for (i = 0; i < table_share->keys; i++) {
13875       if (i == table->s->primary_key) {
13876         continue;
13877       }
13878       if (!grn_index_columns[i]) {
13879         break;
13880       }
13881     }
13882     if (i == table_share->keys) {
13883       DBUG_PRINT("info", ("mroonga: keys are enabled already"));
13884       MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_tables);
13885       MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_columns);
13886       DBUG_RETURN(0);
13887     }
13888     KEY *key_info = table->key_info;
13889     bitmap_clear_all(table->read_set);
13890     mrn::PathMapper mapper(share->table_name);
13891     for (i = 0; i < n_keys; i++) {
13892       if (i == table->s->primary_key) {
13893         continue;
13894       }
13895       if (skip_unique_key && (key_info[i].flags & HA_NOSAME)) {
13896         continue;
13897       }
13898 
13899       if ((error = mrn_add_index_param(share, &key_info[i], i)))
13900       {
13901         break;
13902       }
13903       index_tables[i] = NULL;
13904       if (!grn_index_columns[i]) {
13905         if ((error = storage_create_index(table, mapper.table_name(), grn_table,
13906                                           share, &key_info[i], index_tables,
13907                                           index_columns, i)))
13908         {
13909           break;
13910         }
13911         if (
13912           KEY_N_KEY_PARTS(&(key_info[i])) != 1 &&
13913           !(key_info[i].flags & HA_FULLTEXT)
13914         ) {
13915           mrn_set_bitmap_by_key(table->read_set, &key_info[i]);
13916           have_multiple_column_index = true;
13917         }
13918         grn_index_tables[i] = index_tables[i];
13919         grn_index_columns[i] = index_columns[i];
13920       } else {
13921         index_columns[i] = NULL;
13922       }
13923     }
13924     if (!error && have_multiple_column_index)
13925     {
13926       error = storage_add_index_multiple_columns(key_info, n_keys,
13927                                                  index_tables,
13928                                                  index_columns,
13929                                                  skip_unique_key);
13930     }
13931     bitmap_set_all(table->read_set);
13932   } else {
13933     MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_tables);
13934     MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_columns);
13935     DBUG_RETURN(HA_ERR_WRONG_COMMAND);
13936   }
13937   MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_tables);
13938   MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_columns);
13939   DBUG_RETURN(error);
13940 }
13941 
enable_indexes(uint mode)13942 int ha_mroonga::enable_indexes(uint mode)
13943 {
13944   int error = 0;
13945   MRN_DBUG_ENTER_METHOD();
13946   share->disable_keys = false;
13947   if (share->wrapper_mode)
13948   {
13949     error = wrapper_enable_indexes(mode);
13950   } else {
13951     error = storage_enable_indexes(mode);
13952   }
13953   DBUG_RETURN(error);
13954 }
13955 
wrapper_check(THD * thd,HA_CHECK_OPT * check_opt)13956 int ha_mroonga::wrapper_check(THD* thd, HA_CHECK_OPT* check_opt)
13957 {
13958   int error = 0;
13959   MRN_DBUG_ENTER_METHOD();
13960   MRN_SET_WRAP_SHARE_KEY(share, table->s);
13961   MRN_SET_WRAP_TABLE_KEY(this, table);
13962   error = wrap_handler->ha_check(thd, check_opt);
13963   MRN_SET_BASE_SHARE_KEY(share, table->s);
13964   MRN_SET_BASE_TABLE_KEY(this, table);
13965   DBUG_RETURN(error);
13966 }
13967 
storage_check(THD * thd,HA_CHECK_OPT * check_opt)13968 int ha_mroonga::storage_check(THD* thd, HA_CHECK_OPT* check_opt)
13969 {
13970   MRN_DBUG_ENTER_METHOD();
13971   mrn::DatabaseRepairer repairer(ctx, thd);
13972   if (repairer.is_corrupt()) {
13973     DBUG_RETURN(HA_ADMIN_CORRUPT);
13974   } else {
13975     DBUG_RETURN(HA_ADMIN_OK);
13976   }
13977 }
13978 
check(THD * thd,HA_CHECK_OPT * check_opt)13979 int ha_mroonga::check(THD* thd, HA_CHECK_OPT* check_opt)
13980 {
13981   MRN_DBUG_ENTER_METHOD();
13982   int error = 0;
13983   if (share->wrapper_mode)
13984   {
13985     error = wrapper_check(thd, check_opt);
13986   } else {
13987     error = storage_check(thd, check_opt);
13988   }
13989   DBUG_RETURN(error);
13990 }
13991 
wrapper_fill_indexes(THD * thd,KEY * key_info,grn_obj ** index_columns,uint n_keys)13992 int ha_mroonga::wrapper_fill_indexes(THD *thd, KEY *key_info,
13993                                      grn_obj **index_columns, uint n_keys)
13994 {
13995   int error = 0;
13996   KEY *p_key_info = &table->key_info[table_share->primary_key];
13997   KEY *tmp_key_info;
13998 #ifdef MRN_NEED_M_LOCK_TYPE_CHECK_FOR_WRAPPER_EXTERNAL_LOCK
13999   int wrapper_lock_type_backup = wrap_handler->get_lock_type();
14000 #endif
14001   MRN_DBUG_ENTER_METHOD();
14002   DBUG_PRINT("info", ("mroonga: n_keys=%u", n_keys));
14003 
14004   grn_bool need_lock = true;
14005   if (mrn_lock_type != F_UNLCK) {
14006     need_lock = false;
14007   }
14008 #ifdef MRN_NEED_M_LOCK_TYPE_CHECK_FOR_WRAPPER_EXTERNAL_LOCK
14009   if (wrapper_lock_type_backup != F_UNLCK) {
14010     need_lock = false;
14011   }
14012 #endif
14013   if (need_lock) {
14014     error = wrapper_external_lock(thd, F_WRLCK);
14015   }
14016   if (!error) {
14017     if (
14018       !(error = wrapper_start_stmt(thd, thr_lock_data.type)) &&
14019       !(error = wrapper_rnd_init(true))
14020     ) {
14021       grn_obj key;
14022       GRN_TEXT_INIT(&key, 0);
14023       grn_bulk_space(ctx, &key, p_key_info->key_length);
14024       while (!(error = wrapper_rnd_next(table->record[0])))
14025       {
14026         key_copy((uchar *)(GRN_TEXT_VALUE(&key)), table->record[0],
14027                  p_key_info, p_key_info->key_length);
14028         int added;
14029         grn_id record_id;
14030         mrn_change_encoding(ctx, NULL);
14031         record_id = grn_table_add(ctx, grn_table,
14032                                   GRN_TEXT_VALUE(&key), p_key_info->key_length,
14033                                   &added);
14034         if (record_id == GRN_ID_NIL)
14035         {
14036           char error_message[MRN_MESSAGE_BUFFER_SIZE];
14037           snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
14038                    "failed to add a new record into groonga: key=<%.*s>",
14039                    (int) p_key_info->key_length, GRN_TEXT_VALUE(&key));
14040           error = ER_ERROR_ON_WRITE;
14041           my_message(error, error_message, MYF(0));
14042         }
14043         if (error)
14044           break;
14045 
14046         uint k;
14047         for (k = 0; k < n_keys; k++) {
14048           tmp_key_info = &key_info[k];
14049           if (!(tmp_key_info->flags & HA_FULLTEXT) &&
14050             !mrn_is_geo_key(tmp_key_info)) {
14051             continue;
14052           }
14053           if (!index_columns[k]) {
14054             continue;
14055           }
14056           DBUG_PRINT("info", ("mroonga: key_num=%u", k));
14057 
14058           uint l;
14059           for (l = 0; l < KEY_N_KEY_PARTS(tmp_key_info); l++) {
14060             Field *field = tmp_key_info->key_part[l].field;
14061 
14062             if (field->is_null())
14063               continue;
14064             error = mrn_change_encoding(ctx, field->charset());
14065             if (error)
14066               break;
14067 
14068             error = generic_store_bulk(field, &new_value_buffer);
14069             if (error) {
14070               my_message(error,
14071                          "mroonga: wrapper: "
14072                          "failed to get new value for updating index.",
14073                          MYF(0));
14074               break;
14075             }
14076 
14077             grn_obj *index_column = index_columns[k];
14078             grn_rc rc;
14079             rc = grn_column_index_update(ctx, index_column, record_id, l + 1,
14080                                          NULL, &new_value_buffer);
14081             grn_obj_unlink(ctx, index_column);
14082             if (rc) {
14083               error = ER_ERROR_ON_WRITE;
14084               my_message(error, ctx->errbuf, MYF(0));
14085               break;
14086             }
14087           }
14088           if (error)
14089             break;
14090         }
14091         if (error)
14092           break;
14093       }
14094       grn_obj_unlink(ctx, &key);
14095       if (error != HA_ERR_END_OF_FILE)
14096         wrapper_rnd_end();
14097       else
14098         error = wrapper_rnd_end();
14099     }
14100     if (need_lock) {
14101       wrapper_external_lock(thd, F_UNLCK);
14102     }
14103   }
14104   DBUG_RETURN(error);
14105 }
14106 
wrapper_recreate_indexes(THD * thd)14107 int ha_mroonga::wrapper_recreate_indexes(THD *thd)
14108 {
14109   int error;
14110   uint i, n_keys = table_share->keys;
14111   KEY *p_key_info = &table->key_info[table_share->primary_key];
14112   KEY *key_info = table->key_info;
14113   MRN_DBUG_ENTER_METHOD();
14114   mrn::PathMapper mapper(table_share->normalized_path.str);
14115   bitmap_clear_all(table->read_set);
14116   clear_indexes();
14117   remove_grn_obj_force(mapper.table_name());
14118   grn_table = NULL;
14119   mrn_set_bitmap_by_key(table->read_set, p_key_info);
14120   for (i = 0; i < n_keys; i++) {
14121     if (!(key_info[i].flags & HA_FULLTEXT) && !mrn_is_geo_key(&key_info[i])) {
14122       continue;
14123     }
14124     mrn::IndexTableName index_table_name(mapper.table_name(),
14125                                          table_share->key_info[i].name.str);
14126     char index_column_full_name[MRN_MAX_PATH_SIZE];
14127     snprintf(index_column_full_name, MRN_MAX_PATH_SIZE,
14128              "%s.%s", index_table_name.c_str(), INDEX_COLUMN_NAME);
14129     remove_grn_obj_force(index_column_full_name);
14130     remove_grn_obj_force(index_table_name.c_str());
14131 
14132     char index_column_full_old_name[MRN_MAX_PATH_SIZE];
14133     snprintf(index_column_full_old_name, MRN_MAX_PATH_SIZE,
14134              "%s.%s", index_table_name.old_c_str(), INDEX_COLUMN_NAME);
14135     remove_grn_obj_force(index_column_full_old_name);
14136     remove_grn_obj_force(index_table_name.old_c_str());
14137 
14138     mrn_set_bitmap_by_key(table->read_set, &key_info[i]);
14139   }
14140   error = wrapper_create_index(table_share->normalized_path.str, table, share);
14141   if (error)
14142     DBUG_RETURN(error);
14143   error = wrapper_open_indexes(table_share->normalized_path.str);
14144   if (error)
14145     DBUG_RETURN(error);
14146   error = wrapper_fill_indexes(thd, key_info, grn_index_columns, n_keys);
14147   bitmap_set_all(table->read_set);
14148   DBUG_RETURN(error);
14149 }
14150 
storage_recreate_indexes(THD * thd)14151 int ha_mroonga::storage_recreate_indexes(THD *thd)
14152 {
14153   MRN_DBUG_ENTER_METHOD();
14154 
14155   if (share->disable_keys)
14156     DBUG_RETURN(HA_ADMIN_OK);
14157 
14158   clear_indexes();
14159 
14160   int n_columns = table->s->fields;
14161   for (int i = 0; i < n_columns; i++) {
14162     grn_obj *column = grn_columns[i];
14163 
14164     if (!column)
14165       continue;
14166 
14167     int n_hooks = grn_obj_get_nhooks(ctx, column, GRN_HOOK_SET);
14168     for (int j = 0; j < n_hooks; j++) {
14169       grn_obj_delete_hook(ctx, column, GRN_HOOK_SET, j);
14170     }
14171   }
14172 
14173   uint n_keys = table_share->keys;
14174   mrn::PathMapper mapper(table_share->normalized_path.str);
14175   for (uint i = 0; i < n_keys; i++) {
14176     if (share->index_table && share->index_table[i])
14177       continue;
14178 
14179     if (i == table_share->primary_key)
14180       continue;
14181 
14182     mrn::IndexTableName index_table_name(mapper.table_name(),
14183                                          table_share->key_info[i].name.str);
14184     char index_column_full_name[MRN_MAX_PATH_SIZE];
14185     snprintf(index_column_full_name, MRN_MAX_PATH_SIZE,
14186              "%s.%s", index_table_name.c_str(), INDEX_COLUMN_NAME);
14187     remove_grn_obj_force(index_column_full_name);
14188     remove_grn_obj_force(index_table_name.c_str());
14189 
14190     char index_column_full_old_name[MRN_MAX_PATH_SIZE];
14191     snprintf(index_column_full_old_name, MRN_MAX_PATH_SIZE,
14192              "%s.%s", index_table_name.old_c_str(), INDEX_COLUMN_NAME);
14193     remove_grn_obj_force(index_column_full_old_name);
14194     remove_grn_obj_force(index_table_name.old_c_str());
14195   }
14196 
14197   int error;
14198   error = storage_create_indexes(table, mapper.table_name(), grn_table, share);
14199   if (error)
14200     DBUG_RETURN(HA_ADMIN_FAILED);
14201 
14202   error = storage_open_indexes(table_share->normalized_path.str);
14203   if (error)
14204     DBUG_RETURN(HA_ADMIN_FAILED);
14205 
14206   DBUG_RETURN(HA_ADMIN_OK);
14207 }
14208 
wrapper_repair(THD * thd,HA_CHECK_OPT * check_opt)14209 int ha_mroonga::wrapper_repair(THD* thd, HA_CHECK_OPT* check_opt)
14210 {
14211   int error;
14212   MRN_DBUG_ENTER_METHOD();
14213   MRN_SET_WRAP_SHARE_KEY(share, table->s);
14214   MRN_SET_WRAP_TABLE_KEY(this, table);
14215   error = wrap_handler->ha_repair(thd, check_opt);
14216   MRN_SET_BASE_SHARE_KEY(share, table->s);
14217   MRN_SET_BASE_TABLE_KEY(this, table);
14218   if (error && error != HA_ADMIN_NOT_IMPLEMENTED)
14219     DBUG_RETURN(error);
14220   error = wrapper_recreate_indexes(thd);
14221   DBUG_RETURN(error);
14222 }
14223 
storage_repair(THD * thd,HA_CHECK_OPT * check_opt)14224 int ha_mroonga::storage_repair(THD* thd, HA_CHECK_OPT* check_opt)
14225 {
14226   MRN_DBUG_ENTER_METHOD();
14227   int error = storage_recreate_indexes(thd);
14228   DBUG_RETURN(error);
14229 }
14230 
repair(THD * thd,HA_CHECK_OPT * check_opt)14231 int ha_mroonga::repair(THD* thd, HA_CHECK_OPT* check_opt)
14232 {
14233   MRN_DBUG_ENTER_METHOD();
14234   int error = 0;
14235   share->disable_keys = false;
14236   if (share->wrapper_mode)
14237   {
14238     error = wrapper_repair(thd, check_opt);
14239   } else {
14240     error = storage_repair(thd, check_opt);
14241   }
14242   DBUG_RETURN(error);
14243 }
14244 
wrapper_check_and_repair(THD * thd)14245 bool ha_mroonga::wrapper_check_and_repair(THD *thd)
14246 {
14247   bool is_error_or_not_supported;
14248   MRN_DBUG_ENTER_METHOD();
14249   MRN_SET_WRAP_SHARE_KEY(share, table->s);
14250   MRN_SET_WRAP_TABLE_KEY(this, table);
14251   is_error_or_not_supported = wrap_handler->ha_check_and_repair(thd);
14252   MRN_SET_BASE_SHARE_KEY(share, table->s);
14253   MRN_SET_BASE_TABLE_KEY(this, table);
14254   DBUG_RETURN(is_error_or_not_supported);
14255 }
14256 
storage_check_and_repair(THD * thd)14257 bool ha_mroonga::storage_check_and_repair(THD *thd)
14258 {
14259   MRN_DBUG_ENTER_METHOD();
14260   bool is_error = false;
14261   mrn::DatabaseRepairer repairer(ctx, thd);
14262   is_error = !repairer.repair();
14263   DBUG_RETURN(is_error);
14264 }
14265 
check_and_repair(THD * thd)14266 bool ha_mroonga::check_and_repair(THD *thd)
14267 {
14268   MRN_DBUG_ENTER_METHOD();
14269   bool is_error_or_not_supported;
14270   if (share->wrapper_mode)
14271   {
14272     is_error_or_not_supported = wrapper_check_and_repair(thd);
14273   } else {
14274     is_error_or_not_supported = storage_check_and_repair(thd);
14275   }
14276   DBUG_RETURN(is_error_or_not_supported);
14277 }
14278 
wrapper_analyze(THD * thd,HA_CHECK_OPT * check_opt)14279 int ha_mroonga::wrapper_analyze(THD* thd, HA_CHECK_OPT* check_opt)
14280 {
14281   int error = 0;
14282   MRN_DBUG_ENTER_METHOD();
14283   MRN_SET_WRAP_SHARE_KEY(share, table->s);
14284   MRN_SET_WRAP_TABLE_KEY(this, table);
14285   error = wrap_handler->ha_analyze(thd, check_opt);
14286   MRN_SET_BASE_SHARE_KEY(share, table->s);
14287   MRN_SET_BASE_TABLE_KEY(this, table);
14288   DBUG_RETURN(error);
14289 }
14290 
storage_analyze(THD * thd,HA_CHECK_OPT * check_opt)14291 int ha_mroonga::storage_analyze(THD* thd, HA_CHECK_OPT* check_opt)
14292 {
14293   MRN_DBUG_ENTER_METHOD();
14294   DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED);
14295 }
14296 
analyze(THD * thd,HA_CHECK_OPT * check_opt)14297 int ha_mroonga::analyze(THD* thd, HA_CHECK_OPT* check_opt)
14298 {
14299   MRN_DBUG_ENTER_METHOD();
14300   int error = 0;
14301   if (share->wrapper_mode)
14302   {
14303     error = wrapper_analyze(thd, check_opt);
14304   } else {
14305     error = storage_analyze(thd, check_opt);
14306   }
14307   DBUG_RETURN(error);
14308 }
14309 
wrapper_optimize(THD * thd,HA_CHECK_OPT * check_opt)14310 int ha_mroonga::wrapper_optimize(THD* thd, HA_CHECK_OPT* check_opt)
14311 {
14312   MRN_DBUG_ENTER_METHOD();
14313   DBUG_RETURN(HA_ADMIN_TRY_ALTER);
14314 }
14315 
storage_optimize(THD * thd,HA_CHECK_OPT * check_opt)14316 int ha_mroonga::storage_optimize(THD* thd, HA_CHECK_OPT* check_opt)
14317 {
14318   MRN_DBUG_ENTER_METHOD();
14319   DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED);
14320 }
14321 
optimize(THD * thd,HA_CHECK_OPT * check_opt)14322 int ha_mroonga::optimize(THD* thd, HA_CHECK_OPT* check_opt)
14323 {
14324   MRN_DBUG_ENTER_METHOD();
14325   int error = 0;
14326   if (share->wrapper_mode)
14327   {
14328     error = wrapper_optimize(thd, check_opt);
14329   } else {
14330     error = storage_optimize(thd, check_opt);
14331   }
14332   DBUG_RETURN(error);
14333 }
14334 
wrapper_is_fatal_error(int error_num,uint flags)14335 bool ha_mroonga::wrapper_is_fatal_error(int error_num, uint flags)
14336 {
14337   bool res;
14338   MRN_DBUG_ENTER_METHOD();
14339   MRN_SET_WRAP_SHARE_KEY(share, table->s);
14340   MRN_SET_WRAP_TABLE_KEY(this, table);
14341 #ifdef MRN_HANDLER_IS_FATAL_ERROR_HAVE_FLAGS
14342   res = wrap_handler->is_fatal_error(error_num, flags);
14343 #else
14344   res = wrap_handler->is_fatal_error(error_num);
14345 #endif
14346   MRN_SET_BASE_SHARE_KEY(share, table->s);
14347   MRN_SET_BASE_TABLE_KEY(this, table);
14348   DBUG_RETURN(res);
14349 }
14350 
storage_is_fatal_error(int error_num,uint flags)14351 bool ha_mroonga::storage_is_fatal_error(int error_num, uint flags)
14352 {
14353   MRN_DBUG_ENTER_METHOD();
14354 #ifdef MRN_HANDLER_IS_FATAL_ERROR_HAVE_FLAGS
14355   bool is_fatal_error = handler::is_fatal_error(error_num, flags);
14356 #else
14357   bool is_fatal_error = handler::is_fatal_error(error_num);
14358 #endif
14359   DBUG_RETURN(is_fatal_error);
14360 }
14361 
is_fatal_error(int error_num,uint flags)14362 bool ha_mroonga::is_fatal_error(int error_num, uint flags)
14363 {
14364   MRN_DBUG_ENTER_METHOD();
14365   bool is_fatal_error;
14366   if (share->wrapper_mode)
14367   {
14368     is_fatal_error = wrapper_is_fatal_error(error_num, flags);
14369   } else {
14370     is_fatal_error = storage_is_fatal_error(error_num, flags);
14371   }
14372   DBUG_RETURN(is_fatal_error);
14373 }
14374 
wrapper_check_if_incompatible_data(HA_CREATE_INFO * create_info,uint table_changes)14375 bool ha_mroonga::wrapper_check_if_incompatible_data(
14376   HA_CREATE_INFO *create_info, uint table_changes)
14377 {
14378   bool res;
14379   MRN_DBUG_ENTER_METHOD();
14380   MRN_SET_WRAP_SHARE_KEY(share, table->s);
14381   MRN_SET_WRAP_TABLE_KEY(this, table);
14382   res = wrap_handler->check_if_incompatible_data(create_info, table_changes);
14383   MRN_SET_BASE_SHARE_KEY(share, table->s);
14384   MRN_SET_BASE_TABLE_KEY(this, table);
14385   DBUG_RETURN(res);
14386 }
14387 
storage_check_if_incompatible_data(HA_CREATE_INFO * create_info,uint table_changes)14388 bool ha_mroonga::storage_check_if_incompatible_data(
14389   HA_CREATE_INFO *create_info, uint table_changes)
14390 {
14391   MRN_DBUG_ENTER_METHOD();
14392   uint n = table_share->fields;
14393   for (uint i = 0; i < n; i++) {
14394     Field *field = table->field[i];
14395     if (field->flags & FIELD_IS_RENAMED) {
14396       DBUG_RETURN(COMPATIBLE_DATA_NO);
14397     }
14398   }
14399   DBUG_RETURN(COMPATIBLE_DATA_YES);
14400 }
14401 
check_if_incompatible_data(HA_CREATE_INFO * create_info,uint table_changes)14402 bool ha_mroonga::check_if_incompatible_data(
14403   HA_CREATE_INFO *create_info, uint table_changes)
14404 {
14405   MRN_DBUG_ENTER_METHOD();
14406   bool res;
14407   if (
14408     create_info->comment.str != table_share->comment.str ||
14409     create_info->connect_string.str != table_share->connect_string.str
14410   ) {
14411     DBUG_RETURN(COMPATIBLE_DATA_NO);
14412   }
14413   if (share->wrapper_mode)
14414   {
14415     res = wrapper_check_if_incompatible_data(create_info, table_changes);
14416   } else {
14417     res = storage_check_if_incompatible_data(create_info, table_changes);
14418   }
14419   DBUG_RETURN(res);
14420 }
14421 
storage_add_index_multiple_columns(KEY * key_info,uint num_of_keys,grn_obj ** index_tables,grn_obj ** index_columns,bool skip_unique_key)14422 int ha_mroonga::storage_add_index_multiple_columns(KEY *key_info,
14423                                                    uint num_of_keys,
14424                                                    grn_obj **index_tables,
14425                                                    grn_obj **index_columns,
14426                                                    bool skip_unique_key)
14427 {
14428   MRN_DBUG_ENTER_METHOD();
14429 
14430   int error = 0;
14431 
14432   if (!(error = storage_rnd_init(true)))
14433   {
14434     while (!(error = storage_rnd_next(table->record[0])))
14435     {
14436       for (uint i = 0; i < num_of_keys; i++) {
14437         KEY *current_key_info = key_info + i;
14438         if (
14439           KEY_N_KEY_PARTS(current_key_info) == 1 ||
14440           (current_key_info->flags & HA_FULLTEXT)
14441           ) {
14442           continue;
14443         }
14444         if (skip_unique_key && (key_info[i].flags & HA_NOSAME)) {
14445           continue;
14446         }
14447         if (!index_columns[i]) {
14448           continue;
14449         }
14450 
14451         /* fix key_info.key_length */
14452         for (uint j = 0; j < KEY_N_KEY_PARTS(current_key_info); j++) {
14453           if (
14454             !current_key_info->key_part[j].null_bit &&
14455             current_key_info->key_part[j].field->null_bit
14456             ) {
14457             current_key_info->key_length++;
14458             current_key_info->key_part[j].null_bit =
14459               current_key_info->key_part[j].field->null_bit;
14460           }
14461         }
14462         if (key_info[i].flags & HA_NOSAME) {
14463           grn_id key_id;
14464           if ((error = storage_write_row_unique_index(table->record[0],
14465                                                       current_key_info,
14466                                                       index_tables[i],
14467                                                       index_columns[i],
14468                                                       &key_id)))
14469           {
14470             if (error == HA_ERR_FOUND_DUPP_KEY)
14471             {
14472               error = HA_ERR_FOUND_DUPP_UNIQUE;
14473             }
14474             break;
14475           }
14476         }
14477         if ((error = storage_write_row_multiple_column_index(table->record[0],
14478                                                              record_id,
14479                                                              current_key_info,
14480                                                              index_columns[i])))
14481         {
14482           break;
14483         }
14484       }
14485       if (error)
14486         break;
14487     }
14488     if (error != HA_ERR_END_OF_FILE) {
14489       storage_rnd_end();
14490     } else {
14491       error = storage_rnd_end();
14492     }
14493   }
14494 
14495   DBUG_RETURN(error);
14496 }
14497 
14498 #ifdef MRN_HANDLER_HAVE_CHECK_IF_SUPPORTED_INPLACE_ALTER
wrapper_is_comment_changed(TABLE * table1,TABLE * table2)14499 bool ha_mroonga::wrapper_is_comment_changed(TABLE *table1, TABLE *table2)
14500 {
14501   MRN_DBUG_ENTER_METHOD();
14502 
14503   if (table1->s->comment.length != table2->s->comment.length) {
14504     DBUG_RETURN(true);
14505   }
14506 
14507   if (strncmp(table1->s->comment.str,
14508               table2->s->comment.str,
14509               table1->s->comment.length) == 0) {
14510     DBUG_RETURN(false);
14511   } else {
14512     DBUG_RETURN(true);
14513   }
14514 }
14515 
wrapper_check_if_supported_inplace_alter(TABLE * altered_table,Alter_inplace_info * ha_alter_info)14516 enum_alter_inplace_result ha_mroonga::wrapper_check_if_supported_inplace_alter(
14517   TABLE *altered_table,
14518   Alter_inplace_info *ha_alter_info)
14519 {
14520   MRN_DBUG_ENTER_METHOD();
14521   uint n_keys;
14522   uint i;
14523   enum_alter_inplace_result result_mroonga = HA_ALTER_INPLACE_NO_LOCK;
14524   DBUG_PRINT("info",
14525              ("mroonga: handler_flags=%lu",
14526               static_cast<ulong>(ha_alter_info->handler_flags)));
14527 
14528   if (wrapper_is_comment_changed(table, altered_table)) {
14529     DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
14530   }
14531   if (
14532     (ha_alter_info->handler_flags & ALTER_ADD_NON_UNIQUE_NON_PRIM_INDEX) &&
14533     (ha_alter_info->handler_flags &
14534       (
14535         ALTER_ADD_COLUMN |
14536         ALTER_DROP_COLUMN |
14537         MRN_ALTER_INPLACE_INFO_ALTER_STORED_COLUMN_TYPE |
14538         MRN_ALTER_INPLACE_INFO_ALTER_STORED_COLUMN_ORDER |
14539         ALTER_COLUMN_NULLABLE |
14540         ALTER_COLUMN_NOT_NULLABLE |
14541         ALTER_COLUMN_STORAGE_TYPE |
14542         ALTER_ADD_STORED_GENERATED_COLUMN |
14543         ALTER_COLUMN_COLUMN_FORMAT
14544       )
14545     )
14546   ) {
14547     DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
14548   }
14549   if (ha_alter_info->handler_flags & ALTER_RENAME)
14550   {
14551     DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
14552   }
14553 
14554   DBUG_ASSERT(ha_alter_info->key_count == altered_table->s->keys);
14555   alter_key_count = 0;
14556   alter_index_drop_count = 0;
14557   alter_index_add_count = 0;
14558   alter_handler_flags = ha_alter_info->handler_flags;
14559   if (!(alter_key_info_buffer = (KEY *)
14560     mrn_my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
14561       &alter_key_info_buffer, sizeof(KEY) * ha_alter_info->key_count,
14562       &alter_index_drop_buffer, sizeof(KEY) * ha_alter_info->index_drop_count,
14563       &alter_index_add_buffer, sizeof(uint) * ha_alter_info->index_add_count,
14564       &wrap_altered_table, sizeof(TABLE),
14565       &wrap_altered_table_key_info, sizeof(KEY) * altered_table->s->keys,
14566       &wrap_altered_table_share, sizeof(TABLE_SHARE),
14567       &wrap_altered_table_share_key_info, sizeof(KEY) * altered_table->s->keys,
14568       NullS))
14569   ) {
14570     DBUG_RETURN(HA_ALTER_ERROR);
14571   }
14572   *wrap_altered_table= *altered_table;
14573   *wrap_altered_table_share= *altered_table->s;
14574   mrn_init_sql_alloc(ha_thd(), &(wrap_altered_table_share->mem_root));
14575 
14576   n_keys = ha_alter_info->index_drop_count;
14577   for (i = 0; i < n_keys; ++i) {
14578     const KEY *key = ha_alter_info->index_drop_buffer[i];
14579     if (key->flags & HA_FULLTEXT || mrn_is_geo_key(key)) {
14580       result_mroonga = HA_ALTER_INPLACE_EXCLUSIVE_LOCK;
14581     } else {
14582       memcpy(&alter_index_drop_buffer[alter_index_drop_count],
14583         ha_alter_info->index_drop_buffer[i], sizeof(KEY));
14584       ++alter_index_drop_count;
14585     }
14586   }
14587   if (!alter_index_drop_count) {
14588     alter_handler_flags &= ~ALTER_DROP_NON_UNIQUE_NON_PRIM_INDEX;
14589   }
14590   n_keys = ha_alter_info->index_add_count;
14591   for (i = 0; i < n_keys; ++i) {
14592     const KEY *key =
14593       &altered_table->key_info[ha_alter_info->index_add_buffer[i]];
14594     if (key->flags & HA_FULLTEXT || mrn_is_geo_key(key)) {
14595       result_mroonga = HA_ALTER_INPLACE_EXCLUSIVE_LOCK;
14596     } else {
14597       alter_index_add_buffer[alter_index_add_count] =
14598         ha_alter_info->index_add_buffer[i];
14599       ++alter_index_add_count;
14600     }
14601   }
14602   if (!alter_index_add_count) {
14603     alter_handler_flags &= ~ALTER_ADD_NON_UNIQUE_NON_PRIM_INDEX;
14604   }
14605   uint add_index_pos = 0;
14606   n_keys = ha_alter_info->key_count;
14607   for (i = 0; i < n_keys; ++i) {
14608     const KEY *key = &altered_table->key_info[i];
14609     if (!(key->flags & HA_FULLTEXT || mrn_is_geo_key(key))) {
14610       memcpy(&alter_key_info_buffer[alter_key_count],
14611              &ha_alter_info->key_info_buffer[i], sizeof(KEY));
14612       memcpy(&wrap_altered_table_key_info[alter_key_count],
14613              &altered_table->key_info[i], sizeof(KEY));
14614       memcpy(&wrap_altered_table_share_key_info[alter_key_count],
14615              &altered_table->s->key_info[i], sizeof(KEY));
14616       if (add_index_pos < alter_index_add_count &&
14617              alter_index_add_buffer[add_index_pos] == i) {
14618         alter_index_add_buffer[add_index_pos] = alter_key_count;
14619         ++add_index_pos;
14620       }
14621       ++alter_key_count;
14622     }
14623   }
14624   wrap_altered_table->key_info = wrap_altered_table_key_info;
14625   wrap_altered_table_share->key_info = wrap_altered_table_share_key_info;
14626   wrap_altered_table_share->keys = alter_key_count;
14627   wrap_altered_table->s = wrap_altered_table_share;
14628 
14629   if (!alter_handler_flags) {
14630     DBUG_RETURN(result_mroonga);
14631   }
14632   enum_alter_inplace_result result;
14633   MRN_SET_WRAP_ALTER_KEY(this, ha_alter_info);
14634   MRN_SET_WRAP_SHARE_KEY(share, table->s);
14635   MRN_SET_WRAP_TABLE_KEY(this, table);
14636   result = wrap_handler->check_if_supported_inplace_alter(wrap_altered_table,
14637                                                           ha_alter_info);
14638   MRN_SET_BASE_ALTER_KEY(this, ha_alter_info);
14639   MRN_SET_BASE_SHARE_KEY(share, table->s);
14640   MRN_SET_BASE_TABLE_KEY(this, table);
14641   if (result_mroonga > result)
14642     DBUG_RETURN(result);
14643   DBUG_RETURN(result_mroonga);
14644 }
14645 
storage_check_if_supported_inplace_alter(TABLE * altered_table,Alter_inplace_info * ha_alter_info)14646 enum_alter_inplace_result ha_mroonga::storage_check_if_supported_inplace_alter(
14647   TABLE *altered_table,
14648   Alter_inplace_info *ha_alter_info)
14649 {
14650   MRN_DBUG_ENTER_METHOD();
14651   alter_table_operations explicitly_unsupported_flags =
14652     ALTER_ADD_FOREIGN_KEY |
14653     ALTER_DROP_FOREIGN_KEY;
14654   alter_table_operations supported_flags =
14655     ALTER_ADD_NON_UNIQUE_NON_PRIM_INDEX |
14656     ALTER_DROP_NON_UNIQUE_NON_PRIM_INDEX |
14657     ALTER_ADD_UNIQUE_INDEX |
14658     ALTER_DROP_UNIQUE_INDEX |
14659     MRN_ALTER_INPLACE_INFO_ADD_VIRTUAL_COLUMN |
14660     MRN_ALTER_INPLACE_INFO_ADD_STORED_BASE_COLUMN |
14661     ALTER_DROP_COLUMN |
14662     ALTER_COLUMN_NAME;
14663   if (ha_alter_info->handler_flags & explicitly_unsupported_flags) {
14664     DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
14665   } else if (ha_alter_info->handler_flags & supported_flags) {
14666     DBUG_RETURN(HA_ALTER_INPLACE_EXCLUSIVE_LOCK);
14667   } else {
14668     DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
14669   }
14670 }
14671 
check_if_supported_inplace_alter(TABLE * altered_table,Alter_inplace_info * ha_alter_info)14672 enum_alter_inplace_result ha_mroonga::check_if_supported_inplace_alter(
14673   TABLE *altered_table,
14674   Alter_inplace_info *ha_alter_info)
14675 {
14676   MRN_DBUG_ENTER_METHOD();
14677   enum_alter_inplace_result result;
14678   if (share->wrapper_mode) {
14679     result = wrapper_check_if_supported_inplace_alter(altered_table,
14680                                                       ha_alter_info);
14681   } else {
14682     result = storage_check_if_supported_inplace_alter(altered_table,
14683                                                       ha_alter_info);
14684   }
14685   DBUG_RETURN(result);
14686 }
14687 
wrapper_prepare_inplace_alter_table(TABLE * altered_table,Alter_inplace_info * ha_alter_info)14688 bool ha_mroonga::wrapper_prepare_inplace_alter_table(
14689   TABLE *altered_table,
14690   Alter_inplace_info *ha_alter_info)
14691 {
14692   bool result;
14693   MRN_DBUG_ENTER_METHOD();
14694   if (!alter_handler_flags) {
14695     DBUG_RETURN(false);
14696   }
14697 
14698 #ifdef MRN_SUPPORT_CUSTOM_OPTIONS
14699   int error = 0;
14700   MRN_SHARE *tmp_share;
14701   tmp_share = mrn_get_share(altered_table->s->table_name.str,
14702                             altered_table,
14703                             &error);
14704   if (error != 0) {
14705     DBUG_RETURN(true);
14706   }
14707 
14708   if (parse_engine_table_options(ha_thd(),
14709                                   tmp_share->hton,
14710                                   wrap_altered_table->s)) {
14711     mrn_free_share(tmp_share);
14712     DBUG_RETURN(true);
14713   }
14714 #endif
14715 
14716   MRN_SET_WRAP_ALTER_KEY(this, ha_alter_info);
14717   MRN_SET_WRAP_SHARE_KEY(share, table->s);
14718   MRN_SET_WRAP_TABLE_KEY(this, table);
14719   result = wrap_handler->ha_prepare_inplace_alter_table(wrap_altered_table,
14720                                                         ha_alter_info);
14721   MRN_SET_BASE_ALTER_KEY(this, ha_alter_info);
14722   MRN_SET_BASE_SHARE_KEY(share, table->s);
14723   MRN_SET_BASE_TABLE_KEY(this, table);
14724 
14725 #ifdef MRN_SUPPORT_CUSTOM_OPTIONS
14726   mrn_free_share(tmp_share);
14727 #endif
14728 
14729   DBUG_RETURN(result);
14730 }
14731 
storage_prepare_inplace_alter_table(TABLE * altered_table,Alter_inplace_info * ha_alter_info)14732 bool ha_mroonga::storage_prepare_inplace_alter_table(
14733   TABLE *altered_table,
14734   Alter_inplace_info *ha_alter_info)
14735 {
14736   MRN_DBUG_ENTER_METHOD();
14737   DBUG_RETURN(false);
14738 }
14739 
prepare_inplace_alter_table(TABLE * altered_table,Alter_inplace_info * ha_alter_info)14740 bool ha_mroonga::prepare_inplace_alter_table(
14741   TABLE *altered_table,
14742   Alter_inplace_info *ha_alter_info)
14743 {
14744   MRN_DBUG_ENTER_METHOD();
14745   bool result;
14746   if (share->wrapper_mode) {
14747     result = wrapper_prepare_inplace_alter_table(altered_table, ha_alter_info);
14748   } else {
14749     result = storage_prepare_inplace_alter_table(altered_table, ha_alter_info);
14750   }
14751   DBUG_RETURN(result);
14752 }
14753 
wrapper_inplace_alter_table(TABLE * altered_table,Alter_inplace_info * ha_alter_info)14754 bool ha_mroonga::wrapper_inplace_alter_table(
14755   TABLE *altered_table,
14756   Alter_inplace_info *ha_alter_info)
14757 {
14758   int error;
14759   bool result = false;
14760   uint n_keys;
14761   uint i, j = 0;
14762   KEY *key_info = table_share->key_info;
14763   MRN_DBUG_ENTER_METHOD();
14764   error = mrn_change_encoding(ctx, system_charset_info);
14765   if (error)
14766     DBUG_RETURN(true);
14767 
14768   DBUG_PRINT("info", ("mroonga: table_name=%s", share->table_name));
14769   mrn::PathMapper mapper(share->table_name);
14770   n_keys = ha_alter_info->index_drop_count;
14771   for (i = 0; i < n_keys; ++i) {
14772     const KEY *key = ha_alter_info->index_drop_buffer[i];
14773     if (!(key->flags & HA_FULLTEXT || mrn_is_geo_key(key))) {
14774       continue;
14775     }
14776     while (strcmp(key_info[j].name.str, key->name.str)) {
14777       ++j;
14778     }
14779     DBUG_PRINT("info", ("mroonga: key_name=%s", key->name.str));
14780     error = drop_index(share, j);
14781     if (error)
14782       DBUG_RETURN(true);
14783     grn_index_tables[j] = NULL;
14784     grn_index_columns[j] = NULL;
14785   }
14786 
14787   MRN_ALLOCATE_VARIABLE_LENGTH_ARRAYS(grn_obj *, index_tables,
14788                                       ha_alter_info->key_count);
14789   MRN_ALLOCATE_VARIABLE_LENGTH_ARRAYS(grn_obj *, index_columns,
14790                                       ha_alter_info->key_count);
14791   MRN_SHARE *tmp_share;
14792   TABLE_SHARE tmp_table_share;
14793   char **key_tokenizer;
14794   uint *key_tokenizer_length;
14795   KEY *p_key_info = &table->key_info[table_share->primary_key];
14796   bool need_fill_index = false;
14797   memset(index_tables, 0, sizeof(grn_obj *) * ha_alter_info->key_count);
14798   memset(index_columns, 0, sizeof(grn_obj *) * ha_alter_info->key_count);
14799   tmp_table_share.keys = ha_alter_info->key_count;
14800   tmp_table_share.fields = 0;
14801   if (!(tmp_share = (MRN_SHARE *)
14802     mrn_my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
14803       &tmp_share, sizeof(*tmp_share),
14804       &key_tokenizer, sizeof(char *) * (tmp_table_share.keys),
14805       &key_tokenizer_length, sizeof(uint) * (tmp_table_share.keys),
14806       NullS))
14807   ) {
14808     MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_tables);
14809     MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_columns);
14810     DBUG_RETURN(true);
14811   }
14812   tmp_share->engine = NULL;
14813   tmp_share->table_share = &tmp_table_share;
14814   tmp_share->index_table = NULL;
14815   tmp_share->index_table_length = NULL;
14816   tmp_share->key_tokenizer = key_tokenizer;
14817   tmp_share->key_tokenizer_length = key_tokenizer_length;
14818   bitmap_clear_all(table->read_set);
14819   mrn_set_bitmap_by_key(table->read_set, p_key_info);
14820   n_keys = ha_alter_info->index_add_count;
14821   for (i = 0; i < n_keys; ++i) {
14822     uint key_pos = ha_alter_info->index_add_buffer[i];
14823     KEY *key = &altered_table->key_info[key_pos];
14824     if (!(key->flags & HA_FULLTEXT || mrn_is_geo_key(key))) {
14825       continue;
14826     }
14827     if (share->disable_keys) {
14828       continue;
14829     }
14830     if ((error = mrn_add_index_param(tmp_share, key, key_pos)))
14831     {
14832       break;
14833     }
14834     DBUG_PRINT("info", ("mroonga: add key pos=%u", key_pos));
14835     if (
14836       (key->flags & HA_FULLTEXT) &&
14837       (error = wrapper_create_index_fulltext(mapper.table_name(),
14838                                              key_pos,
14839                                              key, index_tables, NULL,
14840                                              tmp_share))
14841     ) {
14842       break;
14843     } else if (
14844       mrn_is_geo_key(key) &&
14845       (error = wrapper_create_index_geo(mapper.table_name(),
14846                                         key_pos, key,
14847                                         index_tables, NULL, tmp_share))
14848     ) {
14849       break;
14850     }
14851     mrn_set_bitmap_by_key(table->read_set, key);
14852     index_columns[key_pos] = grn_obj_column(ctx,
14853                                             index_tables[key_pos],
14854                                             INDEX_COLUMN_NAME,
14855                                             strlen(INDEX_COLUMN_NAME));
14856     need_fill_index = true;
14857   }
14858   if (!error && need_fill_index) {
14859     my_ptrdiff_t diff =
14860       PTR_BYTE_DIFF(table->record[0], altered_table->record[0]);
14861     mrn::TableFieldsOffsetMover mover(altered_table, diff);
14862     error = wrapper_fill_indexes(ha_thd(), altered_table->key_info,
14863                                  index_columns, ha_alter_info->key_count);
14864   }
14865   bitmap_set_all(table->read_set);
14866 
14867   if (!error && alter_handler_flags) {
14868 #ifdef MRN_SUPPORT_CUSTOM_OPTIONS
14869     {
14870       MRN_SHARE *alter_tmp_share;
14871       alter_tmp_share = mrn_get_share(altered_table->s->table_name.str,
14872                                       altered_table,
14873                                       &error);
14874       if (alter_tmp_share) {
14875         if (parse_engine_table_options(ha_thd(),
14876                                        alter_tmp_share->hton,
14877                                        wrap_altered_table->s)) {
14878           error = MRN_GET_ERROR_NUMBER;
14879         }
14880         mrn_free_share(alter_tmp_share);
14881       }
14882     }
14883 #endif
14884     if (!error) {
14885       MRN_SET_WRAP_ALTER_KEY(this, ha_alter_info);
14886       MRN_SET_WRAP_SHARE_KEY(share, table->s);
14887       MRN_SET_WRAP_TABLE_KEY(this, table);
14888       result = wrap_handler->ha_inplace_alter_table(wrap_altered_table,
14889                                                     ha_alter_info);
14890       MRN_SET_BASE_ALTER_KEY(this, ha_alter_info);
14891       MRN_SET_BASE_SHARE_KEY(share, table->s);
14892       MRN_SET_BASE_TABLE_KEY(this, table);
14893     }
14894   }
14895 
14896   if (result || error)
14897   {
14898     n_keys = ha_alter_info->index_add_count;
14899     for (i = 0; i < n_keys; ++i) {
14900       uint key_pos = ha_alter_info->index_add_buffer[i];
14901       KEY *key = &altered_table->key_info[key_pos];
14902       if (!(key->flags & HA_FULLTEXT || mrn_is_geo_key(key))) {
14903         continue;
14904       }
14905       if (share->disable_keys) {
14906         continue;
14907       }
14908       if (index_tables[key_pos])
14909       {
14910         grn_obj_remove(ctx, index_tables[key_pos]);
14911       }
14912     }
14913     result = true;
14914   }
14915   mrn_free_share_alloc(tmp_share);
14916   my_free(tmp_share);
14917   MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_tables);
14918   MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_columns);
14919   DBUG_RETURN(result);
14920 }
14921 
storage_inplace_alter_table_add_index(TABLE * altered_table,Alter_inplace_info * ha_alter_info)14922 bool ha_mroonga::storage_inplace_alter_table_add_index(
14923   TABLE *altered_table,
14924   Alter_inplace_info *ha_alter_info)
14925 {
14926   MRN_DBUG_ENTER_METHOD();
14927 
14928   MRN_ALLOCATE_VARIABLE_LENGTH_ARRAYS(grn_obj *, index_tables,
14929                                       ha_alter_info->key_count);
14930   MRN_ALLOCATE_VARIABLE_LENGTH_ARRAYS(grn_obj *, index_columns,
14931                                       ha_alter_info->key_count);
14932   MRN_SHARE *tmp_share;
14933   TABLE_SHARE tmp_table_share;
14934   char **index_table, **key_tokenizer, **col_flags, **col_type;
14935   uint *index_table_length, *key_tokenizer_length, *col_flags_length, *col_type_length;
14936   bool have_multiple_column_index = false;
14937   memset(index_tables, 0, sizeof(grn_obj *) * ha_alter_info->key_count);
14938   memset(index_columns, 0, sizeof(grn_obj *) * ha_alter_info->key_count);
14939   tmp_table_share.keys = ha_alter_info->key_count;
14940   tmp_table_share.fields = 0;
14941   if (!(tmp_share = (MRN_SHARE *)
14942     mrn_my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
14943       &tmp_share, sizeof(*tmp_share),
14944       &index_table, sizeof(char *) * tmp_table_share.keys,
14945       &index_table_length, sizeof(uint) * tmp_table_share.keys,
14946       &key_tokenizer, sizeof(char *) * tmp_table_share.keys,
14947       &key_tokenizer_length, sizeof(uint) * tmp_table_share.keys,
14948       &col_flags, sizeof(char *) * tmp_table_share.fields,
14949       &col_flags_length, sizeof(uint) * tmp_table_share.fields,
14950       &col_type, sizeof(char *) * tmp_table_share.fields,
14951       &col_type_length, sizeof(uint) * tmp_table_share.fields,
14952       NullS))
14953   ) {
14954     MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_tables);
14955     MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_columns);
14956     DBUG_RETURN(true);
14957   }
14958   tmp_share->engine = NULL;
14959   tmp_share->table_share = &tmp_table_share;
14960   tmp_share->index_table = index_table;
14961   tmp_share->index_table_length = index_table_length;
14962   tmp_share->key_tokenizer = key_tokenizer;
14963   tmp_share->key_tokenizer_length = key_tokenizer_length;
14964   tmp_share->col_flags = col_flags;
14965   tmp_share->col_flags_length = col_flags_length;
14966   tmp_share->col_type = col_type;
14967   tmp_share->col_type_length = col_type_length;
14968   bitmap_clear_all(table->read_set);
14969   if (table_share->primary_key != MAX_KEY) {
14970     KEY *p_key_info = &table->key_info[table_share->primary_key];
14971     mrn_set_bitmap_by_key(table->read_set, p_key_info);
14972   }
14973   int error = 0;
14974   uint n_keys = ha_alter_info->index_add_count;
14975   for (uint i = 0; i < n_keys; ++i) {
14976     uint key_pos = ha_alter_info->index_add_buffer[i];
14977     KEY *key = &altered_table->key_info[key_pos];
14978     if (share->disable_keys && !(key->flags & HA_NOSAME)) {
14979       continue; // key is disabled
14980     }
14981     if ((error = mrn_add_index_param(tmp_share, key, key_pos)))
14982     {
14983       break;
14984     }
14985     DBUG_PRINT("info", ("mroonga: add key pos=%u", key_pos));
14986     mrn::PathMapper mapper(share->table_name);
14987     if ((error = storage_create_index(table, mapper.table_name(), grn_table,
14988                                       tmp_share, key, index_tables,
14989                                       index_columns, key_pos)))
14990     {
14991       break;
14992     }
14993     if (
14994       KEY_N_KEY_PARTS(key) == 1 &&
14995       (key->flags & HA_NOSAME) &&
14996       grn_table_size(ctx, grn_table) !=
14997         grn_table_size(ctx, index_tables[key_pos])
14998     ) {
14999       error = HA_ERR_FOUND_DUPP_UNIQUE;
15000       my_printf_error(ER_DUP_UNIQUE, ER(ER_DUP_UNIQUE), MYF(0),
15001                       table_share->table_name);
15002       ++i;
15003       break;
15004     }
15005     if (
15006       KEY_N_KEY_PARTS(key) != 1 &&
15007       !(key->flags & HA_FULLTEXT)
15008     ) {
15009       mrn_set_bitmap_by_key(table->read_set, key);
15010       have_multiple_column_index = true;
15011     }
15012   }
15013   if (!error && have_multiple_column_index) {
15014     my_ptrdiff_t diff =
15015       PTR_BYTE_DIFF(table->record[0], altered_table->record[0]);
15016     mrn::TableFieldsOffsetMover mover(altered_table, diff);
15017     error = storage_add_index_multiple_columns(altered_table->key_info,
15018                                                ha_alter_info->key_count,
15019                                                index_tables,
15020                                                index_columns, false);
15021     if (error == HA_ERR_FOUND_DUPP_UNIQUE) {
15022       my_printf_error(ER_DUP_UNIQUE, ER(ER_DUP_UNIQUE), MYF(0),
15023                       table_share->table_name);
15024     } else if (error) {
15025       my_message(error, "failed to create multiple column index", MYF(0));
15026     }
15027   }
15028   bitmap_set_all(table->read_set);
15029 
15030   bool have_error = false;
15031   if (error)
15032   {
15033     n_keys = ha_alter_info->index_add_count;
15034     for (uint i = 0; i < n_keys; ++i) {
15035       uint key_pos = ha_alter_info->index_add_buffer[i];
15036       KEY *key =
15037         &altered_table->key_info[key_pos];
15038       if (share->disable_keys && !(key->flags & HA_NOSAME)) {
15039         continue;
15040       }
15041       if (index_tables[key_pos])
15042       {
15043         grn_obj_remove(ctx, index_columns[key_pos]);
15044         grn_obj_remove(ctx, index_tables[key_pos]);
15045       }
15046     }
15047     have_error = true;
15048   }
15049   mrn_free_share_alloc(tmp_share);
15050   my_free(tmp_share);
15051   MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_tables);
15052   MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_columns);
15053 
15054   DBUG_RETURN(have_error);
15055 }
15056 
storage_inplace_alter_table_drop_index(TABLE * altered_table,Alter_inplace_info * ha_alter_info)15057 bool ha_mroonga::storage_inplace_alter_table_drop_index(
15058   TABLE *altered_table,
15059   Alter_inplace_info *ha_alter_info)
15060 {
15061   MRN_DBUG_ENTER_METHOD();
15062 
15063   bool have_error = false;
15064   uint n_keys;
15065   uint i, j = 0;
15066   KEY *key_info = table_share->key_info;
15067   mrn::PathMapper mapper(share->table_name);
15068   n_keys = ha_alter_info->index_drop_count;
15069   for (i = 0; i < n_keys; ++i) {
15070     KEY *key = ha_alter_info->index_drop_buffer[i];
15071     while (strcmp(key_info[j].name.str, key->name.str) != 0) {
15072       ++j;
15073     }
15074     int error = drop_index(share, j);
15075     if (error != 0)
15076       DBUG_RETURN(true);
15077     grn_index_tables[j] = NULL;
15078     grn_index_columns[j] = NULL;
15079   }
15080 
15081   DBUG_RETURN(have_error);
15082 }
15083 
storage_inplace_alter_table_add_column(TABLE * altered_table,Alter_inplace_info * ha_alter_info)15084 bool ha_mroonga::storage_inplace_alter_table_add_column(
15085   TABLE *altered_table,
15086   Alter_inplace_info *ha_alter_info)
15087 {
15088   MRN_DBUG_ENTER_METHOD();
15089 
15090   bool have_error = false;
15091 
15092   MRN_SHARE *tmp_share;
15093   TABLE_SHARE tmp_table_share;
15094   char **index_table, **key_tokenizer, **col_flags, **col_type;
15095   uint *index_table_length, *key_tokenizer_length, *col_flags_length, *col_type_length;
15096   tmp_table_share.keys = 0;
15097   tmp_table_share.fields = altered_table->s->fields;
15098   tmp_share = (MRN_SHARE *)mrn_my_multi_malloc(
15099     MYF(MY_WME | MY_ZEROFILL),
15100     &tmp_share, sizeof(*tmp_share),
15101     &index_table, sizeof(char *) * tmp_table_share.keys,
15102     &index_table_length, sizeof(uint) * tmp_table_share.keys,
15103     &key_tokenizer, sizeof(char *) * tmp_table_share.keys,
15104     &key_tokenizer_length, sizeof(uint) * tmp_table_share.keys,
15105     &col_flags, sizeof(char *) * tmp_table_share.fields,
15106     &col_flags_length, sizeof(uint) * tmp_table_share.fields,
15107     &col_type, sizeof(char *) * tmp_table_share.fields,
15108     &col_type_length, sizeof(uint) * tmp_table_share.fields,
15109     NullS);
15110   if (!tmp_share) {
15111     have_error = true;
15112     DBUG_RETURN(have_error);
15113   }
15114   tmp_share->engine = NULL;
15115   tmp_share->table_share = &tmp_table_share;
15116   tmp_share->index_table = index_table;
15117   tmp_share->index_table_length = index_table_length;
15118   tmp_share->key_tokenizer = key_tokenizer;
15119   tmp_share->key_tokenizer_length = key_tokenizer_length;
15120   tmp_share->col_flags = col_flags;
15121   tmp_share->col_flags_length = col_flags_length;
15122   tmp_share->col_type = col_type;
15123   tmp_share->col_type_length = col_type_length;
15124 
15125   mrn::PathMapper mapper(share->table_name);
15126   grn_obj *table_obj;
15127   table_obj = grn_ctx_get(ctx, mapper.table_name(), strlen(mapper.table_name()));
15128 
15129   Alter_info *alter_info = ha_alter_info->alter_info;
15130   List_iterator_fast<Create_field> create_fields(alter_info->create_list);
15131   for (uint i = 0; Create_field *create_field = create_fields++; i++) {
15132     if (create_field->field) {
15133       continue;
15134     }
15135 
15136     Field *field = altered_table->s->field[i];
15137 
15138 #ifdef MRN_SUPPORT_GENERATED_COLUMNS
15139     if (MRN_GENERATED_COLUMNS_FIELD_IS_VIRTUAL(field)) {
15140       continue;
15141     }
15142 #endif
15143 
15144     mrn::ColumnName column_name(field->field_name);
15145     int error = mrn_add_column_param(tmp_share, field, i);
15146     if (error) {
15147       have_error = true;
15148       break;
15149     }
15150 
15151     grn_obj_flags col_flags = GRN_OBJ_PERSISTENT;
15152     if (!find_column_flags(field, tmp_share, i, &col_flags)) {
15153       col_flags |= GRN_OBJ_COLUMN_SCALAR;
15154     }
15155 
15156     grn_obj *col_type;
15157     {
15158       int column_type_error_code = ER_WRONG_FIELD_SPEC;
15159       col_type = find_column_type(field, tmp_share, i, column_type_error_code);
15160       if (!col_type) {
15161         error = column_type_error_code;
15162         have_error = true;
15163         break;
15164       }
15165     }
15166     char *col_path = NULL; // we don't specify path
15167 
15168     grn_obj *column_obj =
15169       grn_column_create(ctx, table_obj,
15170                         column_name.c_str(),
15171                         column_name.length(),
15172                         col_path, col_flags, col_type);
15173     if (ctx->rc) {
15174       error = ER_WRONG_COLUMN_NAME;
15175       my_message(error, ctx->errbuf, MYF(0));
15176       have_error = true;
15177       break;
15178     }
15179 
15180 #ifdef MRN_SUPPORT_GENERATED_COLUMNS
15181     if (MRN_GENERATED_COLUMNS_FIELD_IS_STORED(field)) {
15182 #  ifndef MRN_MARIADB_P
15183       MY_BITMAP generated_column_bitmap;
15184       if (bitmap_init(&generated_column_bitmap, NULL,
15185                       altered_table->s->fields, false)) {
15186         error = HA_ERR_OUT_OF_MEM;
15187         my_message(ER_OUTOFMEMORY,
15188                    "mroonga: storage: "
15189                    "failed to allocate memory for getting generated value",
15190                     MYF(0));
15191         have_error = true;
15192         grn_obj_remove(ctx, column_obj);
15193         break;
15194       }
15195       mrn::SmartBitmap smart_generated_column_bitmap(&generated_column_bitmap);
15196       bitmap_set_bit(&generated_column_bitmap, field->field_index);
15197 #  endif
15198 
15199       my_ptrdiff_t diff =
15200         PTR_BYTE_DIFF(table->record[0], altered_table->record[0]);
15201       mrn::TableFieldsOffsetMover mover(altered_table, diff);
15202 
15203       error = storage_rnd_init(true);
15204       if (error) {
15205         have_error = true;
15206         grn_obj_remove(ctx, column_obj);
15207         break;
15208       }
15209 
15210       Field *altered_field = altered_table->field[i];
15211       grn_obj new_value;
15212       GRN_VOID_INIT(&new_value);
15213       mrn::SmartGrnObj smart_new_value(ctx, &new_value);
15214       while (!have_error) {
15215         int next_error = storage_rnd_next(table->record[0]);
15216         if (next_error == HA_ERR_END_OF_FILE) {
15217           break;
15218         } else if (next_error != 0) {
15219           error = next_error;
15220           have_error = true;
15221           grn_obj_remove(ctx, column_obj);
15222           break;
15223         }
15224 
15225 #  ifdef MRN_MARIADB_P
15226         MRN_GENERATED_COLUMNS_UPDATE_VIRTUAL_FIELD(altered_table, altered_field);
15227 #  else
15228         if (update_generated_write_fields(&generated_column_bitmap, altered_table)) {
15229           error = ER_ERROR_ON_WRITE;
15230           my_message(error,
15231                      "mroonga: storage: "
15232                      "failed to update generated value for updating column",
15233                      MYF(0));
15234           have_error = true;
15235           grn_obj_remove(ctx, column_obj);
15236           break;
15237         }
15238 #  endif
15239 
15240         error = mrn_change_encoding(ctx, altered_field->charset());
15241         if (error) {
15242           my_message(error,
15243                      "mroonga: storage: "
15244                      "failed to change encoding to store generated value",
15245                      MYF(0));
15246           have_error = true;
15247           grn_obj_remove(ctx, column_obj);
15248           break;
15249         }
15250         error = generic_store_bulk(altered_field, &new_value);
15251         if (error) {
15252           my_message(error,
15253                      "mroonga: storage: "
15254                      "failed to get generated value for updating column",
15255                      MYF(0));
15256           have_error = true;
15257           grn_obj_remove(ctx, column_obj);
15258           break;
15259         }
15260 
15261         grn_obj_set_value(ctx, column_obj, record_id, &new_value, GRN_OBJ_SET);
15262         if (ctx->rc) {
15263           error = ER_ERROR_ON_WRITE;
15264           my_message(error, ctx->errbuf, MYF(0));
15265           break;
15266         }
15267       }
15268 
15269       int end_error = storage_rnd_end();
15270       if (end_error != 0 && error == 0) {
15271         error = end_error;
15272         grn_obj_remove(ctx, column_obj);
15273         break;
15274       }
15275     }
15276 #endif
15277   }
15278 
15279   grn_obj_unlink(ctx, table_obj);
15280 
15281   mrn_free_share_alloc(tmp_share);
15282   my_free(tmp_share);
15283 
15284   DBUG_RETURN(have_error);
15285 }
15286 
storage_inplace_alter_table_drop_column(TABLE * altered_table,Alter_inplace_info * ha_alter_info)15287 bool ha_mroonga::storage_inplace_alter_table_drop_column(
15288   TABLE *altered_table,
15289   Alter_inplace_info *ha_alter_info)
15290 {
15291   MRN_DBUG_ENTER_METHOD();
15292 
15293   bool have_error = false;
15294 
15295   mrn::PathMapper mapper(share->table_name);
15296   grn_obj *table_obj;
15297   table_obj = grn_ctx_get(ctx, mapper.table_name(), strlen(mapper.table_name()));
15298 
15299   Alter_info *alter_info = ha_alter_info->alter_info;
15300 
15301   uint n_fields = table->s->fields;
15302   for (uint i = 0; i < n_fields; i++) {
15303     Field *field = table->field[i];
15304 
15305     bool dropped = true;
15306     List_iterator_fast<Create_field> create_fields(alter_info->create_list);
15307     while (Create_field *create_field = create_fields++) {
15308       if (create_field->field == field) {
15309         dropped = false;
15310         break;
15311       }
15312     }
15313     if (!dropped) {
15314       continue;
15315     }
15316 
15317     const char *column_name = field->field_name.str;
15318     int column_name_size = field->field_name.length;
15319 
15320     grn_obj *column_obj;
15321     column_obj = grn_obj_column(ctx, table_obj, column_name, column_name_size);
15322     if (column_obj) {
15323       grn_obj_remove(ctx, column_obj);
15324     }
15325     if (ctx->rc) {
15326       int error = ER_WRONG_COLUMN_NAME;
15327       my_message(error, ctx->errbuf, MYF(0));
15328       have_error = true;
15329       break;
15330     }
15331   }
15332   grn_obj_unlink(ctx, table_obj);
15333 
15334   DBUG_RETURN(have_error);
15335 }
15336 
storage_inplace_alter_table_rename_column(TABLE * altered_table,Alter_inplace_info * ha_alter_info)15337 bool ha_mroonga::storage_inplace_alter_table_rename_column(
15338   TABLE *altered_table,
15339   Alter_inplace_info *ha_alter_info)
15340 {
15341   MRN_DBUG_ENTER_METHOD();
15342 
15343   bool have_error = false;
15344 
15345   mrn::PathMapper mapper(share->table_name);
15346   grn_obj *table_obj;
15347   table_obj = grn_ctx_get(ctx, mapper.table_name(), strlen(mapper.table_name()));
15348 
15349   Alter_info *alter_info = ha_alter_info->alter_info;
15350   uint n_fields = table->s->fields;
15351   for (uint i = 0; i < n_fields; i++) {
15352     Field *field = table->field[i];
15353 
15354     if (!(field->flags & FIELD_IS_RENAMED)) {
15355       continue;
15356     }
15357 
15358     LEX_CSTRING new_name;
15359     new_name.str= 0;
15360     List_iterator_fast<Create_field> create_fields(alter_info->create_list);
15361     while (Create_field *create_field = create_fields++) {
15362       if (create_field->field == field) {
15363         new_name = create_field->field_name;
15364         break;
15365       }
15366     }
15367 
15368     if (!new_name.str) {
15369       continue;
15370     }
15371 
15372     const char *old_name = field->field_name.str;
15373     grn_obj *column_obj;
15374     column_obj = grn_obj_column(ctx, table_obj, old_name,
15375                                 field->field_name.length);
15376     if (column_obj) {
15377       grn_column_rename(ctx, column_obj, new_name.str, new_name.length);
15378       if (ctx->rc) {
15379         int error = ER_WRONG_COLUMN_NAME;
15380         my_message(error, ctx->errbuf, MYF(0));
15381         have_error = true;
15382       }
15383       grn_obj_unlink(ctx, column_obj);
15384     }
15385 
15386     if (have_error) {
15387       break;
15388     }
15389   }
15390   grn_obj_unlink(ctx, table_obj);
15391 
15392   DBUG_RETURN(have_error);
15393 }
15394 
storage_inplace_alter_table(TABLE * altered_table,Alter_inplace_info * ha_alter_info)15395 bool ha_mroonga::storage_inplace_alter_table(
15396   TABLE *altered_table,
15397   Alter_inplace_info *ha_alter_info)
15398 {
15399   MRN_DBUG_ENTER_METHOD();
15400 
15401   bool have_error = false;
15402 
15403   int error = mrn_change_encoding(ctx, system_charset_info);
15404   if (error) {
15405     have_error = true;
15406   }
15407 
15408   alter_table_operations drop_index_related_flags =
15409     ALTER_DROP_INDEX |
15410     ALTER_DROP_NON_UNIQUE_NON_PRIM_INDEX |
15411     ALTER_DROP_UNIQUE_INDEX |
15412     ALTER_DROP_PK_INDEX;
15413   if (!have_error &&
15414       (ha_alter_info->handler_flags & drop_index_related_flags)) {
15415     have_error = storage_inplace_alter_table_drop_index(altered_table,
15416                                                         ha_alter_info);
15417   }
15418 
15419   alter_table_operations add_column_related_flags =
15420     ALTER_ADD_COLUMN;
15421   if (!have_error &&
15422       (ha_alter_info->handler_flags & add_column_related_flags)) {
15423     have_error = storage_inplace_alter_table_add_column(altered_table, ha_alter_info);
15424   }
15425 
15426   alter_table_operations drop_column_related_flags = ALTER_DROP_COLUMN;
15427   if (!have_error &&
15428       (ha_alter_info->handler_flags & drop_column_related_flags)) {
15429     have_error = storage_inplace_alter_table_drop_column(altered_table, ha_alter_info);
15430   }
15431 
15432   alter_table_operations rename_column_related_flags = ALTER_COLUMN_NAME;
15433   if (!have_error &&
15434       (ha_alter_info->handler_flags & rename_column_related_flags)) {
15435     have_error = storage_inplace_alter_table_rename_column(altered_table, ha_alter_info);
15436   }
15437 
15438   alter_table_operations add_index_related_flags =
15439     ALTER_ADD_INDEX |
15440     ALTER_ADD_NON_UNIQUE_NON_PRIM_INDEX |
15441     ALTER_ADD_UNIQUE_INDEX |
15442     ALTER_ADD_PK_INDEX;
15443   if (!have_error &&
15444       (ha_alter_info->handler_flags & add_index_related_flags)) {
15445     have_error = storage_inplace_alter_table_add_index(altered_table,
15446                                                        ha_alter_info);
15447   }
15448 
15449   DBUG_RETURN(have_error);
15450 }
15451 
inplace_alter_table(TABLE * altered_table,Alter_inplace_info * ha_alter_info)15452 bool ha_mroonga::inplace_alter_table(
15453   TABLE *altered_table,
15454   Alter_inplace_info *ha_alter_info)
15455 {
15456   MRN_DBUG_ENTER_METHOD();
15457   bool result;
15458   if (share->wrapper_mode) {
15459     result = wrapper_inplace_alter_table(altered_table, ha_alter_info);
15460   } else {
15461     result = storage_inplace_alter_table(altered_table, ha_alter_info);
15462   }
15463   DBUG_RETURN(result);
15464 }
15465 
wrapper_commit_inplace_alter_table(TABLE * altered_table,Alter_inplace_info * ha_alter_info,bool commit)15466 bool ha_mroonga::wrapper_commit_inplace_alter_table(
15467   TABLE *altered_table,
15468   Alter_inplace_info *ha_alter_info,
15469   bool commit)
15470 {
15471   bool result;
15472   MRN_DBUG_ENTER_METHOD();
15473   if (!alter_handler_flags) {
15474     free_root(&(wrap_altered_table_share->mem_root), MYF(0));
15475     my_free(alter_key_info_buffer);
15476     alter_key_info_buffer = NULL;
15477     DBUG_RETURN(false);
15478   }
15479   MRN_SET_WRAP_ALTER_KEY(this, ha_alter_info);
15480   MRN_SET_WRAP_SHARE_KEY(share, table->s);
15481   MRN_SET_WRAP_TABLE_KEY(this, table);
15482   result = wrap_handler->ha_commit_inplace_alter_table(wrap_altered_table,
15483                                                        ha_alter_info,
15484                                                        commit);
15485   MRN_SET_BASE_ALTER_KEY(this, ha_alter_info);
15486   MRN_SET_BASE_SHARE_KEY(share, table->s);
15487   MRN_SET_BASE_TABLE_KEY(this, table);
15488   free_root(&(wrap_altered_table_share->mem_root), MYF(0));
15489   my_free(alter_key_info_buffer);
15490   alter_key_info_buffer = NULL;
15491   DBUG_RETURN(result);
15492 }
15493 
storage_commit_inplace_alter_table(TABLE * altered_table,Alter_inplace_info * ha_alter_info,bool commit)15494 bool ha_mroonga::storage_commit_inplace_alter_table(
15495   TABLE *altered_table,
15496   Alter_inplace_info *ha_alter_info,
15497   bool commit)
15498 {
15499   MRN_DBUG_ENTER_METHOD();
15500   DBUG_RETURN(false);
15501 }
15502 
commit_inplace_alter_table(TABLE * altered_table,Alter_inplace_info * ha_alter_info,bool commit)15503 bool ha_mroonga::commit_inplace_alter_table(
15504   TABLE *altered_table,
15505   Alter_inplace_info *ha_alter_info,
15506   bool commit)
15507 {
15508   MRN_DBUG_ENTER_METHOD();
15509   bool result;
15510   if (share->wrapper_mode) {
15511     result = wrapper_commit_inplace_alter_table(altered_table, ha_alter_info,
15512                                                 commit);
15513   } else {
15514     result = storage_commit_inplace_alter_table(altered_table, ha_alter_info,
15515                                                 commit);
15516   }
15517   DBUG_RETURN(result);
15518 }
15519 
wrapper_notify_table_changed()15520 void ha_mroonga::wrapper_notify_table_changed()
15521 {
15522   MRN_DBUG_ENTER_METHOD();
15523   MRN_SET_WRAP_SHARE_KEY(share, table->s);
15524   MRN_SET_WRAP_TABLE_KEY(this, table);
15525   wrap_handler->ha_notify_table_changed();
15526   MRN_SET_BASE_SHARE_KEY(share, table->s);
15527   MRN_SET_BASE_TABLE_KEY(this, table);
15528   DBUG_VOID_RETURN;
15529 }
15530 
storage_notify_table_changed()15531 void ha_mroonga::storage_notify_table_changed()
15532 {
15533   MRN_DBUG_ENTER_METHOD();
15534   DBUG_VOID_RETURN;
15535 }
15536 
notify_table_changed()15537 void ha_mroonga::notify_table_changed()
15538 {
15539   MRN_DBUG_ENTER_METHOD();
15540   if (share->wrapper_mode) {
15541     wrapper_notify_table_changed();
15542   } else {
15543     storage_notify_table_changed();
15544   }
15545   DBUG_VOID_RETURN;
15546 }
15547 #else
wrapper_alter_table_flags(alter_table_operations flags)15548 alter_table_operations ha_mroonga::wrapper_alter_table_flags(alter_table_operations flags)
15549 {
15550   alter_table_operations res;
15551   MRN_DBUG_ENTER_METHOD();
15552   MRN_SET_WRAP_SHARE_KEY(share, table->s);
15553   MRN_SET_WRAP_TABLE_KEY(this, table);
15554   res = wrap_handler->alter_table_flags(flags);
15555   MRN_SET_BASE_SHARE_KEY(share, table->s);
15556   MRN_SET_BASE_TABLE_KEY(this, table);
15557   DBUG_RETURN(res);
15558 }
15559 
storage_alter_table_flags(alter_table_operations flags)15560 alter_table_operations ha_mroonga::storage_alter_table_flags(alter_table_operations flags)
15561 {
15562   MRN_DBUG_ENTER_METHOD();
15563   alter_table_operations res = handler::alter_table_flags(flags);
15564   DBUG_RETURN(res);
15565 }
15566 
alter_table_flags(alter_table_operations flags)15567 alter_table_operations ha_mroonga::alter_table_flags(alter_table_operations flags)
15568 {
15569   MRN_DBUG_ENTER_METHOD();
15570   alter_table_operations res;
15571   if (share->wrapper_mode)
15572   {
15573     res = wrapper_alter_table_flags(flags);
15574   } else {
15575     res = storage_alter_table_flags(flags);
15576   }
15577   DBUG_RETURN(res);
15578 }
15579 
15580 #ifdef MRN_HANDLER_HAVE_FINAL_ADD_INDEX
wrapper_add_index(TABLE * table_arg,KEY * key_info,uint num_of_keys,handler_add_index ** add)15581 int ha_mroonga::wrapper_add_index(TABLE *table_arg, KEY *key_info,
15582                                   uint num_of_keys, handler_add_index **add)
15583 #else
15584 int ha_mroonga::wrapper_add_index(TABLE *table_arg, KEY *key_info,
15585                                   uint num_of_keys)
15586 #endif
15587 {
15588   int error = 0;
15589   uint i, j, k;
15590   uint n_keys = table->s->keys;
15591   MRN_ALLOCATE_VARIABLE_LENGTH_ARRAYS(grn_obj *, index_tables, num_of_keys + n_keys);
15592   MRN_ALLOCATE_VARIABLE_LENGTH_ARRAYS(grn_obj *, index_columns, num_of_keys + n_keys);
15593   THD *thd = ha_thd();
15594   MRN_SHARE *tmp_share;
15595   TABLE_SHARE tmp_table_share;
15596   char **key_tokenizer;
15597   uint *key_tokenizer_length;
15598   MRN_DBUG_ENTER_METHOD();
15599   if (!(wrap_alter_key_info = (KEY *) mrn_my_malloc(sizeof(KEY) * num_of_keys,
15600                                                     MYF(MY_WME)))) {
15601     MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_tables);
15602     MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_columns);
15603     DBUG_RETURN(HA_ERR_OUT_OF_MEM);
15604   }
15605   KEY *p_key_info = &table->key_info[table_share->primary_key], *tmp_key_info;
15606   tmp_table_share.keys = n_keys + num_of_keys;
15607   tmp_table_share.fields = 0;
15608   if (!(tmp_share = (MRN_SHARE *)
15609     mrn_my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
15610       &tmp_share, sizeof(*tmp_share),
15611       &key_tokenizer, sizeof(char *) * (n_keys + num_of_keys),
15612       &key_tokenizer_length, sizeof(uint) * (n_keys + num_of_keys),
15613       NullS))
15614   ) {
15615     MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_tables);
15616     MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_columns);
15617     DBUG_RETURN(HA_ERR_OUT_OF_MEM);
15618   }
15619   tmp_share->engine = NULL;
15620   tmp_share->table_share = &tmp_table_share;
15621   tmp_share->index_table = NULL;
15622   tmp_share->index_table_length = NULL;
15623   tmp_share->key_tokenizer = key_tokenizer;
15624   tmp_share->key_tokenizer_length = key_tokenizer_length;
15625   tmp_share->col_flags = NULL;
15626   tmp_share->col_type = NULL;
15627 #ifdef MRN_HANDLER_HAVE_FINAL_ADD_INDEX
15628   hnd_add_index = NULL;
15629 #endif
15630   bitmap_clear_all(table->read_set);
15631   mrn_set_bitmap_by_key(table->read_set, p_key_info);
15632   mrn::PathMapper mapper(share->table_name);
15633   for (i = 0, j = 0; i < num_of_keys; i++) {
15634     if (!(key_info[i].flags & HA_FULLTEXT) && !mrn_is_geo_key(&key_info[i])) {
15635       wrap_alter_key_info[j] = key_info[i];
15636       j++;
15637       continue;
15638     }
15639     if (share->disable_keys) {
15640       continue;
15641     }
15642     if ((error = mrn_add_index_param(tmp_share, &key_info[i], i + n_keys)))
15643     {
15644       break;
15645     }
15646     index_tables[i + n_keys] = NULL;
15647     if (
15648       (key_info[i].flags & HA_FULLTEXT) &&
15649       (error = wrapper_create_index_fulltext(mapper.table_name(),
15650                                              i + n_keys,
15651                                              &key_info[i], index_tables, NULL,
15652                                              tmp_share))
15653     ) {
15654       break;
15655     } else if (
15656       mrn_is_geo_key(&key_info[i]) &&
15657       (error = wrapper_create_index_geo(mapper.table_name(),
15658                                         i + n_keys, &key_info[i],
15659                                         index_tables, NULL, tmp_share))
15660     ) {
15661       break;
15662     }
15663     mrn_set_bitmap_by_key(table->read_set, &key_info[i]);
15664   }
15665   if (!error && i > j && !share->disable_keys) {
15666     for (k = 0; k < num_of_keys; k++) {
15667       tmp_key_info = &key_info[k];
15668       if (!(tmp_key_info->flags & HA_FULLTEXT) &&
15669         !mrn_is_geo_key(tmp_key_info)) {
15670         continue;
15671       }
15672       index_columns[k + n_keys] = grn_obj_column(ctx,
15673                                                  index_tables[k + n_keys],
15674                                                  INDEX_COLUMN_NAME,
15675                                                  strlen(INDEX_COLUMN_NAME));
15676     }
15677     error = wrapper_fill_indexes(thd, key_info, &index_columns[n_keys],
15678                                  num_of_keys);
15679   }
15680   bitmap_set_all(table->read_set);
15681 
15682   if (!error && j)
15683   {
15684     MRN_SET_WRAP_SHARE_KEY(share, table->s);
15685     MRN_SET_WRAP_TABLE_KEY(this, table);
15686 #ifdef MRN_HANDLER_HAVE_FINAL_ADD_INDEX
15687     error = wrap_handler->add_index(table_arg, wrap_alter_key_info, j,
15688                                     &hnd_add_index);
15689 #else
15690     error = wrap_handler->add_index(table_arg, wrap_alter_key_info, j);
15691 #endif
15692     MRN_SET_BASE_SHARE_KEY(share, table->s);
15693     MRN_SET_BASE_TABLE_KEY(this, table);
15694   }
15695   if (error)
15696   {
15697     for (k = 0; k < i; k++) {
15698       if (!(key_info[k].flags & HA_FULLTEXT) && !mrn_is_geo_key(&key_info[k]))
15699       {
15700         continue;
15701       }
15702       if (index_tables[k + n_keys])
15703       {
15704         grn_obj_remove(ctx, index_tables[k + n_keys]);
15705       }
15706     }
15707   }
15708 #ifdef MRN_HANDLER_HAVE_FINAL_ADD_INDEX
15709   else {
15710     *add = new handler_add_index(table_arg, key_info, num_of_keys);
15711   }
15712 #endif
15713   mrn_free_share_alloc(tmp_share);
15714   my_free(tmp_share);
15715   MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_tables);
15716   MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_columns);
15717   DBUG_RETURN(error);
15718 }
15719 
15720 #ifdef MRN_HANDLER_HAVE_FINAL_ADD_INDEX
storage_add_index(TABLE * table_arg,KEY * key_info,uint num_of_keys,handler_add_index ** add)15721 int ha_mroonga::storage_add_index(TABLE *table_arg, KEY *key_info,
15722                                   uint num_of_keys, handler_add_index **add)
15723 #else
15724 int ha_mroonga::storage_add_index(TABLE *table_arg, KEY *key_info,
15725                                   uint num_of_keys)
15726 #endif
15727 {
15728   int error = 0;
15729   uint i;
15730   uint n_keys = table->s->keys;
15731   MRN_ALLOCATE_VARIABLE_LENGTH_ARRAYS(grn_obj *, index_tables, num_of_keys + n_keys);
15732   MRN_ALLOCATE_VARIABLE_LENGTH_ARRAYS(grn_obj *, index_columns, num_of_keys + n_keys);
15733   MRN_SHARE *tmp_share;
15734   TABLE_SHARE tmp_table_share;
15735   char **index_table, **key_tokenizer, **col_flags, **col_type;
15736   uint *index_table_length, *key_tokenizer_length, *col_flags_length, *col_type_length;
15737   bool have_multiple_column_index = false;
15738 
15739   MRN_DBUG_ENTER_METHOD();
15740   tmp_table_share.keys = n_keys + num_of_keys;
15741   tmp_table_share.fields = 0;
15742   if (!(tmp_share = (MRN_SHARE *)
15743     mrn_my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
15744       &tmp_share, sizeof(*tmp_share),
15745       &index_table, sizeof(char*) *  tmp_table_share.keys,
15746       &index_table_length, sizeof(uint) * tmp_table_share.keys,
15747       &key_tokenizer, sizeof(char *) * tmp_table_share.keys,
15748       &key_tokenizer_length, sizeof(uint) * tmp_table_share.keys,
15749       &col_flags, sizeof(char *) * tmp_table_share.fields,
15750       &col_flags_length, sizeof(uint) * tmp_table_share.fields,
15751       &col_type, sizeof(char *) * tmp_table_share.fields,
15752       &col_type_length, sizeof(uint) * tmp_table_share.fields,
15753       NullS))
15754   ) {
15755     MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_tables);
15756     MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_columns);
15757     DBUG_RETURN(HA_ERR_OUT_OF_MEM);
15758   }
15759   tmp_share->engine = NULL;
15760   tmp_share->table_share = &tmp_table_share;
15761   tmp_share->index_table = index_table;
15762   tmp_share->index_table_length = index_table_length;
15763   tmp_share->key_tokenizer = key_tokenizer;
15764   tmp_share->key_tokenizer_length = key_tokenizer_length;
15765   tmp_share->col_flags = col_flags;
15766   tmp_share->col_flags_length = col_flags_length;
15767   tmp_share->col_type = col_type;
15768   tmp_share->col_type_length = col_type_length;
15769   bitmap_clear_all(table->read_set);
15770   mrn::PathMapper mapper(share->table_name);
15771   for (i = 0; i < num_of_keys; i++) {
15772     if (share->disable_keys && !(key_info[i].flags & HA_NOSAME)) {
15773       continue; // key is disabled
15774     }
15775     index_tables[i + n_keys] = NULL;
15776     index_columns[i + n_keys] = NULL;
15777     if ((error = mrn_add_index_param(tmp_share, &key_info[i], i + n_keys)))
15778     {
15779       break;
15780     }
15781     if ((error = storage_create_index(table, mapper.table_name(), grn_table,
15782                                       tmp_share, &key_info[i], index_tables,
15783                                       index_columns, i + n_keys)))
15784     {
15785       break;
15786     }
15787     if (
15788       KEY_N_KEY_PARTS(&(key_info[i])) == 1 &&
15789       (key_info[i].flags & HA_NOSAME) &&
15790       grn_table_size(ctx, grn_table) !=
15791         grn_table_size(ctx, index_tables[i + n_keys])
15792     ) {
15793       error = HA_ERR_FOUND_DUPP_UNIQUE;
15794       i++;
15795       break;
15796     }
15797     if (
15798       KEY_N_KEY_PARTS(&(key_info[i])) != 1 &&
15799       !(key_info[i].flags & HA_FULLTEXT)
15800     ) {
15801       mrn_set_bitmap_by_key(table->read_set, &key_info[i]);
15802       have_multiple_column_index = true;
15803     }
15804   }
15805   if (!error && have_multiple_column_index)
15806   {
15807     error = storage_add_index_multiple_columns(key_info, num_of_keys,
15808                                                index_tables + n_keys,
15809                                                index_columns + n_keys, false);
15810   }
15811   bitmap_set_all(table->read_set);
15812   if (error)
15813   {
15814     for (uint j = 0; j < i; j++) {
15815       if (index_tables[j + n_keys])
15816       {
15817         grn_obj_remove(ctx, index_columns[j + n_keys]);
15818         grn_obj_remove(ctx, index_tables[j + n_keys]);
15819       }
15820     }
15821   }
15822 #ifdef MRN_HANDLER_HAVE_FINAL_ADD_INDEX
15823   else {
15824     *add = new handler_add_index(table_arg, key_info, num_of_keys);
15825   }
15826 #endif
15827   mrn_free_share_alloc(tmp_share);
15828   my_free(tmp_share);
15829   MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_tables);
15830   MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_columns);
15831   DBUG_RETURN(error);
15832 }
15833 #ifdef MRN_HANDLER_HAVE_FINAL_ADD_INDEX
add_index(TABLE * table_arg,KEY * key_info,uint num_of_keys,handler_add_index ** add)15834 int ha_mroonga::add_index(TABLE *table_arg, KEY *key_info,
15835                           uint num_of_keys, handler_add_index **add)
15836 {
15837   MRN_DBUG_ENTER_METHOD();
15838   int error;
15839   if (share->wrapper_mode)
15840   {
15841     error = wrapper_add_index(table_arg, key_info, num_of_keys, add);
15842   } else {
15843     error = storage_add_index(table_arg, key_info, num_of_keys, add);
15844   }
15845   DBUG_RETURN(error);
15846 }
15847 #else
add_index(TABLE * table_arg,KEY * key_info,uint num_of_keys)15848 int ha_mroonga::add_index(TABLE *table_arg, KEY *key_info,
15849                           uint num_of_keys)
15850 {
15851   MRN_DBUG_ENTER_METHOD();
15852   int error;
15853   if (share->wrapper_mode)
15854   {
15855     error = wrapper_add_index(table_arg, key_info, num_of_keys);
15856   } else {
15857     error = storage_add_index(table_arg, key_info, num_of_keys);
15858   }
15859   DBUG_RETURN(error);
15860 }
15861 #endif
15862 
15863 #ifdef MRN_HANDLER_HAVE_FINAL_ADD_INDEX
wrapper_final_add_index(handler_add_index * add,bool commit)15864 int ha_mroonga::wrapper_final_add_index(handler_add_index *add, bool commit)
15865 {
15866   int error = 0;
15867   MRN_DBUG_ENTER_METHOD();
15868   if (hnd_add_index)
15869   {
15870     MRN_SET_WRAP_SHARE_KEY(share, table->s);
15871     MRN_SET_WRAP_TABLE_KEY(this, table);
15872     error = wrap_handler->final_add_index(hnd_add_index, commit);
15873     MRN_SET_BASE_SHARE_KEY(share, table->s);
15874     MRN_SET_BASE_TABLE_KEY(this, table);
15875   }
15876   if (add)
15877   {
15878     delete add;
15879   }
15880   DBUG_RETURN(error);
15881 }
15882 
storage_final_add_index(handler_add_index * add,bool commit)15883 int ha_mroonga::storage_final_add_index(handler_add_index *add, bool commit)
15884 {
15885   MRN_DBUG_ENTER_METHOD();
15886   if (add)
15887   {
15888     delete add;
15889   }
15890   DBUG_RETURN(0);
15891 }
15892 
final_add_index(handler_add_index * add,bool commit)15893 int ha_mroonga::final_add_index(handler_add_index *add, bool commit)
15894 {
15895   MRN_DBUG_ENTER_METHOD();
15896   int error;
15897   if (share->wrapper_mode)
15898   {
15899     error = wrapper_final_add_index(add, commit);
15900   } else {
15901     error = storage_final_add_index(add, commit);
15902   }
15903   DBUG_RETURN(error);
15904 }
15905 #endif
15906 
wrapper_prepare_drop_index(TABLE * table_arg,uint * key_num,uint num_of_keys)15907 int ha_mroonga::wrapper_prepare_drop_index(TABLE *table_arg, uint *key_num,
15908   uint num_of_keys)
15909 {
15910   int res = 0;
15911   uint i, j;
15912   KEY *key_info = table_share->key_info;
15913   MRN_DBUG_ENTER_METHOD();
15914   res = mrn_change_encoding(ctx, system_charset_info);
15915   if (res)
15916     DBUG_RETURN(res);
15917 
15918   MRN_ALLOCATE_VARIABLE_LENGTH_ARRAYS(uint, wrap_key_num, num_of_keys);
15919   for (i = 0, j = 0; i < num_of_keys; i++) {
15920     uint key_index = key_num[i];
15921     if (!(key_info[key_index].flags & HA_FULLTEXT) &&
15922         !mrn_is_geo_key(&key_info[key_index])) {
15923       wrap_key_num[j] = share->wrap_key_nr[key_index];
15924       j++;
15925       continue;
15926     }
15927 
15928     res = drop_index(share, key_index);
15929     if (res)
15930       DBUG_RETURN(res);
15931     grn_index_tables[key_index] = NULL;
15932     grn_index_columns[key_index] = NULL;
15933   }
15934   if (j)
15935   {
15936     MRN_SET_WRAP_SHARE_KEY(share, table->s);
15937     MRN_SET_WRAP_TABLE_KEY(this, table);
15938     res = wrap_handler->prepare_drop_index(table_arg, wrap_key_num, j);
15939     MRN_SET_BASE_SHARE_KEY(share, table->s);
15940     MRN_SET_BASE_TABLE_KEY(this, table);
15941   }
15942   MRN_FREE_VARIABLE_LENGTH_ARRAYS(wrap_key_num);
15943   DBUG_RETURN(res);
15944 }
15945 
storage_prepare_drop_index(TABLE * table_arg,uint * key_num,uint num_of_keys)15946 int ha_mroonga::storage_prepare_drop_index(TABLE *table_arg, uint *key_num,
15947                                            uint num_of_keys)
15948 {
15949   int error;
15950   uint i;
15951   MRN_DBUG_ENTER_METHOD();
15952   error = mrn_change_encoding(ctx, system_charset_info);
15953   if (error)
15954     DBUG_RETURN(error);
15955 
15956   for (i = 0; i < num_of_keys; i++) {
15957     uint key_index = key_num[i];
15958     error = drop_index(share, key_index);
15959     if (error)
15960       break;
15961     grn_index_tables[key_index] = NULL;
15962     grn_index_columns[key_index] = NULL;
15963   }
15964   DBUG_RETURN(error);
15965 }
15966 
prepare_drop_index(TABLE * table_arg,uint * key_num,uint num_of_keys)15967 int ha_mroonga::prepare_drop_index(TABLE *table_arg, uint *key_num,
15968   uint num_of_keys)
15969 {
15970   MRN_DBUG_ENTER_METHOD();
15971   int res;
15972   if (share->wrapper_mode)
15973   {
15974     res = wrapper_prepare_drop_index(table_arg, key_num, num_of_keys);
15975   } else {
15976     res = storage_prepare_drop_index(table_arg, key_num, num_of_keys);
15977   }
15978   DBUG_RETURN(res);
15979 }
15980 
wrapper_final_drop_index(TABLE * table_arg)15981 int ha_mroonga::wrapper_final_drop_index(TABLE *table_arg)
15982 {
15983   uint res;
15984   MRN_DBUG_ENTER_METHOD();
15985   MRN_SET_WRAP_SHARE_KEY(share, table->s);
15986   MRN_SET_WRAP_TABLE_KEY(this, table);
15987   res = wrap_handler->final_drop_index(table_arg);
15988   MRN_SET_BASE_SHARE_KEY(share, table->s);
15989   MRN_SET_BASE_TABLE_KEY(this, table);
15990   DBUG_RETURN(res);
15991 }
15992 
storage_final_drop_index(TABLE * table_arg)15993 int ha_mroonga::storage_final_drop_index(TABLE *table_arg)
15994 {
15995   MRN_DBUG_ENTER_METHOD();
15996   DBUG_RETURN(0);
15997 }
15998 
final_drop_index(TABLE * table_arg)15999 int ha_mroonga::final_drop_index(TABLE *table_arg)
16000 {
16001   MRN_DBUG_ENTER_METHOD();
16002   uint res;
16003   if (share->wrapper_mode)
16004   {
16005     res = wrapper_final_drop_index(table_arg);
16006   } else {
16007     res = storage_final_drop_index(table_arg);
16008   }
16009   DBUG_RETURN(res);
16010 }
16011 #endif
16012 
wrapper_update_auto_increment()16013 int ha_mroonga::wrapper_update_auto_increment()
16014 {
16015   int res;
16016   MRN_DBUG_ENTER_METHOD();
16017   MRN_SET_WRAP_SHARE_KEY(share, table->s);
16018   MRN_SET_WRAP_TABLE_KEY(this, table);
16019   res = wrap_handler->update_auto_increment();
16020   MRN_SET_BASE_SHARE_KEY(share, table->s);
16021   MRN_SET_BASE_TABLE_KEY(this, table);
16022   DBUG_RETURN(res);
16023 }
16024 
storage_update_auto_increment()16025 int ha_mroonga::storage_update_auto_increment()
16026 {
16027   MRN_DBUG_ENTER_METHOD();
16028   int res = handler::update_auto_increment();
16029   DBUG_PRINT("info", ("mroonga: auto_inc_value=%llu",
16030     table->next_number_field->val_int()));
16031   DBUG_RETURN(res);
16032 }
16033 
update_auto_increment()16034 int ha_mroonga::update_auto_increment()
16035 {
16036   MRN_DBUG_ENTER_METHOD();
16037   int res;
16038   if (share->wrapper_mode)
16039   {
16040     res = wrapper_update_auto_increment();
16041   } else {
16042     res = storage_update_auto_increment();
16043   }
16044   DBUG_RETURN(res);
16045 }
16046 
wrapper_set_next_insert_id(ulonglong id)16047 void ha_mroonga::wrapper_set_next_insert_id(ulonglong id)
16048 {
16049   MRN_DBUG_ENTER_METHOD();
16050   MRN_SET_WRAP_SHARE_KEY(share, table->s);
16051   MRN_SET_WRAP_TABLE_KEY(this, table);
16052   wrap_handler->set_next_insert_id(id);
16053   MRN_SET_BASE_SHARE_KEY(share, table->s);
16054   MRN_SET_BASE_TABLE_KEY(this, table);
16055   DBUG_VOID_RETURN;
16056 }
16057 
storage_set_next_insert_id(ulonglong id)16058 void ha_mroonga::storage_set_next_insert_id(ulonglong id)
16059 {
16060   MRN_DBUG_ENTER_METHOD();
16061   handler::set_next_insert_id(id);
16062   DBUG_VOID_RETURN;
16063 }
16064 
set_next_insert_id(ulonglong id)16065 void ha_mroonga::set_next_insert_id(ulonglong id)
16066 {
16067   MRN_DBUG_ENTER_METHOD();
16068   if (share->wrapper_mode)
16069   {
16070     wrapper_set_next_insert_id(id);
16071   } else {
16072     storage_set_next_insert_id(id);
16073   }
16074   DBUG_VOID_RETURN;
16075 }
16076 
wrapper_get_auto_increment(ulonglong offset,ulonglong increment,ulonglong nb_desired_values,ulonglong * first_value,ulonglong * nb_reserved_values)16077 void ha_mroonga::wrapper_get_auto_increment(ulonglong offset,
16078                                             ulonglong increment,
16079                                             ulonglong nb_desired_values,
16080                                             ulonglong *first_value,
16081                                             ulonglong *nb_reserved_values)
16082 {
16083   MRN_DBUG_ENTER_METHOD();
16084   MRN_SET_WRAP_SHARE_KEY(share, table->s);
16085   MRN_SET_WRAP_TABLE_KEY(this, table);
16086   wrap_handler->get_auto_increment(offset, increment, nb_desired_values,
16087                                       first_value, nb_reserved_values);
16088   MRN_SET_BASE_SHARE_KEY(share, table->s);
16089   MRN_SET_BASE_TABLE_KEY(this, table);
16090   DBUG_VOID_RETURN;
16091 }
16092 
storage_get_auto_increment(ulonglong offset,ulonglong increment,ulonglong nb_desired_values,ulonglong * first_value,ulonglong * nb_reserved_values)16093 void ha_mroonga::storage_get_auto_increment(ulonglong offset,
16094                                             ulonglong increment,
16095                                             ulonglong nb_desired_values,
16096                                             ulonglong *first_value,
16097                                             ulonglong *nb_reserved_values)
16098 {
16099   MRN_LONG_TERM_SHARE *long_term_share = share->long_term_share;
16100   MRN_DBUG_ENTER_METHOD();
16101   if (table->found_next_number_field &&
16102       !table->s->next_number_keypart) {
16103     if (long_term_share->auto_inc_inited) {
16104       *first_value = long_term_share->auto_inc_value;
16105       DBUG_PRINT("info", ("mroonga: *first_value(auto_inc_value)=%llu",
16106         *first_value));
16107       *nb_reserved_values = UINT_MAX64;
16108     } else {
16109       handler::get_auto_increment(offset, increment, nb_desired_values,
16110                                   first_value, nb_reserved_values);
16111       long_term_share->auto_inc_value = *first_value;
16112       DBUG_PRINT("info", ("mroonga: auto_inc_value=%llu",
16113         long_term_share->auto_inc_value));
16114       long_term_share->auto_inc_inited = true;
16115     }
16116   } else {
16117     handler::get_auto_increment(offset, increment, nb_desired_values,
16118                                 first_value, nb_reserved_values);
16119   }
16120   DBUG_VOID_RETURN;
16121 }
16122 
get_auto_increment(ulonglong offset,ulonglong increment,ulonglong nb_desired_values,ulonglong * first_value,ulonglong * nb_reserved_values)16123 void ha_mroonga::get_auto_increment(ulonglong offset, ulonglong increment,
16124                                     ulonglong nb_desired_values,
16125                                     ulonglong *first_value,
16126                                     ulonglong *nb_reserved_values)
16127 {
16128   MRN_DBUG_ENTER_METHOD();
16129   if (share->wrapper_mode)
16130   {
16131     wrapper_get_auto_increment(offset, increment, nb_desired_values,
16132                                first_value, nb_reserved_values);
16133   } else {
16134     MRN_LONG_TERM_SHARE *long_term_share = share->long_term_share;
16135     mrn::Lock lock(&long_term_share->auto_inc_mutex);
16136     storage_get_auto_increment(offset, increment, nb_desired_values,
16137                                first_value, nb_reserved_values);
16138     long_term_share->auto_inc_value += nb_desired_values * increment;
16139     DBUG_PRINT("info", ("mroonga: auto_inc_value=%llu",
16140       long_term_share->auto_inc_value));
16141   }
16142   DBUG_VOID_RETURN;
16143 }
16144 
wrapper_restore_auto_increment(ulonglong prev_insert_id)16145 void ha_mroonga::wrapper_restore_auto_increment(ulonglong prev_insert_id)
16146 {
16147   MRN_DBUG_ENTER_METHOD();
16148   MRN_SET_WRAP_SHARE_KEY(share, table->s);
16149   MRN_SET_WRAP_TABLE_KEY(this, table);
16150   wrap_handler->restore_auto_increment(prev_insert_id);
16151   MRN_SET_BASE_SHARE_KEY(share, table->s);
16152   MRN_SET_BASE_TABLE_KEY(this, table);
16153   DBUG_VOID_RETURN;
16154 }
16155 
storage_restore_auto_increment(ulonglong prev_insert_id)16156 void ha_mroonga::storage_restore_auto_increment(ulonglong prev_insert_id)
16157 {
16158   MRN_DBUG_ENTER_METHOD();
16159   handler::restore_auto_increment(prev_insert_id);
16160   DBUG_VOID_RETURN;
16161 }
16162 
restore_auto_increment(ulonglong prev_insert_id)16163 void ha_mroonga::restore_auto_increment(ulonglong prev_insert_id)
16164 {
16165   MRN_DBUG_ENTER_METHOD();
16166   if (share->wrapper_mode)
16167   {
16168     wrapper_restore_auto_increment(prev_insert_id);
16169   } else {
16170     storage_restore_auto_increment(prev_insert_id);
16171   }
16172   DBUG_VOID_RETURN;
16173 }
16174 
wrapper_release_auto_increment()16175 void ha_mroonga::wrapper_release_auto_increment()
16176 {
16177   MRN_DBUG_ENTER_METHOD();
16178   MRN_SET_WRAP_SHARE_KEY(share, table->s);
16179   MRN_SET_WRAP_TABLE_KEY(this, table);
16180   wrap_handler->ha_release_auto_increment();
16181   MRN_SET_BASE_SHARE_KEY(share, table->s);
16182   MRN_SET_BASE_TABLE_KEY(this, table);
16183   DBUG_VOID_RETURN;
16184 }
16185 
storage_release_auto_increment()16186 void ha_mroonga::storage_release_auto_increment()
16187 {
16188   MRN_DBUG_ENTER_METHOD();
16189   DBUG_VOID_RETURN;
16190 }
16191 
release_auto_increment()16192 void ha_mroonga::release_auto_increment()
16193 {
16194   MRN_DBUG_ENTER_METHOD();
16195   if (share->wrapper_mode)
16196   {
16197     wrapper_release_auto_increment();
16198   } else {
16199     storage_release_auto_increment();
16200   }
16201   DBUG_VOID_RETURN;
16202 }
16203 
wrapper_check_for_upgrade(HA_CHECK_OPT * check_opt)16204 int ha_mroonga::wrapper_check_for_upgrade(HA_CHECK_OPT *check_opt)
16205 {
16206   MRN_DBUG_ENTER_METHOD();
16207   MRN_SET_WRAP_SHARE_KEY(share, table->s);
16208   MRN_SET_WRAP_TABLE_KEY(this, table);
16209   int error = wrap_handler->ha_check_for_upgrade(check_opt);
16210   MRN_SET_BASE_SHARE_KEY(share, table->s);
16211   MRN_SET_BASE_TABLE_KEY(this, table);
16212   DBUG_RETURN(error);
16213 }
16214 
storage_check_for_upgrade(HA_CHECK_OPT * check_opt)16215 int ha_mroonga::storage_check_for_upgrade(HA_CHECK_OPT *check_opt)
16216 {
16217   MRN_DBUG_ENTER_METHOD();
16218   for (uint i = 0; i < table->s->fields; ++i) {
16219     grn_obj *column = grn_columns[i];
16220     if (!column) {
16221       continue;
16222     }
16223     Field *field = table->field[i];
16224     grn_id column_range = grn_obj_get_range(ctx, column);
16225     switch (field->real_type()) {
16226     case MYSQL_TYPE_ENUM:
16227       if (column_range != GRN_DB_UINT16) {
16228         DBUG_RETURN(HA_ADMIN_NEEDS_ALTER);
16229       }
16230       break;
16231     case MYSQL_TYPE_SET:
16232       if (column_range != GRN_DB_UINT64) {
16233         DBUG_RETURN(HA_ADMIN_NEEDS_ALTER);
16234       }
16235       break;
16236     default:
16237       break;
16238     }
16239   }
16240   DBUG_RETURN(HA_ADMIN_OK);
16241 }
16242 
check_for_upgrade(HA_CHECK_OPT * check_opt)16243 int ha_mroonga::check_for_upgrade(HA_CHECK_OPT *check_opt)
16244 {
16245   MRN_DBUG_ENTER_METHOD();
16246   int error;
16247   if (share->wrapper_mode) {
16248     error = wrapper_check_for_upgrade(check_opt);
16249   } else {
16250     error = storage_check_for_upgrade(check_opt);
16251   }
16252   DBUG_RETURN(error);
16253 }
16254 
16255 #ifdef MRN_HANDLER_HAVE_RESET_AUTO_INCREMENT
wrapper_reset_auto_increment(ulonglong value)16256 int ha_mroonga::wrapper_reset_auto_increment(ulonglong value)
16257 {
16258   int res;
16259   MRN_DBUG_ENTER_METHOD();
16260   MRN_SET_WRAP_SHARE_KEY(share, table->s);
16261   MRN_SET_WRAP_TABLE_KEY(this, table);
16262   res = wrap_handler->ha_reset_auto_increment(value);
16263   MRN_SET_BASE_SHARE_KEY(share, table->s);
16264   MRN_SET_BASE_TABLE_KEY(this, table);
16265   DBUG_RETURN(res);
16266 }
16267 
storage_reset_auto_increment(ulonglong value)16268 int ha_mroonga::storage_reset_auto_increment(ulonglong value)
16269 {
16270   MRN_LONG_TERM_SHARE *long_term_share = share->long_term_share;
16271   MRN_DBUG_ENTER_METHOD();
16272   mrn::Lock lock(&long_term_share->auto_inc_mutex);
16273   long_term_share->auto_inc_value = value;
16274   DBUG_PRINT("info", ("mroonga: auto_inc_value=%llu",
16275     long_term_share->auto_inc_value));
16276   long_term_share->auto_inc_inited = true;
16277   DBUG_RETURN(0);
16278 }
16279 
reset_auto_increment(ulonglong value)16280 int ha_mroonga::reset_auto_increment(ulonglong value)
16281 {
16282   MRN_DBUG_ENTER_METHOD();
16283   int res;
16284   if (share->wrapper_mode)
16285   {
16286     res = wrapper_reset_auto_increment(value);
16287   } else {
16288     res = storage_reset_auto_increment(value);
16289   }
16290   DBUG_RETURN(res);
16291 }
16292 #endif
16293 
set_pk_bitmap()16294 void ha_mroonga::set_pk_bitmap()
16295 {
16296   MRN_DBUG_ENTER_METHOD();
16297   KEY *key_info = &(table->key_info[table_share->primary_key]);
16298   uint j;
16299   for (j = 0; j < KEY_N_KEY_PARTS(key_info); j++) {
16300     Field *field = key_info->key_part[j].field;
16301     bitmap_set_bit(table->read_set, field->field_index);
16302   }
16303   DBUG_VOID_RETURN;
16304 }
16305 
wrapper_was_semi_consistent_read()16306 bool ha_mroonga::wrapper_was_semi_consistent_read()
16307 {
16308   bool res;
16309   MRN_DBUG_ENTER_METHOD();
16310   MRN_SET_WRAP_SHARE_KEY(share, table->s);
16311   MRN_SET_WRAP_TABLE_KEY(this, table);
16312   res = wrap_handler->was_semi_consistent_read();
16313   MRN_SET_BASE_SHARE_KEY(share, table->s);
16314   MRN_SET_BASE_TABLE_KEY(this, table);
16315   DBUG_RETURN(res);
16316 }
16317 
storage_was_semi_consistent_read()16318 bool ha_mroonga::storage_was_semi_consistent_read()
16319 {
16320   bool res;
16321   MRN_DBUG_ENTER_METHOD();
16322   res = handler::was_semi_consistent_read();
16323   DBUG_RETURN(res);
16324 }
16325 
was_semi_consistent_read()16326 bool ha_mroonga::was_semi_consistent_read()
16327 {
16328   bool res;
16329   MRN_DBUG_ENTER_METHOD();
16330   if (share->wrapper_mode)
16331   {
16332     res = wrapper_was_semi_consistent_read();
16333   } else {
16334     res = storage_was_semi_consistent_read();
16335   }
16336   DBUG_RETURN(res);
16337 }
16338 
wrapper_try_semi_consistent_read(bool yes)16339 void ha_mroonga::wrapper_try_semi_consistent_read(bool yes)
16340 {
16341   MRN_DBUG_ENTER_METHOD();
16342   MRN_SET_WRAP_SHARE_KEY(share, table->s);
16343   MRN_SET_WRAP_TABLE_KEY(this, table);
16344   wrap_handler->try_semi_consistent_read(yes);
16345   MRN_SET_BASE_SHARE_KEY(share, table->s);
16346   MRN_SET_BASE_TABLE_KEY(this, table);
16347   DBUG_VOID_RETURN;
16348 }
16349 
storage_try_semi_consistent_read(bool yes)16350 void ha_mroonga::storage_try_semi_consistent_read(bool yes)
16351 {
16352   MRN_DBUG_ENTER_METHOD();
16353   handler::try_semi_consistent_read(yes);
16354   DBUG_VOID_RETURN;
16355 }
16356 
try_semi_consistent_read(bool yes)16357 void ha_mroonga::try_semi_consistent_read(bool yes)
16358 {
16359   MRN_DBUG_ENTER_METHOD();
16360   if (share->wrapper_mode)
16361   {
16362     wrapper_try_semi_consistent_read(yes);
16363   } else {
16364     storage_try_semi_consistent_read(yes);
16365   }
16366   DBUG_VOID_RETURN;
16367 }
16368 
wrapper_unlock_row()16369 void ha_mroonga::wrapper_unlock_row()
16370 {
16371   MRN_DBUG_ENTER_METHOD();
16372   MRN_SET_WRAP_SHARE_KEY(share, table->s);
16373   MRN_SET_WRAP_TABLE_KEY(this, table);
16374   wrap_handler->unlock_row();
16375   MRN_SET_BASE_SHARE_KEY(share, table->s);
16376   MRN_SET_BASE_TABLE_KEY(this, table);
16377   DBUG_VOID_RETURN;
16378 }
16379 
storage_unlock_row()16380 void ha_mroonga::storage_unlock_row()
16381 {
16382   MRN_DBUG_ENTER_METHOD();
16383   handler::unlock_row();
16384   DBUG_VOID_RETURN;
16385 }
16386 
unlock_row()16387 void ha_mroonga::unlock_row()
16388 {
16389   MRN_DBUG_ENTER_METHOD();
16390   if (share->wrapper_mode)
16391   {
16392     wrapper_unlock_row();
16393   } else {
16394     storage_unlock_row();
16395   }
16396   DBUG_VOID_RETURN;
16397 }
16398 
wrapper_start_stmt(THD * thd,thr_lock_type lock_type)16399 int ha_mroonga::wrapper_start_stmt(THD *thd, thr_lock_type lock_type)
16400 {
16401   int res;
16402   MRN_DBUG_ENTER_METHOD();
16403   MRN_SET_WRAP_SHARE_KEY(share, table->s);
16404   MRN_SET_WRAP_TABLE_KEY(this, table);
16405   res = wrap_handler->start_stmt(thd, lock_type);
16406   MRN_SET_BASE_SHARE_KEY(share, table->s);
16407   MRN_SET_BASE_TABLE_KEY(this, table);
16408   DBUG_RETURN(res);
16409 }
16410 
storage_start_stmt(THD * thd,thr_lock_type lock_type)16411 int ha_mroonga::storage_start_stmt(THD *thd, thr_lock_type lock_type)
16412 {
16413   int res;
16414   MRN_DBUG_ENTER_METHOD();
16415   res = handler::start_stmt(thd, lock_type);
16416   DBUG_RETURN(res);
16417 }
16418 
start_stmt(THD * thd,thr_lock_type lock_type)16419 int ha_mroonga::start_stmt(THD *thd, thr_lock_type lock_type)
16420 {
16421   int res;
16422   MRN_DBUG_ENTER_METHOD();
16423   if (share->wrapper_mode)
16424   {
16425     res = wrapper_start_stmt(thd, lock_type);
16426   } else {
16427     res = storage_start_stmt(thd, lock_type);
16428   }
16429   DBUG_RETURN(res);
16430 }
16431 
wrapper_change_table_ptr(TABLE * table_arg,TABLE_SHARE * share_arg)16432 void ha_mroonga::wrapper_change_table_ptr(TABLE *table_arg,
16433                                           TABLE_SHARE *share_arg)
16434 {
16435   MRN_DBUG_ENTER_METHOD();
16436   MRN_SET_WRAP_SHARE_KEY(share, table->s);
16437   MRN_SET_WRAP_TABLE_KEY(this, table);
16438   wrap_handler->change_table_ptr(table_arg, share->wrap_table_share);
16439   MRN_SET_BASE_SHARE_KEY(share, table->s);
16440   MRN_SET_BASE_TABLE_KEY(this, table);
16441   DBUG_VOID_RETURN;
16442 }
16443 
storage_change_table_ptr(TABLE * table_arg,TABLE_SHARE * share_arg)16444 void ha_mroonga::storage_change_table_ptr(TABLE *table_arg,
16445                                           TABLE_SHARE *share_arg)
16446 {
16447   MRN_DBUG_ENTER_METHOD();
16448   DBUG_VOID_RETURN;
16449 }
16450 
change_table_ptr(TABLE * table_arg,TABLE_SHARE * share_arg)16451 void ha_mroonga::change_table_ptr(TABLE *table_arg, TABLE_SHARE *share_arg)
16452 {
16453   MRN_DBUG_ENTER_METHOD();
16454   handler::change_table_ptr(table_arg, share_arg);
16455   if (share && share->wrapper_mode)
16456   {
16457     wrapper_change_table_ptr(table_arg, share_arg);
16458   } else {
16459     storage_change_table_ptr(table_arg, share_arg);
16460   }
16461   DBUG_VOID_RETURN;
16462 }
16463 
wrapper_primary_key_is_clustered()16464 bool ha_mroonga::wrapper_primary_key_is_clustered()
16465 {
16466   MRN_DBUG_ENTER_METHOD();
16467   bool is_clustered;
16468   MRN_SET_WRAP_SHARE_KEY(share, table->s);
16469   MRN_SET_WRAP_TABLE_KEY(this, table);
16470   is_clustered = wrap_handler->primary_key_is_clustered();
16471   MRN_SET_BASE_SHARE_KEY(share, table->s);
16472   MRN_SET_BASE_TABLE_KEY(this, table);
16473   DBUG_RETURN(is_clustered);
16474 }
16475 
storage_primary_key_is_clustered()16476 bool ha_mroonga::storage_primary_key_is_clustered()
16477 {
16478   MRN_DBUG_ENTER_METHOD();
16479   bool is_clustered = handler::primary_key_is_clustered();
16480   DBUG_RETURN(is_clustered);
16481 }
16482 
primary_key_is_clustered()16483 bool ha_mroonga::primary_key_is_clustered()
16484 {
16485   MRN_DBUG_ENTER_METHOD();
16486   bool is_clustered;
16487   if (share && share->wrapper_mode)
16488   {
16489     is_clustered = wrapper_primary_key_is_clustered();
16490   } else {
16491     is_clustered = storage_primary_key_is_clustered();
16492   }
16493   DBUG_RETURN(is_clustered);
16494 }
16495 
wrapper_is_fk_defined_on_table_or_index(uint index)16496 bool ha_mroonga::wrapper_is_fk_defined_on_table_or_index(uint index)
16497 {
16498   MRN_DBUG_ENTER_METHOD();
16499   bool res;
16500   MRN_SET_WRAP_SHARE_KEY(share, table->s);
16501   MRN_SET_WRAP_TABLE_KEY(this, table);
16502   res = wrap_handler->is_fk_defined_on_table_or_index(index);
16503   MRN_SET_BASE_SHARE_KEY(share, table->s);
16504   MRN_SET_BASE_TABLE_KEY(this, table);
16505   DBUG_RETURN(res);
16506 }
16507 
storage_is_fk_defined_on_table_or_index(uint index)16508 bool ha_mroonga::storage_is_fk_defined_on_table_or_index(uint index)
16509 {
16510   MRN_DBUG_ENTER_METHOD();
16511   bool res = handler::is_fk_defined_on_table_or_index(index);
16512   DBUG_RETURN(res);
16513 }
16514 
is_fk_defined_on_table_or_index(uint index)16515 bool ha_mroonga::is_fk_defined_on_table_or_index(uint index)
16516 {
16517   MRN_DBUG_ENTER_METHOD();
16518   bool res;
16519   if (share->wrapper_mode)
16520   {
16521     res = wrapper_is_fk_defined_on_table_or_index(index);
16522   } else {
16523     res = storage_is_fk_defined_on_table_or_index(index);
16524   }
16525   DBUG_RETURN(res);
16526 }
16527 
wrapper_get_foreign_key_create_info()16528 char *ha_mroonga::wrapper_get_foreign_key_create_info()
16529 {
16530   MRN_DBUG_ENTER_METHOD();
16531   char *res;
16532   MRN_SET_WRAP_SHARE_KEY(share, table->s);
16533   MRN_SET_WRAP_TABLE_KEY(this, table);
16534   res = wrap_handler->get_foreign_key_create_info();
16535   MRN_SET_BASE_SHARE_KEY(share, table->s);
16536   MRN_SET_BASE_TABLE_KEY(this, table);
16537   DBUG_RETURN(res);
16538 }
16539 
16540 #ifdef MRN_SUPPORT_FOREIGN_KEYS
storage_get_foreign_key_create_info()16541 char *ha_mroonga::storage_get_foreign_key_create_info()
16542 {
16543   int error;
16544   uint i;
16545   grn_obj *column;
16546   uint n_columns = table_share->fields;
16547   char create_info_buff[2048], *create_info;
16548   String create_info_str(create_info_buff, sizeof(create_info_buff),
16549     system_charset_info);
16550   MRN_DBUG_ENTER_METHOD();
16551   create_info_str.length(0);
16552   for (i = 0; i < n_columns; ++i) {
16553     Field *field = table_share->field[i];
16554 
16555     if (!is_foreign_key_field(table_share->table_name.str,
16556                               field->field_name.str)) {
16557       continue;
16558     }
16559 
16560     mrn::ColumnName column_name(field->field_name);
16561     column = grn_obj_column(ctx,
16562                             grn_table,
16563                             column_name.c_str(),
16564                             column_name.length());
16565     if (!column) {
16566       continue;
16567     }
16568     grn_id ref_table_id = grn_obj_get_range(ctx, column);
16569     grn_obj *ref_table = grn_ctx_at(ctx, ref_table_id);
16570     char ref_table_buff[NAME_LEN + 1];
16571     int ref_table_name_length = grn_obj_name(ctx, ref_table, ref_table_buff,
16572                                              NAME_LEN);
16573     ref_table_buff[ref_table_name_length] = '\0';
16574 
16575     if (create_info_str.reserve(15)) {
16576       DBUG_RETURN(NULL);
16577     }
16578     create_info_str.q_append(",\n  CONSTRAINT ", 15);
16579     append_identifier(ha_thd(),
16580                       &create_info_str,
16581                       column_name.c_str(),
16582                       column_name.length());
16583     if (create_info_str.reserve(14)) {
16584       DBUG_RETURN(NULL);
16585     }
16586     create_info_str.q_append(" FOREIGN KEY (", 14);
16587     append_identifier(ha_thd(),
16588                       &create_info_str,
16589                       column_name.c_str(),
16590                       column_name.length());
16591     if (create_info_str.reserve(13)) {
16592       DBUG_RETURN(NULL);
16593     }
16594     create_info_str.q_append(") REFERENCES ", 13);
16595     append_identifier(ha_thd(), &create_info_str, table_share->db.str,
16596                       table_share->db.length);
16597     if (create_info_str.reserve(1)) {
16598       DBUG_RETURN(NULL);
16599     }
16600     create_info_str.q_append(".", 1);
16601     append_identifier(ha_thd(), &create_info_str, ref_table_buff,
16602                       ref_table_name_length);
16603     if (create_info_str.reserve(2)) {
16604       DBUG_RETURN(NULL);
16605     }
16606     create_info_str.q_append(" (", 2);
16607 
16608     char ref_path[FN_REFLEN + 1];
16609     TABLE_LIST table_list;
16610     TABLE_SHARE *tmp_ref_table_share;
16611     build_table_filename(ref_path, sizeof(ref_path) - 1,
16612                          table_share->db.str, ref_table_buff, "", 0);
16613     DBUG_PRINT("info", ("mroonga: ref_path=%s", ref_path));
16614 
16615     LEX_CSTRING table_name= { ref_table_buff, (size_t) ref_table_name_length };
16616     table_list.init_one_table(&table_share->db, &table_name, 0, TL_WRITE);
16617     mrn_open_mutex_lock(table_share);
16618     tmp_ref_table_share =
16619       mrn_create_tmp_table_share(&table_list, ref_path, &error);
16620     mrn_open_mutex_unlock(table_share);
16621     if (!tmp_ref_table_share) {
16622       DBUG_RETURN(NULL);
16623     }
16624     uint ref_pkey_nr = tmp_ref_table_share->primary_key;
16625     KEY *ref_key_info = &tmp_ref_table_share->key_info[ref_pkey_nr];
16626     Field *ref_field = &ref_key_info->key_part->field[0];
16627     append_identifier(ha_thd(), &create_info_str, ref_field->field_name.str,
16628                       ref_field->field_name.length);
16629     mrn_open_mutex_lock(table_share);
16630     mrn_free_tmp_table_share(tmp_ref_table_share);
16631     mrn_open_mutex_unlock(table_share);
16632     if (create_info_str.reserve(39)) {
16633       DBUG_RETURN(NULL);
16634     }
16635     create_info_str.q_append(") ON DELETE RESTRICT ON UPDATE RESTRICT", 39);
16636   }
16637   if (!(create_info = (char *) mrn_my_malloc(create_info_str.length() + 1,
16638                                              MYF(MY_WME)))) {
16639     DBUG_RETURN(NULL);
16640   }
16641   memcpy(create_info, create_info_str.ptr(), create_info_str.length());
16642   create_info[create_info_str.length()] = '\0';
16643   DBUG_RETURN(create_info);
16644 }
16645 #else
storage_get_foreign_key_create_info()16646 char *ha_mroonga::storage_get_foreign_key_create_info()
16647 {
16648   MRN_DBUG_ENTER_METHOD();
16649   char *res = handler::get_foreign_key_create_info();
16650   DBUG_RETURN(res);
16651 }
16652 #endif
16653 
get_foreign_key_create_info()16654 char *ha_mroonga::get_foreign_key_create_info()
16655 {
16656   MRN_DBUG_ENTER_METHOD();
16657   char *res;
16658   if (share->wrapper_mode)
16659   {
16660     res = wrapper_get_foreign_key_create_info();
16661   } else {
16662     res = storage_get_foreign_key_create_info();
16663   }
16664   DBUG_RETURN(res);
16665 }
16666 
16667 #ifdef MRN_HANDLER_HAVE_GET_TABLESPACE_NAME
wrapper_get_tablespace_name(THD * thd,char * name,uint name_len)16668 char *ha_mroonga::wrapper_get_tablespace_name(THD *thd, char *name,
16669                                               uint name_len)
16670 {
16671   MRN_DBUG_ENTER_METHOD();
16672   char *res;
16673   MRN_SET_WRAP_SHARE_KEY(share, table->s);
16674   MRN_SET_WRAP_TABLE_KEY(this, table);
16675   res = wrap_handler->get_tablespace_name(thd, name, name_len);
16676   MRN_SET_BASE_SHARE_KEY(share, table->s);
16677   MRN_SET_BASE_TABLE_KEY(this, table);
16678   DBUG_RETURN(res);
16679 }
16680 
storage_get_tablespace_name(THD * thd,char * name,uint name_len)16681 char *ha_mroonga::storage_get_tablespace_name(THD *thd, char *name,
16682                                               uint name_len)
16683 {
16684   MRN_DBUG_ENTER_METHOD();
16685   char *res = handler::get_tablespace_name(thd, name, name_len);
16686   DBUG_RETURN(res);
16687 }
16688 
get_tablespace_name(THD * thd,char * name,uint name_len)16689 char *ha_mroonga::get_tablespace_name(THD *thd, char *name, uint name_len)
16690 {
16691   MRN_DBUG_ENTER_METHOD();
16692   char *res;
16693   if (share->wrapper_mode)
16694   {
16695     res = wrapper_get_tablespace_name(thd, name, name_len);
16696   } else {
16697     res = storage_get_tablespace_name(thd, name, name_len);
16698   }
16699   DBUG_RETURN(res);
16700 }
16701 #endif
16702 
wrapper_can_switch_engines()16703 bool ha_mroonga::wrapper_can_switch_engines()
16704 {
16705   MRN_DBUG_ENTER_METHOD();
16706   bool res;
16707   MRN_SET_WRAP_SHARE_KEY(share, table->s);
16708   MRN_SET_WRAP_TABLE_KEY(this, table);
16709   res = wrap_handler->can_switch_engines();
16710   MRN_SET_BASE_SHARE_KEY(share, table->s);
16711   MRN_SET_BASE_TABLE_KEY(this, table);
16712   DBUG_RETURN(res);
16713 }
16714 
storage_can_switch_engines()16715 bool ha_mroonga::storage_can_switch_engines()
16716 {
16717   MRN_DBUG_ENTER_METHOD();
16718   bool res = handler::can_switch_engines();
16719   DBUG_RETURN(res);
16720 }
16721 
can_switch_engines()16722 bool ha_mroonga::can_switch_engines()
16723 {
16724   MRN_DBUG_ENTER_METHOD();
16725   bool res;
16726   if (share->wrapper_mode)
16727   {
16728     res = wrapper_can_switch_engines();
16729   } else {
16730     res = storage_can_switch_engines();
16731   }
16732   DBUG_RETURN(res);
16733 }
16734 
wrapper_get_foreign_key_list(THD * thd,List<FOREIGN_KEY_INFO> * f_key_list)16735 int ha_mroonga::wrapper_get_foreign_key_list(THD *thd,
16736                                            List<FOREIGN_KEY_INFO> *f_key_list)
16737 {
16738   MRN_DBUG_ENTER_METHOD();
16739   int res;
16740   MRN_SET_WRAP_SHARE_KEY(share, table->s);
16741   MRN_SET_WRAP_TABLE_KEY(this, table);
16742   res = wrap_handler->get_foreign_key_list(thd, f_key_list);
16743   MRN_SET_BASE_SHARE_KEY(share, table->s);
16744   MRN_SET_BASE_TABLE_KEY(this, table);
16745   DBUG_RETURN(res);
16746 }
16747 
16748 #ifdef MRN_SUPPORT_FOREIGN_KEYS
storage_get_foreign_key_list(THD * thd,List<FOREIGN_KEY_INFO> * f_key_list)16749 int ha_mroonga::storage_get_foreign_key_list(THD *thd,
16750                                              List<FOREIGN_KEY_INFO> *f_key_list)
16751 {
16752   int error;
16753   uint i;
16754   grn_obj *column;
16755   uint n_columns = table_share->fields;
16756   MRN_DBUG_ENTER_METHOD();
16757   for (i = 0; i < n_columns; ++i) {
16758     Field *field = table_share->field[i];
16759 
16760     if (!is_foreign_key_field(table_share->table_name.str,
16761                               field->field_name.str)) {
16762       continue;
16763     }
16764 
16765     mrn::ColumnName column_name(field->field_name);
16766     column = grn_obj_column(ctx,
16767                             grn_table,
16768                             column_name.c_str(),
16769                             column_name.length());
16770     if (!column) {
16771       continue;
16772     }
16773     grn_id ref_table_id = grn_obj_get_range(ctx, column);
16774     grn_obj *ref_table = grn_ctx_at(ctx, ref_table_id);
16775     FOREIGN_KEY_INFO f_key_info;
16776     f_key_info.foreign_id = thd_make_lex_string(thd,
16777                                                 NULL,
16778                                                 column_name.c_str(),
16779                                                 column_name.length(),
16780                                                 TRUE);
16781     f_key_info.foreign_db = thd_make_lex_string(thd, NULL,
16782                                                 table_share->db.str,
16783                                                 table_share->db.length,
16784                                                 TRUE);
16785     f_key_info.foreign_table = thd_make_lex_string(thd, NULL,
16786                                                    table_share->table_name.str,
16787                                                    table_share->table_name.length,
16788                                                    TRUE);
16789     f_key_info.referenced_db = f_key_info.foreign_db;
16790 
16791     char ref_table_buff[NAME_LEN + 1];
16792     int ref_table_name_length = grn_obj_name(ctx, ref_table, ref_table_buff,
16793                                              NAME_LEN);
16794     ref_table_buff[ref_table_name_length] = '\0';
16795     DBUG_PRINT("info", ("mroonga: ref_table_buff=%s", ref_table_buff));
16796     DBUG_PRINT("info", ("mroonga: ref_table_name_length=%d", ref_table_name_length));
16797     f_key_info.referenced_table = thd_make_lex_string(thd, NULL,
16798                                                        ref_table_buff,
16799                                                        ref_table_name_length,
16800                                                        TRUE);
16801     f_key_info.update_method = FK_OPTION_RESTRICT;
16802     f_key_info.delete_method = FK_OPTION_RESTRICT;
16803     f_key_info.referenced_key_name = thd_make_lex_string(thd, NULL, "PRIMARY",
16804                                                           7, TRUE);
16805     LEX_CSTRING *field_name = thd_make_lex_string(thd,
16806                                                  NULL,
16807                                                  column_name.c_str(),
16808                                                  column_name.length(),
16809                                                  TRUE);
16810     f_key_info.foreign_fields.push_back(field_name);
16811 
16812     char ref_path[FN_REFLEN + 1];
16813     TABLE_LIST table_list;
16814     TABLE_SHARE *tmp_ref_table_share;
16815     build_table_filename(ref_path, sizeof(ref_path) - 1,
16816                          table_share->db.str, ref_table_buff, "", 0);
16817     DBUG_PRINT("info", ("mroonga: ref_path=%s", ref_path));
16818 
16819     LEX_CSTRING table_name= { ref_table_buff, (size_t) ref_table_name_length };
16820     table_list.init_one_table(&table_share->db, &table_name, 0, TL_WRITE);
16821     mrn_open_mutex_lock(table_share);
16822     tmp_ref_table_share =
16823       mrn_create_tmp_table_share(&table_list, ref_path, &error);
16824     mrn_open_mutex_unlock(table_share);
16825     if (!tmp_ref_table_share) {
16826       DBUG_RETURN(error);
16827     }
16828     uint ref_pkey_nr = tmp_ref_table_share->primary_key;
16829     KEY *ref_key_info = &tmp_ref_table_share->key_info[ref_pkey_nr];
16830     Field *ref_field = &ref_key_info->key_part->field[0];
16831     LEX_CSTRING *ref_col_name = thd_make_lex_string(thd, NULL,
16832                                                    ref_field->field_name.str,
16833                                                    ref_field->field_name.length,
16834                                                    TRUE);
16835     f_key_info.referenced_fields.push_back(ref_col_name);
16836     mrn_open_mutex_lock(table_share);
16837     mrn_free_tmp_table_share(tmp_ref_table_share);
16838     mrn_open_mutex_unlock(table_share);
16839     FOREIGN_KEY_INFO *p_f_key_info =
16840       (FOREIGN_KEY_INFO *) thd_memdup(thd, &f_key_info,
16841                                       sizeof(FOREIGN_KEY_INFO));
16842     if (!p_f_key_info) {
16843       DBUG_RETURN(HA_ERR_OUT_OF_MEM);
16844     }
16845     f_key_list->push_back(p_f_key_info);
16846   }
16847   DBUG_RETURN(0);
16848 }
16849 #else
storage_get_foreign_key_list(THD * thd,List<FOREIGN_KEY_INFO> * f_key_list)16850 int ha_mroonga::storage_get_foreign_key_list(THD *thd,
16851                                            List<FOREIGN_KEY_INFO> *f_key_list)
16852 {
16853   MRN_DBUG_ENTER_METHOD();
16854   int res = handler::get_foreign_key_list(thd, f_key_list);
16855   DBUG_RETURN(res);
16856 }
16857 #endif
16858 
get_foreign_key_list(THD * thd,List<FOREIGN_KEY_INFO> * f_key_list)16859 int ha_mroonga::get_foreign_key_list(THD *thd,
16860                                      List<FOREIGN_KEY_INFO> *f_key_list)
16861 {
16862   MRN_DBUG_ENTER_METHOD();
16863   int res;
16864   if (share->wrapper_mode)
16865   {
16866     res = wrapper_get_foreign_key_list(thd, f_key_list);
16867   } else {
16868     res = storage_get_foreign_key_list(thd, f_key_list);
16869   }
16870   DBUG_RETURN(res);
16871 }
16872 
wrapper_get_parent_foreign_key_list(THD * thd,List<FOREIGN_KEY_INFO> * f_key_list)16873 int ha_mroonga::wrapper_get_parent_foreign_key_list(THD *thd,
16874                                             List<FOREIGN_KEY_INFO> *f_key_list)
16875 {
16876   MRN_DBUG_ENTER_METHOD();
16877   int res;
16878   MRN_SET_WRAP_SHARE_KEY(share, table->s);
16879   MRN_SET_WRAP_TABLE_KEY(this, table);
16880   res = wrap_handler->get_parent_foreign_key_list(thd, f_key_list);
16881   MRN_SET_BASE_SHARE_KEY(share, table->s);
16882   MRN_SET_BASE_TABLE_KEY(this, table);
16883   DBUG_RETURN(res);
16884 }
16885 
storage_get_parent_foreign_key_list(THD * thd,List<FOREIGN_KEY_INFO> * f_key_list)16886 int ha_mroonga::storage_get_parent_foreign_key_list(THD *thd,
16887                                             List<FOREIGN_KEY_INFO> *f_key_list)
16888 {
16889   MRN_DBUG_ENTER_METHOD();
16890   int res = handler::get_parent_foreign_key_list(thd, f_key_list);
16891   DBUG_RETURN(res);
16892 }
16893 
get_parent_foreign_key_list(THD * thd,List<FOREIGN_KEY_INFO> * f_key_list)16894 int ha_mroonga::get_parent_foreign_key_list(THD *thd,
16895                                             List<FOREIGN_KEY_INFO> *f_key_list)
16896 {
16897   MRN_DBUG_ENTER_METHOD();
16898   int res;
16899   if (share->wrapper_mode)
16900   {
16901     res = wrapper_get_parent_foreign_key_list(thd, f_key_list);
16902   } else {
16903     res = storage_get_parent_foreign_key_list(thd, f_key_list);
16904   }
16905   DBUG_RETURN(res);
16906 }
16907 
wrapper_referenced_by_foreign_key()16908 uint ha_mroonga::wrapper_referenced_by_foreign_key()
16909 {
16910   MRN_DBUG_ENTER_METHOD();
16911   uint res;
16912   MRN_SET_WRAP_SHARE_KEY(share, table->s);
16913   MRN_SET_WRAP_TABLE_KEY(this, table);
16914   res = wrap_handler->referenced_by_foreign_key();
16915   MRN_SET_BASE_SHARE_KEY(share, table->s);
16916   MRN_SET_BASE_TABLE_KEY(this, table);
16917   DBUG_RETURN(res);
16918 }
16919 
storage_referenced_by_foreign_key()16920 uint ha_mroonga::storage_referenced_by_foreign_key()
16921 {
16922   MRN_DBUG_ENTER_METHOD();
16923   uint res = handler::referenced_by_foreign_key();
16924   DBUG_RETURN(res);
16925 }
16926 
referenced_by_foreign_key()16927 uint ha_mroonga::referenced_by_foreign_key()
16928 {
16929   MRN_DBUG_ENTER_METHOD();
16930   uint res;
16931   if (share->wrapper_mode)
16932   {
16933     res = wrapper_referenced_by_foreign_key();
16934   } else {
16935     res = storage_referenced_by_foreign_key();
16936   }
16937   DBUG_RETURN(res);
16938 }
16939 
wrapper_init_table_handle_for_HANDLER()16940 void ha_mroonga::wrapper_init_table_handle_for_HANDLER()
16941 {
16942   MRN_DBUG_ENTER_METHOD();
16943   MRN_SET_WRAP_SHARE_KEY(share, table->s);
16944   MRN_SET_WRAP_TABLE_KEY(this, table);
16945   wrap_handler->init_table_handle_for_HANDLER();
16946   MRN_SET_BASE_SHARE_KEY(share, table->s);
16947   MRN_SET_BASE_TABLE_KEY(this, table);
16948   DBUG_VOID_RETURN;
16949 }
16950 
storage_init_table_handle_for_HANDLER()16951 void ha_mroonga::storage_init_table_handle_for_HANDLER()
16952 {
16953   MRN_DBUG_ENTER_METHOD();
16954   handler::init_table_handle_for_HANDLER();
16955   DBUG_VOID_RETURN;
16956 }
16957 
init_table_handle_for_HANDLER()16958 void ha_mroonga::init_table_handle_for_HANDLER()
16959 {
16960   MRN_DBUG_ENTER_METHOD();
16961   if (share->wrapper_mode)
16962   {
16963     wrapper_init_table_handle_for_HANDLER();
16964   } else {
16965     storage_init_table_handle_for_HANDLER();
16966   }
16967   DBUG_VOID_RETURN;
16968 }
16969 
wrapper_free_foreign_key_create_info(char * str)16970 void ha_mroonga::wrapper_free_foreign_key_create_info(char* str)
16971 {
16972   MRN_DBUG_ENTER_METHOD();
16973   MRN_SET_WRAP_SHARE_KEY(share, table->s);
16974   MRN_SET_WRAP_TABLE_KEY(this, table);
16975   wrap_handler->free_foreign_key_create_info(str);
16976   MRN_SET_BASE_SHARE_KEY(share, table->s);
16977   MRN_SET_BASE_TABLE_KEY(this, table);
16978   DBUG_VOID_RETURN;
16979 }
16980 
16981 #ifdef MRN_SUPPORT_FOREIGN_KEYS
storage_free_foreign_key_create_info(char * str)16982 void ha_mroonga::storage_free_foreign_key_create_info(char* str)
16983 {
16984   MRN_DBUG_ENTER_METHOD();
16985   my_free(str);
16986   DBUG_VOID_RETURN;
16987 }
16988 #else
storage_free_foreign_key_create_info(char * str)16989 void ha_mroonga::storage_free_foreign_key_create_info(char* str)
16990 {
16991   MRN_DBUG_ENTER_METHOD();
16992   handler::free_foreign_key_create_info(str);
16993   DBUG_VOID_RETURN;
16994 }
16995 #endif
16996 
free_foreign_key_create_info(char * str)16997 void ha_mroonga::free_foreign_key_create_info(char* str)
16998 {
16999   MRN_DBUG_ENTER_METHOD();
17000   if (share->wrapper_mode)
17001   {
17002     wrapper_free_foreign_key_create_info(str);
17003   } else {
17004     storage_free_foreign_key_create_info(str);
17005   }
17006   DBUG_VOID_RETURN;
17007 }
17008 
17009 #ifdef MRN_RBR_UPDATE_NEED_ALL_COLUMNS
check_written_by_row_based_binlog()17010 bool ha_mroonga::check_written_by_row_based_binlog()
17011 {
17012   MRN_DBUG_ENTER_METHOD();
17013   THD *thd = ha_thd();
17014 
17015   int current_stmt_binlog_row;
17016 #ifdef MRN_ROW_BASED_CHECK_IS_METHOD
17017   current_stmt_binlog_row = thd->is_current_stmt_binlog_format_row();
17018 #else
17019   current_stmt_binlog_row = thd->current_stmt_binlog_row_based;
17020 #endif
17021   if (!current_stmt_binlog_row) {
17022     DBUG_RETURN(false);
17023   }
17024 
17025   if (table->s->tmp_table != NO_TMP_TABLE) {
17026     DBUG_RETURN(false);
17027   }
17028 
17029   if (!mrn_binlog_filter->db_ok(table->s->db.str)) {
17030     DBUG_RETURN(false);
17031   }
17032 
17033   if (!thd_test_options(thd, OPTION_BIN_LOG)) {
17034     DBUG_RETURN(false);
17035   }
17036 
17037   if (!mysql_bin_log.is_open()) {
17038     DBUG_RETURN(false);
17039   }
17040 
17041   DBUG_RETURN(true);
17042 }
17043 #endif
17044 
17045 #ifdef MRN_HAVE_HA_REBIND_PSI
wrapper_unbind_psi()17046 void ha_mroonga::wrapper_unbind_psi()
17047 {
17048   MRN_DBUG_ENTER_METHOD();
17049   MRN_SET_WRAP_SHARE_KEY(share, table->s);
17050   MRN_SET_WRAP_TABLE_KEY(this, table);
17051   wrap_handler->unbind_psi();
17052   MRN_SET_BASE_SHARE_KEY(share, table->s);
17053   MRN_SET_BASE_TABLE_KEY(this, table);
17054   DBUG_VOID_RETURN;
17055 }
17056 
storage_unbind_psi()17057 void ha_mroonga::storage_unbind_psi()
17058 {
17059   MRN_DBUG_ENTER_METHOD();
17060   DBUG_VOID_RETURN;
17061 }
17062 
unbind_psi()17063 void ha_mroonga::unbind_psi()
17064 {
17065   MRN_DBUG_ENTER_METHOD();
17066   handler::unbind_psi();
17067   if (share->wrapper_mode)
17068   {
17069     wrapper_unbind_psi();
17070   } else {
17071     storage_unbind_psi();
17072   }
17073   DBUG_VOID_RETURN;
17074 }
17075 
wrapper_rebind_psi()17076 void ha_mroonga::wrapper_rebind_psi()
17077 {
17078   MRN_DBUG_ENTER_METHOD();
17079   MRN_SET_WRAP_SHARE_KEY(share, table->s);
17080   MRN_SET_WRAP_TABLE_KEY(this, table);
17081   wrap_handler->rebind_psi();
17082   MRN_SET_BASE_SHARE_KEY(share, table->s);
17083   MRN_SET_BASE_TABLE_KEY(this, table);
17084   DBUG_VOID_RETURN;
17085 }
17086 
storage_rebind_psi()17087 void ha_mroonga::storage_rebind_psi()
17088 {
17089   MRN_DBUG_ENTER_METHOD();
17090   DBUG_VOID_RETURN;
17091 }
17092 
rebind_psi()17093 void ha_mroonga::rebind_psi()
17094 {
17095   MRN_DBUG_ENTER_METHOD();
17096   handler::rebind_psi();
17097   if (share->wrapper_mode)
17098   {
17099     wrapper_rebind_psi();
17100   } else {
17101     storage_rebind_psi();
17102   }
17103   DBUG_VOID_RETURN;
17104 }
17105 #endif
17106 
wrapper_register_query_cache_table(THD * thd,const char * table_key,uint key_length,qc_engine_callback * engine_callback,ulonglong * engine_data)17107 my_bool ha_mroonga::wrapper_register_query_cache_table(THD *thd,
17108                                                        const char *table_key,
17109                                                        uint key_length,
17110                                                        qc_engine_callback
17111                                                        *engine_callback,
17112                                                        ulonglong *engine_data)
17113 {
17114   MRN_DBUG_ENTER_METHOD();
17115   my_bool res;
17116   MRN_SET_WRAP_SHARE_KEY(share, table->s);
17117   MRN_SET_WRAP_TABLE_KEY(this, table);
17118   res = wrap_handler->register_query_cache_table(thd,
17119                                                  table_key,
17120                                                  key_length,
17121                                                  engine_callback,
17122                                                  engine_data);
17123   MRN_SET_BASE_SHARE_KEY(share, table->s);
17124   MRN_SET_BASE_TABLE_KEY(this, table);
17125   DBUG_RETURN(res);
17126 }
17127 
storage_register_query_cache_table(THD * thd,const char * table_key,uint key_length,qc_engine_callback * engine_callback,ulonglong * engine_data)17128 my_bool ha_mroonga::storage_register_query_cache_table(THD *thd,
17129                                                        const char *table_key,
17130                                                        uint key_length,
17131                                                        qc_engine_callback
17132                                                        *engine_callback,
17133                                                        ulonglong *engine_data)
17134 {
17135   MRN_DBUG_ENTER_METHOD();
17136   my_bool res = handler::register_query_cache_table(thd,
17137                                                     table_key,
17138                                                     key_length,
17139                                                     engine_callback,
17140                                                     engine_data);
17141   DBUG_RETURN(res);
17142 }
17143 
register_query_cache_table(THD * thd,const char * table_key,uint key_length,qc_engine_callback * engine_callback,ulonglong * engine_data)17144 my_bool ha_mroonga::register_query_cache_table(THD *thd,
17145                                                const char *table_key,
17146                                                uint key_length,
17147                                                qc_engine_callback
17148                                                *engine_callback,
17149                                                ulonglong *engine_data)
17150 {
17151   MRN_DBUG_ENTER_METHOD();
17152   my_bool res;
17153   if (share->wrapper_mode)
17154   {
17155     res = wrapper_register_query_cache_table(thd,
17156                                              table_key,
17157                                              key_length,
17158                                              engine_callback,
17159                                              engine_data);
17160   } else {
17161     res = storage_register_query_cache_table(thd,
17162                                              table_key,
17163                                              key_length,
17164                                              engine_callback,
17165                                              engine_data);
17166   }
17167   DBUG_RETURN(res);
17168 }
17169 
17170 #ifdef __cplusplus
17171 }
17172 #endif
17173 
17174 namespace mrn {
17175   namespace variables {
get_boolean_mode_syntax_flags(THD * thd)17176     ulonglong get_boolean_mode_syntax_flags(THD *thd) {
17177       ulonglong flags = BOOLEAN_MODE_SYNTAX_FLAG_DEFAULT;
17178 #ifdef MRN_SUPPORT_THDVAR_SET
17179       flags = THDVAR(thd, boolean_mode_syntax_flags);
17180 #endif
17181       return flags;
17182     }
17183 
get_action_on_fulltext_query_error(THD * thd)17184     ActionOnError get_action_on_fulltext_query_error(THD *thd) {
17185       ulong action = THDVAR(thd, action_on_fulltext_query_error);
17186       return static_cast<ActionOnError>(action);
17187     }
17188   }
17189 }
17190