~ubuntu-branches/ubuntu/trusty/mysql-5.6/trusty

« back to all changes in this revision

Viewing changes to plugin/innodb_memcached/innodb_memcache/src/handler_api.cc

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2014-02-12 11:54:27 UTC
  • Revision ID: package-import@ubuntu.com-20140212115427-oq6tfsqxl1wuwehi
Tags: upstream-5.6.15
ImportĀ upstreamĀ versionĀ 5.6.15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*****************************************************************************
 
2
 
 
3
Copyright (c) 2011, 2013, Oracle and/or its affiliates. All Rights Reserved.
 
4
 
 
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.
 
8
 
 
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.
 
12
 
 
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
 
16
 
 
17
****************************************************************************/
 
18
 
 
19
/**************************************************//**
 
20
@file handler_api.c
 
21
 
 
22
Created 3/14/2011 Jimmy Yang
 
23
*******************************************************/
 
24
 
 
25
#include "handler_api.h"
 
26
 
 
27
#include <my_global.h>
 
28
#include <sql_priv.h>
 
29
#include <stdlib.h>
 
30
#include <ctype.h>
 
31
#include <mysql_version.h>
 
32
#include <mysql/plugin.h>
 
33
#include <my_dir.h>
 
34
#include "my_pthread.h"
 
35
#include "my_sys.h"
 
36
#include "m_string.h"
 
37
#include "sql_plugin.h"
 
38
#include "table.h"
 
39
#include "sql_class.h"
 
40
#include <sql_base.h>
 
41
#include "key.h"
 
42
#include "lock.h"
 
43
#include "transaction.h"
 
44
#include "sql_handler.h"
 
45
#include "handler.h"
 
46
 
 
47
#include "log_event.h"
 
48
#include "innodb_config.h"
 
49
#include "binlog.h"
 
50
 
 
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);
 
56
 
 
57
/** function to close a connection and thd, defined in sql/handler.cc */
 
58
extern void ha_close_connection(THD* thd);
 
59
 
 
60
/** binlog a row operation */
 
61
extern int binlog_log_row(TABLE*          table,
 
62
                          const uchar     *before_record,
 
63
                          const uchar     *after_record,
 
64
                          Log_func*       log_func);
 
65
 
 
66
/**********************************************************************//**
 
67
Create a THD object.
 
68
@return a pointer to the THD object, NULL if failed */
 
69
void*
 
70
handler_create_thd(
 
71
/*===============*/
 
72
        bool    enable_binlog)          /*!< in: whether to enable binlog */
 
73
{
 
74
        THD*    thd;
 
75
 
 
76
        if (enable_binlog && !binlog_enabled()) {
 
77
                fprintf(stderr, "  InnoDB_Memcached: MySQL server"
 
78
                                " binlog not enabled\n");
 
79
                return(NULL);
 
80
        }
 
81
 
 
82
        my_thread_init();
 
83
        thd = new THD;
 
84
 
 
85
        if (!thd) {
 
86
                return(NULL);
 
87
        }
 
88
 
 
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);
 
93
        thd->store_globals();
 
94
 
 
95
        if (enable_binlog) {
 
96
                thd->binlog_setup_trx_data();
 
97
 
 
98
                /* set binlog_format to "ROW" */
 
99
                thd->set_current_stmt_binlog_format_row();
 
100
        }
 
101
 
 
102
        return(thd);
 
103
}
 
104
 
 
105
/**********************************************************************//**
 
106
This is used to temporarily switch to another session, so that
 
107
POSIX thread looks like session attached to */
 
108
void
 
109
handler_thd_attach(
 
110
/*===============*/
 
111
        void*   my_thd,         /*!< in: THD* */
 
112
        void**  original_thd)   /*!< out: current THD */
 
113
{
 
114
        THD*    thd = static_cast<THD*>(my_thd);
 
115
 
 
116
        if (original_thd) {
 
117
                *original_thd = my_pthread_getspecific(THD*, THR_THD);
 
118
                assert(thd->mysys_var);
 
119
        }
 
120
 
 
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);
 
