MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
innodb_api.c
Go to the documentation of this file.
1 /***********************************************************************
2 
3 Copyright (c) 2013, Oracle and/or its affiliates. All Rights Reserved.
4 
5 This program is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published by the
7 Free Software Foundation; version 2 of the License.
8 
9 This program is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
12 Public License for more details.
13 
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
17 
18 ***********************************************************************/
19 
20 /**************************************************/
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <sys/time.h>
32 #include "innodb_api.h"
33 #include "memcached/util.h"
34 #include <innodb_cb_api.h>
35 #include <innodb_config.h>
36 
38 #define UPDATE_ALL_VAL_COL -1
39 
41 
43 static ib_cb_t* innodb_memcached_api[] = {
44  (ib_cb_t*) &ib_cb_open_table,
45  (ib_cb_t*) &ib_cb_read_row,
46  (ib_cb_t*) &ib_cb_insert_row,
47  (ib_cb_t*) &ib_cb_delete_row,
48  (ib_cb_t*) &ib_cb_update_row,
49  (ib_cb_t*) &ib_cb_moveto,
50  (ib_cb_t*) &ib_cb_cursor_first,
51  (ib_cb_t*) &ib_cb_cursor_next,
52  (ib_cb_t*) &ib_cb_cursor_last,
53  (ib_cb_t*) &ib_cb_cursor_set_match_mode,
54  (ib_cb_t*) &ib_cb_search_tuple_create,
55  (ib_cb_t*) &ib_cb_read_tuple_create,
56  (ib_cb_t*) &ib_cb_tuple_delete,
57  (ib_cb_t*) &ib_cb_tuple_copy,
58  (ib_cb_t*) &ib_cb_tuple_read_u8,
59  (ib_cb_t*) &ib_cb_tuple_write_u8,
60  (ib_cb_t*) &ib_cb_tuple_read_u16,
61  (ib_cb_t*) &ib_cb_tuple_write_u16,
62  (ib_cb_t*) &ib_cb_tuple_read_u32,
63  (ib_cb_t*) &ib_cb_tuple_write_u32,
64  (ib_cb_t*) &ib_cb_tuple_read_u64,
65  (ib_cb_t*) &ib_cb_tuple_write_u64,
66  (ib_cb_t*) &ib_cb_tuple_read_i8,
67  (ib_cb_t*) &ib_cb_tuple_write_i8,
68  (ib_cb_t*) &ib_cb_tuple_read_i16,
69  (ib_cb_t*) &ib_cb_tuple_write_i16,
70  (ib_cb_t*) &ib_cb_tuple_read_i32,
71  (ib_cb_t*) &ib_cb_tuple_write_i32,
72  (ib_cb_t*) &ib_cb_tuple_read_i64,
73  (ib_cb_t*) &ib_cb_tuple_write_i64,
74  (ib_cb_t*) &ib_cb_tuple_get_n_cols,
75  (ib_cb_t*) &ib_cb_col_set_value,
76  (ib_cb_t*) &ib_cb_col_get_value,
77  (ib_cb_t*) &ib_cb_col_get_meta,
78  (ib_cb_t*) &ib_cb_trx_begin,
79  (ib_cb_t*) &ib_cb_trx_commit,
80  (ib_cb_t*) &ib_cb_trx_rollback,
81  (ib_cb_t*) &ib_cb_trx_start,
82  (ib_cb_t*) &ib_cb_trx_release,
83  (ib_cb_t*) &ib_cb_trx_state,
84  (ib_cb_t*) &ib_cb_cursor_lock,
85  (ib_cb_t*) &ib_cb_cursor_close,
86  (ib_cb_t*) &ib_cb_cursor_new_trx,
87  (ib_cb_t*) &ib_cb_cursor_reset,
88  (ib_cb_t*) &ib_cb_open_table_by_name,
89  (ib_cb_t*) &ib_cb_col_get_name,
90  (ib_cb_t*) &ib_cb_table_truncate,
91  (ib_cb_t*) &ib_cb_cursor_open_index_using_name,
92  (ib_cb_t*) &ib_cb_close_thd,
93  (ib_cb_t*) &ib_cb_get_cfg,
94  (ib_cb_t*) &ib_cb_cursor_set_cluster_access,
95  (ib_cb_t*) &ib_cb_cursor_commit_trx,
96  (ib_cb_t*) &ib_cb_cfg_trx_level,
97  (ib_cb_t*) &ib_cb_get_n_user_cols,
98  (ib_cb_t*) &ib_cb_cursor_set_lock,
99  (ib_cb_t*) &ib_cb_cursor_clear_trx,
100  (ib_cb_t*) &ib_cb_get_idx_field_name,
101  (ib_cb_t*) &ib_cb_trx_get_start_time,
102  (ib_cb_t*) &ib_cb_cfg_bk_commit_interval
103 };
104 
108 #define SET_EXP_TIME(exp) \
109 if (exp) { \
110  if (exp < 60*60*24*30) { \
111  exp += mci_get_time(); \
112  } \
113 }
114 
115 /*************************************************************/
117 void
119 /*===============*/
120  void* p)
121 {
122  int i;
123  int array_size;
124  ib_cb_t*func_ptr = (ib_cb_t*) p;
125 
126  array_size = sizeof(innodb_memcached_api)
127  / sizeof(*innodb_memcached_api);
128 
129  for (i = 0; i < array_size; i++) {
130  *innodb_memcached_api[i] = *(ib_cb_t*)func_ptr;
131  func_ptr++;
132  }
133 }
134 
135 /*************************************************************/
138 ib_err_t
140 /*=============*/
142  engine,
143  const char* dbname,
144  const char* name,
145  innodb_conn_data_t* conn_data,
147  ib_trx_t ib_trx,
148  ib_crsr_t* crsr,
149  ib_crsr_t* idx_crsr,
150  ib_lck_mode_t lock_mode)
151 {
152  ib_err_t err = DB_SUCCESS;
153  char table_name[MAX_TABLE_NAME_LEN + MAX_DATABASE_NAME_LEN];
154 
155  if (!*crsr) {
156 #ifdef __WIN__
157  sprintf(table_name, "%s\%s", dbname, name);
158 #else
159  snprintf(table_name, sizeof(table_name),
160  "%s/%s", dbname, name);
161 #endif
162 
163  err = ib_cb_open_table(table_name, ib_trx, crsr);
164 
165  if (err != DB_SUCCESS) {
166  fprintf(stderr, " InnoDB_Memcached: Unable to open"
167  " table '%s'\n", table_name);
168  return(err);
169  }
170 
171  err = innodb_cb_cursor_lock(engine, *crsr, lock_mode);
172 
173  if (err != DB_SUCCESS) {
174  fprintf(stderr, " InnoDB_Memcached: Fail to lock"
175  " table '%s'\n", table_name);
176  return(err);
177  }
178 
179  if (engine) {
180  meta_cfg_info_t* meta_info = conn_data->conn_meta;
181  meta_index_t* meta_index = &meta_info->index_info;
182 
183  if (!engine->enable_mdl || !conn_data->mysql_tbl) {
184  err = innodb_verify_low(
185  meta_info , *crsr, true);
186 
187  if (err != DB_SUCCESS) {
188  fprintf(stderr, " InnoDB_Memcached:"
189  " Table definition"
190  " modified for"
191  " table '%s'\n",
192  table_name);
193  return(err);
194  }
195  }
196 
197  /* Open the cursor */
198  if (meta_index->srch_use_idx == META_USE_SECONDARY) {
199  int index_type;
200  ib_id_u64_t index_id;
201 
202  ib_cb_cursor_open_index_using_name(
203  *crsr, meta_index->idx_name,
204  idx_crsr, &index_type, &index_id);
205 
206  err = innodb_cb_cursor_lock(engine, *idx_crsr,
207  lock_mode);
208  }
209 
210  /* Create a "Fake" THD if binlog is enabled */
211  if (conn_data && (engine->enable_binlog
212  || engine->enable_mdl)) {
213  if (!conn_data->thd) {
214  conn_data->thd = handler_create_thd(
215  engine->enable_binlog);
216 
217  if (!conn_data->thd) {
218  innodb_cb_cursor_close(*crsr);
219  *crsr = NULL;
220  return(DB_ERROR);
221  }
222  }
223 
224  if (!conn_data->mysql_tbl) {
225  conn_data->mysql_tbl =
227  conn_data->thd,
228  dbname,
229  name, HDL_WRITE);
230  }
231  }
232  }
233  } else {
234  ib_cb_cursor_new_trx(*crsr, ib_trx);
235 
236  err = innodb_cb_cursor_lock(engine, *crsr, lock_mode);
237 
238  if (err != DB_SUCCESS) {
239  fprintf(stderr, " InnoDB_Memcached: Fail to lock"
240  " table '%s'\n", name);
241  return(err);
242  }
243 
244  if (engine) {
245  meta_cfg_info_t* meta_info = conn_data->conn_meta;
246  meta_index_t* meta_index = &meta_info->index_info;
247 
248  /* set up secondary index cursor */
249  if (meta_index->srch_use_idx == META_USE_SECONDARY) {
250  ib_cb_cursor_new_trx(*idx_crsr, ib_trx);
251  err = innodb_cb_cursor_lock(engine, *idx_crsr,
252  lock_mode);
253  }
254  }
255  }
256 
257  return(err);
258 }
259 
260 /*************************************************************/
263 static
264 uint64_t
265 innodb_api_read_uint64(
266 /*================*/
267  const ib_col_meta_t*
268  m_col,
269  ib_tpl_t read_tpl,
270  int i)
271 {
272  uint64_t value64;
273 
274  assert (m_col->type == IB_INT && m_col->type_len == sizeof(uint64_t)
275  && m_col->attr == IB_COL_UNSIGNED);
276 
277  ib_cb_tuple_read_u64(read_tpl, i, &value64);
278 
279  return(value64);
280 }
281 
282 /*************************************************************/
285 static
286 int64_t
287 innodb_api_read_int(
288 /*================*/
289  const ib_col_meta_t*
290  m_col,
291  ib_tpl_t read_tpl,
292  int i)
293 {
294  int64_t value = 0;
295 
296  assert (m_col->type == IB_INT);
297  assert (m_col->type_len == sizeof(uint64_t)
298  || m_col->type_len == sizeof(uint32_t)
299  || m_col->type_len == sizeof(uint16_t)
300  || m_col->type_len == sizeof(uint8_t));
301 
302  if (m_col->attr == IB_COL_UNSIGNED) {
303  if (m_col->type_len == sizeof(uint64_t)) {
304  /* We handle uint64 in innodb_api_read_uint64 */
305  assert(0);
306  } else if (m_col->type_len == sizeof(uint32_t)) {
307  uint32_t value32;
308  ib_cb_tuple_read_u32(read_tpl, i, &value32);
309  value = (int64_t) value32;
310  } else if (m_col->type_len == sizeof(uint16_t)) {
311  uint16_t value16;
312  ib_cb_tuple_read_u16(read_tpl, i, &value16);
313  value = (int64_t) value16;
314  } else if (m_col->type_len == sizeof(uint8_t)) {
315  uint8_t value8;
316  ib_cb_tuple_read_u8(read_tpl, i, &value8);
317  value = (int64_t) value8;
318  }
319  } else {
320  if (m_col->type_len == sizeof(int64_t)) {
321  ib_cb_tuple_read_i64(read_tpl, i, &value);
322  } else if (m_col->type_len == sizeof(int32_t)) {
323  int32_t value32;
324  ib_cb_tuple_read_i32(read_tpl, i, &value32);
325  value = (int64_t) value32;
326  } else if (m_col->type_len == sizeof(int16_t)) {
327  int16_t value16;
328  ib_cb_tuple_read_i16(read_tpl, i, &value16);
329  value = (int64_t) value16;
330  } else if (m_col->type_len == sizeof(int8_t)) {
331  int8_t value8;
332  ib_cb_tuple_read_i8(read_tpl, i, &value8);
333  value = (int64_t) value8;
334  }
335  }
336 
337  return(value);
338 }
339 
340 /*************************************************************/
343 static
344 ib_err_t
345 innodb_api_write_int(
346 /*=================*/
347  ib_tpl_t tpl,
348  int field,
349  int64_t value,
350  void* table)
352 {
353  ib_col_meta_t col_meta;
354  ib_col_meta_t* m_col = &col_meta;
355  void* src = NULL;
356  int64_t value_i64;
357  uint32_t value_u32;
358  int32_t value_i32;
359  uint16_t value_u16;
360  int16_t value_i16;
361  uint8_t value_u8;
362  int8_t value_i8;
363 
364  ib_cb_col_get_meta(tpl, field, m_col);
365 
366  assert(m_col->type == IB_INT);
367  assert(m_col->type_len == 8 || m_col->type_len == 4
368  || m_col->type_len == 2 || m_col->type_len == 1);
369 
370  if (m_col->attr == IB_COL_UNSIGNED) {
371  if (m_col->type_len == 8) {
372  src = &value;
373 
374  /* If table is non-NULL, set up corresponding
375  TABLE->record[0] field for replication */
376  if (table) {
378  table, field, value, true,
379  false);
380  }
381  } else if (m_col->type_len == 4) {
382  value_u32 = (uint32_t) value;
383 
384  src = &value_u32;
385  if (table) {
387  table, field, value_u32, true, false);
388  }
389  } else if (m_col->type_len == 2) {
390  value_u16 = (uint16_t) value;
391 
392  src = &value_u16;
393  if (table) {
395  table, field, value_u16, true, false);
396  }
397  } else if (m_col->type_len == 1) {
398  value_u8 = (uint8_t) value;
399 
400  src = &value_u8;
401  if (table) {
403  table, field, value_u8, true, false);
404  }
405  }
406  } else {
407  if (m_col->type_len == 8) {
408  value_i64 = (int64_t) value;
409 
410  src= &value_i64;
411  if (table) {
413  table, field, value_i64, false, false);
414  }
415  } else if (m_col->type_len == 4) {
416  value_i32 = (int32_t) value;
417 
418  src = &value_i32;
419  if (table) {
421  table, field, value_i32, false, false);
422  }
423  } else if (m_col->type_len == 2) {
424  value_i16 = (int16_t) value;
425 
426  src = &value_i16;
427  if (table) {
429  table, field, value_i16, false, false);
430  }
431  } else if (m_col->type_len == 1) {
432  value_i8 = (int8_t) value;
433 
434  src = &value_i8;
435  if (table) {
437  table, field, value_i8, false, false);
438  }
439  }
440  }
441 
442  ib_cb_col_set_value(tpl, field, src, m_col->type_len, true);
443  return(DB_SUCCESS);
444 }
445 
446 /*************************************************************/
449 static
450 ib_err_t
451 innodb_api_write_uint64(
452 /*====================*/
453  ib_tpl_t tpl,
454  int field,
455  uint64_t value,
456  void* table)
458 {
459  ib_col_meta_t col_meta;
460  ib_col_meta_t* m_col = &col_meta;
461  void* src = NULL;
462 
463  ib_cb_col_get_meta(tpl, field, m_col);
464 
465  assert(m_col->type == IB_INT && m_col->type_len == 8
466  && m_col->attr == IB_COL_UNSIGNED);
467 
468  src = &value;
469 
470  /* If table is non-NULL, set up corresponding
471  TABLE->record[0] field for replication */
472  if (table) {
474  table, field, value, true, false);
475  }
476 
477  ib_cb_col_set_value(tpl, field, src, m_col->type_len, true);
478  return(DB_SUCCESS);
479 }
480 
481 /*************************************************************/
484 static
485 ib_err_t
486 innodb_api_setup_field_value(
487 /*=========================*/
488  ib_tpl_t tpl,
489  int field_id,
490  meta_column_t* col_info,
491  const char* value,
492  ib_ulint_t val_len,
493  void* table,
495  bool need_cpy)
496 {
497  ib_err_t err = DB_ERROR;
498 
499  /* if value is null, we just set the field to NULL. */
500  if (val_len == IB_SQL_NULL)
501  {
502  assert(value == NULL);
503  err = ib_cb_col_set_value(tpl, field_id,
504  value, val_len, need_cpy);
505  return(err);
506  }
507 
508  if (col_info->col_meta.type == IB_INT) {
509  char* end_ptr;
510  char val_buf[256];
511 
512  /* Need this memcpy to strip the junk */
513  memcpy(val_buf, value, val_len);
514  val_buf[val_len] = 0;
515 
516  if (col_info->col_meta.attr == IB_COL_UNSIGNED) {
517  uint64_t int_value = 0;
518 
519  int_value = strtoull(val_buf, &end_ptr, 10);
520 
521  /* If the value is not a valid string of integer,
522  we will return error. */
523  if (end_ptr == val_buf) {
524  fprintf(stderr,
525  " InnoDB_Memcached: Unable to convert"
526  " value '%s' to integer\n", value);
527  return(DB_ERROR);
528  }
529 
530  err = innodb_api_write_uint64(tpl, field_id,
531  int_value, table);
532  } else {
533  int64_t int_value = 0;
534 
535  int_value = strtoll(val_buf, &end_ptr, 10);
536  /* If the value is not a valid string of integer,
537  we will return error. */
538  if (end_ptr == val_buf) {
539  fprintf(stderr,
540  " InnoDB_Memcached: Unable to convert"
541  " value '%s' to integer\n", value);
542  return(DB_ERROR);
543  }
544  err = innodb_api_write_int(tpl, field_id,
545  int_value, table);
546  }
547 
548  } else {
549  err = ib_cb_col_set_value(tpl, field_id,
550  value, val_len, need_cpy);
551 
552  if (table) {
553  handler_rec_setup_str(table, field_id,
554  value, val_len);
555  }
556  }
557 
558  return(err);
559 }
560 
561 /*************************************************************/
564 static
565 bool
566 innodb_api_fill_mci(
567 /*================*/
568  ib_tpl_t read_tpl,
569  int col_id,
572 {
573  ib_ulint_t data_len;
574  ib_col_meta_t col_meta;
575 
576  data_len = ib_cb_col_get_meta(read_tpl, col_id, &col_meta);
577 
578  if (data_len == IB_SQL_NULL) {
579  mci_item->value_str = NULL;
580  mci_item->value_len = 0;
581  mci_item->is_str = true;
582  } else {
583  if (col_meta.type == IB_INT) {
584  if (col_meta.attr == IB_COL_UNSIGNED
585  && data_len == 8) {
586  mci_item->value_int =
587  innodb_api_read_uint64(&col_meta,
588  read_tpl,
589  col_id);
590  } else {
591  mci_item->value_int =
592  innodb_api_read_int(&col_meta,
593  read_tpl,
594  col_id);
595  }
596 
597  mci_item->value_str = NULL;
598  mci_item->value_len = sizeof(mci_item->value_int);
599  mci_item->is_str = false;
600  } else {
601 
602  mci_item->value_str = (char*)ib_cb_col_get_value(
603  read_tpl, col_id);
604  mci_item->value_len = data_len;
605  mci_item->is_str = true;
606  }
607  }
608 
609  mci_item->allocated = false;
610  mci_item->is_valid = true;
611 
612  return(true);
613 }
614 
615 /*************************************************************/
618 static
619 bool
620 innodb_api_copy_mci(
621 /*================*/
622  ib_tpl_t read_tpl,
623  int col_id,
625  mci_column_t* mci_item)
626 {
627  ib_ulint_t data_len;
628  ib_col_meta_t col_meta;
629 
630  data_len = ib_cb_col_get_meta(read_tpl, col_id, &col_meta);
631 
632  if (data_len == IB_SQL_NULL) {
633  mci_item->value_str = NULL;
634  mci_item->value_len = 0;
635  mci_item->allocated = false;
636  } else {
637  if (col_meta.type == IB_INT) {
638  mci_item->value_str = malloc(50);
639  memset(mci_item->value_str, 0, 50);
640 
641  if (col_meta.attr == IB_COL_UNSIGNED) {
642  uint64_t int_val = 0;
643 
644  int_val = innodb_api_read_uint64(&col_meta,
645  read_tpl,
646  col_id);
647 
648  sprintf(mci_item->value_str,
649  "%" PRIu64, int_val);
650  } else {
651  int64_t int_val = 0;
652 
653  int_val = innodb_api_read_int(&col_meta,
654  read_tpl,
655  col_id);
656 
657  sprintf(mci_item->value_str,
658  "%" PRIi64, int_val);
659  }
660 
661  mci_item->value_len = strlen(mci_item->value_str);
662  mci_item->allocated = true;
663 
664  } else {
665  mci_item->value_str = malloc(data_len);
666 
667  if (!mci_item->value_str) {
668  return(false);
669  }
670 
671  mci_item->allocated = true;
672  memcpy(mci_item->value_str,
673  ib_cb_col_get_value(read_tpl, col_id),
674  data_len);
675  mci_item->value_len = data_len;
676  }
677  }
678 
679  mci_item->is_str = true;
680  mci_item->is_valid = true;
681 
682  return(true);
683 }
684 
685 /*************************************************************/
688 static
689 ib_err_t
690 innodb_api_fill_value(
691 /*==================*/
693  meta_info,
694  mci_item_t* item,
695  ib_tpl_t read_tpl,
696  int col_id,
697  bool alloc_mem)
698 {
699  ib_err_t err = DB_NOT_FOUND;
700 
701  /* If just read a single "value", fill mci_item[MCI_COL_VALUE],
702  otherwise, fill multiple value in extra_col_value[i] */
703  if (meta_info->n_extra_col == 0) {
704  meta_column_t* col_info = meta_info->col_info;
705 
706  if (col_id == col_info[CONTAINER_VALUE].field_id) {
707 
708  if (alloc_mem) {
709  innodb_api_copy_mci(
710  read_tpl, col_id,
711  &item->col_value[MCI_COL_VALUE]);
712  } else {
713  innodb_api_fill_mci(
714  read_tpl, col_id,
715  &item->col_value[MCI_COL_VALUE]);
716  }
717 
718  err = DB_SUCCESS;
719  }
720  } else {
721  int i;
722 
723  for (i = 0; i < meta_info->n_extra_col; i++) {
724  if (col_id == meta_info->extra_col_info[i].field_id) {
725  if (alloc_mem) {
726  innodb_api_copy_mci(
727  read_tpl, col_id,
728  &item->extra_col_value[i]);
729  } else {
730  innodb_api_fill_mci(
731  read_tpl, col_id,
732  &item->extra_col_value[i]);
733  }
734 
735  err = DB_SUCCESS;
736  break;
737  }
738  }
739  }
740 
741  return(err);
742 }
743 
744 /*************************************************************/
747 ib_err_t
749 /*==============*/
750  innodb_conn_data_t* cursor_data,
751  ib_crsr_t* crsr,
752  const char* key,
753  int len,
754  mci_item_t* item,
755  ib_tpl_t* r_tpl,
757  bool sel_only)
758 {
759  ib_err_t err = DB_SUCCESS;
760  meta_cfg_info_t* meta_info = cursor_data->conn_meta;
761  meta_column_t* col_info = meta_info->col_info;
762  meta_index_t* meta_index = &meta_info->index_info;
763  ib_tpl_t key_tpl;
764  ib_crsr_t srch_crsr;
765 
766  if (item) {
767  memset(item, 0, sizeof(*item));
768  }
769 
770  /* If srch_use_idx is set to META_USE_SECONDARY, we will use the
771  secondary index to find the record first */
772  if (meta_index->srch_use_idx == META_USE_SECONDARY) {
773  ib_crsr_t idx_crsr;
774 
775  if (sel_only) {
776  idx_crsr = cursor_data->idx_read_crsr;
777  } else {
778  idx_crsr = cursor_data->idx_crsr;
779  }
780 
781  ib_cb_cursor_set_cluster_access(idx_crsr);
782 
783  key_tpl = ib_cb_search_tuple_create(idx_crsr);
784 
785  srch_crsr = idx_crsr;
786 
787  } else {
788  ib_crsr_t crsr;
789 
790  if (sel_only) {
791  crsr = cursor_data->read_crsr;
792  } else {
793  crsr = cursor_data->crsr;
794  }
795 
796  key_tpl = ib_cb_search_tuple_create(crsr);
797  srch_crsr = crsr;
798  }
799 
800  err = innodb_api_setup_field_value(key_tpl, 0,
801  &col_info[CONTAINER_KEY],
802  key, len,
803  NULL, true);
804 
805  ib_cb_cursor_set_match_mode(srch_crsr, IB_EXACT_MATCH);
806 
807  err = ib_cb_moveto(srch_crsr, key_tpl, IB_CUR_GE);
808 
809  if (err != DB_SUCCESS) {
810  if (r_tpl) {
811  *r_tpl = NULL;
812  }
813  goto func_exit;
814  }
815 
816  /* If item is NULL, this function is used just to position the cursor.
817  Otherwise, fetch the data from the read tuple */
818  if (item) {
819  ib_tpl_t read_tpl;
820  int n_cols;
821  int i;
822 
823  read_tpl = ib_cb_read_tuple_create(
824  sel_only ? cursor_data->read_crsr
825  : cursor_data->crsr);
826 
827  err = ib_cb_read_row(srch_crsr, read_tpl);
828 
829  if (err != DB_SUCCESS) {
830  ib_cb_tuple_delete(read_tpl);
831 
832  if (r_tpl) {
833  *r_tpl = NULL;
834  }
835  goto func_exit;
836  }
837 
838  n_cols = ib_cb_tuple_get_n_cols(read_tpl);
839 
840  if (meta_info->n_extra_col > 0) {
841  /* If there are multiple values to read,allocate
842  memory */
843  item->extra_col_value = malloc(
844  meta_info->n_extra_col
845  * sizeof(*item->extra_col_value));
846  item->n_extra_col = meta_info->n_extra_col;
847  } else {
848  item->extra_col_value = NULL;
849  item->n_extra_col = 0;
850  }
851 
852  /* The table must have at least MCI_COL_TO_GET(5) columns
853  for memcached key, value, flag, cas and time expiration info */
854  assert(n_cols >= MCI_COL_TO_GET);
855 
856  for (i = 0; i < n_cols; ++i) {
857  ib_ulint_t data_len;
858  ib_col_meta_t col_meta;
859 
860  data_len = ib_cb_col_get_meta(read_tpl, i, &col_meta);
861 
862  if (i == col_info[CONTAINER_KEY].field_id) {
863  assert(data_len != IB_SQL_NULL);
865  (char*)ib_cb_col_get_value(read_tpl, i);
866  item->col_value[MCI_COL_KEY].value_len = data_len;
867  item->col_value[MCI_COL_KEY].is_str = true;
868  item->col_value[MCI_COL_KEY].is_valid = true;
869  } else if (meta_info->flag_enabled
870  && i == col_info[CONTAINER_FLAG].field_id) {
871  mci_column_t* col_value;
872  ib_col_meta_t* col_meta;
873 
874  col_value = &(item->col_value[MCI_COL_FLAG]);
875  col_meta = &col_info[CONTAINER_FLAG].col_meta;
876  if (data_len == IB_SQL_NULL) {
877  col_value->is_null = true;
878  } else {
879  if (col_meta->attr == IB_COL_UNSIGNED
880  && data_len == 8) {
881  col_value->value_int =
882  innodb_api_read_uint64(col_meta,
883  read_tpl,
884  i);
885  } else {
886  col_value->value_int =
887  innodb_api_read_int(col_meta,
888  read_tpl,
889  i);
890  }
891  col_value->is_str = false;
892  col_value->value_len = data_len;
893  col_value->is_valid = true;
894  }
895  } else if (meta_info->cas_enabled
896  && i == col_info[CONTAINER_CAS].field_id) {
897  mci_column_t* col_value;
898  ib_col_meta_t* col_meta;
899 
900  col_value = &(item->col_value[MCI_COL_CAS]);
901  col_meta = &col_info[CONTAINER_CAS].col_meta;
902  if (data_len == IB_SQL_NULL) {
903  col_value->is_null = true;
904  } else {
905  if (col_meta->attr == IB_COL_UNSIGNED
906  && data_len == 8) {
907  col_value->value_int =
908  innodb_api_read_uint64(col_meta,
909  read_tpl,
910  i);
911  } else {
912  /* Since the CAS value * must be
913  unsigned, we just cast sout the sign
914  value. */
915  col_value->value_int =
916  innodb_api_read_int(col_meta,
917  read_tpl,
918  i);
919  }
920  col_value->is_str = false;
921  col_value->value_len = data_len;
922  col_value->is_valid = true;
923  }
924  } else if (meta_info->exp_enabled
925  && i == col_info[CONTAINER_EXP].field_id) {
926  mci_column_t* col_value;
927  ib_col_meta_t* col_meta;
928 
929  col_value = &(item->col_value[MCI_COL_EXP]);
930  col_meta = &col_info[CONTAINER_EXP].col_meta;
931  if (data_len == IB_SQL_NULL) {
932  col_value->is_null = true;
933  } else {
934  if (col_meta->attr == IB_COL_UNSIGNED
935  && data_len == 8) {
936  col_value->value_int =
937  innodb_api_read_uint64(col_meta,
938  read_tpl,
939  i);
940  } else {
941  col_value->value_int =
942  innodb_api_read_int(col_meta,
943  read_tpl,
944  i);
945  }
946  col_value->is_str = false;
947  col_value->value_len = data_len;
948  col_value->is_valid = true;
949  }
950  } else {
951  innodb_api_fill_value(meta_info, item,
952  read_tpl, i, sel_only);
953  }
954  }
955 
956  if (r_tpl) {
957  *r_tpl = read_tpl;
958  } else if (key_tpl) {
959  ib_cb_tuple_delete(read_tpl);
960  }
961  }
962 
963 func_exit:
964  *crsr = srch_crsr;
965 
966  ib_cb_tuple_delete(key_tpl);
967 
968  return(err);
969 }
970 
971 /*************************************************************/
974 static
975 uint64_t
976 mci_get_cas(
977 /*========*/
978  innodb_engine_t* eng)
980 {
981  static uint64_t cas_id = 0;
982 
983 #if defined(HAVE_IB_GCC_ATOMIC_BUILTINS)
984  return(__sync_add_and_fetch(&cas_id, 1));
985 #else
986  pthread_mutex_lock(&eng->cas_mutex);
987  cas_id++;
988  pthread_mutex_unlock(&eng->cas_mutex);
989  return(cas_id);
990 #endif
991 }
992 
993 /*************************************************************/
996 uint64_t
998 /*==============*/
999 {
1000  struct timeval tv;
1001 
1002  /* FIXME: need to address it different when port the project to
1003  Windows. Please see ut_gettimeofday() */
1004  gettimeofday(&tv,NULL);
1005 
1006  return((uint64_t)tv.tv_sec);
1007 }
1008 
1009 /*************************************************************/
1012 static
1013 ib_err_t
1014 innodb_api_set_multi_cols(
1015 /*======================*/
1016  ib_tpl_t tpl,
1017  meta_cfg_info_t* meta_info,
1018  char* value,
1019  int value_len,
1020  void* table)
1021 {
1022  ib_err_t err = DB_ERROR;
1023  meta_column_t* col_info;
1024  char* last;
1025  char* col_val;
1026  char* end;
1027  int i = 0;
1028  char* sep;
1029  size_t sep_len;
1030  char* my_value;
1031 
1032  if (!value_len) {
1033  return(DB_SUCCESS);
1034  }
1035 
1036  col_info = meta_info->extra_col_info;
1037  my_value = malloc(value_len + 1);
1038 
1039  if (!my_value) {
1040  return(DB_ERROR);
1041  }
1042 
1043  memcpy(my_value, value, value_len);
1044  my_value[value_len] = 0;
1045  value = my_value;
1046  end = value + value_len;
1047 
1048  /* Get the default setting if user did not config it */
1049  GET_OPTION(meta_info, OPTION_ID_COL_SEP, sep, sep_len);
1050  assert(sep_len > 0);
1051 
1052  if (value[0] == *sep) {
1053  err = innodb_api_setup_field_value(
1054  tpl, col_info[i].field_id, &col_info[i],
1055  NULL, IB_SQL_NULL, table, true);
1056  i++;
1057 
1058  if (err != DB_SUCCESS) {
1059  free(my_value);
1060  return(err);
1061  }
1062  value++;
1063  }
1064 
1065  /* Input values are separated with "sep" */
1066  for (col_val = strtok_r(value, sep, &last);
1067  last <= end && i < meta_info->n_extra_col;
1068  col_val = strtok_r(NULL, sep, &last), i++) {
1069 
1070  if (!col_val) {
1071  err = innodb_api_setup_field_value(
1072  tpl, col_info[i].field_id, &col_info[i],
1073  NULL, IB_SQL_NULL, table, true);
1074  break;
1075  } else {
1076  err = innodb_api_setup_field_value(
1077  tpl, col_info[i].field_id, &col_info[i],
1078  col_val, strlen(col_val), table, true);
1079 
1080  if (table) {
1082  table, col_info[i].field_id,
1083  col_val, strlen(col_val));
1084  }
1085  }
1086 
1087  if (err != DB_SUCCESS) {
1088  break;
1089  }
1090  }
1091 
1092  for (; i < meta_info->n_extra_col; i++) {
1093  err = innodb_api_setup_field_value(
1094  tpl, col_info[i].field_id, &col_info[i],
1095  NULL, IB_SQL_NULL, table, true);
1096 
1097  if (err != DB_SUCCESS) {
1098  break;
1099  }
1100  }
1101 
1102  free(my_value);
1103  return(err);
1104 }
1105 
1106 /*************************************************************/
1108 static
1109 void
1110 innodb_api_setup_hdl_rec(
1111 /*=====================*/
1112  mci_item_t* item,
1114  meta_column_t* col_info,
1115  void* table)
1116 {
1117  int i;
1118 
1119  for (i = 0; i < MCI_COL_TO_GET; i++) {
1120  if (item->col_value[i].is_str) {
1122  table, col_info[CONTAINER_KEY + i].field_id,
1123  item->col_value[i].value_str,
1124  item->col_value[i].value_len);
1125  } else {
1127  table, col_info[CONTAINER_KEY + i].field_id,
1128  item->col_value[i].value_int, true,
1129  item->col_value[i].is_null);
1130  }
1131  }
1132 }
1133 
1134 /*************************************************************/
1137 static
1138 ib_err_t
1139 innodb_api_set_tpl(
1140 /*===============*/
1141  ib_tpl_t tpl,
1142  meta_cfg_info_t* meta_info,
1143  meta_column_t* col_info,
1144  const char* key,
1145  int key_len,
1146  const char* value,
1147  int value_len,
1148  uint64_t cas,
1149  uint64_t exp,
1150  uint64_t flag,
1151  int col_to_set,
1152  void* table,
1153  bool need_cpy)
1154 {
1155  ib_err_t err = DB_ERROR;
1156 
1157  /* If "table" is not NULL, we need to setup MySQL record
1158  for binlogging */
1159  if (table) {
1160  handler_rec_init(table);
1161  }
1162 
1163  err = innodb_api_setup_field_value(
1164  tpl, col_info[CONTAINER_KEY].field_id,
1165  &col_info[CONTAINER_KEY], key, key_len, table, need_cpy);
1166 
1167  if (err != DB_SUCCESS) {
1168  return(err);
1169  }
1170 
1171  assert(err == DB_SUCCESS);
1172 
1173  if (meta_info->n_extra_col > 0) {
1174  if (col_to_set == UPDATE_ALL_VAL_COL) {
1175  err = innodb_api_set_multi_cols(tpl, meta_info,
1176  (char*) value,
1177  value_len,
1178  table);
1179  } else {
1180  err = ib_cb_col_set_value(
1181  tpl,
1182  meta_info->extra_col_info[col_to_set].field_id,
1183  value, value_len, need_cpy);
1184 
1185  if (table) {
1187  table,
1188  col_info[col_to_set].field_id,
1189  value, value_len);
1190  }
1191  }
1192  } else {
1193  err = innodb_api_setup_field_value(
1194  tpl, col_info[CONTAINER_VALUE].field_id,
1195  &col_info[CONTAINER_VALUE], value,
1196  value_len, table, need_cpy);
1197  }
1198 
1199  if (err != DB_SUCCESS) {
1200  return(err);
1201  }
1202 
1203  if (meta_info->cas_enabled) {
1204  err = innodb_api_write_int(
1205  tpl, col_info[CONTAINER_CAS].field_id, cas, table);
1206  if (err != DB_SUCCESS) {
1207  return(err);
1208  }
1209  }
1210 
1211  if (meta_info->exp_enabled) {
1212  err = innodb_api_write_int(
1213  tpl, col_info[CONTAINER_EXP].field_id, exp, table);
1214  if (err != DB_SUCCESS) {
1215  return(err);
1216  }
1217  }
1218 
1219  if (meta_info->flag_enabled) {
1220  err = innodb_api_write_int(
1221  tpl, col_info[CONTAINER_FLAG].field_id, flag, table);
1222  if (err != DB_SUCCESS) {
1223  return(err);
1224  }
1225  }
1226 
1227  return(err);
1228 }
1229 
1230 /*************************************************************/
1233 ib_err_t
1235 /*==============*/
1236  innodb_engine_t* engine,
1237  innodb_conn_data_t* cursor_data,
1238  const char* key,
1239  int len,
1240  uint32_t val_len,
1241  uint64_t exp,
1242  uint64_t* cas,
1243  uint64_t flags)
1244 {
1245  uint64_t new_cas;
1246  ib_err_t err = DB_ERROR;
1247  ib_tpl_t tpl = NULL;
1248  meta_cfg_info_t* meta_info = cursor_data->conn_meta;
1249  meta_column_t* col_info = meta_info->col_info;
1250 
1251  new_cas = mci_get_cas(engine);
1252 
1253  tpl = ib_cb_read_tuple_create(cursor_data->crsr);
1254  assert(tpl != NULL);
1255 
1256  /* Set expiration time */
1257  SET_EXP_TIME(exp);
1258 
1259  assert(!cursor_data->mysql_tbl || engine->enable_binlog
1260  || engine->enable_mdl);
1261 
1262  err = innodb_api_set_tpl(tpl, meta_info, col_info, key, len,
1263  key + len, val_len,
1264  new_cas, exp, flags, UPDATE_ALL_VAL_COL,
1265  engine->enable_binlog
1266  ? cursor_data->mysql_tbl : NULL,
1267  false);
1268 
1269  if (err == DB_SUCCESS) {
1270  err = ib_cb_insert_row(cursor_data->crsr, tpl);
1271  }
1272 
1273  if (err == DB_SUCCESS) {
1274  *cas = new_cas;
1275 
1276  if (engine->enable_binlog && cursor_data->mysql_tbl) {
1277  handler_binlog_row(cursor_data->thd,
1278  cursor_data->mysql_tbl,
1279  HDL_INSERT);
1280  }
1281 
1282  }
1283 
1284  ib_cb_tuple_delete(tpl);
1285  return(err);
1286 }
1287 
1288 /*************************************************************/
1292 static
1293 ib_err_t
1294 innodb_api_update(
1295 /*==============*/
1296  innodb_engine_t* engine,
1297  innodb_conn_data_t* cursor_data,
1298  ib_crsr_t srch_crsr,
1299  const char* key,
1300  int len,
1301  uint32_t val_len,
1302  uint64_t exp,
1303  uint64_t* cas,
1304  uint64_t flags,
1305  ib_tpl_t old_tpl,
1306  mci_item_t* result)
1308 {
1309  uint64_t new_cas;
1310  ib_tpl_t new_tpl;
1311  meta_cfg_info_t* meta_info = cursor_data->conn_meta;
1312  meta_column_t* col_info = meta_info->col_info;
1313  ib_err_t err = DB_SUCCESS;
1314 
1315  assert(old_tpl != NULL);
1316 
1317  new_tpl = ib_cb_read_tuple_create(cursor_data->crsr);
1318  assert(new_tpl != NULL);
1319 
1320  /* cas will be updated for each update */
1321  new_cas = mci_get_cas(engine);
1322 
1323  SET_EXP_TIME(exp);
1324 
1325  if (engine->enable_binlog) {
1326  innodb_api_setup_hdl_rec(result, col_info,
1327  cursor_data->mysql_tbl);
1328  handler_store_record(cursor_data->mysql_tbl);
1329  }
1330 
1331  assert(!cursor_data->mysql_tbl || engine->enable_binlog
1332  || engine->enable_mdl);
1333 
1334  err = innodb_api_set_tpl(new_tpl, meta_info, col_info, key,
1335  len, key + len, val_len,
1336  new_cas, exp, flags, UPDATE_ALL_VAL_COL,
1337  engine->enable_binlog
1338  ? cursor_data->mysql_tbl : NULL,
1339  true);
1340 
1341  if (err == DB_SUCCESS) {
1342  err = ib_cb_update_row(srch_crsr, old_tpl, new_tpl);
1343  }
1344 
1345  if (err == DB_SUCCESS) {
1346  *cas = new_cas;
1347 
1348  if (engine->enable_binlog) {
1349  assert(cursor_data->mysql_tbl);
1350 
1351  handler_binlog_row(cursor_data->thd,
1352  cursor_data->mysql_tbl,
1353  HDL_UPDATE);
1354  }
1355 
1356  }
1357 
1358  ib_cb_tuple_delete(new_tpl);
1359 
1360  return(err);
1361 }
1362 
1363 /*************************************************************/
1366 ENGINE_ERROR_CODE
1368 /*==============*/
1369  innodb_engine_t* engine,
1370  innodb_conn_data_t* cursor_data,
1371  const char* key,
1372  int len)
1373 {
1374  ib_err_t err = DB_SUCCESS;
1375  ib_crsr_t srch_crsr = cursor_data->crsr;
1376  mci_item_t result;
1377  ib_tpl_t tpl_delete;
1378 
1379  /* First look for the record, and check whether it exists */
1380  err = innodb_api_search(cursor_data, &srch_crsr, key, len,
1381  &result, &tpl_delete, false);
1382 
1383  if (err != DB_SUCCESS) {
1384  ib_cb_tuple_delete(tpl_delete);
1385  return(ENGINE_KEY_ENOENT);
1386  }
1387 
1388  /* The "result" structure contains only pointers to the data value
1389  when returning from innodb_api_search(), so store the delete row info
1390  before calling ib_cb_delete_row() */
1391  if (engine->enable_binlog) {
1392  meta_cfg_info_t* meta_info = cursor_data->conn_meta;
1393  meta_column_t* col_info = meta_info->col_info;
1394 
1395  assert(cursor_data->mysql_tbl);
1396 
1397  innodb_api_setup_hdl_rec(&result, col_info,
1398  cursor_data->mysql_tbl);
1399  }
1400 
1401  err = ib_cb_delete_row(srch_crsr);
1402 
1403  /* Do the binlog of the row being deleted */
1404  if (engine->enable_binlog) {
1405  if (err == DB_SUCCESS) {
1406  handler_binlog_row(cursor_data->thd,
1407  cursor_data->mysql_tbl, HDL_DELETE);
1408  }
1409  }
1410 
1411  ib_cb_tuple_delete(tpl_delete);
1412  return(err == DB_SUCCESS ? ENGINE_SUCCESS : ENGINE_KEY_ENOENT);
1413 }
1414 
1415 /*************************************************************/
1419 static
1420 ib_err_t
1421 innodb_api_link(
1422 /*============*/
1423  innodb_engine_t* engine,
1424  innodb_conn_data_t* cursor_data,
1425  ib_crsr_t srch_crsr,
1426  const char* key,
1427  int len,
1428  uint32_t val_len,
1429  uint64_t exp,
1430  uint64_t* cas,
1431  uint64_t flags,
1432  bool append,
1434  ib_tpl_t old_tpl,
1435  mci_item_t* result)
1437 {
1438  ib_err_t err = DB_SUCCESS;
1439  char* append_buf;
1440  int before_len;
1441  int total_len;
1442  ib_tpl_t new_tpl;
1443  uint64_t new_cas;
1444  meta_cfg_info_t* meta_info = cursor_data->conn_meta;
1445  meta_column_t* col_info = meta_info->col_info;
1446  char* before_val;
1447  int column_used;
1448 
1449  if (engine->enable_binlog) {
1450  assert(cursor_data->mysql_tbl);
1451 
1452  innodb_api_setup_hdl_rec(result, col_info,
1453  cursor_data->mysql_tbl);
1454  handler_store_record(cursor_data->mysql_tbl);
1455  }
1456 
1457  /* If we have multiple value columns, the column to append the
1458  string needs to be defined. We will use user supplied flags
1459  as an indication on which column to apply the operation. Otherwise,
1460  the first column will be appended / prepended */
1461  if (meta_info->n_extra_col > 0) {
1462  if (flags < (uint64_t) meta_info->n_extra_col) {
1463  column_used = flags;
1464  } else {
1465  column_used = 0;
1466  }
1467 
1468  before_len = result->extra_col_value[column_used].value_len;
1469  before_val = result->extra_col_value[column_used].value_str;
1470  } else {
1471  before_len = result->col_value[MCI_COL_VALUE].value_len;
1472  before_val = result->col_value[MCI_COL_VALUE].value_str;
1473  column_used = UPDATE_ALL_VAL_COL;
1474  }
1475 
1476  total_len = before_len + val_len;
1477 
1478  append_buf = (char*) malloc(total_len);
1479 
1480  if (append) {
1481  memcpy(append_buf, before_val, before_len);
1482  memcpy(append_buf + before_len, key + len, val_len);
1483  } else {
1484  memcpy(append_buf, key + len, val_len);
1485  memcpy(append_buf + val_len, before_val, before_len);
1486  }
1487 
1488  new_tpl = ib_cb_read_tuple_create(cursor_data->crsr);
1489  new_cas = mci_get_cas(engine);
1490 
1491  if (exp) {
1492  uint64_t time;
1493  time = mci_get_time();
1494  exp += time;
1495  }
1496 
1497  assert(!cursor_data->mysql_tbl || engine->enable_binlog
1498  || engine->enable_mdl);
1499 
1500  err = innodb_api_set_tpl(new_tpl, meta_info, col_info,
1501  key, len, append_buf, total_len,
1502  new_cas, exp, flags, column_used,
1503  engine->enable_binlog
1504  ? cursor_data->mysql_tbl : NULL,
1505  true);
1506 
1507  if (err == DB_SUCCESS) {
1508  err = ib_cb_update_row(srch_crsr, old_tpl, new_tpl);
1509  }
1510 
1511  ib_cb_tuple_delete(new_tpl);
1512 
1513  free(append_buf);
1514  append_buf = NULL;
1515 
1516  if (err == DB_SUCCESS) {
1517  *cas = new_cas;
1518 
1519  if (engine->enable_binlog) {
1520  handler_binlog_row(cursor_data->thd,
1521  cursor_data->mysql_tbl,
1522  HDL_UPDATE);
1523  }
1524  }
1525 
1526  return(err);
1527 }
1528 
1529 /*************************************************************/
1532 ENGINE_ERROR_CODE
1534 /*==================*/
1535  innodb_engine_t* engine,
1536  innodb_conn_data_t* cursor_data,
1537  const char* key,
1538  int len,
1539  int delta,
1540  bool increment,
1541  uint64_t* cas,
1542  rel_time_t exp_time __attribute__((unused)),
1544  bool create,
1546  uint64_t initial,
1547  uint64_t* out_result)
1548 {
1549 
1550  ib_err_t err = DB_SUCCESS;
1551  char value_buf[128];
1552  mci_item_t result;
1553  ib_tpl_t old_tpl;
1554  ib_tpl_t new_tpl;
1555  uint64_t value = 0;
1556  bool create_new = false;
1557  char* end_ptr;
1558  meta_cfg_info_t* meta_info = cursor_data->conn_meta;
1559  meta_column_t* col_info = meta_info->col_info;
1560  ib_crsr_t srch_crsr = cursor_data->crsr;
1561  char* before_val;
1562  unsigned int before_len;
1563  int column_used = 0;
1564  ENGINE_ERROR_CODE ret = ENGINE_SUCCESS;
1565 
1566  err = innodb_api_search(cursor_data, &srch_crsr, key, len,
1567  &result, &old_tpl, false);
1568 
1569  /* If the return message is not success or record not found, just
1570  exit */
1571  if (err != DB_SUCCESS && err != DB_RECORD_NOT_FOUND) {
1572  ib_cb_tuple_delete(old_tpl);
1573  goto func_exit;
1574  }
1575 
1576  memset(value_buf, 0, 128);
1577 
1578  /* Can't find the row, decide whether to insert a new row */
1579  if (err != DB_SUCCESS) {
1580  ib_cb_tuple_delete(old_tpl);
1581 
1582  /* If create is true, insert a new row */
1583  if (create) {
1584  snprintf(value_buf, sizeof(value_buf),
1585  "%" PRIu64, initial);
1586  create_new = true;
1587  goto create_new_value;
1588  } else {
1589  /* cursor_data->mysql_tbl can't be created.
1590  So safe to return here */
1591  return(DB_RECORD_NOT_FOUND);
1592  }
1593  }
1594 
1595  /* Save the original value, this would be an update */
1596  if (engine->enable_binlog) {
1597  innodb_api_setup_hdl_rec(&result, col_info,
1598  cursor_data->mysql_tbl);
1599  handler_store_record(cursor_data->mysql_tbl);
1600  }
1601 
1602  /* If we have multiple value columns, the column to append the
1603  string needs to be defined. We will use user supplied flags
1604  as an indication on which column to apply the operation. Otherwise,
1605  the first column will be appended / prepended */
1606  if (meta_info->n_extra_col > 0) {
1607  uint64_t flags = result.col_value[MCI_COL_FLAG].value_int;
1608 
1609  if (flags < (uint64_t) meta_info->n_extra_col) {
1610  column_used = flags;
1611  } else {
1612  column_used = 0;
1613  }
1614 
1615  before_len = result.extra_col_value[column_used].value_len;
1616  before_val = result.extra_col_value[column_used].value_str;
1617  } else {
1618  before_len = result.col_value[MCI_COL_VALUE].value_len;
1619  before_val = result.col_value[MCI_COL_VALUE].value_str;
1620  column_used = UPDATE_ALL_VAL_COL;
1621  }
1622 
1623  if (before_len >= (sizeof(value_buf) - 1)) {
1624  ib_cb_tuple_delete(old_tpl);
1625  ret = ENGINE_EINVAL;
1626  goto func_exit;
1627  }
1628 
1629  errno = 0;
1630 
1631  if (before_val) {
1632  value = strtoull(before_val, &end_ptr, 10);
1633  }
1634 
1635  if (errno == ERANGE) {
1636  ib_cb_tuple_delete(old_tpl);
1637  ret = ENGINE_EINVAL;
1638  goto func_exit;
1639  }
1640 
1641  if (increment) {
1642  value += delta;
1643  } else {
1644  if (delta > (int) value) {
1645  value = 0;
1646  } else {
1647  value -= delta;
1648  }
1649  }
1650 
1651  snprintf(value_buf, sizeof(value_buf), "%" PRIu64, value);
1652 create_new_value:
1653  *cas = mci_get_cas(engine);
1654 
1655  new_tpl = ib_cb_read_tuple_create(cursor_data->crsr);
1656 
1657  assert(!cursor_data->mysql_tbl || engine->enable_binlog
1658  || engine->enable_mdl);
1659 
1660  /* The cas, exp and flags field are not changing, so use the
1661  data from result */
1662  err = innodb_api_set_tpl(new_tpl, meta_info, col_info,
1663  key, len, value_buf, strlen(value_buf),
1664  *cas,
1667  column_used,
1668  engine->enable_binlog
1669  ? cursor_data->mysql_tbl : NULL,
1670  true);
1671 
1672  if (err != DB_SUCCESS) {
1673  ib_cb_tuple_delete(new_tpl);
1674  ib_cb_tuple_delete(old_tpl);
1675  goto func_exit;
1676  }
1677 
1678  if (create_new) {
1679  err = ib_cb_insert_row(cursor_data->crsr, new_tpl);
1680  *out_result = initial;
1681 
1682  if (engine->enable_binlog) {
1683  handler_binlog_row(cursor_data->thd,
1684  cursor_data->mysql_tbl, HDL_INSERT);
1685  }
1686  } else {
1687  err = ib_cb_update_row(srch_crsr, old_tpl, new_tpl);
1688  *out_result = value;
1689 
1690  if (engine->enable_binlog) {
1691  handler_binlog_row(cursor_data->thd,
1692  cursor_data->mysql_tbl, HDL_UPDATE);
1693  }
1694  }
1695 
1696  ib_cb_tuple_delete(new_tpl);
1697  ib_cb_tuple_delete(old_tpl);
1698 
1699 func_exit:
1700  /* Free memory of result. */
1701  if (result.extra_col_value) {
1702  free(result.extra_col_value);
1703  } else {
1704  if (result.col_value[MCI_COL_VALUE].allocated) {
1705  free(result.col_value[MCI_COL_VALUE].value_str);
1706  result.col_value[MCI_COL_VALUE].allocated = false;
1707  }
1708  }
1709 
1710  if (ret == ENGINE_SUCCESS) {
1711  ret = (err == DB_SUCCESS) ? ENGINE_SUCCESS : ENGINE_NOT_STORED;
1712  }
1713 
1714  return(ret);
1715 }
1716 
1717 /*************************************************************/
1726 ENGINE_ERROR_CODE
1728 /*=============*/
1729  innodb_engine_t* engine,
1730  innodb_conn_data_t* cursor_data,
1731  const char* key,
1732  int len,
1733  uint32_t val_len,
1734  uint64_t exp,
1735  uint64_t* cas,
1736  uint64_t input_cas,
1737  uint64_t flags,
1738  ENGINE_STORE_OPERATION op)
1739 {
1740  ib_err_t err = DB_ERROR;
1741  mci_item_t result;
1742  ib_tpl_t old_tpl = NULL;
1743  ENGINE_ERROR_CODE stored = ENGINE_NOT_STORED;
1744  ib_crsr_t srch_crsr = cursor_data->crsr;
1745 
1746  /* Skip search for add operation. Rely on the unique index of
1747  key to check any duplicates */
1748  if (op == OPERATION_ADD) {
1749  err = DB_RECORD_NOT_FOUND;
1750  memset(&result, 0, sizeof(result));
1751  } else {
1752  /* First check whether record with the key value exists */
1753  err = innodb_api_search(cursor_data, &srch_crsr,
1754  key, len, &result, &old_tpl, false);
1755  }
1756 
1757  /* If the return message is not success or record not found, just
1758  exit */
1759  if (err != DB_SUCCESS && err != DB_RECORD_NOT_FOUND) {
1760  goto func_exit;
1761  }
1762 
1763  switch (op) {
1764  case OPERATION_ADD:
1765  err = innodb_api_insert(engine, cursor_data, key, len,
1766  val_len, exp, cas, flags);
1767  break;
1768  case OPERATION_REPLACE:
1769  if (err == DB_SUCCESS) {
1770  err = innodb_api_update(engine, cursor_data, srch_crsr,
1771  key, len, val_len, exp,
1772  cas, flags, old_tpl, &result);
1773  }
1774  break;
1775  case OPERATION_APPEND:
1776  case OPERATION_PREPEND:
1777  /* FIXME: Check cas is used for append and prepend */
1778  /* if (*cas != result.col_value[MCI_COL_CAS].value_int) {
1779  stored = ENGINE_KEY_EEXISTS;
1780  break;
1781  } */
1782 
1783  if (err == DB_SUCCESS) {
1784  err = innodb_api_link(engine, cursor_data, srch_crsr,
1785  key, len, val_len, exp,
1786  cas, flags,
1787  (op == OPERATION_APPEND),
1788  old_tpl, &result);
1789  }
1790  break;
1791  case OPERATION_SET:
1792  if (err == DB_SUCCESS) {
1793  err = innodb_api_update(engine, cursor_data,
1794  srch_crsr, key, len, val_len,
1795  exp, cas, flags,
1796  old_tpl, &result);
1797  } else {
1798  err = innodb_api_insert(engine, cursor_data, key, len,
1799  val_len, exp, cas, flags);
1800  }
1801  break;
1802  case OPERATION_CAS:
1803  if (err != DB_SUCCESS) {
1804  stored = ENGINE_KEY_ENOENT;
1805 
1806  } else if (input_cas
1807  == result.col_value[MCI_COL_CAS].value_int) {
1808  err = innodb_api_update(engine, cursor_data, srch_crsr,
1809  key, len, val_len, exp,
1810  cas, flags, old_tpl, &result);
1811 
1812  } else {
1813  stored = ENGINE_KEY_EEXISTS;
1814  }
1815  break;
1816  }
1817 
1818  /* Free memory of result. */
1819  if (result.extra_col_value) {
1820  free(result.extra_col_value);
1821  } else {
1822  if (result.col_value[MCI_COL_VALUE].allocated) {
1823  free(result.col_value[MCI_COL_VALUE].value_str);
1824  result.col_value[MCI_COL_VALUE].allocated = false;
1825  }
1826  }
1827 
1828 func_exit:
1829  ib_cb_tuple_delete(old_tpl);
1830 
1831  if (err == DB_SUCCESS && stored == ENGINE_NOT_STORED) {
1832  stored = ENGINE_SUCCESS;
1833  }
1834 
1835  return(stored);
1836 }
1837 
1838 /*************************************************************/
1841 ENGINE_ERROR_CODE
1843 /*=============*/
1844  innodb_engine_t* engine,
1845  innodb_conn_data_t* conn_data,
1847  const char* dbname,
1848  const char* name)
1849 {
1850  ib_err_t err = DB_SUCCESS;
1852  + MAX_DATABASE_NAME_LEN + 1];
1853  ib_id_u64_t new_id;
1854 
1855 #ifdef __WIN__
1856  sprintf(table_name, "%s\%s", dbname, name);
1857 #else
1858  snprintf(table_name, sizeof(table_name), "%s/%s", dbname, name);
1859 #endif
1860  /* currently, we implement engine flush as truncate table */
1861  err = ib_cb_table_truncate(table_name, &new_id);
1862 
1863  /* If binlog is enabled, log the truncate table statement */
1864  if (err == DB_SUCCESS && engine->enable_binlog) {
1865  void* thd = conn_data->thd;
1866 
1867  snprintf(table_name, sizeof(table_name), "%s.%s", dbname, name);
1868  handler_binlog_truncate(thd, table_name);
1869  }
1870 
1871  return(err);
1872 }
1873 
1874 /*************************************************************/
1877 bool
1879 /*==============*/
1880  innodb_conn_data_t* conn_data,
1882  bool has_lock,
1884  bool commit,
1885  bool has_binlog)
1886 {
1887  bool commit_trx = false;
1888 
1889  LOCK_CURRENT_CONN_IF_NOT_LOCKED(has_lock, conn_data);
1890 
1891  if (conn_data->crsr) {
1892  ib_cb_cursor_reset(conn_data->crsr);
1893  }
1894 
1895  if (conn_data->read_crsr) {
1896  ib_cb_cursor_reset(conn_data->read_crsr);
1897  }
1898 
1899  if (conn_data->idx_crsr) {
1900  ib_cb_cursor_reset(conn_data->idx_crsr);
1901  }
1902 
1903  if (conn_data->idx_read_crsr) {
1904  ib_cb_cursor_reset(conn_data->idx_read_crsr);
1905  }
1906 
1907  if (conn_data->crsr_trx) {
1908  ib_crsr_t ib_crsr;
1909  meta_cfg_info_t* meta_info = conn_data->conn_meta;
1910  meta_index_t* meta_index = &meta_info->index_info;
1911 
1912  if (meta_index->srch_use_idx == META_USE_SECONDARY) {
1913  assert(conn_data->idx_crsr
1914  || conn_data->idx_read_crsr);
1915 
1916  ib_crsr = conn_data->idx_crsr
1917  ? conn_data->idx_crsr
1918  : conn_data->idx_read_crsr;
1919  } else {
1920  assert(conn_data->crsr
1921  || conn_data->read_crsr);
1922 
1923  ib_crsr = conn_data->crsr
1924  ? conn_data->crsr
1925  : conn_data->read_crsr;
1926  }
1927 
1928  if (commit) {
1929  ib_cb_cursor_commit_trx(
1930  ib_crsr, conn_data->crsr_trx);
1931 
1932  if (has_binlog && conn_data->thd
1933  && conn_data->mysql_tbl) {
1934  handler_binlog_commit(conn_data->thd,
1935  conn_data->mysql_tbl);
1936  }
1937  } else {
1938  ib_cb_trx_rollback(conn_data->crsr_trx);
1939 
1940  if (has_binlog && conn_data->thd
1941  && conn_data->mysql_tbl) {
1942  handler_binlog_rollback(conn_data->thd,
1943  conn_data->mysql_tbl);
1944  }
1945  }
1946 
1947  conn_data->crsr_trx = NULL;
1948 
1949  if (conn_data->crsr) {
1950  ib_cb_cursor_clear_trx(
1951  conn_data->crsr);
1952  }
1953 
1954  if (conn_data->read_crsr) {
1955  ib_cb_cursor_clear_trx(
1956  conn_data->read_crsr);
1957  }
1958 
1959  if (conn_data->idx_crsr) {
1960  ib_cb_cursor_clear_trx(
1961  conn_data->idx_crsr);
1962  }
1963 
1964  if (conn_data->idx_read_crsr) {
1965  ib_cb_cursor_clear_trx(
1966  conn_data->idx_read_crsr);
1967  }
1968 
1969  commit_trx = true;
1970  conn_data->in_use = false;
1971  }
1972 
1973  conn_data->n_writes_since_commit = 0;
1974  conn_data->n_reads_since_commit = 0;
1975 
1976  UNLOCK_CURRENT_CONN_IF_NOT_LOCKED(has_lock, conn_data);
1977  return(commit_trx);
1978 }
1979 
1980 /*************************************************************/
1983 void
1985 /*====================*/
1986  innodb_engine_t* engine,
1988  innodb_conn_data_t* conn_data,
1990  conn_op_type_t op_type,
1991  bool commit)
1992 {
1993  bool commit_trx = false;
1994 
1995  switch (op_type) {
1996  case CONN_OP_READ:
1997  conn_data->n_total_reads++;
1998  conn_data->n_reads_since_commit++;
1999  break;
2000  case CONN_OP_DELETE:
2001  case CONN_OP_WRITE:
2002  conn_data->n_total_writes++;
2003  conn_data->n_writes_since_commit++;
2004  break;
2005  case CONN_OP_FLUSH:
2006  break;
2007  }
2008 
2009  if (conn_data->n_reads_since_commit >= engine->read_batch_size
2010  || conn_data->n_writes_since_commit >= engine->write_batch_size
2011  || (op_type == CONN_OP_FLUSH) || !commit) {
2012  commit_trx = innodb_reset_conn(
2013  conn_data, op_type == CONN_OP_FLUSH, commit,
2014  engine->enable_binlog);
2015  }
2016 
2017  if (!commit_trx) {
2019  conn_data);
2020  if (op_type != CONN_OP_FLUSH) {
2021  assert(conn_data->in_use);
2022  }
2023 
2024  conn_data->in_use = false;
2025  UNLOCK_CURRENT_CONN_IF_NOT_LOCKED(op_type == CONN_OP_FLUSH,
2026  conn_data);
2027  }
2028 }
2029 
2033 /*************************************************************/
2036 ib_err_t
2038 /*===================*/
2039  ib_crsr_t ib_crsr)
2040 {
2041  return(ib_cb_cursor_close(ib_crsr));
2042 }
2043 
2044 /*************************************************************/
2047 ib_err_t
2049 /*=================*/
2050  ib_trx_t ib_trx)
2051 {
2052  return(ib_cb_trx_commit(ib_trx));
2053 }
2054 
2055 /*************************************************************/
2058 ib_err_t
2060 /*=================*/
2061  void* thd)
2062 {
2063  return(ib_cb_close_thd(thd));
2064 }
2065 
2066 /*************************************************************/
2069 ib_trx_t
2071 /*================*/
2072  ib_trx_level_t ib_trx_level)
2073 {
2074  return(ib_cb_trx_begin(ib_trx_level));
2075 }
2076 
2077 /*****************************************************************/
2080 ib_err_t
2082 /*=====================*/
2083  ib_crsr_t ib_crsr,
2084  ib_trx_t ib_trx)
2085 {
2086  return(ib_cb_cursor_new_trx(ib_crsr, ib_trx));
2087 }
2088 
2089 /*****************************************************************/
2092 ib_err_t
2094 /*==================*/
2095  innodb_engine_t* eng,
2096  ib_crsr_t ib_crsr,
2097  ib_lck_mode_t ib_lck_mode)
2098 {
2099  ib_err_t err = DB_SUCCESS;
2100 
2101  if (ib_lck_mode == IB_LOCK_TABLE_X) {
2102  /* Table lock only */
2103  err = ib_cb_cursor_lock(ib_crsr, IB_LOCK_X);
2104  } else if (eng && eng->cfg_status & IB_CFG_DISABLE_ROWLOCK) {
2105  /* Table lock only */
2106  if (ib_lck_mode == IB_LOCK_X) {
2107  err = ib_cb_cursor_lock(ib_crsr, IB_LOCK_IX);
2108  } else {
2109  err = ib_cb_cursor_lock(ib_crsr, IB_LOCK_IS);
2110  }
2111  } else {
2112  err = ib_cb_cursor_set_lock(ib_crsr, ib_lck_mode);
2113  }
2114 
2115  return(err);
2116 }
2117 
2118 /*****************************************************************/
2121 ib_tpl_t
2123 /*========================*/
2124  ib_crsr_t ib_crsr)
2125 {
2126  return(ib_cb_read_tuple_create(ib_crsr));
2127 }
2128 
2129 /*****************************************************************/
2132 ib_err_t
2134 /*===================*/
2135  ib_crsr_t ib_crsr)
2136 {
2137  return(ib_cb_cursor_first(ib_crsr));
2138 }
2139 
2140 /*****************************************************************/
2143 ib_err_t
2145 /*===============*/
2146  ib_crsr_t ib_crsr,
2147  ib_tpl_t ib_tpl)
2148 {
2149  return(ib_cb_read_row(ib_crsr, ib_tpl));
2150 }
2151 
2152 /*****************************************************************/
2155 ib_ulint_t
2157 /*===================*/
2158  ib_tpl_t ib_tpl,
2159  ib_ulint_t i,
2160  ib_col_meta_t* ib_col_meta)
2161 {
2162  return(ib_cb_col_get_meta(ib_tpl, i, ib_col_meta));
2163 }
2164 
2165 /*****************************************************************/
2167 void
2169 /*===================*/
2170  ib_tpl_t ib_tpl)
2171 {
2172  ib_cb_tuple_delete(ib_tpl);
2173  return;
2174 }
2175 
2176 /*****************************************************************/
2179 ib_ulint_t
2181 /*=======================*/
2182  const ib_tpl_t ib_tpl)
2183 {
2184  return(ib_cb_tuple_get_n_cols(ib_tpl));
2185 }
2186 
2187 /*****************************************************************/
2190 const void*
2192 /*====================*/
2193  ib_tpl_t ib_tpl,
2194  ib_ulint_t i)
2195 {
2196  return(ib_cb_col_get_value(ib_tpl, i));
2197 }
2198 
2199 /********************************************************************/
2202 ib_err_t
2204 /*=================*/
2205  const char* name,
2206  ib_trx_t ib_trx,
2207  ib_crsr_t* ib_crsr)
2208 {
2209  return(ib_cb_open_table(name, ib_trx, ib_crsr));
2210 }
2211 
2212 /*****************************************************************/
2215 char*
2217 /*===================*/
2218  ib_crsr_t ib_crsr,
2219  ib_ulint_t i)
2220 {
2221  return(ib_cb_col_get_name(ib_crsr, i));
2222 }
2223 
2224 /*****************************************************************/
2227 ib_err_t
2229 /*===================================*/
2230  ib_crsr_t ib_open_crsr,
2231  const char* index_name,
2232  ib_crsr_t* ib_crsr,
2233  int* idx_type,
2234  ib_id_u64_t* idx_id)
2235 {
2236  return(ib_cb_cursor_open_index_using_name(ib_open_crsr, index_name,
2237  ib_crsr, idx_type, idx_id));
2238 }
2239 /*****************************************************************/
2242 int
2244 /*===============*/
2245 {
2246  return(ib_cb_get_cfg());
2247 }
2248