1
/*****************************************************************************
3
Copyright (c) 2011, 2013, Oracle and/or its affiliates. All Rights Reserved.
5
This program is free software; you can redistribute it and/or modify it under
6
the terms of the GNU General Public License as published by the Free Software
7
Foundation; version 2 of the License.
9
This program is distributed in the hope that it will be useful, but WITHOUT
10
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
You should have received a copy of the GNU General Public License along with
14
this program; if not, write to the Free Software Foundation, Inc.,
15
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
17
****************************************************************************/
19
/**************************************************//**
22
Created 3/14/2011 Jimmy Yang
23
*******************************************************/
25
#include "handler_api.h"
27
#include <my_global.h>
31
#include <mysql_version.h>
32
#include <mysql/plugin.h>
34
#include "my_pthread.h"
37
#include "sql_plugin.h"
39
#include "sql_class.h"
43
#include "transaction.h"
44
#include "sql_handler.h"
47
#include "log_event.h"
48
#include "innodb_config.h"
51
/** Some handler functions defined in sql/sql_table.cc and sql/handler.cc etc.
52
and being used here */
53
extern int write_bin_log(THD *thd, bool clear_error,
54
char const *query, ulong query_length,
55
bool is_trans= false);
57
/** function to close a connection and thd, defined in sql/handler.cc */
58
extern void ha_close_connection(THD* thd);
60
/** binlog a row operation */
61
extern int binlog_log_row(TABLE* table,
62
const uchar *before_record,
63
const uchar *after_record,
66
/**********************************************************************//**
68
@return a pointer to the THD object, NULL if failed */
72
bool enable_binlog) /*!< in: whether to enable binlog */
76
if (enable_binlog && !binlog_enabled()) {
77
fprintf(stderr, " InnoDB_Memcached: MySQL server"
78
" binlog not enabled\n");
89
my_net_init(&thd->net,(st_vio*) 0);
90
thd->variables.pseudo_thread_id = thread_id++;
91
thd->thread_id = thd->variables.pseudo_thread_id;
92
thd->thread_stack = reinterpret_cast<char*>(&thd);
96
thd->binlog_setup_trx_data();
98
/* set binlog_format to "ROW" */
99
thd->set_current_stmt_binlog_format_row();
105
/**********************************************************************//**
106
This is used to temporarily switch to another session, so that
107
POSIX thread looks like session attached to */
111
void* my_thd, /*!< in: THD* */
112
void** original_thd) /*!< out: current THD */
114
THD* thd = static_cast<THD*>(my_thd);
117
*original_thd = my_pthread_getspecific(THD*, THR_THD);
118
assert(thd->mysys_var);
121
my_pthread_setspecific_ptr(THR_THD, thd);
122
my_pthread_setspecific_ptr(THR_MALLOC, &thd->mem_root);
123
set_mysys_var(thd->mysys_var);
126
/**********************************************************************//**
127
Returns a MySQL "TABLE" object with specified database name and table name.
128
@return a pointer to the TABLE object, NULL if does not exist */
132
void* my_thd, /*!< in: THD* */
133
const char* db_name, /*!< in: NUL terminated database name */
134
const char* table_name, /*!< in: NUL terminated table name */
135
int lock_type) /*!< in: lock mode */
138
THD* thd = static_cast<THD*>(my_thd);
139
Open_table_context table_ctx(thd, 0);
140
thr_lock_type lock_mode;
142
lock_mode = (lock_type <= HDL_READ)
146
tables.init_one_table(db_name, strlen(db_name), table_name,
147
strlen(table_name), table_name, lock_mode);
149
tables.mdl_request.init(MDL_key::TABLE, db_name, table_name,
150
(lock_mode > TL_READ)
152
: MDL_SHARED_READ, MDL_TRANSACTION);
154
if (!open_table(thd, &tables, &table_ctx)) {
155
TABLE* table = tables.table;
156
table->use_all_columns();
163
/**********************************************************************//**
164
Wrapper of function binlog_log_row() to binlog an operation on a row */
168
void* my_thd, /*!< in: THD* */
169
void* my_table, /*!< in: TABLE structure */
170
int mode) /*!< in: type of DML */
172
TABLE* table = static_cast<TABLE*>(my_table);
173
THD* thd = static_cast<THD*>(my_thd);
176
if (thd->get_binlog_table_maps() == 0) {
177
/* Write the table map and BEGIN mark */
178
thd->binlog_write_table_map(
179
static_cast<TABLE*>(my_table), 1, 0);
184
/* Updated record must be allocated and filled */
185
assert(table->record[1]);
186
log_func = Update_rows_log_event::binlog_row_logging_function;
187
binlog_log_row(table, table->record[1], table->record[0],
191
log_func = Write_rows_log_event::binlog_row_logging_function;
192
binlog_log_row(table, 0, table->record[0], log_func);
195
log_func = Delete_rows_log_event::binlog_row_logging_function;
196
binlog_log_row(table, table->record[0], 0, log_func);
203
/**********************************************************************//**
204
Commit and flush binlog from cache to binlog file */
206
handler_binlog_commit(
207
/*==================*/
208
void* my_thd, /*!< in: THD* */
209
void* my_table) /*!< in: TABLE structure */
211
THD* thd = static_cast<THD*>(my_thd);
214
tc_log->commit(thd, true);
216
trans_commit_stmt(thd);
219
/**********************************************************************//**
220
Rollback a transaction */
222
handler_binlog_rollback(
223
/*====================*/
224
void* my_thd, /*!< in: THD* */
225
void* my_table) /*!< in: TABLE structure */
227
THD* thd = static_cast<THD*>(my_thd);
230
Memcached plugin doesn't use thd_mark_transaction_to_rollback()
231
on deadlocks. So no special handling for this flag is needed.
234
tc_log->rollback(thd, true);
236
trans_rollback_stmt(thd);
239
/**********************************************************************//**
240
Binlog a truncate table statement */
242
handler_binlog_truncate(
243
/*====================*/
244
void* my_thd, /*!< in: THD* */
245
char* table_name) /*!< in: table name */
247
THD* thd = (THD*) my_thd;
248
char query_str[MAX_FULL_NAME_LEN + 16];
251
memset(query_str, 0, sizeof(query_str));
253
assert(strlen(table_name) < MAX_FULL_NAME_LEN);
255
snprintf(query_str, MAX_FULL_NAME_LEN + 16, "%s %s",
256
"truncate table", table_name);
258
len = strlen(query_str);
260
write_bin_log(thd, 1, query_str, len);
263
/**********************************************************************//**
264
Reset TABLE->record[0] */
268
void* my_table) /*!< in/out: TABLE structure */
270
empty_record(static_cast<TABLE*>(my_table));
273
/**********************************************************************//**
274
Store a string in TABLE->record[0] for field specified by "field_id" */
276
handler_rec_setup_str(
277
/*==================*/
278
void* my_table, /*!< in/out: TABLE structure */
279
int field_id, /*!< in: Field ID for the field */
280
const char* str, /*!< in: string to set */
281
int len) /*!< in: length of string */
284
TABLE* table = static_cast<TABLE*>(my_table);
286
fld = table->field[field_id];
291
fld->store(str, len, &my_charset_bin);
298
/**********************************************************************//**
299
Set up an integer field in TABLE->record[0] */
301
handler_rec_setup_int(
302
/*==================*/
303
void* my_table, /*!< in/out: TABLE structure */
304
int field_id, /*!< in: Field ID for the field */
305
int value, /*!< in: value to set */
306
bool unsigned_flag, /*!< in: whether it is unsigned */
307
bool is_null) /*!< in: whether it is null value */
310
TABLE* table = static_cast<TABLE*>(my_table);
312
fld = table->field[field_id];
318
fld->store(value, unsigned_flag);
322
/**********************************************************************//**
323
Set up an unsigned int64 field in TABLE->record[0] */
325
handler_rec_setup_uint64(
326
/*=====================*/
327
void* my_table, /*!< in/out: TABLE structure */
328
int field_id, /*!< in: Field ID for the field */
330
value, /*!< in: value to set */
331
bool unsigned_flag, /*!< in: whether it is unsigned */
332
bool is_null) /*!< in: whether it is null value */
335
TABLE* table = static_cast<TABLE*>(my_table);
337
fld = table->field[field_id];
343
fld->store(value, unsigned_flag);
347
/**********************************************************************//**
350
handler_store_record(
351
/*=================*/
352
void* my_table) /*!< in: TABLE */
354
store_record(static_cast<TABLE*>(my_table), record[1]);
357
/**********************************************************************//**
362
void* my_thd) /*!< in: THD */
364
THD* thd = static_cast<THD*>(my_thd);
366
/* destructor will not free it, because net.vio is 0. */
369
thd->release_resources();
372
/* Don't have a THD anymore */
373
my_pthread_setspecific_ptr(THR_THD, 0);
376
/**********************************************************************//**
377
Unlock a table and commit the transaction
378
return 0 if failed to commit the transaction */
380
handler_unlock_table(
381
/*=================*/
382
void* my_thd, /*!< in: thread */
383
void* my_table, /*!< in: Table metadata */
384
int mode) /*!< in: mode */
387
THD* thd = static_cast<THD*>(my_thd);
388
TABLE* table = static_cast<TABLE*>(my_table);
389
thr_lock_type lock_mode;
391
lock_mode = (mode & HDL_READ) ? TL_READ : TL_WRITE;
393
if (lock_mode == TL_WRITE) {
394
query_cache_invalidate3(thd, table, 1);
395
table->file->ha_release_auto_increment();
398
result = trans_commit_stmt(thd);
401
mysql_unlock_tables(thd, thd->lock);
404
close_mysql_tables(thd);
410
/**********************************************************************
411
Following APIs can perform DMLs through MySQL handler interface. They
412
are currently disabled and under HANDLER_API_MEMCACHED define
413
**********************************************************************/
415
#ifdef HANDLER_API_MEMCACHED
416
/**********************************************************************//**
417
Search table for a record with particular search criteria
418
@return a pointer to table->record[0] */
422
TABLE* my_table, /*!< in: TABLE structure */
423
field_arg_t* srch_args, /*!< in: field to search */
424
int idx_to_use) /*!< in: index to use */
426
KEY* key_info = &my_table->key_info[0];
427
uchar* srch_buf = new uchar[key_info->key_length];
428
size_t total_key_len = 0;
429
key_part_map part_map;
431
handler* handle = my_table->file;
433
assert(srch_args->num_arg <= key_info->key_parts);
435
for (unsigned int i = 0; i < key_info->key_parts; i++) {
436
KEY_PART_INFO* key_part;
438
key_part = &key_info->key_part[i];
440
if (i < srch_args->num_arg) {
441
int srch_len = srch_args->len[i];
443
assert(srch_len >= 0);
446
key_part->field->set_null();
448
char* srch_value = srch_args->value[i];
449
key_part->field->set_notnull();
450
key_part->field->store(srch_value,
453
total_key_len += key_part->store_length;
456
key_part->field->set_null();
460
assert(key_info->key_length >= total_key_len);
462
key_copy(srch_buf, my_table->record[0], key_info, total_key_len);
463
my_table->read_set = &my_table->s->all_set;
465
/* Max column supported is 4096 */
466
assert(srch_args->num_arg <= 4096);
468
part_map = (1 << srch_args->num_arg) - 1;
470
handle->ha_index_or_rnd_end();
471
handle->ha_index_init(idx_to_use, 1);
473
result = handle->index_read_map(my_table->record[0], srch_buf,
474
part_map, HA_READ_KEY_EXACT);
479
return(my_table->record[0]);
485
/**********************************************************************//**
486
Insert a record to the table
487
return 0 if successfully inserted */
491
TABLE* my_table, /*!< in: TABLE structure */
492
field_arg_t* store_args) /*!< in: inserting row data */
495
KEY* key_info = &(table->key_info[0]);
496
handler* handle = my_table->file;
498
empty_record(my_table);
500
assert(table->reginfo.lock_type > TL_READ
501
&& table->reginfo.lock_type <= TL_WRITE_ONLY);
503
insert_buf = my_table->record[0];
504
memset(insert_buf, 0, my_table->s->null_bytes);
506
assert(store_args->num_arg == key_info->key_parts);
508
for (unsigned int i = 0; i < key_info->key_parts; i++) {
511
fld = table->field[i];
512
if (store_args->len[i]) {
513
fld->store(store_args->value[i],
514
store_args->len[i], &my_charset_bin);
521
return(handle->ha_write_row((uchar *)my_table->record[0]));
524
/**********************************************************************//**
526
return 0 if successfully inserted */
530
TABLE* my_table, /*!< in: TABLE structure */
531
field_arg_t* store_args) /*!< in: update row data */
533
uchar* buf = my_table->record[0];
534
handler* handle = my_table->file;
535
KEY* key_info = &my_table->key_info[0];
537
store_record(my_table, record[1]);
539
for (unsigned int i = 0; i < key_info->key_parts; i++) {
542
fld = my_table->field[i];
543
fld->store(store_args->value[i],
544
store_args->len[i], &my_charset_bin);
548
return(handle->ha_update_row(my_table->record[1], buf));
551
/**********************************************************************//**
553
return 0 if successfully inserted */
557
TABLE* my_table) /*!< in: TABLE structure */
559
return(my_table->file->ha_delete_row(my_table->record[0]));
562
/**********************************************************************//**
564
return a lock structure pointer on success, NULL on error */
568
THD* my_thd, /*!< in: thread */
569
TABLE* my_table, /*!< in: Table metadata */
570
thr_lock_type lock_mode) /*!< in: lock mode */
573
my_table->reginfo.lock_type = lock_mode;
574
my_thd->lock = mysql_lock_tables(my_thd, &my_table, 1, 0);
576
return(my_thd->lock);
578
#endif /* HANDLER_API_MEMCACHED */