124
}
 
125
 
 
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 */
 
129
void*
 
130
handler_open_table(
 
131
/*===============*/
 
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 */
 
136
{
 
137
        TABLE_LIST              tables;
 
138
        THD*                    thd = static_cast<THD*>(my_thd);
 
139
        Open_table_context      table_ctx(thd, 0);
 
140
        thr_lock_type           lock_mode;
 
141
 
 
142
        lock_mode = (lock_type <= HDL_READ)
 
143
                     ? TL_READ
 
144
                     : TL_WRITE;
 
145
 
 
146
        tables.init_one_table(db_name, strlen(db_name), table_name,
 
147
                              strlen(table_name), table_name, lock_mode);
 
148
 
 
149
        tables.mdl_request.init(MDL_key::TABLE, db_name, table_name,
 
150
                                (lock_mode > TL_READ)
 
151
                                ? MDL_SHARED_WRITE
 
152
                                : MDL_SHARED_READ, MDL_TRANSACTION);
 
153
 
 
154
        if (!open_table(thd, &tables, &table_ctx)) {
 
155
                TABLE*  table = tables.table;
 
156
                table->use_all_columns();
 
157
                return(table);
 
158
        }
 
159
 
 
160
        return(NULL);
 
161
}
 
162
 
 
163
/**********************************************************************//**
 
164
Wrapper of function binlog_log_row() to binlog an operation on a row */
 
165
void
 
166
handler_binlog_row(
 
167
/*===============*/
 
168
        void*           my_thd,         /*!< in: THD* */
 
169
        void*           my_table,       /*!< in: TABLE structure */
 
170
        int             mode)           /*!< in: type of DML */
 
171
{
 
172
        TABLE*          table = static_cast<TABLE*>(my_table);
 
173
        THD*            thd = static_cast<THD*>(my_thd);
 
174
        Log_func*       log_func;
 
175
 
 
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);
 
180
        }
 
181
 
 
182
        switch (mode) {
 
183
        case HDL_UPDATE:
 
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],
 
188
                               log_func);
 
189
                break;
 
190
        case HDL_INSERT:
 
191
                log_func = Write_rows_log_event::binlog_row_logging_function;
 
192
                binlog_log_row(table, 0, table->record[0], log_func);
 
193
                break;
 
194
        case HDL_DELETE:
 
195
                log_func = Delete_rows_log_event::binlog_row_logging_function;
 
196
                binlog_log_row(table, table->record[0], 0, log_func);
 
197
                break;
 
198
        default:
 
199
                assert(0);
 
200
        }
 
201
}
 
202
 
 
203
/**********************************************************************//**
 
204
Commit and flush binlog from cache to binlog file */
 
205
void
 
206
handler_binlog_commit(
 
207
/*==================*/
 
208
        void*           my_thd,         /*!< in: THD* */
 
209
        void*           my_table)       /*!< in: TABLE structure */
 
210
{
 
211
        THD*            thd = static_cast<THD*>(my_thd);
 
212
 
 
213
        if (tc_log) {
 
214
                tc_log->commit(thd, true);
 
215
        }
 
216
        trans_commit_stmt(thd);
 
217
}
 
218
 
 
219
/**********************************************************************//**
 
220
Rollback a transaction */
 
221
void
 
222
handler_binlog_rollback(
 
223
/*====================*/
 
224
        void*           my_thd,         /*!< in: THD* */
 
225
        void*           my_table)       /*!< in: TABLE structure */
 
226
{
 
227
        THD*            thd = static_cast<THD*>(my_thd);
 
228
 
 
229
        /*
 
230
          Memcached plugin doesn't use thd_mark_transaction_to_rollback()
 
231
          on deadlocks. So no special handling for this flag is needed.
 
232
        */
 
233
        if (tc_log) {
 
234
                tc_log->rollback(thd, true);
 
235
        }
 
236
        trans_rollback_stmt(thd);
 
237
}
 
238
 
 
239
/**********************************************************************//**
 
240
Binlog a truncate table statement */
 
241
void
 
242
handler_binlog_truncate(
 
243
/*====================*/
 
244
        void*           my_thd,         /*!< in: THD* */
 
245
        char*           table_name)     /*!< in: table name */
 
246
{
 
247
        THD*            thd = (THD*) my_thd;
 
248
        char            query_str[MAX_FULL_NAME_LEN + 16];
 
249
        int             len;
 
250
 
 
251
        memset(query_str, 0, sizeof(query_str));
 
252
 
 
253
        assert(strlen(table_name) < MAX_FULL_NAME_LEN);
 
254
 
 
255
        snprintf(query_str, MAX_FULL_NAME_LEN + 16, "%s %s",
 
256
                 "truncate table", table_name);
 
257
 
 
258
        len = strlen(query_str);
 
259
 
 
260
        write_bin_log(thd, 1, query_str, len);
 
261
}
 
262
 
 
263
/**********************************************************************//**
 
264
Reset TABLE->record[0] */
 
265
void
 
266
handler_rec_init(
 
267
/*=============*/
 
268
        void*           my_table)       /*!< in/out: TABLE structure */
 
269
{
 
270
        empty_record(static_cast<TABLE*>(my_table));
 
271
}
 
272
 
 
273
/**********************************************************************//**
 
274
Store a string in TABLE->record[0] for field specified by "field_id" */
 
275
void
 
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 */
 
282
{
 
283
        Field*          fld;
 
284
        TABLE*          table = static_cast<TABLE*>(my_table);
 
285
 
 
286
        fld = table->field[field_id];
 
287
 
 
288
        assert(len >= 0);
 
289
 
 
290
        if (len) {
 
291
                fld->store(str, len, &my_charset_bin);
 
292
                fld->set_notnull();
 
293
        } else {
 
294
                fld->set_null();
 
295
        }
 
296
}
 
297
 
 
298
/**********************************************************************//**
 
299
Set up an integer field in TABLE->record[0] */
 
300
void
 
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 */
 
308
{
 
309
        Field*          fld;
 
310
        TABLE*          table = static_cast<TABLE*>(my_table);
 
311
 
 
312
        fld = table->field[field_id];
 
313
 
 
314
        if (is_null) {
 
315
                fld->set_null();
 
316
        } else {
 
317
                fld->set_notnull();
 
318
                fld->store(value, unsigned_flag);
 
319
        }
 
320
}
 
321
 
 
322
/**********************************************************************//**
 
323
Set up an unsigned int64 field in TABLE->record[0] */
 
324
void
 
325
handler_rec_setup_uint64(
 
326
/*=====================*/
 
327
        void*           my_table,       /*!< in/out: TABLE structure */
 
328
        int             field_id,       /*!< in: Field ID for the field */
 
329
        unsigned long long
 
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 */
 
333
{
 
334
        Field*          fld;
 
335
        TABLE*          table = static_cast<TABLE*>(my_table);
 
336
 
 
337
        fld = table->field[field_id];
 
338
 
 
339
        if (is_null) {
 
340
                fld->set_null();
 
341
        } else {
 
342
                fld->set_notnull();
 
343
                fld->store(value, unsigned_flag);
 
344
        }
 
345
}
 
346
 
 
347
/**********************************************************************//**
 
348
Store a record */
 
349
void
 
350
handler_store_record(
 
351
/*=================*/
 
352
        void*           my_table)       /*!< in: TABLE */
 
353
{
 
354
        store_record(static_cast<TABLE*>(my_table), record[1]);
 
355
}
 
356
 
 
357
/**********************************************************************//**
 
358
Close the handler */
 
359
void
 
360
handler_close_thd(
 
361
/*==============*/
 
362
        void*           my_thd)         /*!< in: THD */
 
363
{
 
364
        THD*    thd = static_cast<THD*>(my_thd);
 
365
 
 
366
        /* destructor will not free it, because net.vio is 0. */
 
367
        net_end(&thd->net);
 
368
 
 
369
        thd->release_resources();
 
370
        delete (thd);
 
371
 
 
372
        /* Don't have a THD anymore */
 
373
        my_pthread_setspecific_ptr(THR_THD,  0);
 
374
}
 
375
 
 
376
/**********************************************************************//**
 
377
Unlock a table and commit the transaction
 
378
return 0 if failed to commit the transaction */
 
379
int
 
380
handler_unlock_table(
 
381
/*=================*/
 
382
        void*           my_thd,         /*!< in: thread */
 
383
        void*           my_table,       /*!< in: Table metadata */
 
384
        int             mode)           /*!< in: mode */
 
385
{
 
386
        int                     result;
 
387
        THD*                    thd = static_cast<THD*>(my_thd);
 
388
        TABLE*                  table = static_cast<TABLE*>(my_table);
 
389
        thr_lock_type           lock_mode;
 
390
 
 
391
        lock_mode = (mode & HDL_READ) ? TL_READ : TL_WRITE;
 
392
 
 
393
        if (lock_mode == TL_WRITE) {
 
394
                query_cache_invalidate3(thd, table, 1);
 
395
                table->file->ha_release_auto_increment();
 
396
        }
 
397
 
 
398
        result = trans_commit_stmt(thd);
 
399
 
 
400
        if (thd->lock) {
 
401
                mysql_unlock_tables(thd, thd->lock);
 
402
        }
 
403
 
 
404
        close_mysql_tables(thd);
 
405
        thd->lock = 0;
 
406
 
 
407
        return(result);
 
408
}
 
409
 
 
410
/**********************************************************************
 
411
Following APIs can perform DMLs through MySQL handler interface. They
 
412
are currently disabled and under HANDLER_API_MEMCACHED define
 
413
**********************************************************************/
 
414
 
 
415
#ifdef HANDLER_API_MEMCACHED
 
416
/**********************************************************************//**
 
417
Search table for a record with particular search criteria
 
418
@return a pointer to table->record[0] */
 
419
uchar*
 
420
handler_select_rec(
 
421
/*===============*/
 
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 */
 
425
{
 
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;
 
430
        int             result;
 
431
        handler*        handle = my_table->file;
 
432
 
 
433
        assert(srch_args->num_arg <= key_info->key_parts);
 
434
 
 
435
        for (unsigned int i = 0; i < key_info->key_parts; i++) {
 
436
                KEY_PART_INFO*  key_part;
 
437
 
 
438
                key_part = &key_info->key_part[i];
 
439
 
 
440
                if (i < srch_args->num_arg) {
 
441
                        int     srch_len = srch_args->len[i];
 
442
 
 
443
                        assert(srch_len >= 0);
 
444
 
 
445
                        if (srch_len != 0) {
 
446
                                key_part->field->set_null();
 
447
                        } else {
 
448
                                char*   srch_value = srch_args->value[i];
 
449
                                key_part->field->set_notnull();
 
450
                                key_part->field->store(srch_value,
 
451
                                                       srch_len,
 
452
                                                       &my_charset_bin);
 
453
                                total_key_len += key_part->store_length;
 
454
                        }
 
455
                } else {
 
456
                        key_part->field->set_null();
 
457
                }
 
458
        }
 
459
 
 
460
        assert(key_info->key_length >= total_key_len);
 
461
 
 
462
        key_copy(srch_buf, my_table->record[0], key_info, total_key_len);
 
463
        my_table->read_set = &my_table->s->all_set;
 
464
 
 
465
        /* Max column supported is 4096 */
 
466
        assert(srch_args->num_arg <= 4096);
 
467
 
 
468
        part_map = (1 << srch_args->num_arg) - 1;
 
469
 
 
470
        handle->ha_index_or_rnd_end();
 
471
        handle->ha_index_init(idx_to_use, 1);
 
472
 
 
473
        result = handle->index_read_map(my_table->record[0], srch_buf,
 
474
                                        part_map, HA_READ_KEY_EXACT);
 
475
 
 
476
        delete[] srch_buf;
 
477
 
 
478
        if (!result) {
 
479
                return(my_table->record[0]);
 
480
        }
 
481
 
 
482
        return(NULL);
 
483
}
 
484
 
 
485
/**********************************************************************//**
 
486
Insert a record to the table
 
487
return 0 if successfully inserted */
 
488
int
 
489
handler_insert_rec(
 
490
/*===============*/
 
491
        TABLE*          my_table,       /*!< in: TABLE structure */
 
492
        field_arg_t*    store_args)     /*!< in: inserting row data */
 
493
{
 
494
        uchar*          insert_buf;
 
495
        KEY*            key_info = &(table->key_info[0]);
 
496
        handler*        handle = my_table->file;
 
497
 
 
498
        empty_record(my_table);
 
499
 
 
500
        assert(table->reginfo.lock_type > TL_READ
 
501
               && table->reginfo.lock_type <= TL_WRITE_ONLY);
 
502
 
 
503
        insert_buf = my_table->record[0];
 
504
        memset(insert_buf, 0, my_table->s->null_bytes);
 
505
 
 
506
        assert(store_args->num_arg == key_info->key_parts);
 
507
 
 
508
        for (unsigned int i = 0; i < key_info->key_parts; i++) {
 
509
                Field*          fld;
 
510
 
 
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);
 
515
                        fld->set_notnull();
 
516
                } else {
 
517
                        fld->set_null();
 
518
                }
 
519
        }
 
520
 
 
521
        return(handle->ha_write_row((uchar *)my_table->record[0]));
 
522
}
 
523
 
 
524
/**********************************************************************//**
 
525
Update a record
 
526
return 0 if successfully inserted */
 
527
int
 
528
handler_update_rec(
 
529
/*===============*/
 
530
        TABLE*          my_table,       /*!< in: TABLE structure */
 
531
        field_arg_t*    store_args)     /*!< in: update row data */
 
532
{
 
533
        uchar*          buf = my_table->record[0];
 
534
        handler*        handle = my_table->file;
 
535
        KEY*            key_info = &my_table->key_info[0];
 
536
 
 
537
        store_record(my_table, record[1]);
 
538
 
 
539
        for (unsigned int i = 0; i < key_info->key_parts; i++) {
 
540
                Field*          fld;
 
541
 
 
542
                fld = my_table->field[i];
 
543
                fld->store(store_args->value[i],
 
544
                           store_args->len[i], &my_charset_bin);
 
545
                fld->set_notnull();
 
546
        }
 
547
 
 
548
        return(handle->ha_update_row(my_table->record[1], buf));
 
549
}
 
550
 
 
551
/**********************************************************************//**
 
552
Delete a record
 
553
return 0 if successfully inserted */
 
554
int
 
555
handler_delete_rec(
 
556
/*===============*/
 
557
        TABLE*          my_table)       /*!< in: TABLE structure */
 
558
{
 
559
        return(my_table->file->ha_delete_row(my_table->record[0]));
 
560
}
 
561
 
 
562
/**********************************************************************//**
 
563
Lock a table
 
564
return a lock structure pointer on success, NULL on error */
 
565
MYSQL_LOCK *
 
566
handler_lock_table(
 
567
/*===============*/
 
568
        THD*            my_thd,         /*!< in: thread */
 
569
        TABLE*          my_table,       /*!< in: Table metadata */
 
570
        thr_lock_type   lock_mode)      /*!< in: lock mode */
 
571
{
 
572
 
 
573
        my_table->reginfo.lock_type = lock_mode;
 
574
        my_thd->lock = mysql_lock_tables(my_thd, &my_table, 1, 0);
 
575
 
 
576
        return(my_thd->lock);
 
577
}
 
578
#endif /* HANDLER_API_MEMCACHED */