~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/innobase/handler/ha_innodb.cc

Merge Monty.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*****************************************************************************
 
2
 
 
3
Copyright (c) 2000, 2009, MySQL AB & Innobase Oy. All Rights Reserved.
 
4
Copyright (c) 2008, 2009 Google Inc.
 
5
 
 
6
Portions of this file contain modifications contributed and copyrighted by
 
7
Google, Inc. Those modifications are gratefully acknowledged and are described
 
8
briefly in the InnoDB documentation. The contributions by Google are
 
9
incorporated with their permission, and subject to the conditions contained in
 
10
the file COPYING.Google.
 
11
 
 
12
This program is free software; you can redistribute it and/or modify it under
 
13
the terms of the GNU General Public License as published by the Free Software
 
14
Foundation; version 2 of the License.
 
15
 
 
16
This program is distributed in the hope that it will be useful, but WITHOUT
 
17
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 
18
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 
19
 
 
20
You should have received a copy of the GNU General Public License along with
 
21
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 
22
Place, Suite 330, Boston, MA 02111-1307 USA
 
23
 
 
24
*****************************************************************************/
 
25
/***********************************************************************
 
26
 
 
27
Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved.
 
28
Copyright (c) 2009, Percona Inc.
 
29
 
 
30
Portions of this file contain modifications contributed and copyrighted
 
31
by Percona Inc.. Those modifications are
 
32
gratefully acknowledged and are described briefly in the InnoDB
 
33
documentation. The contributions by Percona Inc. are incorporated with
 
34
their permission, and subject to the conditions contained in the file
 
35
COPYING.Percona.
 
36
 
 
37
This program is free software; you can redistribute it and/or modify it
 
38
under the terms of the GNU General Public License as published by the
 
39
Free Software Foundation; version 2 of the License.
 
40
 
 
41
This program is distributed in the hope that it will be useful, but
 
42
WITHOUT ANY WARRANTY; without even the implied warranty of
 
43
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 
44
Public License for more details.
 
45
 
 
46
You should have received a copy of the GNU General Public License along
 
47
with this program; if not, write to the Free Software Foundation, Inc.,
 
48
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
49
 
 
50
***********************************************************************/
 
51
 
 
52
/* TODO list for the InnoDB Cursor in 5.0:
 
53
  - Remove the flag trx->active_trans and look at trx->conc_state
 
54
  - fix savepoint functions to use savepoint storage area
 
55
  - Find out what kind of problems the OS X case-insensitivity causes to
 
56
    table and database names; should we 'normalize' the names like we do
 
57
    in Windows?
 
58
*/
 
59
 
 
60
#include "config.h"
 
61
 
 
62
#include <limits.h>
 
63
#include <fcntl.h>
 
64
 
 
65
#include "drizzled/error.h"
 
66
#include "drizzled/errmsg_print.h"
 
67
#include "drizzled/charset_info.h"
 
68
#include "drizzled/internal/m_string.h"
 
69
#include "drizzled/internal/my_sys.h"
 
70
#include "drizzled/my_hash.h"
 
71
#include "drizzled/my_error.h"
 
72
#include "drizzled/plugin.h"
 
73
#include "drizzled/show.h"
 
74
#include "drizzled/data_home.h"
 
75
#include "drizzled/error.h"
 
76
#include "drizzled/field.h"
 
77
#include "drizzled/charset.h"
 
78
#include "drizzled/session.h"
 
79
#include "drizzled/current_session.h"
 
80
#include "drizzled/table.h"
 
81
#include "drizzled/field/blob.h"
 
82
#include "drizzled/field/varstring.h"
 
83
#include "drizzled/field/timestamp.h"
 
84
#include "drizzled/plugin/storage_engine.h"
 
85
#include "drizzled/plugin/info_schema_table.h"
 
86
#include "drizzled/memory/multi_malloc.h"
 
87
#include "drizzled/pthread_globals.h"
 
88
 
 
89
/** @file ha_innodb.cc */
 
90
 
 
91
/* Include necessary InnoDB headers */
 
92
extern "C" {
 
93
#include "univ.i"
 
94
#include "btr0sea.h"
 
95
#include "os0file.h"
 
96
#include "os0thread.h"
 
97
#include "srv0start.h"
 
98
#include "srv0srv.h"
 
99
#include "trx0roll.h"
 
100
#include "trx0trx.h"
 
101
#include "trx0sys.h"
 
102
#include "mtr0mtr.h"
 
103
#include "row0ins.h"
 
104
#include "row0mysql.h"
 
105
#include "row0sel.h"
 
106
#include "row0upd.h"
 
107
#include "log0log.h"
 
108
#include "lock0lock.h"
 
109
#include "dict0crea.h"
 
110
#include "btr0cur.h"
 
111
#include "btr0btr.h"
 
112
#include "fsp0fsp.h"
 
113
#include "sync0sync.h"
 
114
#include "fil0fil.h"
 
115
#include "trx0xa.h"
 
116
#include "row0merge.h"
 
117
#include "thr0loc.h"
 
118
#include "dict0boot.h"
 
119
#include "ha_prototypes.h"
 
120
#include "ut0mem.h"
 
121
#include "ibuf0ibuf.h"
 
122
}
 
123
 
 
124
#include "ha_innodb.h"
 
125
#include "i_s.h"
 
126
#include "handler0vars.h"
 
127
 
 
128
#include <string>
 
129
 
 
130
using namespace std;
 
131
 
 
132
 
 
133
#ifndef DRIZZLE_SERVER
 
134
/* This is needed because of Bug #3596.  Let us hope that pthread_mutex_t
 
135
is defined the same in both builds: the MySQL server and the InnoDB plugin. */
 
136
extern pthread_mutex_t LOCK_thread_count;
 
137
 
 
138
#endif /* DRIZZLE_SERVER */
 
139
 
 
140
/** to protect innobase_open_files */
 
141
static pthread_mutex_t innobase_share_mutex;
 
142
/** to force correct commit order in binlog */
 
143
static pthread_mutex_t prepare_commit_mutex;
 
144
static ulong commit_threads = 0;
 
145
static pthread_mutex_t commit_threads_m;
 
146
static pthread_cond_t commit_cond;
 
147
static pthread_mutex_t commit_cond_m;
 
148
static bool innodb_inited = 0;
 
149
 
 
150
#define INSIDE_HA_INNOBASE_CC
 
151
 
 
152
/* In the Windows plugin, the return value of current_session is
 
153
undefined.  Map it to NULL. */
 
154
#if defined MYSQL_DYNAMIC_PLUGIN && defined __WIN__
 
155
# undef current_session
 
156
# define current_session NULL
 
157
# define EQ_CURRENT_SESSION(session) TRUE
 
158
#else /* MYSQL_DYNAMIC_PLUGIN && __WIN__ */
 
159
# define EQ_CURRENT_SESSION(session) ((session) == current_session)
 
160
#endif /* MYSQL_DYNAMIC_PLUGIN && __WIN__ */
 
161
 
 
162
static drizzled::plugin::StorageEngine* innodb_engine_ptr= NULL;
 
163
 
 
164
static const long AUTOINC_OLD_STYLE_LOCKING = 0;
 
165
static const long AUTOINC_NEW_STYLE_LOCKING = 1;
 
166
static const long AUTOINC_NO_LOCKING = 2;
 
167
 
 
168
static long innobase_mirrored_log_groups, innobase_log_files_in_group,
 
169
        innobase_log_buffer_size,
 
170
        innobase_additional_mem_pool_size, innobase_file_io_threads,
 
171
        innobase_force_recovery, innobase_open_files,
 
172
        innobase_autoinc_lock_mode;
 
173
static ulong innobase_commit_concurrency = 0;
 
174
static ulong innobase_read_io_threads;
 
175
static ulong innobase_write_io_threads;
 
176
 
 
177
/**
 
178
 * @TODO: Turn this into size_t as soon as we have a Variable<size_t>
 
179
 */
 
180
static int64_t innobase_buffer_pool_size, innobase_log_file_size;
 
181
 
 
182
/* The default values for the following char* start-up parameters
 
183
are determined in innobase_init below: */
 
184
 
 
185
static char*    innobase_data_home_dir                  = NULL;
 
186
static char*    innobase_data_file_path                 = NULL;
 
187
static char*    innobase_log_group_home_dir             = NULL;
 
188
static char*    innobase_file_format_name               = NULL;
 
189
static char*    innobase_change_buffering               = NULL;
 
190
 
 
191
/* Note: This variable can be set to on/off and any of the supported
 
192
file formats in the configuration file, but can only be set to any
 
193
of the supported file formats during runtime. */
 
194
static char*    innobase_file_format_check              = NULL;
 
195
 
 
196
/* The following has a misleading name: starting from 4.0.5, this also
 
197
affects Windows: */
 
198
static char*    innobase_unix_file_flush_method         = NULL;
 
199
 
 
200
/* Below we have boolean-valued start-up parameters, and their default
 
201
values */
 
202
 
 
203
static ulong    innobase_fast_shutdown                  = 1;
 
204
#ifdef UNIV_LOG_ARCHIVE
 
205
static my_bool  innobase_log_archive                    = FALSE;
 
206
static char*    innobase_log_arch_dir                   = NULL;
 
207
#endif /* UNIV_LOG_ARCHIVE */
 
208
static my_bool  innobase_use_doublewrite                = TRUE;
 
209
static my_bool  innobase_use_checksums                  = TRUE;
 
210
static my_bool  innobase_locks_unsafe_for_binlog        = TRUE;
 
211
static my_bool  innobase_rollback_on_timeout            = FALSE;
 
212
static my_bool  innobase_create_status_file             = FALSE;
 
213
static my_bool  innobase_stats_on_metadata              = TRUE;
 
214
 
 
215
static char*    internal_innobase_data_file_path        = NULL;
 
216
 
 
217
static char*    innodb_version_str = (char*) INNODB_VERSION_STR;
 
218
 
 
219
/* The following counter is used to convey information to InnoDB
 
220
about server activity: in selects it is not sensible to call
 
221
srv_active_wake_master_thread after each fetch or search, we only do
 
222
it every INNOBASE_WAKE_INTERVAL'th step. */
 
223
 
 
224
#define INNOBASE_WAKE_INTERVAL  32
 
225
static ulong    innobase_active_counter = 0;
 
226
 
 
227
static hash_table_t*    innobase_open_tables;
 
228
 
 
229
#ifdef __NETWARE__      /* some special cleanup for NetWare */
 
230
bool nw_panic = FALSE;
 
231
#endif
 
232
 
 
233
/** Allowed values of innodb_change_buffering */
 
234
static const char* innobase_change_buffering_values[IBUF_USE_COUNT] = {
 
235
        "none",         /* IBUF_USE_NONE */
 
236
        "inserts"       /* IBUF_USE_INSERT */
 
237
};
 
238
 
 
239
/********************************************************************
 
240
Gives the file extension of an InnoDB single-table tablespace. */
 
241
static const char* ha_innobase_exts[] = {
 
242
  ".ibd",
 
243
  NULL
 
244
};
 
245
 
 
246
static INNOBASE_SHARE *get_share(const char *table_name);
 
247
static void free_share(INNOBASE_SHARE *share);
 
248
 
 
249
class InnobaseEngine : public drizzled::plugin::StorageEngine
 
250
{
 
251
public:
 
252
  InnobaseEngine(string name_arg)
 
253
   : drizzled::plugin::StorageEngine(name_arg,
 
254
                                     HTON_NULL_IN_KEY |
 
255
                                     HTON_CAN_INDEX_BLOBS |
 
256
                                     HTON_PRIMARY_KEY_REQUIRED_FOR_POSITION |
 
257
                                     HTON_PRIMARY_KEY_IN_READ_INDEX |
 
258
                                     HTON_PARTIAL_COLUMN_READ |
 
259
                                     HTON_TABLE_SCAN_ON_INDEX |
 
260
                                     HTON_MRR_CANT_SORT |
 
261
                                     HTON_HAS_DOES_TRANSACTIONS, sizeof(trx_named_savept_t))
 
262
  {
 
263
    table_definition_ext= drizzled::plugin::DEFAULT_DEFINITION_FILE_EXT;
 
264
    addAlias("INNOBASE");
 
265
  }
 
266
 
 
267
  virtual
 
268
  int
 
269
  close_connection(
 
270
/*======================*/
 
271
                        /* out: 0 or error number */
 
272
        Session*        session);       /* in: handle to the MySQL thread of the user
 
273
                        whose resources should be free'd */
 
274
 
 
275
  virtual int savepoint_set_hook(Session* session,
 
276
                                 void *savepoint);
 
277
  virtual int savepoint_rollback_hook(Session* session,
 
278
                                      void *savepoint);
 
279
  virtual int savepoint_release_hook(Session* session,
 
280
                                     void *savepoint);
 
281
  virtual int commit(Session* session, bool all);
 
282
  virtual int rollback(Session* session, bool all);
 
283
 
 
284
  /***********************************************************************
 
285
  This function is used to prepare X/Open XA distributed transaction   */
 
286
  virtual
 
287
  int
 
288
  prepare(
 
289
  /*================*/
 
290
                        /* out: 0 or error number */
 
291
        Session*        session,        /* in: handle to the MySQL thread of the user
 
292
                        whose XA transaction should be prepared */
 
293
        bool    all);   /* in: TRUE - commit transaction
 
294
                        FALSE - the current SQL statement ended */
 
295
  /***********************************************************************
 
296
  This function is used to recover X/Open XA distributed transactions   */
 
297
  virtual
 
298
  int
 
299
  recover(
 
300
  /*================*/
 
301
                                /* out: number of prepared transactions
 
302
                                stored in xid_list */
 
303
        XID*    xid_list,       /* in/out: prepared transactions */
 
304
        uint    len);           /* in: number of slots in xid_list */
 
305
  /***********************************************************************
 
306
  This function is used to commit one X/Open XA distributed transaction
 
307
  which is in the prepared state */
 
308
  virtual
 
309
  int
 
310
  commit_by_xid(
 
311
  /*===================*/
 
312
                        /* out: 0 or error number */
 
313
        XID*    xid);   /* in: X/Open XA transaction identification */
 
314
  /***********************************************************************
 
315
  This function is used to rollback one X/Open XA distributed transaction
 
316
  which is in the prepared state */
 
317
  virtual
 
318
  int
 
319
  rollback_by_xid(
 
320
  /*=====================*/
 
321
                        /* out: 0 or error number */
 
322
        XID     *xid);  /* in: X/Open XA transaction identification */
 
323
 
 
324
  virtual Cursor *create(TableShare &table,
 
325
                         drizzled::memory::Root *mem_root)
 
326
  {
 
327
    return new (mem_root) ha_innobase(*this, table);
 
328
  }
 
329
 
 
330
  /*********************************************************************
 
331
  Removes all tables in the named database inside InnoDB. */
 
332
  virtual
 
333
  void
 
334
  drop_database(
 
335
  /*===================*/
 
336
                        /* out: error number */
 
337
        char*   path);  /* in: database path; inside InnoDB the name
 
338
                        of the last directory in the path is used as
 
339
                        the database name: for example, in 'mysql/data/test'
 
340
                        the database name is 'test' */
 
341
 
 
342
  /*********************************************************************
 
343
  Creates an InnoDB transaction struct for the session if it does not yet have one.
 
344
  Starts a new InnoDB transaction if a transaction is not yet started. And
 
345
  assigns a new snapshot for a consistent read if the transaction does not yet
 
346
  have one. */
 
347
  virtual
 
348
  int
 
349
  start_consistent_snapshot(
 
350
  /*====================================*/
 
351
                        /* out: 0 */
 
352
        Session*        session);       /* in: MySQL thread handle of the user for whom
 
353
                        the transaction should be committed */
 
354
  /********************************************************************
 
355
  Flushes InnoDB logs to disk and makes a checkpoint. Really, a commit flushes
 
356
  the logs, and the name of this function should be innobase_checkpoint. */
 
357
  virtual
 
358
  bool
 
359
  flush_logs();
 
360
  /*================*/
 
361
                                /* out: TRUE if error */
 
362
  
 
363
  /****************************************************************************
 
364
  Implements the SHOW INNODB STATUS command. Sends the output of the InnoDB
 
365
  Monitor to the client. */
 
366
  virtual
 
367
  bool
 
368
  show_status(
 
369
  /*===============*/
 
370
        Session*        session,        /* in: the MySQL query thread of the caller */
 
371
        stat_print_fn *stat_print,
 
372
        enum ha_stat_type stat_type);
 
373
 
 
374
  virtual
 
375
  int
 
376
  release_temporary_latches(
 
377
  /*===============================*/
 
378
                                /* out: 0 */
 
379
        Session*                session);       /* in: MySQL thread */
 
380
 
 
381
 
 
382
  const char** bas_ext() const {
 
383
        return(ha_innobase_exts);
 
384
  }
 
385
 
 
386
  UNIV_INTERN int doCreateTable(Session *session,
 
387
                                const char *table_name,
 
388
                                Table& form,
 
389
                                drizzled::message::Table&);
 
390
  UNIV_INTERN int doRenameTable(Session* session,
 
391
                                const char* from,
 
392
                                const char* to);
 
393
  UNIV_INTERN int doDropTable(Session& session, const string table_path);
 
394
 
 
395
  UNIV_INTERN virtual bool get_error_message(int error, String *buf);
 
396
 
 
397
  UNIV_INTERN uint32_t max_supported_keys() const;
 
398
  UNIV_INTERN uint32_t max_supported_key_length() const;
 
399
  UNIV_INTERN uint32_t max_supported_key_part_length() const;
 
400
 
 
401
 
 
402
  UNIV_INTERN uint32_t index_flags(enum  ha_key_alg) const
 
403
  {
 
404
    return (HA_READ_NEXT |
 
405
            HA_READ_PREV |
 
406
            HA_READ_ORDER |
 
407
            HA_READ_RANGE |
 
408
            HA_KEYREAD_ONLY);
 
409
  }
 
410
};
 
411
 
 
412
/** @brief Initialize the default value of innodb_commit_concurrency.
 
413
 
 
414
Once InnoDB is running, the innodb_commit_concurrency must not change
 
415
from zero to nonzero. (Bug #42101)
 
416
 
 
417
The initial default value is 0, and without this extra initialization,
 
418
SET GLOBAL innodb_commit_concurrency=DEFAULT would set the parameter
 
419
to 0, even if it was initially set to nonzero at the command line
 
420
or configuration file. */
 
421
static
 
422
void
 
423
innobase_commit_concurrency_init_default(void);
 
424
/*==========================================*/
 
425
 
 
426
/************************************************************//**
 
427
Validate the file format name and return its corresponding id.
 
428
@return valid file format id */
 
429
static
 
430
uint
 
431
innobase_file_format_name_lookup(
 
432
/*=============================*/
 
433
        const char*     format_name);           /*!< in: pointer to file format
 
434
                                                name */
 
435
/************************************************************//**
 
436
Validate the file format check config parameters, as a side effect it
 
437
sets the srv_check_file_format_at_startup variable.
 
438
@return true if one of  "on" or "off" */
 
439
static
 
440
bool
 
441
innobase_file_format_check_on_off(
 
442
/*==============================*/
 
443
        const char*     format_check);          /*!< in: parameter value */
 
444
/************************************************************//**
 
445
Validate the file format check config parameters, as a side effect it
 
446
sets the srv_check_file_format_at_startup variable.
 
447
@return true if valid config value */
 
448
static
 
449
bool
 
450
innobase_file_format_check_validate(
 
451
/*================================*/
 
452
        const char*     format_check);          /*!< in: parameter value */
 
453
 
 
454
static const char innobase_engine_name[]= "InnoDB";
 
455
 
 
456
/*************************************************************//**
 
457
Check for a valid value of innobase_commit_concurrency.
 
458
@return 0 for valid innodb_commit_concurrency */
 
459
static
 
460
int
 
461
innobase_commit_concurrency_validate(
 
462
/*=================================*/
 
463
        Session*                        ,       /*!< in: thread handle */
 
464
        drizzle_sys_var*        ,       /*!< in: pointer to system
 
465
                                                variable */
 
466
        void*                           save,   /*!< out: immediate result
 
467
                                                for update function */
 
468
        drizzle_value*          value)  /*!< in: incoming string */
 
469
{
 
470
        int64_t         intbuf;
 
471
        ulong           commit_concurrency;
 
472
 
 
473
        if (value->val_int(value, &intbuf)) {
 
474
                /* The value is NULL. That is invalid. */
 
475
                return(1);
 
476
        }
 
477
 
 
478
        *reinterpret_cast<ulong*>(save) = commit_concurrency
 
479
                = static_cast<ulong>(intbuf);
 
480
 
 
481
        /* Allow the value to be updated, as long as it remains zero
 
482
        or nonzero. */
 
483
        return(!(!commit_concurrency == !innobase_commit_concurrency));
 
484
}
 
485
 
 
486
static DRIZZLE_SessionVAR_BOOL(support_xa, PLUGIN_VAR_OPCMDARG,
 
487
  "Enable InnoDB support for the XA two-phase commit",
 
488
  /* check_func */ NULL, /* update_func */ NULL,
 
489
  /* default */ TRUE);
 
490
 
 
491
static DRIZZLE_SessionVAR_BOOL(table_locks, PLUGIN_VAR_OPCMDARG,
 
492
  "Enable InnoDB locking in LOCK TABLES",
 
493
  /* check_func */ NULL, /* update_func */ NULL,
 
494
  /* default */ TRUE);
 
495
 
 
496
static DRIZZLE_SessionVAR_BOOL(strict_mode, PLUGIN_VAR_OPCMDARG,
 
497
  "Use strict mode when evaluating create options.",
 
498
  NULL, NULL, FALSE);
 
499
 
 
500
static DRIZZLE_SessionVAR_ULONG(lock_wait_timeout, PLUGIN_VAR_RQCMDARG,
 
501
  "Timeout in seconds an InnoDB transaction may wait for a lock before being rolled back. Values above 100000000 disable the timeout.",
 
502
  NULL, NULL, 50, 1, 1024 * 1024 * 1024, 0);
 
503
 
 
504
 
 
505
/***********************************************************************
 
506
Closes an InnoDB database. */
 
507
static
 
508
int
 
509
innobase_deinit(drizzled::plugin::Registry &registry);
 
510
 
 
511
/*****************************************************************//**
 
512
Commits a transaction in an InnoDB database. */
 
513
static
 
514
void
 
515
innobase_commit_low(
 
516
/*================*/
 
517
        trx_t*  trx);   /*!< in: transaction handle */
 
518
 
 
519
static SHOW_VAR innodb_status_variables[]= {
 
520
  {"buffer_pool_pages_data",
 
521
  (char*) &export_vars.innodb_buffer_pool_pages_data,     SHOW_LONG},
 
522
  {"buffer_pool_pages_dirty",
 
523
  (char*) &export_vars.innodb_buffer_pool_pages_dirty,    SHOW_LONG},
 
524
  {"buffer_pool_pages_flushed",
 
525
  (char*) &export_vars.innodb_buffer_pool_pages_flushed,  SHOW_LONG},
 
526
  {"buffer_pool_pages_free",
 
527
  (char*) &export_vars.innodb_buffer_pool_pages_free,     SHOW_LONG},
 
528
#ifdef UNIV_DEBUG
 
529
  {"buffer_pool_pages_latched",
 
530
  (char*) &export_vars.innodb_buffer_pool_pages_latched,  SHOW_LONG},
 
531
#endif /* UNIV_DEBUG */
 
532
  {"buffer_pool_pages_misc",
 
533
  (char*) &export_vars.innodb_buffer_pool_pages_misc,     SHOW_LONG},
 
534
  {"buffer_pool_pages_total",
 
535
  (char*) &export_vars.innodb_buffer_pool_pages_total,    SHOW_LONG},
 
536
  {"buffer_pool_read_ahead_rnd",
 
537
  (char*) &export_vars.innodb_buffer_pool_read_ahead_rnd, SHOW_LONG},
 
538
  {"buffer_pool_read_ahead_seq",
 
539
  (char*) &export_vars.innodb_buffer_pool_read_ahead_seq, SHOW_LONG},
 
540
  {"buffer_pool_read_requests",
 
541
  (char*) &export_vars.innodb_buffer_pool_read_requests,  SHOW_LONG},
 
542
  {"buffer_pool_reads",
 
543
  (char*) &export_vars.innodb_buffer_pool_reads,          SHOW_LONG},
 
544
  {"buffer_pool_wait_free",
 
545
  (char*) &export_vars.innodb_buffer_pool_wait_free,      SHOW_LONG},
 
546
  {"buffer_pool_write_requests",
 
547
  (char*) &export_vars.innodb_buffer_pool_write_requests, SHOW_LONG},
 
548
  {"data_fsyncs",
 
549
  (char*) &export_vars.innodb_data_fsyncs,                SHOW_LONG},
 
550
  {"data_pending_fsyncs",
 
551
  (char*) &export_vars.innodb_data_pending_fsyncs,        SHOW_LONG},
 
552
  {"data_pending_reads",
 
553
  (char*) &export_vars.innodb_data_pending_reads,         SHOW_LONG},
 
554
  {"data_pending_writes",
 
555
  (char*) &export_vars.innodb_data_pending_writes,        SHOW_LONG},
 
556
  {"data_read",
 
557
  (char*) &export_vars.innodb_data_read,                  SHOW_LONG},
 
558
  {"data_reads",
 
559
  (char*) &export_vars.innodb_data_reads,                 SHOW_LONG},
 
560
  {"data_writes",
 
561
  (char*) &export_vars.innodb_data_writes,                SHOW_LONG},
 
562
  {"data_written",
 
563
  (char*) &export_vars.innodb_data_written,               SHOW_LONG},
 
564
  {"dblwr_pages_written",
 
565
  (char*) &export_vars.innodb_dblwr_pages_written,        SHOW_LONG},
 
566
  {"dblwr_writes",
 
567
  (char*) &export_vars.innodb_dblwr_writes,               SHOW_LONG},
 
568
  {"have_atomic_builtins",
 
569
  (char*) &export_vars.innodb_have_atomic_builtins,       SHOW_BOOL},
 
570
  {"log_waits",
 
571
  (char*) &export_vars.innodb_log_waits,                  SHOW_LONG},
 
572
  {"log_write_requests",
 
573
  (char*) &export_vars.innodb_log_write_requests,         SHOW_LONG},
 
574
  {"log_writes",
 
575
  (char*) &export_vars.innodb_log_writes,                 SHOW_LONG},
 
576
  {"os_log_fsyncs",
 
577
  (char*) &export_vars.innodb_os_log_fsyncs,              SHOW_LONG},
 
578
  {"os_log_pending_fsyncs",
 
579
  (char*) &export_vars.innodb_os_log_pending_fsyncs,      SHOW_LONG},
 
580
  {"os_log_pending_writes",
 
581
  (char*) &export_vars.innodb_os_log_pending_writes,      SHOW_LONG},
 
582
  {"os_log_written",
 
583
  (char*) &export_vars.innodb_os_log_written,             SHOW_LONG},
 
584
  {"page_size",
 
585
  (char*) &export_vars.innodb_page_size,                  SHOW_LONG},
 
586
  {"pages_created",
 
587
  (char*) &export_vars.innodb_pages_created,              SHOW_LONG},
 
588
  {"pages_read",
 
589
  (char*) &export_vars.innodb_pages_read,                 SHOW_LONG},
 
590
  {"pages_written",
 
591
  (char*) &export_vars.innodb_pages_written,              SHOW_LONG},
 
592
  {"row_lock_current_waits",
 
593
  (char*) &export_vars.innodb_row_lock_current_waits,     SHOW_LONG},
 
594
  {"row_lock_time",
 
595
  (char*) &export_vars.innodb_row_lock_time,              SHOW_LONGLONG},
 
596
  {"row_lock_time_avg",
 
597
  (char*) &export_vars.innodb_row_lock_time_avg,          SHOW_LONG},
 
598
  {"row_lock_time_max",
 
599
  (char*) &export_vars.innodb_row_lock_time_max,          SHOW_LONG},
 
600
  {"row_lock_waits",
 
601
  (char*) &export_vars.innodb_row_lock_waits,             SHOW_LONG},
 
602
  {"rows_deleted",
 
603
  (char*) &export_vars.innodb_rows_deleted,               SHOW_LONG},
 
604
  {"rows_inserted",
 
605
  (char*) &export_vars.innodb_rows_inserted,              SHOW_LONG},
 
606
  {"rows_read",
 
607
  (char*) &export_vars.innodb_rows_read,                  SHOW_LONG},
 
608
  {"rows_updated",
 
609
  (char*) &export_vars.innodb_rows_updated,               SHOW_LONG},
 
610
  {NULL, NULL, SHOW_LONG}
 
611
};
 
612
 
 
613
/* General functions */
 
614
 
 
615
/******************************************************************//**
 
616
Returns true if the thread is the replication thread on the slave
 
617
server. Used in srv_conc_enter_innodb() to determine if the thread
 
618
should be allowed to enter InnoDB - the replication thread is treated
 
619
differently than other threads. Also used in
 
620
srv_conc_force_exit_innodb().
 
621
 
 
622
DRIZZLE: Note, we didn't change this name to avoid more ifdef forking 
 
623
         in non-Cursor code.
 
624
@return true if session is the replication thread */
 
625
extern "C" UNIV_INTERN
 
626
ibool
 
627
thd_is_replication_slave_thread(
 
628
/*============================*/
 
629
        void*   )       /*!< in: thread handle (Session*) */
 
630
{
 
631
        return false;
 
632
}
 
633
 
 
634
/******************************************************************//**
 
635
Save some CPU by testing the value of srv_thread_concurrency in inline
 
636
functions. */
 
637
static inline
 
638
void
 
639
innodb_srv_conc_enter_innodb(
 
640
/*=========================*/
 
641
        trx_t*  trx)    /*!< in: transaction handle */
 
642
{
 
643
        if (UNIV_LIKELY(!srv_thread_concurrency)) {
 
644
 
 
645
                return;
 
646
        }
 
647
 
 
648
        srv_conc_enter_innodb(trx);
 
649
}
 
650
 
 
651
/******************************************************************//**
 
652
Save some CPU by testing the value of srv_thread_concurrency in inline
 
653
functions. */
 
654
static inline
 
655
void
 
656
innodb_srv_conc_exit_innodb(
 
657
/*========================*/
 
658
        trx_t*  trx)    /*!< in: transaction handle */
 
659
{
 
660
        if (UNIV_LIKELY(!trx->declared_to_be_inside_innodb)) {
 
661
 
 
662
                return;
 
663
        }
 
664
 
 
665
        srv_conc_exit_innodb(trx);
 
666
}
 
667
 
 
668
/******************************************************************//**
 
669
Releases possible search latch and InnoDB thread FIFO ticket. These should
 
670
be released at each SQL statement end, and also when mysqld passes the
 
671
control to the client. It does no harm to release these also in the middle
 
672
of an SQL statement. */
 
673
static inline
 
674
void
 
675
innobase_release_stat_resources(
 
676
/*============================*/
 
677
        trx_t*  trx)    /*!< in: transaction object */
 
678
{
 
679
        if (trx->has_search_latch) {
 
680
                trx_search_latch_release_if_reserved(trx);
 
681
        }
 
682
 
 
683
        if (trx->declared_to_be_inside_innodb) {
 
684
                /* Release our possible ticket in the FIFO */
 
685
 
 
686
                srv_conc_force_exit_innodb(trx);
 
687
        }
 
688
}
 
689
 
 
690
/******************************************************************//**
 
691
Returns true if the transaction this thread is processing has edited
 
692
non-transactional tables. Used by the deadlock detector when deciding
 
693
which transaction to rollback in case of a deadlock - we try to avoid
 
694
rolling back transactions that have edited non-transactional tables.
 
695
 
 
696
DRIZZLE: Note, we didn't change this name to avoid more ifdef forking 
 
697
         in non-Cursor code.
 
698
@return true if non-transactional tables have been edited */
 
699
extern "C" UNIV_INTERN
 
700
ibool
 
701
thd_has_edited_nontrans_tables(
 
702
/*===========================*/
 
703
        void*           session)        /*!< in: thread handle (Session*) */
 
704
{
 
705
        return((ibool) session_non_transactional_update((Session*) session));
 
706
}
 
707
 
 
708
/******************************************************************//**
 
709
Returns true if the thread is executing a SELECT statement.
 
710
@return true if session is executing SELECT */
 
711
extern "C" UNIV_INTERN
 
712
ibool
 
713
thd_is_select(
 
714
/*==========*/
 
715
        const void*     session)        /*!< in: thread handle (Session*) */
 
716
{
 
717
        return(session_sql_command((const Session*) session) == SQLCOM_SELECT);
 
718
}
 
719
 
 
720
/******************************************************************//**
 
721
Returns true if the thread supports XA,
 
722
global value of innodb_supports_xa if session is NULL.
 
723
@return true if session has XA support */
 
724
extern "C" UNIV_INTERN
 
725
ibool
 
726
thd_supports_xa(
 
727
/*============*/
 
728
        void*   session)        /*!< in: thread handle (Session*), or NULL to query
 
729
                                the global innodb_supports_xa */
 
730
{
 
731
        return(SessionVAR((Session*) session, support_xa));
 
732
}
 
733
 
 
734
/******************************************************************//**
 
735
Returns the lock wait timeout for the current connection.
 
736
@return the lock wait timeout, in seconds */
 
737
extern "C" UNIV_INTERN
 
738
ulong
 
739
thd_lock_wait_timeout(
 
740
/*==================*/
 
741
        void*   session)        /*!< in: thread handle (Session*), or NULL to query
 
742
                        the global innodb_lock_wait_timeout */
 
743
{
 
744
        /* According to <drizzle/plugin.h>, passing session == NULL
 
745
        returns the global value of the session variable. */
 
746
        return(SessionVAR((Session*) session, lock_wait_timeout));
 
747
}
 
748
 
 
749
/********************************************************************//**
 
750
Obtain the InnoDB transaction of a MySQL thread.
 
751
@return reference to transaction pointer */
 
752
static inline
 
753
trx_t*&
 
754
session_to_trx(
 
755
/*=======*/
 
756
        Session*        session)        /*!< in: Drizzle Session */
 
757
{
 
758
        return *(trx_t**) session->getEngineData(innodb_engine_ptr);
 
759
}
 
760
 
 
761
/********************************************************************//**
 
762
Call this function when mysqld passes control to the client. That is to
 
763
avoid deadlocks on the adaptive hash S-latch possibly held by session. For more
 
764
documentation, see Cursor.cc.
 
765
@return 0 */
 
766
int
 
767
InnobaseEngine::release_temporary_latches(
 
768
/*===============================*/
 
769
        Session*                session)        /*!< in: MySQL thread */
 
770
{
 
771
        trx_t*  trx;
 
772
 
 
773
        assert(this == innodb_engine_ptr);
 
774
 
 
775
        if (!innodb_inited) {
 
776
 
 
777
                return(0);
 
778
        }
 
779
 
 
780
        trx = session_to_trx(session);
 
781
 
 
782
        if (trx) {
 
783
                innobase_release_stat_resources(trx);
 
784
        }
 
785
        return(0);
 
786
}
 
787
 
 
788
/********************************************************************//**
 
789
Increments innobase_active_counter and every INNOBASE_WAKE_INTERVALth
 
790
time calls srv_active_wake_master_thread. This function should be used
 
791
when a single database operation may introduce a small need for
 
792
server utility activity, like checkpointing. */
 
793
static inline
 
794
void
 
795
innobase_active_small(void)
 
796
/*=======================*/
 
797
{
 
798
        innobase_active_counter++;
 
799
 
 
800
        if ((innobase_active_counter % INNOBASE_WAKE_INTERVAL) == 0) {
 
801
                srv_active_wake_master_thread();
 
802
        }
 
803
}
 
804
 
 
805
/********************************************************************//**
 
806
Converts an InnoDB error code to a MySQL error code and also tells to MySQL
 
807
about a possible transaction rollback inside InnoDB caused by a lock wait
 
808
timeout or a deadlock.
 
809
@return MySQL error code */
 
810
extern "C" UNIV_INTERN
 
811
int
 
812
convert_error_code_to_mysql(
 
813
/*========================*/
 
814
        int             error,  /*!< in: InnoDB error code */
 
815
        ulint           flags,  /*!< in: InnoDB table flags, or 0 */
 
816
        Session*        session)/*!< in: user thread handle or NULL */
 
817
{
 
818
        switch (error) {
 
819
        case DB_SUCCESS:
 
820
                return(0);
 
821
 
 
822
        case DB_ERROR:
 
823
        default:
 
824
                return(-1); /* unspecified error */
 
825
 
 
826
        case DB_DUPLICATE_KEY:
 
827
                return(HA_ERR_FOUND_DUPP_KEY);
 
828
 
 
829
        case DB_FOREIGN_DUPLICATE_KEY:
 
830
                return(HA_ERR_FOREIGN_DUPLICATE_KEY);
 
831
 
 
832
        case DB_MISSING_HISTORY:
 
833
                return(HA_ERR_TABLE_DEF_CHANGED);
 
834
 
 
835
        case DB_RECORD_NOT_FOUND:
 
836
                return(HA_ERR_NO_ACTIVE_RECORD);
 
837
 
 
838
        case DB_DEADLOCK:
 
839
                /* Since we rolled back the whole transaction, we must
 
840
                tell it also to MySQL so that MySQL knows to empty the
 
841
                cached binlog for this transaction */
 
842
 
 
843
                session_mark_transaction_to_rollback(session, TRUE);
 
844
 
 
845
                return(HA_ERR_LOCK_DEADLOCK);
 
846
 
 
847
        case DB_LOCK_WAIT_TIMEOUT:
 
848
                /* Starting from 5.0.13, we let MySQL just roll back the
 
849
                latest SQL statement in a lock wait timeout. Previously, we
 
850
                rolled back the whole transaction. */
 
851
 
 
852
                session_mark_transaction_to_rollback(session,
 
853
                                             (bool)row_rollback_on_timeout);
 
854
 
 
855
                return(HA_ERR_LOCK_WAIT_TIMEOUT);
 
856
 
 
857
        case DB_NO_REFERENCED_ROW:
 
858
                return(HA_ERR_NO_REFERENCED_ROW);
 
859
 
 
860
        case DB_ROW_IS_REFERENCED:
 
861
                return(HA_ERR_ROW_IS_REFERENCED);
 
862
 
 
863
        case DB_CANNOT_ADD_CONSTRAINT:
 
864
                return(HA_ERR_CANNOT_ADD_FOREIGN);
 
865
 
 
866
        case DB_CANNOT_DROP_CONSTRAINT:
 
867
 
 
868
                return(HA_ERR_ROW_IS_REFERENCED); /* TODO: This is a bit
 
869
                                                misleading, a new MySQL error
 
870
                                                code should be introduced */
 
871
 
 
872
        case DB_COL_APPEARS_TWICE_IN_INDEX:
 
873
        case DB_CORRUPTION:
 
874
                return(HA_ERR_CRASHED);
 
875
 
 
876
        case DB_OUT_OF_FILE_SPACE:
 
877
                return(HA_ERR_RECORD_FILE_FULL);
 
878
 
 
879
        case DB_TABLE_IS_BEING_USED:
 
880
                return(HA_ERR_WRONG_COMMAND);
 
881
 
 
882
        case DB_TABLE_NOT_FOUND:
 
883
                return(HA_ERR_NO_SUCH_TABLE);
 
884
 
 
885
        case DB_TOO_BIG_RECORD:
 
886
                my_error(ER_TOO_BIG_ROWSIZE, MYF(0),
 
887
                         page_get_free_space_of_empty(flags
 
888
                                                      & DICT_TF_COMPACT) / 2);
 
889
                return(HA_ERR_TO_BIG_ROW);
 
890
 
 
891
        case DB_NO_SAVEPOINT:
 
892
                return(HA_ERR_NO_SAVEPOINT);
 
893
 
 
894
        case DB_LOCK_TABLE_FULL:
 
895
                /* Since we rolled back the whole transaction, we must
 
896
                tell it also to MySQL so that MySQL knows to empty the
 
897
                cached binlog for this transaction */
 
898
 
 
899
                session_mark_transaction_to_rollback(session, TRUE);
 
900
 
 
901
                return(HA_ERR_LOCK_TABLE_FULL);
 
902
 
 
903
        case DB_PRIMARY_KEY_IS_NULL:
 
904
                return(ER_PRIMARY_CANT_HAVE_NULL);
 
905
 
 
906
        case DB_TOO_MANY_CONCURRENT_TRXS:
 
907
 
 
908
                /* Once MySQL add the appropriate code to errmsg.txt then
 
909
                we can get rid of this #ifdef. NOTE: The code checked by
 
910
                the #ifdef is the suggested name for the error condition
 
911
                and the actual error code name could very well be different.
 
912
                This will require some monitoring, ie. the status
 
913
                of this request on our part.*/
 
914
#ifdef ER_TOO_MANY_CONCURRENT_TRXS
 
915
                return(ER_TOO_MANY_CONCURRENT_TRXS);
 
916
#else
 
917
                return(HA_ERR_RECORD_FILE_FULL);
 
918
#endif
 
919
        case DB_UNSUPPORTED:
 
920
                return(HA_ERR_UNSUPPORTED);
 
921
        }
 
922
}
 
923
 
 
924
/*************************************************************//**
 
925
If you want to print a session that is not associated with the current thread,
 
926
you must call this function before reserving the InnoDB kernel_mutex, to
 
927
protect Drizzle from setting session->query NULL. If you print a session of the
 
928
current thread, we know that Drizzle cannot modify sesion->query, and it is
 
929
not necessary to call this. Call innobase_mysql_end_print_arbitrary_thd()
 
930
after you release the kernel_mutex.
 
931
 
 
932
DRIZZLE: Note, we didn't change this name to avoid more ifdef forking 
 
933
         in non-Cursor code.
 
934
 */
 
935
extern "C" UNIV_INTERN
 
936
void
 
937
innobase_mysql_prepare_print_arbitrary_thd(void)
 
938
/*============================================*/
 
939
{
 
940
        ut_ad(!mutex_own(&kernel_mutex));
 
941
        pthread_mutex_lock(&LOCK_thread_count);
 
942
}
 
943
 
 
944
/*************************************************************//**
 
945
Releases the mutex reserved by innobase_mysql_prepare_print_arbitrary_thd().
 
946
In the InnoDB latching order, the mutex sits right above the
 
947
kernel_mutex.  In debug builds, we assert that the kernel_mutex is
 
948
released before this function is invoked. 
 
949
 
 
950
DRIZZLE: Note, we didn't change this name to avoid more ifdef forking 
 
951
         in non-Cursor code.
 
952
*/
 
953
extern "C" UNIV_INTERN
 
954
void
 
955
innobase_mysql_end_print_arbitrary_thd(void)
 
956
/*========================================*/
 
957
{
 
958
        ut_ad(!mutex_own(&kernel_mutex));
 
959
        pthread_mutex_unlock(&LOCK_thread_count);
 
960
}
 
961
 
 
962
/*************************************************************//**
 
963
Prints info of a Session object (== user session thread) to the given file. */
 
964
extern "C" UNIV_INTERN
 
965
void
 
966
innobase_mysql_print_thd(
 
967
/*=====================*/
 
968
        FILE*   f,              /*!< in: output stream */
 
969
        void * in_session,      /*!< in: pointer to a Drizzle Session object */
 
970
        uint    )               /*!< in: max query length to print, or 0 to
 
971
                                   use the default max length */
 
972
{
 
973
  Session *session= reinterpret_cast<Session *>(in_session);
 
974
  fprintf(f,
 
975
          "Drizzle thread %"PRIu64", query id %"PRIu64", %s, %s, %s ",
 
976
          static_cast<uint64_t>(session_get_thread_id( session)),
 
977
          static_cast<uint64_t>(session->getQueryId()),
 
978
          glob_hostname,
 
979
          session->security_ctx.ip.c_str(),
 
980
          session->security_ctx.user.c_str()
 
981
  );
 
982
  fprintf(f,
 
983
          "\n%s", session->getQueryString()
 
984
  );
 
985
        putc('\n', f);
 
986
}
 
987
 
 
988
/******************************************************************//**
 
989
Get the variable length bounds of the given character set. */
 
990
extern "C" UNIV_INTERN
 
991
void
 
992
innobase_get_cset_width(
 
993
/*====================*/
 
994
        ulint   cset,           /*!< in: MySQL charset-collation code */
 
995
        ulint*  mbminlen,       /*!< out: minimum length of a char (in bytes) */
 
996
        ulint*  mbmaxlen)       /*!< out: maximum length of a char (in bytes) */
 
997
{
 
998
        CHARSET_INFO*   cs;
 
999
        ut_ad(cset < 256);
 
1000
        ut_ad(mbminlen);
 
1001
        ut_ad(mbmaxlen);
 
1002
 
 
1003
        cs = all_charsets[cset];
 
1004
        if (cs) {
 
1005
                *mbminlen = cs->mbminlen;
 
1006
                *mbmaxlen = cs->mbmaxlen;
 
1007
        } else {
 
1008
                ut_a(cset == 0);
 
1009
                *mbminlen = *mbmaxlen = 0;
 
1010
        }
 
1011
}
 
1012
 
 
1013
/******************************************************************//**
 
1014
Converts an identifier to a table name. */
 
1015
extern "C" UNIV_INTERN
 
1016
void
 
1017
innobase_convert_from_table_id(
 
1018
/*===========================*/
 
1019
        const struct charset_info_st*,  /*!< in: the 'from' character set */
 
1020
        char*                   to,     /*!< out: converted identifier */
 
1021
        const char*             from,   /*!< in: identifier to convert */
 
1022
        ulint                   len)    /*!< in: length of 'to', in bytes */
 
1023
{
 
1024
        strncpy(to, from, len);
 
1025
}
 
1026
 
 
1027
/******************************************************************//**
 
1028
Converts an identifier to UTF-8. */
 
1029
extern "C" UNIV_INTERN
 
1030
void
 
1031
innobase_convert_from_id(
 
1032
/*=====================*/
 
1033
        const struct charset_info_st*,  /*!< in: the 'from' character set */
 
1034
        char*                   to,     /*!< out: converted identifier */
 
1035
        const char*             from,   /*!< in: identifier to convert */
 
1036
        ulint                   len)    /*!< in: length of 'to', in bytes */
 
1037
{
 
1038
        strncpy(to, from, len);
 
1039
}
 
1040
 
 
1041
/******************************************************************//**
 
1042
Compares NUL-terminated UTF-8 strings case insensitively.
 
1043
@return 0 if a=b, <0 if a<b, >1 if a>b */
 
1044
extern "C" UNIV_INTERN
 
1045
int
 
1046
innobase_strcasecmp(
 
1047
/*================*/
 
1048
        const char*     a,      /*!< in: first string to compare */
 
1049
        const char*     b)      /*!< in: second string to compare */
 
1050
{
 
1051
        return(my_strcasecmp(system_charset_info, a, b));
 
1052
}
 
1053
 
 
1054
/******************************************************************//**
 
1055
Makes all characters in a NUL-terminated UTF-8 string lower case. */
 
1056
extern "C" UNIV_INTERN
 
1057
void
 
1058
innobase_casedn_str(
 
1059
/*================*/
 
1060
        char*   a)      /*!< in/out: string to put in lower case */
 
1061
{
 
1062
        my_casedn_str(system_charset_info, a);
 
1063
}
 
1064
 
 
1065
/**********************************************************************//**
 
1066
Determines the connection character set.
 
1067
@return connection character set */
 
1068
extern "C" UNIV_INTERN
 
1069
const charset_info_st*
 
1070
innobase_get_charset(
 
1071
/*=================*/
 
1072
        void*   mysql_session)  /*!< in: MySQL thread handle */
 
1073
{
 
1074
        return(session_charset(static_cast<Session*>(mysql_session)));
 
1075
}
 
1076
 
 
1077
#if defined (__WIN__) && defined (MYSQL_DYNAMIC_PLUGIN)
 
1078
/*******************************************************************//**
 
1079
Map an OS error to an errno value. The OS error number is stored in
 
1080
_doserrno and the mapped value is stored in errno) */
 
1081
extern "C"
 
1082
void __cdecl
 
1083
_dosmaperr(
 
1084
        unsigned long); /*!< in: OS error value */
 
1085
 
 
1086
/*********************************************************************//**
 
1087
Creates a temporary file.
 
1088
@return temporary file descriptor, or < 0 on error */
 
1089
extern "C" UNIV_INTERN
 
1090
int
 
1091
innobase_mysql_tmpfile(void)
 
1092
/*========================*/
 
1093
{
 
1094
        int     fd;                             /* handle of opened file */
 
1095
        HANDLE  osfh;                           /* OS handle of opened file */
 
1096
        char*   tmpdir;                         /* point to the directory
 
1097
                                                where to create file */
 
1098
        TCHAR   path_buf[MAX_PATH - 14];        /* buffer for tmp file path.
 
1099
                                                The length cannot be longer
 
1100
                                                than MAX_PATH - 14, or
 
1101
                                                GetTempFileName will fail. */
 
1102
        char    filename[MAX_PATH];             /* name of the tmpfile */
 
1103
        DWORD   fileaccess = GENERIC_READ       /* OS file access */
 
1104
                             | GENERIC_WRITE
 
1105
                             | DELETE;
 
1106
        DWORD   fileshare = FILE_SHARE_READ     /* OS file sharing mode */
 
1107
                            | FILE_SHARE_WRITE
 
1108
                            | FILE_SHARE_DELETE;
 
1109
        DWORD   filecreate = CREATE_ALWAYS;     /* OS method of open/create */
 
1110
        DWORD   fileattrib =                    /* OS file attribute flags */
 
1111
                             FILE_ATTRIBUTE_NORMAL
 
1112
                             | FILE_FLAG_DELETE_ON_CLOSE
 
1113
                             | FILE_ATTRIBUTE_TEMPORARY
 
1114
                             | FILE_FLAG_SEQUENTIAL_SCAN;
 
1115
 
 
1116
        tmpdir = my_tmpdir(&mysql_tmpdir_list);
 
1117
 
 
1118
        /* The tmpdir parameter can not be NULL for GetTempFileName. */
 
1119
        if (!tmpdir) {
 
1120
                uint    ret;
 
1121
 
 
1122
                /* Use GetTempPath to determine path for temporary files. */
 
1123
                ret = GetTempPath(sizeof(path_buf), path_buf);
 
1124
                if (ret > sizeof(path_buf) || (ret == 0)) {
 
1125
 
 
1126
                        _dosmaperr(GetLastError());     /* map error */
 
1127
                        return(-1);
 
1128
                }
 
1129
 
 
1130
                tmpdir = path_buf;
 
1131
        }
 
1132
 
 
1133
        /* Use GetTempFileName to generate a unique filename. */
 
1134
        if (!GetTempFileName(tmpdir, "ib", 0, filename)) {
 
1135
 
 
1136
                _dosmaperr(GetLastError());     /* map error */
 
1137
                return(-1);
 
1138
        }
 
1139
 
 
1140
        /* Open/Create the file. */
 
1141
        osfh = CreateFile(filename, fileaccess, fileshare, NULL,
 
1142
                          filecreate, fileattrib, NULL);
 
1143
        if (osfh == INVALID_HANDLE_VALUE) {
 
1144
 
 
1145
                /* open/create file failed! */
 
1146
                _dosmaperr(GetLastError());     /* map error */
 
1147
                return(-1);
 
1148
        }
 
1149
 
 
1150
        do {
 
1151
                /* Associates a CRT file descriptor with the OS file handle. */
 
1152
                fd = _open_osfhandle((intptr_t) osfh, 0);
 
1153
        } while (fd == -1 && errno == EINTR);
 
1154
 
 
1155
        if (fd == -1) {
 
1156
                /* Open failed, close the file handle. */
 
1157
 
 
1158
                _dosmaperr(GetLastError());     /* map error */
 
1159
                CloseHandle(osfh);              /* no need to check if
 
1160
                                                CloseHandle fails */
 
1161
        }
 
1162
 
 
1163
        return(fd);
 
1164
}
 
1165
#else
 
1166
/*********************************************************************//**
 
1167
Creates a temporary file.
 
1168
@return temporary file descriptor, or < 0 on error */
 
1169
extern "C" UNIV_INTERN
 
1170
int
 
1171
innobase_mysql_tmpfile(void)
 
1172
/*========================*/
 
1173
{
 
1174
        int     fd2 = -1;
 
1175
        int     fd = mysql_tmpfile("ib");
 
1176
        if (fd >= 0) {
 
1177
                /* Copy the file descriptor, so that the additional resources
 
1178
                allocated by create_temp_file() can be freed by invoking
 
1179
                my_close().
 
1180
 
 
1181
                Because the file descriptor returned by this function
 
1182
                will be passed to fdopen(), it will be closed by invoking
 
1183
                fclose(), which in turn will invoke close() instead of
 
1184
                my_close(). */
 
1185
                fd2 = dup(fd);
 
1186
                if (fd2 < 0) {
 
1187
                        errno=errno;
 
1188
                        my_error(EE_OUT_OF_FILERESOURCES,
 
1189
                                 MYF(ME_BELL+ME_WAITTANG),
 
1190
                                 "ib*", errno);
 
1191
                }
 
1192
                my_close(fd, MYF(MY_WME));
 
1193
        }
 
1194
        return(fd2);
 
1195
}
 
1196
#endif /* defined (__WIN__) && defined (MYSQL_DYNAMIC_PLUGIN) */
 
1197
 
 
1198
 
 
1199
/*******************************************************************//**
 
1200
Formats the raw data in "data" (in InnoDB on-disk format) that is of
 
1201
type DATA_(CHAR|VARCHAR|DRIZZLE|VARDRIZZLE) using "charset_coll" and writes
 
1202
the result to "buf". The result is converted to "system_charset_info".
 
1203
Not more than "buf_size" bytes are written to "buf".
 
1204
The result is always NUL-terminated (provided buf_size > 0) and the
 
1205
number of bytes that were written to "buf" is returned (including the
 
1206
terminating NUL).
 
1207
@return number of bytes that were written */
 
1208
extern "C" UNIV_INTERN
 
1209
ulint
 
1210
innobase_raw_format(
 
1211
/*================*/
 
1212
        const char*     data,           /*!< in: raw data */
 
1213
        ulint           data_len,       /*!< in: raw data length
 
1214
                                        in bytes */
 
1215
        ulint           ,               /*!< in: charset collation */
 
1216
        char*           buf,            /*!< out: output buffer */
 
1217
        ulint           buf_size)       /*!< in: output buffer size
 
1218
                                        in bytes */
 
1219
{
 
1220
        return(ut_str_sql_format(data, data_len, buf, buf_size));
 
1221
}
 
1222
 
 
1223
/*********************************************************************//**
 
1224
Compute the next autoinc value.
 
1225
 
 
1226
For MySQL replication the autoincrement values can be partitioned among
 
1227
the nodes. The offset is the start or origin of the autoincrement value
 
1228
for a particular node. For n nodes the increment will be n and the offset
 
1229
will be in the interval [1, n]. The formula tries to allocate the next
 
1230
value for a particular node.
 
1231
 
 
1232
Note: This function is also called with increment set to the number of
 
1233
values we want to reserve for multi-value inserts e.g.,
 
1234
 
 
1235
        INSERT INTO T VALUES(), (), ();
 
1236
 
 
1237
innobase_next_autoinc() will be called with increment set to
 
1238
n * 3 where autoinc_lock_mode != TRADITIONAL because we want
 
1239
to reserve 3 values for the multi-value INSERT above.
 
1240
@return the next value */
 
1241
static
 
1242
uint64_t
 
1243
innobase_next_autoinc(
 
1244
/*==================*/
 
1245
        uint64_t        current,        /*!< in: Current value */
 
1246
        uint64_t        increment,      /*!< in: increment current by */
 
1247
        uint64_t        offset,         /*!< in: AUTOINC offset */
 
1248
        uint64_t        max_value)      /*!< in: max value for type */
 
1249
{
 
1250
        uint64_t        next_value;
 
1251
 
 
1252
        /* Should never be 0. */
 
1253
        ut_a(increment > 0);
 
1254
 
 
1255
        /* According to MySQL documentation, if the offset is greater than
 
1256
        the increment then the offset is ignored. */
 
1257
        if (offset > increment) {
 
1258
                offset = 0;
 
1259
        }
 
1260
 
 
1261
        if (max_value <= current) {
 
1262
                next_value = max_value;
 
1263
        } else if (offset <= 1) {
 
1264
                /* Offset 0 and 1 are the same, because there must be at
 
1265
                least one node in the system. */
 
1266
                if (max_value - current <= increment) {
 
1267
                        next_value = max_value;
 
1268
                } else {
 
1269
                        next_value = current + increment;
 
1270
                }
 
1271
        } else if (max_value > current) {
 
1272
                if (current > offset) {
 
1273
                        next_value = ((current - offset) / increment) + 1;
 
1274
                } else {
 
1275
                        next_value = ((offset - current) / increment) + 1;
 
1276
                }
 
1277
 
 
1278
                ut_a(increment > 0);
 
1279
                ut_a(next_value > 0);
 
1280
 
 
1281
                /* Check for multiplication overflow. */
 
1282
                if (increment > (max_value / next_value)) {
 
1283
 
 
1284
                        next_value = max_value;
 
1285
                } else {
 
1286
                        next_value *= increment;
 
1287
 
 
1288
                        ut_a(max_value >= next_value);
 
1289
 
 
1290
                        /* Check for overflow. */
 
1291
                        if (max_value - next_value <= offset) {
 
1292
                                next_value = max_value;
 
1293
                        } else {
 
1294
                                next_value += offset;
 
1295
                        }
 
1296
                }
 
1297
        } else {
 
1298
                next_value = max_value;
 
1299
        }
 
1300
 
 
1301
        ut_a(next_value <= max_value);
 
1302
 
 
1303
        return(next_value);
 
1304
}
 
1305
 
 
1306
/*********************************************************************//**
 
1307
Initializes some fields in an InnoDB transaction object. */
 
1308
static
 
1309
void
 
1310
innobase_trx_init(
 
1311
/*==============*/
 
1312
        Session*        session,        /*!< in: user thread handle */
 
1313
        trx_t*  trx)    /*!< in/out: InnoDB transaction handle */
 
1314
{
 
1315
        assert(session == trx->mysql_thd);
 
1316
 
 
1317
        trx->check_foreigns = !session_test_options(
 
1318
                session, OPTION_NO_FOREIGN_KEY_CHECKS);
 
1319
 
 
1320
        trx->check_unique_secondary = !session_test_options(
 
1321
                session, OPTION_RELAXED_UNIQUE_CHECKS);
 
1322
 
 
1323
        return;
 
1324
}
 
1325
 
 
1326
/*********************************************************************//**
 
1327
Allocates an InnoDB transaction for a MySQL Cursor object.
 
1328
@return InnoDB transaction handle */
 
1329
extern "C" UNIV_INTERN
 
1330
trx_t*
 
1331
innobase_trx_allocate(
 
1332
/*==================*/
 
1333
        Session*        session)        /*!< in: user thread handle */
 
1334
{
 
1335
        trx_t*  trx;
 
1336
 
 
1337
        assert(session != NULL);
 
1338
        assert(EQ_CURRENT_SESSION(session));
 
1339
 
 
1340
        trx = trx_allocate_for_mysql();
 
1341
 
 
1342
        trx->mysql_thd = session;
 
1343
        trx->mysql_query_str = session_query(session);
 
1344
 
 
1345
        innobase_trx_init(session, trx);
 
1346
 
 
1347
        return(trx);
 
1348
}
 
1349
 
 
1350
/*********************************************************************//**
 
1351
Gets the InnoDB transaction handle for a MySQL Cursor object, creates
 
1352
an InnoDB transaction struct if the corresponding MySQL thread struct still
 
1353
lacks one.
 
1354
@return InnoDB transaction handle */
 
1355
static
 
1356
trx_t*
 
1357
check_trx_exists(
 
1358
/*=============*/
 
1359
        Session*        session)        /*!< in: user thread handle */
 
1360
{
 
1361
        trx_t*& trx = session_to_trx(session);
 
1362
 
 
1363
        ut_ad(EQ_CURRENT_SESSION(session));
 
1364
 
 
1365
        if (trx == NULL) {
 
1366
                trx = innobase_trx_allocate(session);
 
1367
        } else if (UNIV_UNLIKELY(trx->magic_n != TRX_MAGIC_N)) {
 
1368
                mem_analyze_corruption(trx);
 
1369
                ut_error;
 
1370
        }
 
1371
 
 
1372
        innobase_trx_init(session, trx);
 
1373
 
 
1374
        return(trx);
 
1375
}
 
1376
 
 
1377
 
 
1378
/*********************************************************************//**
 
1379
Construct ha_innobase Cursor. */
 
1380
UNIV_INTERN
 
1381
ha_innobase::ha_innobase(drizzled::plugin::StorageEngine &engine_arg,
 
1382
                         TableShare &table_arg)
 
1383
  :Cursor(engine_arg, table_arg),
 
1384
  primary_key(0), /* needs initialization because index_flags() may be called 
 
1385
                     before this is set to the real value. It's ok to have any 
 
1386
                     value here because it doesn't matter if we return the
 
1387
                     HA_DO_INDEX_COND_PUSHDOWN bit from those "early" calls */
 
1388
  start_of_scan(0),
 
1389
  num_write_row(0)
 
1390
{}
 
1391
 
 
1392
/*********************************************************************//**
 
1393
Destruct ha_innobase Cursor. */
 
1394
UNIV_INTERN
 
1395
ha_innobase::~ha_innobase()
 
1396
{
 
1397
}
 
1398
 
 
1399
/*********************************************************************//**
 
1400
Updates the user_thd field in a handle and also allocates a new InnoDB
 
1401
transaction handle if needed, and updates the transaction fields in the
 
1402
prebuilt struct. */
 
1403
UNIV_INTERN inline
 
1404
void
 
1405
ha_innobase::update_session(
 
1406
/*====================*/
 
1407
        Session*        session)        /*!< in: thd to use the handle */
 
1408
{
 
1409
        trx_t*          trx;
 
1410
 
 
1411
        trx = check_trx_exists(session);
 
1412
 
 
1413
        if (prebuilt->trx != trx) {
 
1414
 
 
1415
                row_update_prebuilt_trx(prebuilt, trx);
 
1416
        }
 
1417
 
 
1418
        user_session = session;
 
1419
}
 
1420
 
 
1421
/*********************************************************************//**
 
1422
Updates the user_thd field in a handle and also allocates a new InnoDB
 
1423
transaction handle if needed, and updates the transaction fields in the
 
1424
prebuilt struct. */
 
1425
UNIV_INTERN
 
1426
void
 
1427
ha_innobase::update_session()
 
1428
/*=====================*/
 
1429
{
 
1430
        Session*        session = ha_session();
 
1431
        ut_ad(EQ_CURRENT_SESSION(session));
 
1432
        update_session(session);
 
1433
}
 
1434
 
 
1435
/*********************************************************************//**
 
1436
Registers that InnoDB takes part in an SQL statement, so that MySQL knows to
 
1437
roll back the statement if the statement results in an error. This MUST be
 
1438
called for every SQL statement that may be rolled back by MySQL. Calling this
 
1439
several times to register the same statement is allowed, too. */
 
1440
static inline
 
1441
void
 
1442
innobase_register_stmt(
 
1443
/*===================*/
 
1444
        drizzled::plugin::StorageEngine*        engine, /*!< in: Innobase hton */
 
1445
        Session*        session)        /*!< in: MySQL thd (connection) object */
 
1446
{
 
1447
        assert(engine == innodb_engine_ptr);
 
1448
        /* Register the statement */
 
1449
        trans_register_ha(session, FALSE, engine);
 
1450
}
 
1451
 
 
1452
/*********************************************************************//**
 
1453
Registers an InnoDB transaction in MySQL, so that the MySQL XA code knows
 
1454
to call the InnoDB prepare and commit, or rollback for the transaction. This
 
1455
MUST be called for every transaction for which the user may call commit or
 
1456
rollback. Calling this several times to register the same transaction is
 
1457
allowed, too.
 
1458
This function also registers the current SQL statement. */
 
1459
static inline
 
1460
void
 
1461
innobase_register_trx_and_stmt(
 
1462
/*===========================*/
 
1463
        drizzled::plugin::StorageEngine *engine, /*!< in: Innobase StorageEngine */
 
1464
        Session*        session)        /*!< in: MySQL thd (connection) object */
 
1465
{
 
1466
        /* NOTE that actually innobase_register_stmt() registers also
 
1467
        the transaction in the AUTOCOMMIT=1 mode. */
 
1468
 
 
1469
        innobase_register_stmt(engine, session);
 
1470
 
 
1471
        if (session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
 
1472
 
 
1473
                /* No autocommit mode, register for a transaction */
 
1474
                trans_register_ha(session, TRUE, engine);
 
1475
        }
 
1476
}
 
1477
 
 
1478
/*****************************************************************//**
 
1479
Convert an SQL identifier to the MySQL system_charset_info (UTF-8)
 
1480
and quote it if needed.
 
1481
@return pointer to the end of buf */
 
1482
static
 
1483
char*
 
1484
innobase_convert_identifier(
 
1485
/*========================*/
 
1486
        char*           buf,    /*!< out: buffer for converted identifier */
 
1487
        ulint           buflen, /*!< in: length of buf, in bytes */
 
1488
        const char*     id,     /*!< in: identifier to convert */
 
1489
        ulint           idlen,  /*!< in: length of id, in bytes */
 
1490
        void*           session,/*!< in: MySQL connection thread, or NULL */
 
1491
        ibool           file_id)/*!< in: TRUE=id is a table or database name;
 
1492
                                FALSE=id is an UTF-8 string */
 
1493
{
 
1494
        char nz[NAME_LEN + 1];
 
1495
        char nz2[NAME_LEN + 1 + sizeof srv_mysql50_table_name_prefix];
 
1496
 
 
1497
        const char*     s       = id;
 
1498
        int             q;
 
1499
 
 
1500
        if (file_id) {
 
1501
                /* Decode the table name.  The filename_to_tablename()
 
1502
                function expects a NUL-terminated string.  The input and
 
1503
                output strings buffers must not be shared. */
 
1504
 
 
1505
                if (UNIV_UNLIKELY(idlen > (sizeof nz) - 1)) {
 
1506
                        idlen = (sizeof nz) - 1;
 
1507
                }
 
1508
 
 
1509
                memcpy(nz, id, idlen);
 
1510
                nz[idlen] = 0;
 
1511
 
 
1512
                s = nz2;
 
1513
                idlen = filename_to_tablename(nz, nz2, sizeof nz2);
 
1514
        }
 
1515
 
 
1516
        /* See if the identifier needs to be quoted. */
 
1517
        if (UNIV_UNLIKELY(!session)) {
 
1518
                q = '"';
 
1519
        } else {
 
1520
                q = get_quote_char_for_identifier();
 
1521
        }
 
1522
 
 
1523
        if (q == EOF) {
 
1524
                if (UNIV_UNLIKELY(idlen > buflen)) {
 
1525
                        idlen = buflen;
 
1526
                }
 
1527
                memcpy(buf, s, idlen);
 
1528
                return(buf + idlen);
 
1529
        }
 
1530
 
 
1531
        /* Quote the identifier. */
 
1532
        if (buflen < 2) {
 
1533
                return(buf);
 
1534
        }
 
1535
 
 
1536
        *buf++ = q;
 
1537
        buflen--;
 
1538
 
 
1539
        for (; idlen; idlen--) {
 
1540
                int     c = *s++;
 
1541
                if (UNIV_UNLIKELY(c == q)) {
 
1542
                        if (UNIV_UNLIKELY(buflen < 3)) {
 
1543
                                break;
 
1544
                        }
 
1545
 
 
1546
                        *buf++ = c;
 
1547
                        *buf++ = c;
 
1548
                        buflen -= 2;
 
1549
                } else {
 
1550
                        if (UNIV_UNLIKELY(buflen < 2)) {
 
1551
                                break;
 
1552
                        }
 
1553
 
 
1554
                        *buf++ = c;
 
1555
                        buflen--;
 
1556
                }
 
1557
        }
 
1558
 
 
1559
        *buf++ = q;
 
1560
        return(buf);
 
1561
}
 
1562
 
 
1563
/*****************************************************************//**
 
1564
Convert a table or index name to the MySQL system_charset_info (UTF-8)
 
1565
and quote it if needed.
 
1566
@return pointer to the end of buf */
 
1567
extern "C" UNIV_INTERN
 
1568
char*
 
1569
innobase_convert_name(
 
1570
/*==================*/
 
1571
        char*           buf,    /*!< out: buffer for converted identifier */
 
1572
        ulint           buflen, /*!< in: length of buf, in bytes */
 
1573
        const char*     id,     /*!< in: identifier to convert */
 
1574
        ulint           idlen,  /*!< in: length of id, in bytes */
 
1575
        void*           session,/*!< in: MySQL connection thread, or NULL */
 
1576
        ibool           table_id)/*!< in: TRUE=id is a table or database name;
 
1577
                                FALSE=id is an index name */
 
1578
{
 
1579
        char*           s       = buf;
 
1580
        const char*     bufend  = buf + buflen;
 
1581
 
 
1582
        if (table_id) {
 
1583
                const char*     slash = (const char*) memchr(id, '/', idlen);
 
1584
                if (!slash) {
 
1585
 
 
1586
                        goto no_db_name;
 
1587
                }
 
1588
 
 
1589
                /* Print the database name and table name separately. */
 
1590
                s = innobase_convert_identifier(s, bufend - s, id, slash - id,
 
1591
                                                session, TRUE);
 
1592
                if (UNIV_LIKELY(s < bufend)) {
 
1593
                        *s++ = '.';
 
1594
                        s = innobase_convert_identifier(s, bufend - s,
 
1595
                                                        slash + 1, idlen
 
1596
                                                        - (slash - id) - 1,
 
1597
                                                        session, TRUE);
 
1598
                }
 
1599
        } else if (UNIV_UNLIKELY(*id == TEMP_INDEX_PREFIX)) {
 
1600
                /* Temporary index name (smart ALTER TABLE) */
 
1601
                const char temp_index_suffix[]= "--temporary--";
 
1602
 
 
1603
                s = innobase_convert_identifier(buf, buflen, id + 1, idlen - 1,
 
1604
                                                session, FALSE);
 
1605
                if (s - buf + (sizeof temp_index_suffix - 1) < buflen) {
 
1606
                        memcpy(s, temp_index_suffix,
 
1607
                               sizeof temp_index_suffix - 1);
 
1608
                        s += sizeof temp_index_suffix - 1;
 
1609
                }
 
1610
        } else {
 
1611
no_db_name:
 
1612
                s = innobase_convert_identifier(buf, buflen, id, idlen,
 
1613
                                                session, table_id);
 
1614
        }
 
1615
 
 
1616
        return(s);
 
1617
 
 
1618
}
 
1619
 
 
1620
/**********************************************************************//**
 
1621
Determines if the currently running transaction has been interrupted.
 
1622
@return TRUE if interrupted */
 
1623
extern "C" UNIV_INTERN
 
1624
ibool
 
1625
trx_is_interrupted(
 
1626
/*===============*/
 
1627
        trx_t*  trx)    /*!< in: transaction */
 
1628
{
 
1629
        return(trx && trx->mysql_thd && session_killed((Session*) trx->mysql_thd));
 
1630
}
 
1631
 
 
1632
/**************************************************************//**
 
1633
Resets some fields of a prebuilt struct. The template is used in fast
 
1634
retrieval of just those column values MySQL needs in its processing. */
 
1635
static
 
1636
void
 
1637
reset_template(
 
1638
/*===========*/
 
1639
        row_prebuilt_t* prebuilt)       /*!< in/out: prebuilt struct */
 
1640
{
 
1641
        prebuilt->keep_other_fields_on_keyread = 0;
 
1642
        prebuilt->read_just_key = 0;
 
1643
}
 
1644
 
 
1645
/*****************************************************************//**
 
1646
Call this when you have opened a new table handle in HANDLER, before you
 
1647
call index_read_idx() etc. Actually, we can let the cursor stay open even
 
1648
over a transaction commit! Then you should call this before every operation,
 
1649
fetch next etc. This function inits the necessary things even after a
 
1650
transaction commit. */
 
1651
UNIV_INTERN
 
1652
void
 
1653
ha_innobase::init_table_handle_for_HANDLER(void)
 
1654
/*============================================*/
 
1655
{
 
1656
        /* If current session does not yet have a trx struct, create one.
 
1657
        If the current handle does not yet have a prebuilt struct, create
 
1658
        one. Update the trx pointers in the prebuilt struct. Normally
 
1659
        this operation is done in external_lock. */
 
1660
 
 
1661
        update_session(ha_session());
 
1662
 
 
1663
        /* Initialize the prebuilt struct much like it would be inited in
 
1664
        external_lock */
 
1665
 
 
1666
        innobase_release_stat_resources(prebuilt->trx);
 
1667
 
 
1668
        /* If the transaction is not started yet, start it */
 
1669
 
 
1670
        trx_start_if_not_started(prebuilt->trx);
 
1671
 
 
1672
        /* Assign a read view if the transaction does not have it yet */
 
1673
 
 
1674
        trx_assign_read_view(prebuilt->trx);
 
1675
 
 
1676
        /* Set the MySQL flag to mark that there is an active transaction */
 
1677
 
 
1678
        if (prebuilt->trx->active_trans == 0) {
 
1679
 
 
1680
                innobase_register_trx_and_stmt(engine, user_session);
 
1681
 
 
1682
                prebuilt->trx->active_trans = 1;
 
1683
        }
 
1684
 
 
1685
        /* We did the necessary inits in this function, no need to repeat them
 
1686
        in row_search_for_mysql */
 
1687
 
 
1688
        prebuilt->sql_stat_start = FALSE;
 
1689
 
 
1690
        /* We let HANDLER always to do the reads as consistent reads, even
 
1691
        if the trx isolation level would have been specified as SERIALIZABLE */
 
1692
 
 
1693
        prebuilt->select_lock_type = LOCK_NONE;
 
1694
        prebuilt->stored_select_lock_type = LOCK_NONE;
 
1695
 
 
1696
        /* Always fetch all columns in the index record */
 
1697
 
 
1698
        prebuilt->hint_need_to_fetch_extra_cols = ROW_RETRIEVE_ALL_COLS;
 
1699
 
 
1700
        /* We want always to fetch all columns in the whole row? Or do
 
1701
        we???? */
 
1702
 
 
1703
        prebuilt->used_in_HANDLER = TRUE;
 
1704
        reset_template(prebuilt);
 
1705
}
 
1706
 
 
1707
/*********************************************************************//**
 
1708
Opens an InnoDB database.
 
1709
@return 0 on success, error code on failure */
 
1710
static
 
1711
int
 
1712
innobase_init(
 
1713
/*==========*/
 
1714
        drizzled::plugin::Registry      &registry)      /*!< in: Drizzle Plugin Registry */
 
1715
{
 
1716
        static char     current_dir[3];         /*!< Set if using current lib */
 
1717
        int             err;
 
1718
        bool            ret;
 
1719
        char            *default_path;
 
1720
        uint            format_id;
 
1721
 
 
1722
        innodb_engine_ptr= new InnobaseEngine(innobase_engine_name);
 
1723
 
 
1724
 
 
1725
        ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)DRIZZLE_TYPE_VARCHAR);
 
1726
 
 
1727
#ifdef UNIV_DEBUG
 
1728
        static const char       test_filename[] = "-@";
 
1729
        char                    test_tablename[sizeof test_filename
 
1730
                                + sizeof srv_mysql50_table_name_prefix];
 
1731
        if ((sizeof test_tablename) - 1
 
1732
                        != filename_to_tablename(test_filename, test_tablename,
 
1733
                        sizeof test_tablename)
 
1734
                        || strncmp(test_tablename,
 
1735
                        srv_mysql50_table_name_prefix,
 
1736
                        sizeof srv_mysql50_table_name_prefix)
 
1737
                        || strcmp(test_tablename
 
1738
                        + sizeof srv_mysql50_table_name_prefix,
 
1739
                        test_filename)) {
 
1740
                errmsg_printf(ERRMSG_LVL_ERROR, "tablename encoding has been changed");
 
1741
                goto error;
 
1742
        }
 
1743
#endif /* UNIV_DEBUG */
 
1744
 
 
1745
        /* Check that values don't overflow on 32-bit systems. */
 
1746
        if (sizeof(ulint) == 4) {
 
1747
                if (innobase_buffer_pool_size > UINT32_MAX) {
 
1748
                        errmsg_printf(ERRMSG_LVL_ERROR, 
 
1749
                                "innobase_buffer_pool_size can't be over 4GB"
 
1750
                                " on 32-bit systems");
 
1751
 
 
1752
                        goto error;
 
1753
                }
 
1754
 
 
1755
                if (innobase_log_file_size > UINT32_MAX) {
 
1756
                        errmsg_printf(ERRMSG_LVL_ERROR, 
 
1757
                                "innobase_log_file_size can't be over 4GB"
 
1758
                                " on 32-bit systems");
 
1759
 
 
1760
                        goto error;
 
1761
                }
 
1762
        }
 
1763
 
 
1764
        os_innodb_umask = (ulint)my_umask;
 
1765
 
 
1766
        /* First calculate the default path for innodb_data_home_dir etc.,
 
1767
        in case the user has not given any value.
 
1768
 
 
1769
        Note that when using the embedded server, the datadirectory is not
 
1770
        necessarily the current directory of this program. */
 
1771
 
 
1772
        /* It's better to use current lib, to keep paths short */
 
1773
        current_dir[0] = FN_CURLIB;
 
1774
        current_dir[1] = FN_LIBCHAR;
 
1775
        current_dir[2] = 0;
 
1776
        default_path = current_dir;
 
1777
 
 
1778
        ut_a(default_path);
 
1779
 
 
1780
        srv_set_thread_priorities = TRUE;
 
1781
        srv_query_thread_priority = QUERY_PRIOR;
 
1782
 
 
1783
        /* Set InnoDB initialization parameters according to the values
 
1784
        read from MySQL .cnf file */
 
1785
 
 
1786
        /*--------------- Data files -------------------------*/
 
1787
 
 
1788
        /* The default dir for data files is the datadir of MySQL */
 
1789
 
 
1790
        srv_data_home = (innobase_data_home_dir ? innobase_data_home_dir :
 
1791
                         default_path);
 
1792
 
 
1793
        /* Set default InnoDB data file size to 10 MB and let it be
 
1794
        auto-extending. Thus users can use InnoDB in >= 4.0 without having
 
1795
        to specify any startup options. */
 
1796
 
 
1797
        if (!innobase_data_file_path) {
 
1798
                innobase_data_file_path = (char*) "ibdata1:10M:autoextend";
 
1799
        }
 
1800
 
 
1801
        /* Since InnoDB edits the argument in the next call, we make another
 
1802
        copy of it: */
 
1803
 
 
1804
        internal_innobase_data_file_path = strdup(innobase_data_file_path);
 
1805
 
 
1806
        ret = (bool) srv_parse_data_file_paths_and_sizes(
 
1807
                internal_innobase_data_file_path);
 
1808
        if (ret == FALSE) {
 
1809
                errmsg_printf(ERRMSG_LVL_ERROR, 
 
1810
                        "InnoDB: syntax error in innodb_data_file_path");
 
1811
mem_free_and_error:
 
1812
                srv_free_paths_and_sizes();
 
1813
                if (internal_innobase_data_file_path)
 
1814
                  free(internal_innobase_data_file_path);
 
1815
                goto error;
 
1816
        }
 
1817
 
 
1818
        /* -------------- Log files ---------------------------*/
 
1819
 
 
1820
        /* The default dir for log files is the datadir of MySQL */
 
1821
 
 
1822
        if (!innobase_log_group_home_dir) {
 
1823
                innobase_log_group_home_dir = default_path;
 
1824
        }
 
1825
 
 
1826
#ifdef UNIV_LOG_ARCHIVE
 
1827
        /* Since innodb_log_arch_dir has no relevance under MySQL,
 
1828
        starting from 4.0.6 we always set it the same as
 
1829
        innodb_log_group_home_dir: */
 
1830
 
 
1831
        innobase_log_arch_dir = innobase_log_group_home_dir;
 
1832
 
 
1833
        srv_arch_dir = innobase_log_arch_dir;
 
1834
#endif /* UNIG_LOG_ARCHIVE */
 
1835
 
 
1836
        ret = (bool)
 
1837
                srv_parse_log_group_home_dirs(innobase_log_group_home_dir);
 
1838
 
 
1839
        if (ret == FALSE || innobase_mirrored_log_groups != 1) {
 
1840
          errmsg_printf(ERRMSG_LVL_ERROR, "syntax error in innodb_log_group_home_dir, or a "
 
1841
                          "wrong number of mirrored log groups");
 
1842
 
 
1843
                goto mem_free_and_error;
 
1844
        }
 
1845
 
 
1846
        /* Validate the file format by animal name */
 
1847
        if (innobase_file_format_name != NULL) {
 
1848
 
 
1849
                format_id = innobase_file_format_name_lookup(
 
1850
                        innobase_file_format_name);
 
1851
 
 
1852
                if (format_id > DICT_TF_FORMAT_MAX) {
 
1853
 
 
1854
                        errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB: wrong innodb_file_format.");
 
1855
 
 
1856
                        goto mem_free_and_error;
 
1857
                }
 
1858
        } else {
 
1859
                /* Set it to the default file format id. Though this
 
1860
                should never happen. */
 
1861
                format_id = 0;
 
1862
        }
 
1863
 
 
1864
        srv_file_format = format_id;
 
1865
 
 
1866
        /* Given the type of innobase_file_format_name we have little
 
1867
        choice but to cast away the constness from the returned name.
 
1868
        innobase_file_format_name is used in the MySQL set variable
 
1869
        interface and so can't be const. */
 
1870
 
 
1871
        innobase_file_format_name = 
 
1872
                (char*) trx_sys_file_format_id_to_name(format_id);
 
1873
 
 
1874
        /* Process innobase_file_format_check variable */
 
1875
        ut_a(innobase_file_format_check != NULL);
 
1876
 
 
1877
        /* As a side effect it will set srv_check_file_format_at_startup
 
1878
        on valid input. First we check for "on"/"off". */
 
1879
        if (!innobase_file_format_check_on_off(innobase_file_format_check)) {
 
1880
 
 
1881
                /* Did the user specify a format name that we support ?
 
1882
                As a side effect it will update the variable
 
1883
                srv_check_file_format_at_startup */
 
1884
                if (!innobase_file_format_check_validate(
 
1885
                        innobase_file_format_check)) {
 
1886
 
 
1887
                        errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB: invalid "
 
1888
                                        "innodb_file_format_check value: "
 
1889
                                        "should be either 'on' or 'off' or "
 
1890
                                        "any value up to %s or its "
 
1891
                                        "equivalent numeric id",
 
1892
                                        trx_sys_file_format_id_to_name(
 
1893
                                                DICT_TF_FORMAT_MAX));
 
1894
 
 
1895
                        goto mem_free_and_error;
 
1896
                }
 
1897
        }
 
1898
 
 
1899
        if (innobase_change_buffering) {
 
1900
                ulint   use;
 
1901
 
 
1902
                for (use = 0;
 
1903
                     use < UT_ARR_SIZE(innobase_change_buffering_values);
 
1904
                     use++) {
 
1905
                        if (!innobase_strcasecmp(
 
1906
                                    innobase_change_buffering,
 
1907
                                    innobase_change_buffering_values[use])) {
 
1908
                                ibuf_use = (ibuf_use_t) use;
 
1909
                                goto innobase_change_buffering_inited_ok;
 
1910
                        }
 
1911
                }
 
1912
 
 
1913
                errmsg_printf(ERRMSG_LVL_ERROR,
 
1914
                                "InnoDB: invalid value "
 
1915
                                "innodb_file_format_check=%s",
 
1916
                                innobase_change_buffering);
 
1917
                goto mem_free_and_error;
 
1918
        }
 
1919
 
 
1920
innobase_change_buffering_inited_ok:
 
1921
        ut_a((ulint) ibuf_use < UT_ARR_SIZE(innobase_change_buffering_values));
 
1922
        innobase_change_buffering = (char*)
 
1923
                innobase_change_buffering_values[ibuf_use];
 
1924
 
 
1925
        /* --------------------------------------------------*/
 
1926
 
 
1927
        srv_file_flush_method_str = innobase_unix_file_flush_method;
 
1928
 
 
1929
        srv_n_log_groups = (ulint) innobase_mirrored_log_groups;
 
1930
        srv_n_log_files = (ulint) innobase_log_files_in_group;
 
1931
        srv_log_file_size = (ulint) innobase_log_file_size;
 
1932
 
 
1933
#ifdef UNIV_LOG_ARCHIVE
 
1934
        srv_log_archive_on = (ulint) innobase_log_archive;
 
1935
#endif /* UNIV_LOG_ARCHIVE */
 
1936
        srv_log_buffer_size = (ulint) innobase_log_buffer_size;
 
1937
 
 
1938
        srv_buf_pool_size = (ulint) innobase_buffer_pool_size;
 
1939
 
 
1940
        srv_mem_pool_size = (ulint) innobase_additional_mem_pool_size;
 
1941
 
 
1942
        srv_n_file_io_threads = (ulint) innobase_file_io_threads;
 
1943
        srv_n_read_io_threads = (ulint) innobase_read_io_threads;
 
1944
        srv_n_write_io_threads = (ulint) innobase_write_io_threads;
 
1945
 
 
1946
        srv_force_recovery = (ulint) innobase_force_recovery;
 
1947
 
 
1948
        srv_use_doublewrite_buf = (ibool) innobase_use_doublewrite;
 
1949
        srv_use_checksums = (ibool) innobase_use_checksums;
 
1950
 
 
1951
#ifdef HAVE_LARGE_PAGES
 
1952
        if ((os_use_large_pages = (ibool) my_use_large_pages))
 
1953
                os_large_page_size = (ulint) opt_large_page_size;
 
1954
#endif
 
1955
 
 
1956
        row_rollback_on_timeout = (ibool) innobase_rollback_on_timeout;
 
1957
 
 
1958
        srv_locks_unsafe_for_binlog = (ibool) innobase_locks_unsafe_for_binlog;
 
1959
 
 
1960
        srv_max_n_open_files = (ulint) innobase_open_files;
 
1961
        srv_innodb_status = (ibool) innobase_create_status_file;
 
1962
 
 
1963
        srv_print_verbose_log = true;
 
1964
 
 
1965
        /* Store the default charset-collation number of this MySQL
 
1966
        installation */
 
1967
 
 
1968
        data_mysql_default_charset_coll = (ulint)default_charset_info->number;
 
1969
 
 
1970
 
 
1971
        innobase_commit_concurrency_init_default();
 
1972
 
 
1973
        /* Since we in this module access directly the fields of a trx
 
1974
        struct, and due to different headers and flags it might happen that
 
1975
        mutex_t has a different size in this module and in InnoDB
 
1976
        modules, we check at run time that the size is the same in
 
1977
        these compilation modules. */
 
1978
 
 
1979
        err = innobase_start_or_create_for_mysql();
 
1980
 
 
1981
        if (err != DB_SUCCESS) {
 
1982
                goto mem_free_and_error;
 
1983
        }
 
1984
 
 
1985
        innobase_open_tables = hash_create(200);
 
1986
        pthread_mutex_init(&innobase_share_mutex, MY_MUTEX_INIT_FAST);
 
1987
        pthread_mutex_init(&prepare_commit_mutex, MY_MUTEX_INIT_FAST);
 
1988
        pthread_mutex_init(&commit_threads_m, MY_MUTEX_INIT_FAST);
 
1989
        pthread_mutex_init(&commit_cond_m, MY_MUTEX_INIT_FAST);
 
1990
        pthread_cond_init(&commit_cond, NULL);
 
1991
        innodb_inited= 1;
 
1992
 
 
1993
        if (innodb_locks_init() ||
 
1994
                innodb_trx_init() ||
 
1995
                innodb_lock_waits_init() ||
 
1996
                i_s_cmp_init() ||
 
1997
                i_s_cmp_reset_init() ||
 
1998
                i_s_cmpmem_init() ||
 
1999
                i_s_cmpmem_reset_init())
 
2000
                goto error;
 
2001
 
 
2002
        registry.add(innodb_engine_ptr);
 
2003
 
 
2004
        registry.add(innodb_trx_schema_table);
 
2005
        registry.add(innodb_locks_schema_table);
 
2006
        registry.add(innodb_lock_waits_schema_table);   
 
2007
        registry.add(innodb_cmp_schema_table);
 
2008
        registry.add(innodb_cmp_reset_schema_table);
 
2009
        registry.add(innodb_cmpmem_schema_table);
 
2010
        registry.add(innodb_cmpmem_reset_schema_table);
 
2011
 
 
2012
        /* Get the current high water mark format. */
 
2013
        innobase_file_format_check = (char*) trx_sys_file_format_max_get();
 
2014
 
 
2015
        return(FALSE);
 
2016
error:
 
2017
        return(TRUE);
 
2018
}
 
2019
 
 
2020
/*******************************************************************//**
 
2021
Closes an InnoDB database.
 
2022
@return TRUE if error */
 
2023
static
 
2024
int
 
2025
innobase_deinit(drizzled::plugin::Registry &registry)
 
2026
{
 
2027
        int     err= 0;
 
2028
        i_s_common_deinit(registry);
 
2029
        registry.remove(innodb_engine_ptr);
 
2030
        delete innodb_engine_ptr;
 
2031
 
 
2032
        if (innodb_inited) {
 
2033
 
 
2034
                srv_fast_shutdown = (ulint) innobase_fast_shutdown;
 
2035
                innodb_inited = 0;
 
2036
                hash_table_free(innobase_open_tables);
 
2037
                innobase_open_tables = NULL;
 
2038
                if (innobase_shutdown_for_mysql() != DB_SUCCESS) {
 
2039
                        err = 1;
 
2040
                }
 
2041
                srv_free_paths_and_sizes();
 
2042
                if (internal_innobase_data_file_path)
 
2043
                  free(internal_innobase_data_file_path);
 
2044
                pthread_mutex_destroy(&innobase_share_mutex);
 
2045
                pthread_mutex_destroy(&prepare_commit_mutex);
 
2046
                pthread_mutex_destroy(&commit_threads_m);
 
2047
                pthread_mutex_destroy(&commit_cond_m);
 
2048
                pthread_cond_destroy(&commit_cond);
 
2049
        }
 
2050
 
 
2051
        return(err);
 
2052
}
 
2053
 
 
2054
/****************************************************************//**
 
2055
Flushes InnoDB logs to disk and makes a checkpoint. Really, a commit flushes
 
2056
the logs, and the name of this function should be innobase_checkpoint.
 
2057
@return TRUE if error */
 
2058
bool
 
2059
InnobaseEngine::flush_logs()
 
2060
/*=====================*/
 
2061
{
 
2062
        bool    result = 0;
 
2063
 
 
2064
        assert(this == innodb_engine_ptr);
 
2065
 
 
2066
        log_buffer_flush_to_disk();
 
2067
 
 
2068
        return(result);
 
2069
}
 
2070
 
 
2071
/*****************************************************************//**
 
2072
Commits a transaction in an InnoDB database. */
 
2073
static
 
2074
void
 
2075
innobase_commit_low(
 
2076
/*================*/
 
2077
        trx_t*  trx)    /*!< in: transaction handle */
 
2078
{
 
2079
        if (trx->conc_state == TRX_NOT_STARTED) {
 
2080
 
 
2081
                return;
 
2082
        }
 
2083
 
 
2084
        trx_commit_for_mysql(trx);
 
2085
}
 
2086
 
 
2087
/*****************************************************************//**
 
2088
Creates an InnoDB transaction struct for the thd if it does not yet have one.
 
2089
Starts a new InnoDB transaction if a transaction is not yet started. And
 
2090
assigns a new snapshot for a consistent read if the transaction does not yet
 
2091
have one.
 
2092
@return 0 */
 
2093
int
 
2094
InnobaseEngine::start_consistent_snapshot(
 
2095
/*====================================*/
 
2096
        Session*        session)        /*!< in: MySQL thread handle of the user for whom
 
2097
                        the transaction should be committed */
 
2098
{
 
2099
        trx_t*  trx;
 
2100
 
 
2101
        assert(this == innodb_engine_ptr);
 
2102
 
 
2103
        /* Create a new trx struct for session, if it does not yet have one */
 
2104
 
 
2105
        trx = check_trx_exists(session);
 
2106
 
 
2107
        /* This is just to play safe: release a possible FIFO ticket and
 
2108
        search latch. Since we will reserve the kernel mutex, we have to
 
2109
        release the search system latch first to obey the latching order. */
 
2110
 
 
2111
        innobase_release_stat_resources(trx);
 
2112
 
 
2113
        /* If the transaction is not started yet, start it */
 
2114
 
 
2115
        trx_start_if_not_started(trx);
 
2116
 
 
2117
        /* Assign a read view if the transaction does not have it yet */
 
2118
 
 
2119
        trx_assign_read_view(trx);
 
2120
 
 
2121
        /* Set the MySQL flag to mark that there is an active transaction */
 
2122
 
 
2123
        if (trx->active_trans == 0) {
 
2124
                innobase_register_trx_and_stmt(this, current_session);
 
2125
                trx->active_trans = 1;
 
2126
        }
 
2127
 
 
2128
        return(0);
 
2129
}
 
2130
 
 
2131
/*****************************************************************//**
 
2132
Commits a transaction in an InnoDB database or marks an SQL statement
 
2133
ended.
 
2134
@return 0 */
 
2135
int
 
2136
InnobaseEngine::commit(
 
2137
/*============*/
 
2138
        Session*        session,        /*!< in: MySQL thread handle of the user for whom
 
2139
                        the transaction should be committed */
 
2140
        bool    all)    /*!< in:        TRUE - commit transaction
 
2141
                                FALSE - the current SQL statement ended */
 
2142
{
 
2143
        trx_t*          trx;
 
2144
 
 
2145
        assert(this == innodb_engine_ptr);
 
2146
 
 
2147
        trx = check_trx_exists(session);
 
2148
 
 
2149
        /* Since we will reserve the kernel mutex, we have to release
 
2150
        the search system latch first to obey the latching order. */
 
2151
 
 
2152
        if (trx->has_search_latch) {
 
2153
                trx_search_latch_release_if_reserved(trx);
 
2154
        }
 
2155
 
 
2156
        /* The flag trx->active_trans is set to 1 in
 
2157
 
 
2158
        1. ::external_lock(),
 
2159
        2. ::start_stmt(),
 
2160
        3. innobase_query_caching_of_table_permitted(),
 
2161
        4. InnobaseEngine::savepoint_set(),
 
2162
        5. ::init_table_handle_for_HANDLER(),
 
2163
        6. InnobaseEngine::start_consistent_snapshot(),
 
2164
 
 
2165
        and it is only set to 0 in a commit or a rollback. If it is 0 we know
 
2166
        there cannot be resources to be freed and we could return immediately.
 
2167
        For the time being, we play safe and do the cleanup though there should
 
2168
        be nothing to clean up. */
 
2169
 
 
2170
        if (trx->active_trans == 0
 
2171
                && trx->conc_state != TRX_NOT_STARTED) {
 
2172
 
 
2173
                errmsg_printf(ERRMSG_LVL_ERROR, "trx->active_trans == 0, but"
 
2174
                        " trx->conc_state != TRX_NOT_STARTED");
 
2175
        }
 
2176
        if (all
 
2177
                || (!session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
 
2178
 
 
2179
                /* We were instructed to commit the whole transaction, or
 
2180
                this is an SQL statement end and autocommit is on */
 
2181
 
 
2182
                /* We need current binlog position for ibbackup to work.
 
2183
                Note, the position is current because of
 
2184
                prepare_commit_mutex */
 
2185
retry:
 
2186
                if (innobase_commit_concurrency > 0) {
 
2187
                        pthread_mutex_lock(&commit_cond_m);
 
2188
                        commit_threads++;
 
2189
 
 
2190
                        if (commit_threads > innobase_commit_concurrency) {
 
2191
                                commit_threads--;
 
2192
                                pthread_cond_wait(&commit_cond,
 
2193
                                        &commit_cond_m);
 
2194
                                pthread_mutex_unlock(&commit_cond_m);
 
2195
                                goto retry;
 
2196
                        }
 
2197
                        else {
 
2198
                                pthread_mutex_unlock(&commit_cond_m);
 
2199
                        }
 
2200
                }
 
2201
 
 
2202
                /* Store transaction point for binlog
 
2203
                Later logic tests that this is set to _something_. We need
 
2204
                that logic to fire, even though we do not have a real name. */
 
2205
                trx->mysql_log_file_name = "UNUSED";
 
2206
                trx->mysql_log_offset = 0;
 
2207
 
 
2208
                /* Don't do write + flush right now. For group commit
 
2209
                to work we want to do the flush after releasing the
 
2210
                prepare_commit_mutex. */
 
2211
                trx->flush_log_later = TRUE;
 
2212
                innobase_commit_low(trx);
 
2213
                trx->flush_log_later = FALSE;
 
2214
 
 
2215
                if (innobase_commit_concurrency > 0) {
 
2216
                        pthread_mutex_lock(&commit_cond_m);
 
2217
                        commit_threads--;
 
2218
                        pthread_cond_signal(&commit_cond);
 
2219
                        pthread_mutex_unlock(&commit_cond_m);
 
2220
                }
 
2221
 
 
2222
                if (trx->active_trans == 2) {
 
2223
 
 
2224
                        pthread_mutex_unlock(&prepare_commit_mutex);
 
2225
                }
 
2226
 
 
2227
                /* Now do a write + flush of logs. */
 
2228
                trx_commit_complete_for_mysql(trx);
 
2229
                trx->active_trans = 0;
 
2230
 
 
2231
        } else {
 
2232
                /* We just mark the SQL statement ended and do not do a
 
2233
                transaction commit */
 
2234
 
 
2235
                /* If we had reserved the auto-inc lock for some
 
2236
                table in this SQL statement we release it now */
 
2237
 
 
2238
                row_unlock_table_autoinc_for_mysql(trx);
 
2239
 
 
2240
                /* Store the current undo_no of the transaction so that we
 
2241
                know where to roll back if we have to roll back the next
 
2242
                SQL statement */
 
2243
 
 
2244
                trx_mark_sql_stat_end(trx);
 
2245
        }
 
2246
 
 
2247
        trx->n_autoinc_rows = 0; /* Reset the number AUTO-INC rows required */
 
2248
 
 
2249
        if (trx->declared_to_be_inside_innodb) {
 
2250
                /* Release our possible ticket in the FIFO */
 
2251
 
 
2252
                srv_conc_force_exit_innodb(trx);
 
2253
        }
 
2254
 
 
2255
        /* Tell the InnoDB server that there might be work for utility
 
2256
        threads: */
 
2257
        srv_active_wake_master_thread();
 
2258
 
 
2259
        return(0);
 
2260
}
 
2261
 
 
2262
/*****************************************************************//**
 
2263
Rolls back a transaction or the latest SQL statement.
 
2264
@return 0 or error number */
 
2265
int
 
2266
InnobaseEngine::rollback(
 
2267
/*==============*/
 
2268
        Session*        session,/*!< in: handle to the MySQL thread of the user
 
2269
                        whose transaction should be rolled back */
 
2270
        bool    all)    /*!< in:        TRUE - commit transaction
 
2271
                                FALSE - the current SQL statement ended */
 
2272
{
 
2273
        int     error = 0;
 
2274
        trx_t*  trx;
 
2275
 
 
2276
        assert(this == innodb_engine_ptr);
 
2277
 
 
2278
        trx = check_trx_exists(session);
 
2279
 
 
2280
        /* Release a possible FIFO ticket and search latch. Since we will
 
2281
        reserve the kernel mutex, we have to release the search system latch
 
2282
        first to obey the latching order. */
 
2283
 
 
2284
        innobase_release_stat_resources(trx);
 
2285
 
 
2286
        /* If we had reserved the auto-inc lock for some table (if
 
2287
        we come here to roll back the latest SQL statement) we
 
2288
        release it now before a possibly lengthy rollback */
 
2289
 
 
2290
        row_unlock_table_autoinc_for_mysql(trx);
 
2291
 
 
2292
        if (all
 
2293
                || !session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
 
2294
 
 
2295
                error = trx_rollback_for_mysql(trx);
 
2296
                trx->active_trans = 0;
 
2297
        } else {
 
2298
                error = trx_rollback_last_sql_stat_for_mysql(trx);
 
2299
        }
 
2300
 
 
2301
        return(convert_error_code_to_mysql(error, 0, NULL));
 
2302
}
 
2303
 
 
2304
/*****************************************************************//**
 
2305
Rolls back a transaction
 
2306
@return 0 or error number */
 
2307
static
 
2308
int
 
2309
innobase_rollback_trx(
 
2310
/*==================*/
 
2311
        trx_t*  trx)    /*!< in: transaction */
 
2312
{
 
2313
        int     error = 0;
 
2314
 
 
2315
        /* Release a possible FIFO ticket and search latch. Since we will
 
2316
        reserve the kernel mutex, we have to release the search system latch
 
2317
        first to obey the latching order. */
 
2318
 
 
2319
        innobase_release_stat_resources(trx);
 
2320
 
 
2321
        /* If we had reserved the auto-inc lock for some table (if
 
2322
        we come here to roll back the latest SQL statement) we
 
2323
        release it now before a possibly lengthy rollback */
 
2324
 
 
2325
        row_unlock_table_autoinc_for_mysql(trx);
 
2326
 
 
2327
        error = trx_rollback_for_mysql(trx);
 
2328
 
 
2329
        return(convert_error_code_to_mysql(error, 0, NULL));
 
2330
}
 
2331
 
 
2332
/*****************************************************************//**
 
2333
Rolls back a transaction to a savepoint.
 
2334
@return 0 if success, HA_ERR_NO_SAVEPOINT if no savepoint with the
 
2335
given name */
 
2336
int
 
2337
InnobaseEngine::savepoint_rollback_hook(
 
2338
/*===========================*/
 
2339
        Session*        session,                /*!< in: handle to the MySQL thread of the user
 
2340
                                whose transaction should be rolled back */
 
2341
        void*   savepoint)      /*!< in: savepoint data */
 
2342
{
 
2343
        ib_int64_t      mysql_binlog_cache_pos;
 
2344
        int             error = 0;
 
2345
        trx_t*          trx;
 
2346
        char            sp_name[64];
 
2347
 
 
2348
        assert(this == innodb_engine_ptr);
 
2349
 
 
2350
        trx = check_trx_exists(session);
 
2351
 
 
2352
        /* Release a possible FIFO ticket and search latch. Since we will
 
2353
        reserve the kernel mutex, we have to release the search system latch
 
2354
        first to obey the latching order. */
 
2355
 
 
2356
        innobase_release_stat_resources(trx);
 
2357
 
 
2358
        /* TODO: use provided savepoint data area to store savepoint data */
 
2359
 
 
2360
        int64_t2str((ulint)savepoint, sp_name, 36);
 
2361
 
 
2362
        error = (int) trx_rollback_to_savepoint_for_mysql(trx, sp_name,
 
2363
                                                &mysql_binlog_cache_pos);
 
2364
        return(convert_error_code_to_mysql(error, 0, NULL));
 
2365
}
 
2366
 
 
2367
/*****************************************************************//**
 
2368
Release transaction savepoint name.
 
2369
@return 0 if success, HA_ERR_NO_SAVEPOINT if no savepoint with the
 
2370
given name */
 
2371
int
 
2372
InnobaseEngine::savepoint_release_hook(
 
2373
/*=======================*/
 
2374
        Session*        session,                /*!< in: handle to the MySQL thread of the user
 
2375
                                whose transaction should be rolled back */
 
2376
        void*   savepoint)      /*!< in: savepoint data */
 
2377
{
 
2378
        int             error = 0;
 
2379
        trx_t*          trx;
 
2380
        char            sp_name[64];
 
2381
 
 
2382
        assert(this == innodb_engine_ptr);
 
2383
 
 
2384
        trx = check_trx_exists(session);
 
2385
 
 
2386
        /* TODO: use provided savepoint data area to store savepoint data */
 
2387
 
 
2388
        int64_t2str((ulint)savepoint, sp_name, 36);
 
2389
 
 
2390
        error = (int) trx_release_savepoint_for_mysql(trx, sp_name);
 
2391
 
 
2392
        return(convert_error_code_to_mysql(error, 0, NULL));
 
2393
}
 
2394
 
 
2395
/*****************************************************************//**
 
2396
Sets a transaction savepoint.
 
2397
@return always 0, that is, always succeeds */
 
2398
int
 
2399
InnobaseEngine::savepoint_set_hook(
 
2400
/*===============*/
 
2401
        Session*        session,/*!< in: handle to the MySQL thread */
 
2402
        void*   savepoint)      /*!< in: savepoint data */
 
2403
{
 
2404
        int     error = 0;
 
2405
        trx_t*  trx;
 
2406
 
 
2407
        assert(this == innodb_engine_ptr);
 
2408
 
 
2409
        /*
 
2410
          In the autocommit mode there is no sense to set a savepoint
 
2411
          (unless we are in sub-statement), so SQL layer ensures that
 
2412
          this method is never called in such situation.
 
2413
        */
 
2414
 
 
2415
        trx = check_trx_exists(session);
 
2416
 
 
2417
        /* Release a possible FIFO ticket and search latch. Since we will
 
2418
        reserve the kernel mutex, we have to release the search system latch
 
2419
        first to obey the latching order. */
 
2420
 
 
2421
        innobase_release_stat_resources(trx);
 
2422
 
 
2423
        /* cannot happen outside of transaction */
 
2424
        assert(trx->active_trans);
 
2425
 
 
2426
        /* TODO: use provided savepoint data area to store savepoint data */
 
2427
        char sp_name[64];
 
2428
        int64_t2str((ulint)savepoint,sp_name,36);
 
2429
 
 
2430
        error = (int) trx_savepoint_for_mysql(trx, sp_name, (ib_int64_t)0);
 
2431
 
 
2432
        return(convert_error_code_to_mysql(error, 0, NULL));
 
2433
}
 
2434
 
 
2435
/*****************************************************************//**
 
2436
Frees a possible InnoDB trx object associated with the current Session.
 
2437
@return 0 or error number */
 
2438
int
 
2439
InnobaseEngine::close_connection(
 
2440
/*======================*/
 
2441
        Session*        session)/*!< in: handle to the MySQL thread of the user
 
2442
                        whose resources should be free'd */
 
2443
{
 
2444
        trx_t*  trx;
 
2445
 
 
2446
        assert(this == innodb_engine_ptr);
 
2447
        trx = session_to_trx(session);
 
2448
 
 
2449
        ut_a(trx);
 
2450
 
 
2451
        if (trx->active_trans == 0
 
2452
                && trx->conc_state != TRX_NOT_STARTED) {
 
2453
 
 
2454
                errmsg_printf(ERRMSG_LVL_ERROR, "trx->active_trans == 0, but"
 
2455
                        " trx->conc_state != TRX_NOT_STARTED");
 
2456
        }
 
2457
 
 
2458
 
 
2459
        if (trx->conc_state != TRX_NOT_STARTED &&
 
2460
                global_system_variables.log_warnings) {
 
2461
                errmsg_printf(ERRMSG_LVL_WARN, 
 
2462
                        "MySQL is closing a connection that has an active "
 
2463
                        "InnoDB transaction.  %lu row modifications will "
 
2464
                        "roll back.",
 
2465
                        (ulong) trx->undo_no.low);
 
2466
        }
 
2467
 
 
2468
        innobase_rollback_trx(trx);
 
2469
 
 
2470
        thr_local_free(trx->mysql_thread_id);
 
2471
        trx_free_for_mysql(trx);
 
2472
 
 
2473
        return(0);
 
2474
}
 
2475
 
 
2476
 
 
2477
/*************************************************************************//**
 
2478
** InnoDB database tables
 
2479
*****************************************************************************/
 
2480
 
 
2481
/****************************************************************//**
 
2482
Get the record format from the data dictionary.
 
2483
@return one of ROW_TYPE_REDUNDANT, ROW_TYPE_COMPACT,
 
2484
ROW_TYPE_COMPRESSED, ROW_TYPE_DYNAMIC */
 
2485
UNIV_INTERN
 
2486
enum row_type
 
2487
ha_innobase::get_row_type() const
 
2488
/*=============================*/
 
2489
{
 
2490
        if (prebuilt && prebuilt->table) {
 
2491
                const ulint     flags = prebuilt->table->flags;
 
2492
 
 
2493
                if (UNIV_UNLIKELY(!flags)) {
 
2494
                        return(ROW_TYPE_REDUNDANT);
 
2495
                }
 
2496
 
 
2497
                ut_ad(flags & DICT_TF_COMPACT);
 
2498
 
 
2499
                switch (flags & DICT_TF_FORMAT_MASK) {
 
2500
                case DICT_TF_FORMAT_51 << DICT_TF_FORMAT_SHIFT:
 
2501
                        return(ROW_TYPE_COMPACT);
 
2502
                case DICT_TF_FORMAT_ZIP << DICT_TF_FORMAT_SHIFT:
 
2503
                        if (flags & DICT_TF_ZSSIZE_MASK) {
 
2504
                                return(ROW_TYPE_COMPRESSED);
 
2505
                        } else {
 
2506
                                return(ROW_TYPE_DYNAMIC);
 
2507
                        }
 
2508
#if DICT_TF_FORMAT_ZIP != DICT_TF_FORMAT_MAX
 
2509
# error "DICT_TF_FORMAT_ZIP != DICT_TF_FORMAT_MAX"
 
2510
#endif
 
2511
                }
 
2512
        }
 
2513
        ut_ad(0);
 
2514
        return(ROW_TYPE_NOT_USED);
 
2515
}
 
2516
 
 
2517
 
 
2518
/****************************************************************//**
 
2519
Returns the index type. */
 
2520
UNIV_INTERN
 
2521
const char*
 
2522
ha_innobase::index_type(
 
2523
/*====================*/
 
2524
        uint)
 
2525
                                /*!< out: index type */
 
2526
{
 
2527
        return("BTREE");
 
2528
}
 
2529
 
 
2530
/****************************************************************//**
 
2531
Returns the maximum number of keys.
 
2532
@return MAX_KEY */
 
2533
UNIV_INTERN
 
2534
uint
 
2535
InnobaseEngine::max_supported_keys() const
 
2536
/*===================================*/
 
2537
{
 
2538
        return(MAX_KEY);
 
2539
}
 
2540
 
 
2541
/****************************************************************//**
 
2542
Returns the maximum key length.
 
2543
@return maximum supported key length, in bytes */
 
2544
UNIV_INTERN
 
2545
uint32_t
 
2546
InnobaseEngine::max_supported_key_length() const
 
2547
/*=========================================*/
 
2548
{
 
2549
        /* An InnoDB page must store >= 2 keys; a secondary key record
 
2550
        must also contain the primary key value: max key length is
 
2551
        therefore set to slightly less than 1 / 4 of page size which
 
2552
        is 16 kB; but currently MySQL does not work with keys whose
 
2553
        size is > MAX_KEY_LENGTH */
 
2554
        return(3500);
 
2555
}
 
2556
 
 
2557
/****************************************************************//**
 
2558
Returns the key map of keys that are usable for scanning.
 
2559
@return key_map_full */
 
2560
UNIV_INTERN
 
2561
const key_map*
 
2562
ha_innobase::keys_to_use_for_scanning()
 
2563
{
 
2564
        return(&key_map_full);
 
2565
}
 
2566
 
 
2567
 
 
2568
/****************************************************************//**
 
2569
Determines if the primary key is clustered index.
 
2570
@return true */
 
2571
UNIV_INTERN
 
2572
bool
 
2573
ha_innobase::primary_key_is_clustered()
 
2574
{
 
2575
        return(true);
 
2576
}
 
2577
 
 
2578
/*****************************************************************//**
 
2579
Normalizes a table name string. A normalized name consists of the
 
2580
database name catenated to '/' and table name. An example:
 
2581
test/mytable. On Windows normalization puts both the database name and the
 
2582
table name always to lower case. */
 
2583
static
 
2584
void
 
2585
normalize_table_name(
 
2586
/*=================*/
 
2587
        char*           norm_name,      /*!< out: normalized name as a
 
2588
                                        null-terminated string */
 
2589
        const char*     name)           /*!< in: table name string */
 
2590
{
 
2591
        const char*     name_ptr;
 
2592
        const char*     db_ptr;
 
2593
        const char*     ptr;
 
2594
 
 
2595
        /* Scan name from the end */
 
2596
 
 
2597
        ptr = strchr(name, '\0')-1;
 
2598
 
 
2599
        while (ptr >= name && *ptr != '\\' && *ptr != '/') {
 
2600
                ptr--;
 
2601
        }
 
2602
 
 
2603
        name_ptr = ptr + 1;
 
2604
 
 
2605
        assert(ptr > name);
 
2606
 
 
2607
        ptr--;
 
2608
 
 
2609
        while (ptr >= name && *ptr != '\\' && *ptr != '/') {
 
2610
                ptr--;
 
2611
        }
 
2612
 
 
2613
        db_ptr = ptr + 1;
 
2614
 
 
2615
        memcpy(norm_name, db_ptr, strlen(name) + 1 - (db_ptr - name));
 
2616
 
 
2617
        norm_name[name_ptr - db_ptr - 1] = '/';
 
2618
 
 
2619
#ifdef __WIN__
 
2620
        innobase_casedn_str(norm_name);
 
2621
#endif
 
2622
}
 
2623
 
 
2624
/********************************************************************//**
 
2625
Set the autoinc column max value. This should only be called once from
 
2626
ha_innobase::open(). Therefore there's no need for a covering lock.
 
2627
@return DB_SUCCESS or error code */
 
2628
UNIV_INTERN
 
2629
ulint
 
2630
ha_innobase::innobase_initialize_autoinc()
 
2631
/*======================================*/
 
2632
{
 
2633
        dict_index_t*   index;
 
2634
        uint64_t        auto_inc;
 
2635
        const char*     col_name;
 
2636
        ulint           error;
 
2637
 
 
2638
        col_name = table->found_next_number_field->field_name;
 
2639
        index = innobase_get_index(table->s->next_number_index);
 
2640
 
 
2641
        /* Execute SELECT MAX(col_name) FROM TABLE; */
 
2642
        error = row_search_max_autoinc(index, col_name, &auto_inc);
 
2643
 
 
2644
        switch (error) {
 
2645
        case DB_SUCCESS:
 
2646
 
 
2647
                /* At the this stage we don't know the increment
 
2648
                or the offset, so use default inrement of 1. */
 
2649
                ++auto_inc;
 
2650
                break;
 
2651
 
 
2652
        case DB_RECORD_NOT_FOUND:
 
2653
                ut_print_timestamp(stderr);
 
2654
                fprintf(stderr, "  InnoDB: MySQL and InnoDB data "
 
2655
                        "dictionaries are out of sync.\n"
 
2656
                        "InnoDB: Unable to find the AUTOINC column %s in the "
 
2657
                        "InnoDB table %s.\n"
 
2658
                        "InnoDB: We set the next AUTOINC column value to the "
 
2659
                        "maximum possible value,\n"
 
2660
                        "InnoDB: in effect disabling the AUTOINC next value "
 
2661
                        "generation.\n"
 
2662
                        "InnoDB: You can either set the next AUTOINC value "
 
2663
                        "explicitly using ALTER TABLE\n"
 
2664
                        "InnoDB: or fix the data dictionary by recreating "
 
2665
                        "the table.\n",
 
2666
                        col_name, index->table->name);
 
2667
 
 
2668
                auto_inc = 0xFFFFFFFFFFFFFFFFULL;
 
2669
                break;
 
2670
 
 
2671
        default:
 
2672
                return(error);
 
2673
        }
 
2674
 
 
2675
        dict_table_autoinc_initialize(prebuilt->table, auto_inc);
 
2676
 
 
2677
        return(DB_SUCCESS);
 
2678
}
 
2679
 
 
2680
/*****************************************************************//**
 
2681
Creates and opens a handle to a table which already exists in an InnoDB
 
2682
database.
 
2683
@return 1 if error, 0 if success */
 
2684
UNIV_INTERN
 
2685
int
 
2686
ha_innobase::open(
 
2687
/*==============*/
 
2688
        const char*     name,           /*!< in: table name */
 
2689
        int             mode,           /*!< in: not used */
 
2690
        uint            test_if_locked) /*!< in: not used */
 
2691
{
 
2692
        dict_table_t*   ib_table;
 
2693
        char            norm_name[1000];
 
2694
        Session*                session;
 
2695
        ulint           retries = 0;
 
2696
        char*           is_part = NULL;
 
2697
 
 
2698
        UT_NOT_USED(mode);
 
2699
        UT_NOT_USED(test_if_locked);
 
2700
 
 
2701
        session = ha_session();
 
2702
 
 
2703
        /* Under some cases Drizzle seems to call this function while
 
2704
        holding btr_search_latch. This breaks the latching order as
 
2705
        we acquire dict_sys->mutex below and leads to a deadlock. */
 
2706
        if (session != NULL) {
 
2707
                engine->release_temporary_latches(session);
 
2708
        }
 
2709
 
 
2710
        normalize_table_name(norm_name, name);
 
2711
 
 
2712
        user_session = NULL;
 
2713
 
 
2714
        if (!(share=get_share(name))) {
 
2715
 
 
2716
                return(1);
 
2717
        }
 
2718
 
 
2719
        /* Create buffers for packing the fields of a record. Why
 
2720
        table->stored_rec_length did not work here? Obviously, because char
 
2721
        fields when packed actually became 1 byte longer, when we also
 
2722
        stored the string length as the first byte. */
 
2723
 
 
2724
        upd_and_key_val_buff_len =
 
2725
                                table->s->stored_rec_length
 
2726
                                + table->s->max_key_length
 
2727
                                + MAX_REF_PARTS * 3;
 
2728
        if (!(unsigned char*) drizzled::memory::multi_malloc(false,
 
2729
                        &upd_buff, upd_and_key_val_buff_len,
 
2730
                        &key_val_buff, upd_and_key_val_buff_len,
 
2731
                        NULL)) {
 
2732
                free_share(share);
 
2733
 
 
2734
                return(1);
 
2735
        }
 
2736
 
 
2737
        /* We look for pattern #P# to see if the table is partitioned
 
2738
        MySQL table. The retry logic for partitioned tables is a
 
2739
        workaround for http://bugs.mysql.com/bug.php?id=33349. Look
 
2740
        at support issue https://support.mysql.com/view.php?id=21080
 
2741
        for more details. */
 
2742
        is_part = strstr(norm_name, "#P#");
 
2743
retry:
 
2744
        /* Get pointer to a table object in InnoDB dictionary cache */
 
2745
        ib_table = dict_table_get(norm_name, TRUE);
 
2746
        
 
2747
        if (NULL == ib_table) {
 
2748
                if (is_part && retries < 10) {
 
2749
                        ++retries;
 
2750
                        os_thread_sleep(100000);
 
2751
                        goto retry;
 
2752
                }
 
2753
 
 
2754
                if (is_part) {
 
2755
                        errmsg_printf(ERRMSG_LVL_ERROR, "Failed to open table %s after "
 
2756
                                        "%lu attemtps.\n", norm_name,
 
2757
                                        retries);
 
2758
                }
 
2759
 
 
2760
                errmsg_printf(ERRMSG_LVL_ERROR, "Cannot find or open table %s from\n"
 
2761
                                "the internal data dictionary of InnoDB "
 
2762
                                "though the .frm file for the\n"
 
2763
                                "table exists. Maybe you have deleted and "
 
2764
                                "recreated InnoDB data\n"
 
2765
                                "files but have forgotten to delete the "
 
2766
                                "corresponding .frm files\n"
 
2767
                                "of InnoDB tables, or you have moved .frm "
 
2768
                                "files to another database?\n"
 
2769
                                "or, the table contains indexes that this "
 
2770
                                "version of the engine\n"
 
2771
                                "doesn't support.\n"
 
2772
                                "See " REFMAN "innodb-troubleshooting.html\n"
 
2773
                                "how you can resolve the problem.\n",
 
2774
                                norm_name);
 
2775
                free_share(share);
 
2776
                free(upd_buff);
 
2777
                errno = ENOENT;
 
2778
 
 
2779
                return(HA_ERR_NO_SUCH_TABLE);
 
2780
        }
 
2781
 
 
2782
        if (ib_table->ibd_file_missing && !session_tablespace_op(session)) {
 
2783
                errmsg_printf(ERRMSG_LVL_ERROR, "MySQL is trying to open a table handle but "
 
2784
                                "the .ibd file for\ntable %s does not exist.\n"
 
2785
                                "Have you deleted the .ibd file from the "
 
2786
                                "database directory under\nthe MySQL datadir, "
 
2787
                                "or have you used DISCARD TABLESPACE?\n"
 
2788
                                "See " REFMAN "innodb-troubleshooting.html\n"
 
2789
                                "how you can resolve the problem.\n",
 
2790
                                norm_name);
 
2791
                free_share(share);
 
2792
                free(upd_buff);
 
2793
                errno = ENOENT;
 
2794
 
 
2795
                dict_table_decrement_handle_count(ib_table, FALSE);
 
2796
                return(HA_ERR_NO_SUCH_TABLE);
 
2797
        }
 
2798
 
 
2799
        prebuilt = row_create_prebuilt(ib_table);
 
2800
 
 
2801
        prebuilt->mysql_row_len = table->s->stored_rec_length;
 
2802
        prebuilt->default_rec = table->s->default_values;
 
2803
        ut_ad(prebuilt->default_rec);
 
2804
 
 
2805
        /* Looks like MySQL-3.23 sometimes has primary key number != 0 */
 
2806
 
 
2807
        primary_key = table->s->primary_key;
 
2808
        key_used_on_scan = primary_key;
 
2809
 
 
2810
        /* Allocate a buffer for a 'row reference'. A row reference is
 
2811
        a string of bytes of length ref_length which uniquely specifies
 
2812
        a row in our table. Note that MySQL may also compare two row
 
2813
        references for equality by doing a simple memcmp on the strings
 
2814
        of length ref_length! */
 
2815
 
 
2816
        if (!row_table_got_default_clust_index(ib_table)) {
 
2817
                if (primary_key >= MAX_KEY) {
 
2818
                  errmsg_printf(ERRMSG_LVL_ERROR, "Table %s has a primary key in InnoDB data "
 
2819
                                  "dictionary, but not in MySQL!", name);
 
2820
                }
 
2821
 
 
2822
                prebuilt->clust_index_was_generated = FALSE;
 
2823
 
 
2824
                /* MySQL allocates the buffer for ref. key_info->key_length
 
2825
                includes space for all key columns + one byte for each column
 
2826
                that may be NULL. ref_length must be as exact as possible to
 
2827
                save space, because all row reference buffers are allocated
 
2828
                based on ref_length. */
 
2829
 
 
2830
                ref_length = table->key_info[primary_key].key_length;
 
2831
        } else {
 
2832
                if (primary_key != MAX_KEY) {
 
2833
                  errmsg_printf(ERRMSG_LVL_ERROR, "Table %s has no primary key in InnoDB data "
 
2834
                                  "dictionary, but has one in MySQL! If you "
 
2835
                                  "created the table with a MySQL version < "
 
2836
                                  "3.23.54 and did not define a primary key, "
 
2837
                                  "but defined a unique key with all non-NULL "
 
2838
                                  "columns, then MySQL internally treats that "
 
2839
                                  "key as the primary key. You can fix this "
 
2840
                                  "error by dump + DROP + CREATE + reimport "
 
2841
                                  "of the table.", name);
 
2842
                }
 
2843
 
 
2844
                prebuilt->clust_index_was_generated = TRUE;
 
2845
 
 
2846
                ref_length = DATA_ROW_ID_LEN;
 
2847
 
 
2848
                /* If we automatically created the clustered index, then
 
2849
                MySQL does not know about it, and MySQL must NOT be aware
 
2850
                of the index used on scan, to make it avoid checking if we
 
2851
                update the column of the index. That is why we assert below
 
2852
                that key_used_on_scan is the undefined value MAX_KEY.
 
2853
                The column is the row id in the automatical generation case,
 
2854
                and it will never be updated anyway. */
 
2855
 
 
2856
                if (key_used_on_scan != MAX_KEY) {
 
2857
                        errmsg_printf(ERRMSG_LVL_WARN, 
 
2858
                                "Table %s key_used_on_scan is %lu even "
 
2859
                                "though there is no primary key inside "
 
2860
                                "InnoDB.", name, (ulong) key_used_on_scan);
 
2861
                }
 
2862
        }
 
2863
 
 
2864
        /* Index block size in InnoDB: used by MySQL in query optimization */
 
2865
        stats.block_size = 16 * 1024;
 
2866
 
 
2867
        /* Init table lock structure */
 
2868
        thr_lock_data_init(&share->lock,&lock,(void*) 0);
 
2869
 
 
2870
        if (prebuilt->table) {
 
2871
                /* We update the highest file format in the system table
 
2872
                space, if this table has higher file format setting. */
 
2873
 
 
2874
                trx_sys_file_format_max_upgrade(
 
2875
                        (const char**) &innobase_file_format_check,
 
2876
                        dict_table_get_format(prebuilt->table));
 
2877
        }
 
2878
 
 
2879
        info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
 
2880
 
 
2881
        /* Only if the table has an AUTOINC column. */
 
2882
        if (prebuilt->table != NULL && table->found_next_number_field != NULL) {
 
2883
                ulint   error;
 
2884
 
 
2885
                dict_table_autoinc_lock(prebuilt->table);
 
2886
 
 
2887
                /* Since a table can already be "open" in InnoDB's internal
 
2888
                data dictionary, we only init the autoinc counter once, the
 
2889
                first time the table is loaded. We can safely reuse the
 
2890
                autoinc value from a previous Drizzle open. */
 
2891
                if (dict_table_autoinc_read(prebuilt->table) == 0) {
 
2892
 
 
2893
                        error = innobase_initialize_autoinc();
 
2894
                        ut_a(error == DB_SUCCESS);
 
2895
                }
 
2896
 
 
2897
                dict_table_autoinc_unlock(prebuilt->table);
 
2898
        }
 
2899
 
 
2900
        return(0);
 
2901
}
 
2902
 
 
2903
UNIV_INTERN
 
2904
uint32_t
 
2905
InnobaseEngine::max_supported_key_part_length() const
 
2906
{
 
2907
        return(DICT_MAX_INDEX_COL_LEN - 1);
 
2908
}
 
2909
 
 
2910
/******************************************************************//**
 
2911
Closes a handle to an InnoDB table.
 
2912
@return 0 */
 
2913
UNIV_INTERN
 
2914
int
 
2915
ha_innobase::close(void)
 
2916
/*====================*/
 
2917
{
 
2918
        Session*        session;
 
2919
 
 
2920
        session = ha_session();
 
2921
        if (session != NULL) {
 
2922
                engine->release_temporary_latches(session);
 
2923
        }
 
2924
 
 
2925
        row_prebuilt_free(prebuilt, FALSE);
 
2926
 
 
2927
        free(upd_buff);
 
2928
        free_share(share);
 
2929
 
 
2930
        /* Tell InnoDB server that there might be work for
 
2931
        utility threads: */
 
2932
 
 
2933
        srv_active_wake_master_thread();
 
2934
 
 
2935
        return(0);
 
2936
}
 
2937
 
 
2938
/* The following accessor functions should really be inside MySQL code! */
 
2939
 
 
2940
/**************************************************************//**
 
2941
Gets field offset for a field in a table.
 
2942
@return offset */
 
2943
static inline
 
2944
uint
 
2945
get_field_offset(
 
2946
/*=============*/
 
2947
        Table*  table,  /*!< in: MySQL table object */
 
2948
        Field*  field)  /*!< in: MySQL field object */
 
2949
{
 
2950
        return((uint) (field->ptr - table->record[0]));
 
2951
}
 
2952
 
 
2953
/**************************************************************//**
 
2954
Checks if a field in a record is SQL NULL. Uses the record format
 
2955
information in table to track the null bit in record.
 
2956
@return 1 if NULL, 0 otherwise */
 
2957
static inline
 
2958
uint
 
2959
field_in_record_is_null(
 
2960
/*====================*/
 
2961
        Table*  table,  /*!< in: MySQL table object */
 
2962
        Field*  field,  /*!< in: MySQL field object */
 
2963
        char*   record) /*!< in: a row in MySQL format */
 
2964
{
 
2965
        int     null_offset;
 
2966
 
 
2967
        if (!field->null_ptr) {
 
2968
 
 
2969
                return(0);
 
2970
        }
 
2971
 
 
2972
        null_offset = (uint) ((char*) field->null_ptr
 
2973
                                        - (char*) table->record[0]);
 
2974
 
 
2975
        if (record[null_offset] & field->null_bit) {
 
2976
 
 
2977
                return(1);
 
2978
        }
 
2979
 
 
2980
        return(0);
 
2981
}
 
2982
 
 
2983
/**************************************************************//**
 
2984
Sets a field in a record to SQL NULL. Uses the record format
 
2985
information in table to track the null bit in record. */
 
2986
static inline
 
2987
void
 
2988
set_field_in_record_to_null(
 
2989
/*========================*/
 
2990
        Table*  table,  /*!< in: MySQL table object */
 
2991
        Field*  field,  /*!< in: MySQL field object */
 
2992
        char*   record) /*!< in: a row in MySQL format */
 
2993
{
 
2994
        int     null_offset;
 
2995
 
 
2996
        null_offset = (uint) ((char*) field->null_ptr
 
2997
                                        - (char*) table->record[0]);
 
2998
 
 
2999
        record[null_offset] = record[null_offset] | field->null_bit;
 
3000
}
 
3001
 
 
3002
/*************************************************************//**
 
3003
InnoDB uses this function to compare two data fields for which the data type
 
3004
is such that we must use MySQL code to compare them. NOTE that the prototype
 
3005
of this function is in rem0cmp.c in InnoDB source code! If you change this
 
3006
function, remember to update the prototype there!
 
3007
@return 1, 0, -1, if a is greater, equal, less than b, respectively */
 
3008
extern "C" UNIV_INTERN
 
3009
int
 
3010
innobase_mysql_cmp(
 
3011
/*===============*/
 
3012
        int             mysql_type,     /*!< in: MySQL type */
 
3013
        uint            charset_number, /*!< in: number of the charset */
 
3014
        const unsigned char* a,         /*!< in: data field */
 
3015
        unsigned int    a_length,       /*!< in: data field length,
 
3016
                                        not UNIV_SQL_NULL */
 
3017
        const unsigned char* b,         /* in: data field */
 
3018
        unsigned int    b_length);      /* in: data field length,
 
3019
                                        not UNIV_SQL_NULL */
 
3020
 
 
3021
int
 
3022
innobase_mysql_cmp(
 
3023
/*===============*/
 
3024
                                        /* out: 1, 0, -1, if a is greater,
 
3025
                                        equal, less than b, respectively */
 
3026
        int             mysql_type,     /* in: MySQL type */
 
3027
        uint            charset_number, /* in: number of the charset */
 
3028
        const unsigned char* a,         /* in: data field */
 
3029
        unsigned int    a_length,       /* in: data field length,
 
3030
                                        not UNIV_SQL_NULL */
 
3031
        const unsigned char* b,         /* in: data field */
 
3032
        unsigned int    b_length)       /* in: data field length,
 
3033
                                        not UNIV_SQL_NULL */
 
3034
{
 
3035
        const CHARSET_INFO*     charset;
 
3036
        enum_field_types        mysql_tp;
 
3037
        int                     ret;
 
3038
 
 
3039
        assert(a_length != UNIV_SQL_NULL);
 
3040
        assert(b_length != UNIV_SQL_NULL);
 
3041
 
 
3042
        mysql_tp = (enum_field_types) mysql_type;
 
3043
 
 
3044
        switch (mysql_tp) {
 
3045
 
 
3046
        case DRIZZLE_TYPE_BLOB:
 
3047
        case DRIZZLE_TYPE_VARCHAR:
 
3048
                /* Use the charset number to pick the right charset struct for
 
3049
                the comparison. Since the MySQL function get_charset may be
 
3050
                slow before Bar removes the mutex operation there, we first
 
3051
                look at 2 common charsets directly. */
 
3052
 
 
3053
                if (charset_number == default_charset_info->number) {
 
3054
                        charset = default_charset_info;
 
3055
                } else {
 
3056
                        charset = get_charset(charset_number);
 
3057
 
 
3058
                        if (charset == NULL) {
 
3059
                          errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB needs charset %lu for doing "
 
3060
                                          "a comparison, but MySQL cannot "
 
3061
                                          "find that charset.",
 
3062
                                          (ulong) charset_number);
 
3063
                                ut_a(0);
 
3064
                        }
 
3065
                }
 
3066
 
 
3067
                /* Starting from 4.1.3, we use strnncollsp() in comparisons of
 
3068
                non-latin1_swedish_ci strings. NOTE that the collation order
 
3069
                changes then: 'b\0\0...' is ordered BEFORE 'b  ...'. Users
 
3070
                having indexes on such data need to rebuild their tables! */
 
3071
 
 
3072
                ret = charset->coll->strnncollsp(charset,
 
3073
                                  a, a_length,
 
3074
                                                 b, b_length, 0);
 
3075
                if (ret < 0) {
 
3076
                        return(-1);
 
3077
                } else if (ret > 0) {
 
3078
                        return(1);
 
3079
                } else {
 
3080
                        return(0);
 
3081
                }
 
3082
        default:
 
3083
                ut_error;
 
3084
        }
 
3085
 
 
3086
        return(0);
 
3087
}
 
3088
 
 
3089
/**************************************************************//**
 
3090
Converts a MySQL type to an InnoDB type. Note that this function returns
 
3091
the 'mtype' of InnoDB. InnoDB differentiates between MySQL's old <= 4.1
 
3092
VARCHAR and the new true VARCHAR in >= 5.0.3 by the 'prtype'.
 
3093
@return DATA_BINARY, DATA_VARCHAR, ... */
 
3094
extern "C" UNIV_INTERN
 
3095
ulint
 
3096
get_innobase_type_from_mysql_type(
 
3097
/*==============================*/
 
3098
        ulint*          unsigned_flag,  /*!< out: DATA_UNSIGNED if an
 
3099
                                        'unsigned type';
 
3100
                                        at least ENUM and SET,
 
3101
                                        and unsigned integer
 
3102
                                        types are 'unsigned types' */
 
3103
        const void*     f)              /*!< in: MySQL Field */
 
3104
{
 
3105
        const class Field* field = reinterpret_cast<const class Field*>(f);
 
3106
 
 
3107
        /* The following asserts try to check that the MySQL type code fits in
 
3108
        8 bits: this is used in ibuf and also when DATA_NOT_NULL is ORed to
 
3109
        the type */
 
3110
 
 
3111
        assert((ulint)DRIZZLE_TYPE_DOUBLE < 256);
 
3112
 
 
3113
        if (field->flags & UNSIGNED_FLAG) {
 
3114
 
 
3115
                *unsigned_flag = DATA_UNSIGNED;
 
3116
        } else {
 
3117
                *unsigned_flag = 0;
 
3118
        }
 
3119
 
 
3120
        if (field->real_type() == DRIZZLE_TYPE_ENUM)
 
3121
        {
 
3122
                /* MySQL has field->type() a string type for these, but the
 
3123
                data is actually internally stored as an unsigned integer
 
3124
                code! */
 
3125
 
 
3126
                *unsigned_flag = DATA_UNSIGNED; /* MySQL has its own unsigned
 
3127
                                                flag set to zero, even though
 
3128
                                                internally this is an unsigned
 
3129
                                                integer type */
 
3130
                return(DATA_INT);
 
3131
        }
 
3132
 
 
3133
        switch (field->type()) {
 
3134
                /* NOTE that we only allow string types in DATA_DRIZZLE and
 
3135
                DATA_VARDRIZZLE */
 
3136
        case DRIZZLE_TYPE_VARCHAR:    /* new >= 5.0.3 true VARCHAR */
 
3137
                if (field->binary()) {
 
3138
                        return(DATA_BINARY);
 
3139
                } else {
 
3140
                        return(DATA_VARMYSQL);
 
3141
                }
 
3142
        case DRIZZLE_TYPE_DECIMAL:
 
3143
                return(DATA_FIXBINARY);
 
3144
        case DRIZZLE_TYPE_LONG:
 
3145
        case DRIZZLE_TYPE_LONGLONG:
 
3146
        case DRIZZLE_TYPE_DATETIME:
 
3147
        case DRIZZLE_TYPE_DATE:
 
3148
        case DRIZZLE_TYPE_TIMESTAMP:
 
3149
                return(DATA_INT);
 
3150
        case DRIZZLE_TYPE_DOUBLE:
 
3151
                return(DATA_DOUBLE);
 
3152
        case DRIZZLE_TYPE_BLOB:
 
3153
                return(DATA_BLOB);
 
3154
        default:
 
3155
                ut_error;
 
3156
        }
 
3157
 
 
3158
        return(0);
 
3159
}
 
3160
 
 
3161
/*******************************************************************//**
 
3162
Writes an unsigned integer value < 64k to 2 bytes, in the little-endian
 
3163
storage format. */
 
3164
static inline
 
3165
void
 
3166
innobase_write_to_2_little_endian(
 
3167
/*==============================*/
 
3168
        byte*   buf,    /*!< in: where to store */
 
3169
        ulint   val)    /*!< in: value to write, must be < 64k */
 
3170
{
 
3171
        ut_a(val < 256 * 256);
 
3172
 
 
3173
        buf[0] = (byte)(val & 0xFF);
 
3174
        buf[1] = (byte)(val / 256);
 
3175
}
 
3176
 
 
3177
/*******************************************************************//**
 
3178
Reads an unsigned integer value < 64k from 2 bytes, in the little-endian
 
3179
storage format.
 
3180
@return value */
 
3181
static inline
 
3182
uint
 
3183
innobase_read_from_2_little_endian(
 
3184
/*===============================*/
 
3185
        const unsigned char*    buf)    /*!< in: from where to read */
 
3186
{
 
3187
        return (uint) ((ulint)(buf[0]) + 256 * ((ulint)(buf[1])));
 
3188
}
 
3189
 
 
3190
/*******************************************************************//**
 
3191
Stores a key value for a row to a buffer.
 
3192
@return key value length as stored in buff */
 
3193
UNIV_INTERN
 
3194
uint
 
3195
ha_innobase::store_key_val_for_row(
 
3196
/*===============================*/
 
3197
        uint            keynr,  /*!< in: key number */
 
3198
        char*           buff,   /*!< in/out: buffer for the key value (in MySQL
 
3199
                                format) */
 
3200
        uint            buff_len,/*!< in: buffer length */
 
3201
        const unsigned char*    record)/*!< in: row in MySQL format */
 
3202
{
 
3203
        KEY*            key_info        = table->key_info + keynr;
 
3204
        KEY_PART_INFO*  key_part        = key_info->key_part;
 
3205
        KEY_PART_INFO*  end             = key_part + key_info->key_parts;
 
3206
        char*           buff_start      = buff;
 
3207
        enum_field_types mysql_type;
 
3208
        Field*          field;
 
3209
        ibool           is_null;
 
3210
 
 
3211
        /* The format for storing a key field in MySQL is the following:
 
3212
 
 
3213
        1. If the column can be NULL, then in the first byte we put 1 if the
 
3214
        field value is NULL, 0 otherwise.
 
3215
 
 
3216
        2. If the column is of a BLOB type (it must be a column prefix field
 
3217
        in this case), then we put the length of the data in the field to the
 
3218
        next 2 bytes, in the little-endian format. If the field is SQL NULL,
 
3219
        then these 2 bytes are set to 0. Note that the length of data in the
 
3220
        field is <= column prefix length.
 
3221
 
 
3222
        3. In a column prefix field, prefix_len next bytes are reserved for
 
3223
        data. In a normal field the max field length next bytes are reserved
 
3224
        for data. For a VARCHAR(n) the max field length is n. If the stored
 
3225
        value is the SQL NULL then these data bytes are set to 0.
 
3226
 
 
3227
        4. We always use a 2 byte length for a true >= 5.0.3 VARCHAR. Note that
 
3228
        in the MySQL row format, the length is stored in 1 or 2 bytes,
 
3229
        depending on the maximum allowed length. But in the MySQL key value
 
3230
        format, the length always takes 2 bytes.
 
3231
 
 
3232
        We have to zero-fill the buffer so that MySQL is able to use a
 
3233
        simple memcmp to compare two key values to determine if they are
 
3234
        equal. MySQL does this to compare contents of two 'ref' values. */
 
3235
 
 
3236
        bzero(buff, buff_len);
 
3237
 
 
3238
        for (; key_part != end; key_part++) {
 
3239
                is_null = FALSE;
 
3240
 
 
3241
                if (key_part->null_bit) {
 
3242
                        if (record[key_part->null_offset]
 
3243
                                                & key_part->null_bit) {
 
3244
                                *buff = 1;
 
3245
                                is_null = TRUE;
 
3246
                        } else {
 
3247
                                *buff = 0;
 
3248
                        }
 
3249
                        buff++;
 
3250
                }
 
3251
 
 
3252
                field = key_part->field;
 
3253
                mysql_type = field->type();
 
3254
 
 
3255
                if (mysql_type == DRIZZLE_TYPE_VARCHAR) {
 
3256
                                                /* >= 5.0.3 true VARCHAR */
 
3257
                        ulint           lenlen;
 
3258
                        ulint           len;
 
3259
                        const byte*     data;
 
3260
                        ulint           key_len;
 
3261
                        ulint           true_len;
 
3262
                        const CHARSET_INFO*     cs;
 
3263
                        int             error=0;
 
3264
 
 
3265
                        key_len = key_part->length;
 
3266
 
 
3267
                        if (is_null) {
 
3268
                                buff += key_len + 2;
 
3269
 
 
3270
                                continue;
 
3271
                        }
 
3272
                        cs = field->charset();
 
3273
 
 
3274
                        lenlen = (ulint)
 
3275
                                (((Field_varstring*)field)->length_bytes);
 
3276
 
 
3277
                        data = row_mysql_read_true_varchar(&len,
 
3278
                                (byte*) (record
 
3279
                                + (ulint)get_field_offset(table, field)),
 
3280
                                lenlen);
 
3281
 
 
3282
                        true_len = len;
 
3283
 
 
3284
                        /* For multi byte character sets we need to calculate
 
3285
                        the true length of the key */
 
3286
 
 
3287
                        if (len > 0 && cs->mbmaxlen > 1) {
 
3288
                                true_len = (ulint) cs->cset->well_formed_len(cs,
 
3289
                                                (const char *) data,
 
3290
                                                (const char *) data + len,
 
3291
                                                (uint) (key_len /
 
3292
                                                        cs->mbmaxlen),
 
3293
                                                &error);
 
3294
                        }
 
3295
 
 
3296
                        /* In a column prefix index, we may need to truncate
 
3297
                        the stored value: */
 
3298
 
 
3299
                        if (true_len > key_len) {
 
3300
                                true_len = key_len;
 
3301
                        }
 
3302
 
 
3303
                        /* The length in a key value is always stored in 2
 
3304
                        bytes */
 
3305
 
 
3306
                        row_mysql_store_true_var_len((byte*)buff, true_len, 2);
 
3307
                        buff += 2;
 
3308
 
 
3309
                        memcpy(buff, data, true_len);
 
3310
 
 
3311
                        /* Note that we always reserve the maximum possible
 
3312
                        length of the true VARCHAR in the key value, though
 
3313
                        only len first bytes after the 2 length bytes contain
 
3314
                        actual data. The rest of the space was reset to zero
 
3315
                        in the bzero() call above. */
 
3316
 
 
3317
                        buff += key_len;
 
3318
 
 
3319
                } else if (mysql_type == DRIZZLE_TYPE_BLOB) {
 
3320
 
 
3321
                        const CHARSET_INFO*     cs;
 
3322
                        ulint           key_len;
 
3323
                        ulint           true_len;
 
3324
                        int             error=0;
 
3325
                        ulint           blob_len;
 
3326
                        const byte*     blob_data;
 
3327
 
 
3328
                        ut_a(key_part->key_part_flag & HA_PART_KEY_SEG);
 
3329
 
 
3330
                        key_len = key_part->length;
 
3331
 
 
3332
                        if (is_null) {
 
3333
                                buff += key_len + 2;
 
3334
 
 
3335
                                continue;
 
3336
                        }
 
3337
 
 
3338
                        cs = field->charset();
 
3339
 
 
3340
                        blob_data = row_mysql_read_blob_ref(&blob_len,
 
3341
                                (byte*) (record
 
3342
                                + (ulint)get_field_offset(table, field)),
 
3343
                                        (ulint) field->pack_length());
 
3344
 
 
3345
                        true_len = blob_len;
 
3346
 
 
3347
                        ut_a(get_field_offset(table, field)
 
3348
                                == key_part->offset);
 
3349
 
 
3350
                        /* For multi byte character sets we need to calculate
 
3351
                        the true length of the key */
 
3352
 
 
3353
                        if (blob_len > 0 && cs->mbmaxlen > 1) {
 
3354
                                true_len = (ulint) cs->cset->well_formed_len(cs,
 
3355
                                                (const char *) blob_data,
 
3356
                                                (const char *) blob_data
 
3357
                                                        + blob_len,
 
3358
                                                (uint) (key_len /
 
3359
                                                        cs->mbmaxlen),
 
3360
                                                &error);
 
3361
                        }
 
3362
 
 
3363
                        /* All indexes on BLOB and TEXT are column prefix
 
3364
                        indexes, and we may need to truncate the data to be
 
3365
                        stored in the key value: */
 
3366
 
 
3367
                        if (true_len > key_len) {
 
3368
                                true_len = key_len;
 
3369
                        }
 
3370
 
 
3371
                        /* MySQL reserves 2 bytes for the length and the
 
3372
                        storage of the number is little-endian */
 
3373
 
 
3374
                        innobase_write_to_2_little_endian(
 
3375
                                        (byte*)buff, true_len);
 
3376
                        buff += 2;
 
3377
 
 
3378
                        memcpy(buff, blob_data, true_len);
 
3379
 
 
3380
                        /* Note that we always reserve the maximum possible
 
3381
                        length of the BLOB prefix in the key value. */
 
3382
 
 
3383
                        buff += key_len;
 
3384
                } else {
 
3385
                        /* Here we handle all other data types except the
 
3386
                        true VARCHAR, BLOB and TEXT. Note that the column
 
3387
                        value we store may be also in a column prefix
 
3388
                        index. */
 
3389
 
 
3390
                        ulint                   true_len;
 
3391
                        ulint                   key_len;
 
3392
                        const unsigned char*            src_start;
 
3393
                        enum_field_types        real_type;
 
3394
 
 
3395
                        key_len = key_part->length;
 
3396
 
 
3397
                        if (is_null) {
 
3398
                                 buff += key_len;
 
3399
 
 
3400
                                 continue;
 
3401
                        }
 
3402
 
 
3403
                        src_start = record + key_part->offset;
 
3404
                        real_type = field->real_type();
 
3405
                        true_len = key_len;
 
3406
 
 
3407
                        /* Character set for the field is defined only
 
3408
                        to fields whose type is string and real field
 
3409
                        type is not enum or set. For these fields check
 
3410
                        if character set is multi byte. */
 
3411
 
 
3412
                        memcpy(buff, src_start, true_len);
 
3413
                        buff += true_len;
 
3414
 
 
3415
                        /* Pad the unused space with spaces. Note that no
 
3416
                        padding is ever needed for UCS-2 because in MySQL,
 
3417
                        all UCS2 characters are 2 bytes, as MySQL does not
 
3418
                        support surrogate pairs, which are needed to represent
 
3419
                        characters in the range U+10000 to U+10FFFF. */
 
3420
 
 
3421
                        if (true_len < key_len) {
 
3422
                                ulint pad_len = key_len - true_len;
 
3423
                                memset(buff, ' ', pad_len);
 
3424
                                buff += pad_len;
 
3425
                        }
 
3426
                }
 
3427
        }
 
3428
 
 
3429
        ut_a(buff <= buff_start + buff_len);
 
3430
 
 
3431
        return((uint)(buff - buff_start));
 
3432
}
 
3433
 
 
3434
/**************************************************************//**
 
3435
Builds a 'template' to the prebuilt struct. The template is used in fast
 
3436
retrieval of just those column values MySQL needs in its processing. */
 
3437
static
 
3438
void
 
3439
build_template(
 
3440
/*===========*/
 
3441
        row_prebuilt_t* prebuilt,       /*!< in/out: prebuilt struct */
 
3442
        Session*        ,               /*!< in: current user thread, used
 
3443
                                        only if templ_type is
 
3444
                                        ROW_DRIZZLE_REC_FIELDS */
 
3445
        Table*          table,          /*!< in: MySQL table */
 
3446
        uint            templ_type)     /*!< in: ROW_MYSQL_WHOLE_ROW or
 
3447
                                        ROW_DRIZZLE_REC_FIELDS */
 
3448
{
 
3449
        dict_index_t*   index;
 
3450
        dict_index_t*   clust_index;
 
3451
        mysql_row_templ_t* templ;
 
3452
        Field*          field;
 
3453
        ulint           n_fields;
 
3454
        ulint           n_requested_fields      = 0;
 
3455
        ibool           fetch_all_in_key        = FALSE;
 
3456
        ibool           fetch_primary_key_cols  = FALSE;
 
3457
        ulint           i= 0;
 
3458
        /* byte offset of the end of last requested column */
 
3459
        ulint           mysql_prefix_len        = 0;
 
3460
 
 
3461
        if (prebuilt->select_lock_type == LOCK_X) {
 
3462
                /* We always retrieve the whole clustered index record if we
 
3463
                use exclusive row level locks, for example, if the read is
 
3464
                done in an UPDATE statement. */
 
3465
 
 
3466
                templ_type = ROW_MYSQL_WHOLE_ROW;
 
3467
        }
 
3468
 
 
3469
        if (templ_type == ROW_MYSQL_REC_FIELDS) {
 
3470
                if (prebuilt->hint_need_to_fetch_extra_cols
 
3471
                        == ROW_RETRIEVE_ALL_COLS) {
 
3472
 
 
3473
                        /* We know we must at least fetch all columns in the
 
3474
                        key, or all columns in the table */
 
3475
 
 
3476
                        if (prebuilt->read_just_key) {
 
3477
                                /* MySQL has instructed us that it is enough
 
3478
                                to fetch the columns in the key; looks like
 
3479
                                MySQL can set this flag also when there is
 
3480
                                only a prefix of the column in the key: in
 
3481
                                that case we retrieve the whole column from
 
3482
                                the clustered index */
 
3483
 
 
3484
                                fetch_all_in_key = TRUE;
 
3485
                        } else {
 
3486
                                templ_type = ROW_MYSQL_WHOLE_ROW;
 
3487
                        }
 
3488
                } else if (prebuilt->hint_need_to_fetch_extra_cols
 
3489
                        == ROW_RETRIEVE_PRIMARY_KEY) {
 
3490
                        /* We must at least fetch all primary key cols. Note
 
3491
                           that if the clustered index was internally generated
 
3492
                           by InnoDB on the row id (no primary key was
 
3493
                           defined), then row_search_for_mysql() will always
 
3494
                           retrieve the row id to a special buffer in the
 
3495
                           prebuilt struct. */
 
3496
 
 
3497
                        fetch_primary_key_cols = TRUE;
 
3498
                }
 
3499
        }
 
3500
 
 
3501
        clust_index = dict_table_get_first_index(prebuilt->table);
 
3502
 
 
3503
        if (templ_type == ROW_MYSQL_REC_FIELDS) {
 
3504
                index = prebuilt->index;
 
3505
        } else {
 
3506
                index = clust_index;
 
3507
        }
 
3508
 
 
3509
        if (index == clust_index) {
 
3510
                prebuilt->need_to_access_clustered = TRUE;
 
3511
        } else {
 
3512
                prebuilt->need_to_access_clustered = FALSE;
 
3513
                /* Below we check column by column if we need to access
 
3514
                the clustered index */
 
3515
        }
 
3516
 
 
3517
        n_fields = (ulint)table->s->fields; /* number of columns */
 
3518
 
 
3519
        if (!prebuilt->mysql_template) {
 
3520
                prebuilt->mysql_template = (mysql_row_templ_t*)
 
3521
                        mem_alloc(n_fields * sizeof(mysql_row_templ_t));
 
3522
        }
 
3523
 
 
3524
        prebuilt->template_type = templ_type;
 
3525
        prebuilt->null_bitmap_len = table->s->null_bytes;
 
3526
 
 
3527
        prebuilt->templ_contains_blob = FALSE;
 
3528
 
 
3529
        /* Note that in InnoDB, i is the column number. MySQL calls columns
 
3530
        'fields'. */
 
3531
        for (i = 0; i < n_fields; i++) {
 
3532
                templ = prebuilt->mysql_template + n_requested_fields;
 
3533
                field = table->field[i];
 
3534
 
 
3535
                if (UNIV_LIKELY(templ_type == ROW_MYSQL_REC_FIELDS)) {
 
3536
                        /* Decide which columns we should fetch
 
3537
                        and which we can skip. */
 
3538
                        register const ibool    index_contains_field =
 
3539
                                dict_index_contains_col_or_prefix(index, i);
 
3540
 
 
3541
                        if (!index_contains_field && prebuilt->read_just_key) {
 
3542
                                /* If this is a 'key read', we do not need
 
3543
                                columns that are not in the key */
 
3544
 
 
3545
                                goto skip_field;
 
3546
                        }
 
3547
 
 
3548
                        if (index_contains_field && fetch_all_in_key) {
 
3549
                                /* This field is needed in the query */
 
3550
 
 
3551
                                goto include_field;
 
3552
                        }
 
3553
 
 
3554
                        if (field->isReadSet() || field->isWriteSet())
 
3555
                                /* This field is needed in the query */
 
3556
                                goto include_field;
 
3557
 
 
3558
                        assert(table->isReadSet(i) == field->isReadSet());
 
3559
                        assert(table->isWriteSet(i) == field->isWriteSet());
 
3560
 
 
3561
                        if (fetch_primary_key_cols
 
3562
                                && dict_table_col_in_clustered_key(
 
3563
                                        index->table, i)) {
 
3564
                                /* This field is needed in the query */
 
3565
 
 
3566
                                goto include_field;
 
3567
                        }
 
3568
 
 
3569
                        /* This field is not needed in the query, skip it */
 
3570
 
 
3571
                        goto skip_field;
 
3572
                }
 
3573
include_field:
 
3574
                n_requested_fields++;
 
3575
 
 
3576
                templ->col_no = i;
 
3577
 
 
3578
                if (index == clust_index) {
 
3579
                        templ->rec_field_no = dict_col_get_clust_pos(
 
3580
                                &index->table->cols[i], index);
 
3581
                } else {
 
3582
                        templ->rec_field_no = dict_index_get_nth_col_pos(
 
3583
                                                                index, i);
 
3584
                }
 
3585
 
 
3586
                if (templ->rec_field_no == ULINT_UNDEFINED) {
 
3587
                        prebuilt->need_to_access_clustered = TRUE;
 
3588
                }
 
3589
 
 
3590
                if (field->null_ptr) {
 
3591
                        templ->mysql_null_byte_offset =
 
3592
                                (ulint) ((char*) field->null_ptr
 
3593
                                        - (char*) table->record[0]);
 
3594
 
 
3595
                        templ->mysql_null_bit_mask = (ulint) field->null_bit;
 
3596
                } else {
 
3597
                        templ->mysql_null_bit_mask = 0;
 
3598
                }
 
3599
 
 
3600
                templ->mysql_col_offset = (ulint)
 
3601
                                        get_field_offset(table, field);
 
3602
 
 
3603
                templ->mysql_col_len = (ulint) field->pack_length();
 
3604
                if (mysql_prefix_len < templ->mysql_col_offset
 
3605
                                + templ->mysql_col_len) {
 
3606
                        mysql_prefix_len = templ->mysql_col_offset
 
3607
                                + templ->mysql_col_len;
 
3608
                }
 
3609
                templ->type = index->table->cols[i].mtype;
 
3610
                templ->mysql_type = (ulint)field->type();
 
3611
 
 
3612
                if (templ->mysql_type == DATA_MYSQL_TRUE_VARCHAR) {
 
3613
                        templ->mysql_length_bytes = (ulint)
 
3614
                                (((Field_varstring*)field)->length_bytes);
 
3615
                }
 
3616
 
 
3617
                templ->charset = dtype_get_charset_coll(
 
3618
                        index->table->cols[i].prtype);
 
3619
                templ->mbminlen = index->table->cols[i].mbminlen;
 
3620
                templ->mbmaxlen = index->table->cols[i].mbmaxlen;
 
3621
                templ->is_unsigned = index->table->cols[i].prtype
 
3622
                                                        & DATA_UNSIGNED;
 
3623
                if (templ->type == DATA_BLOB) {
 
3624
                        prebuilt->templ_contains_blob = TRUE;
 
3625
                }
 
3626
skip_field:
 
3627
                ;
 
3628
        }
 
3629
 
 
3630
        prebuilt->n_template = n_requested_fields;
 
3631
        prebuilt->mysql_prefix_len = mysql_prefix_len;
 
3632
 
 
3633
        if (index != clust_index && prebuilt->need_to_access_clustered) {
 
3634
                /* Change rec_field_no's to correspond to the clustered index
 
3635
                record */
 
3636
                for (i = 0; i < n_requested_fields; i++) {
 
3637
                        templ = prebuilt->mysql_template + i;
 
3638
 
 
3639
                        templ->rec_field_no = dict_col_get_clust_pos(
 
3640
                                &index->table->cols[templ->col_no],
 
3641
                                clust_index);
 
3642
                }
 
3643
        }
 
3644
}
 
3645
 
 
3646
/********************************************************************//**
 
3647
Get the upper limit of the MySQL integral and floating-point type. */
 
3648
UNIV_INTERN
 
3649
uint64_t
 
3650
ha_innobase::innobase_get_int_col_max_value(
 
3651
/*========================================*/
 
3652
        const Field*    field)
 
3653
{
 
3654
        uint64_t        max_value = 0;
 
3655
 
 
3656
        switch(field->key_type()) {
 
3657
        /* TINY */
 
3658
        case HA_KEYTYPE_BINARY:
 
3659
                max_value = 0xFFULL;
 
3660
                break;
 
3661
        /* MEDIUM */
 
3662
        case HA_KEYTYPE_UINT24:
 
3663
                max_value = 0xFFFFFFULL;
 
3664
                break;
 
3665
        /* LONG */
 
3666
        case HA_KEYTYPE_ULONG_INT:
 
3667
                max_value = 0xFFFFFFFFULL;
 
3668
                break;
 
3669
        case HA_KEYTYPE_LONG_INT:
 
3670
                max_value = 0x7FFFFFFFULL;
 
3671
                break;
 
3672
        /* BIG */
 
3673
        case HA_KEYTYPE_ULONGLONG:
 
3674
                max_value = 0xFFFFFFFFFFFFFFFFULL;
 
3675
                break;
 
3676
        case HA_KEYTYPE_LONGLONG:
 
3677
                max_value = 0x7FFFFFFFFFFFFFFFULL;
 
3678
                break;
 
3679
        case HA_KEYTYPE_DOUBLE:
 
3680
                /* We use the maximum as per IEEE754-2008 standard, 2^53 */
 
3681
                max_value = 0x20000000000000ULL;
 
3682
                break;
 
3683
        default:
 
3684
                ut_error;
 
3685
        }
 
3686
 
 
3687
        return(max_value);
 
3688
}
 
3689
 
 
3690
/********************************************************************//**
 
3691
This special handling is really to overcome the limitations of MySQL's
 
3692
binlogging. We need to eliminate the non-determinism that will arise in
 
3693
INSERT ... SELECT type of statements, since MySQL binlog only stores the
 
3694
min value of the autoinc interval. Once that is fixed we can get rid of
 
3695
the special lock handling.
 
3696
@return DB_SUCCESS if all OK else error code */
 
3697
UNIV_INTERN
 
3698
ulint
 
3699
ha_innobase::innobase_lock_autoinc(void)
 
3700
/*====================================*/
 
3701
{
 
3702
        ulint           error = DB_SUCCESS;
 
3703
 
 
3704
        switch (innobase_autoinc_lock_mode) {
 
3705
        case AUTOINC_NO_LOCKING:
 
3706
                /* Acquire only the AUTOINC mutex. */
 
3707
                dict_table_autoinc_lock(prebuilt->table);
 
3708
                break;
 
3709
 
 
3710
        case AUTOINC_NEW_STYLE_LOCKING:
 
3711
                /* For simple (single/multi) row INSERTs, we fallback to the
 
3712
                old style only if another transaction has already acquired
 
3713
                the AUTOINC lock on behalf of a LOAD FILE or INSERT ... SELECT
 
3714
                etc. type of statement. */
 
3715
                if (session_sql_command(user_session) == SQLCOM_INSERT
 
3716
                    || session_sql_command(user_session) == SQLCOM_REPLACE) {
 
3717
                        dict_table_t*   d_table = prebuilt->table;
 
3718
 
 
3719
                        /* Acquire the AUTOINC mutex. */
 
3720
                        dict_table_autoinc_lock(d_table);
 
3721
 
 
3722
                        /* We need to check that another transaction isn't
 
3723
                        already holding the AUTOINC lock on the table. */
 
3724
                        if (d_table->n_waiting_or_granted_auto_inc_locks) {
 
3725
                                /* Release the mutex to avoid deadlocks. */
 
3726
                                dict_table_autoinc_unlock(d_table);
 
3727
                        } else {
 
3728
                                break;
 
3729
                        }
 
3730
                }
 
3731
                /* Fall through to old style locking. */
 
3732
 
 
3733
        case AUTOINC_OLD_STYLE_LOCKING:
 
3734
                error = row_lock_table_autoinc_for_mysql(prebuilt);
 
3735
 
 
3736
                if (error == DB_SUCCESS) {
 
3737
 
 
3738
                        /* Acquire the AUTOINC mutex. */
 
3739
                        dict_table_autoinc_lock(prebuilt->table);
 
3740
                }
 
3741
                break;
 
3742
 
 
3743
        default:
 
3744
                ut_error;
 
3745
        }
 
3746
 
 
3747
        return(ulong(error));
 
3748
}
 
3749
 
 
3750
/********************************************************************//**
 
3751
Reset the autoinc value in the table.
 
3752
@return DB_SUCCESS if all went well else error code */
 
3753
UNIV_INTERN
 
3754
ulint
 
3755
ha_innobase::innobase_reset_autoinc(
 
3756
/*================================*/
 
3757
        uint64_t        autoinc)        /*!< in: value to store */
 
3758
{
 
3759
        ulint           error;
 
3760
 
 
3761
        error = innobase_lock_autoinc();
 
3762
 
 
3763
        if (error == DB_SUCCESS) {
 
3764
 
 
3765
                dict_table_autoinc_initialize(prebuilt->table, autoinc);
 
3766
 
 
3767
                dict_table_autoinc_unlock(prebuilt->table);
 
3768
        }
 
3769
 
 
3770
        return(ulong(error));
 
3771
}
 
3772
 
 
3773
/********************************************************************//**
 
3774
Store the autoinc value in the table. The autoinc value is only set if
 
3775
it's greater than the existing autoinc value in the table.
 
3776
@return DB_SUCCESS if all went well else error code */
 
3777
UNIV_INTERN
 
3778
ulint
 
3779
ha_innobase::innobase_set_max_autoinc(
 
3780
/*==================================*/
 
3781
        uint64_t        auto_inc)       /*!< in: value to store */
 
3782
{
 
3783
        ulint           error;
 
3784
 
 
3785
        error = innobase_lock_autoinc();
 
3786
 
 
3787
        if (error == DB_SUCCESS) {
 
3788
 
 
3789
                dict_table_autoinc_update_if_greater(prebuilt->table, auto_inc);
 
3790
 
 
3791
                dict_table_autoinc_unlock(prebuilt->table);
 
3792
        }
 
3793
 
 
3794
        return(ulong(error));
 
3795
}
 
3796
 
 
3797
/********************************************************************//**
 
3798
Stores a row in an InnoDB database, to the table specified in this
 
3799
handle.
 
3800
@return error code */
 
3801
UNIV_INTERN
 
3802
int
 
3803
ha_innobase::write_row(
 
3804
/*===================*/
 
3805
        unsigned char*  record) /*!< in: a row in MySQL format */
 
3806
{
 
3807
        ulint           error = 0;
 
3808
        int             error_result= 0;
 
3809
        ibool           auto_inc_used= FALSE;
 
3810
        ulint           sql_command;
 
3811
        trx_t*          trx = session_to_trx(user_session);
 
3812
 
 
3813
        if (prebuilt->trx != trx) {
 
3814
          errmsg_printf(ERRMSG_LVL_ERROR, "The transaction object for the table handle is at "
 
3815
                          "%p, but for the current thread it is at %p",
 
3816
                          (const void*) prebuilt->trx, (const void*) trx);
 
3817
 
 
3818
                fputs("InnoDB: Dump of 200 bytes around prebuilt: ", stderr);
 
3819
                ut_print_buf(stderr, ((const byte*)prebuilt) - 100, 200);
 
3820
                fputs("\n"
 
3821
                        "InnoDB: Dump of 200 bytes around ha_data: ",
 
3822
                        stderr);
 
3823
                ut_print_buf(stderr, ((const byte*) trx) - 100, 200);
 
3824
                putc('\n', stderr);
 
3825
                ut_error;
 
3826
        }
 
3827
 
 
3828
        ha_statistic_increment(&SSV::ha_write_count);
 
3829
 
 
3830
        sql_command = session_sql_command(user_session);
 
3831
 
 
3832
        if ((sql_command == SQLCOM_ALTER_TABLE
 
3833
             || sql_command == SQLCOM_CREATE_INDEX
 
3834
             || sql_command == SQLCOM_DROP_INDEX)
 
3835
            && num_write_row >= 10000) {
 
3836
                /* ALTER TABLE is COMMITted at every 10000 copied rows.
 
3837
                The IX table lock for the original table has to be re-issued.
 
3838
                As this method will be called on a temporary table where the
 
3839
                contents of the original table is being copied to, it is
 
3840
                a bit tricky to determine the source table.  The cursor
 
3841
                position in the source table need not be adjusted after the
 
3842
                intermediate COMMIT, since writes by other transactions are
 
3843
                being blocked by a MySQL table lock TL_WRITE_ALLOW_READ. */
 
3844
 
 
3845
                dict_table_t*   src_table;
 
3846
                enum lock_mode  mode;
 
3847
 
 
3848
                num_write_row = 0;
 
3849
 
 
3850
                /* Commit the transaction.  This will release the table
 
3851
                locks, so they have to be acquired again. */
 
3852
 
 
3853
                /* Altering an InnoDB table */
 
3854
                /* Get the source table. */
 
3855
                src_table = lock_get_src_table(
 
3856
                                prebuilt->trx, prebuilt->table, &mode);
 
3857
                if (!src_table) {
 
3858
no_commit:
 
3859
                        /* Unknown situation: do not commit */
 
3860
                        /*
 
3861
                        ut_print_timestamp(stderr);
 
3862
                        fprintf(stderr,
 
3863
                                "  InnoDB: ALTER TABLE is holding lock"
 
3864
                                " on %lu tables!\n",
 
3865
                                prebuilt->trx->mysql_n_tables_locked);
 
3866
                        */
 
3867
                        ;
 
3868
                } else if (src_table == prebuilt->table) {
 
3869
                        /* Source table is not in InnoDB format:
 
3870
                        no need to re-acquire locks on it. */
 
3871
 
 
3872
                        /* Altering to InnoDB format */
 
3873
                        engine->commit(user_session, 1);
 
3874
                        /* Note that this transaction is still active. */
 
3875
                        prebuilt->trx->active_trans = 1;
 
3876
                        /* We will need an IX lock on the destination table. */
 
3877
                        prebuilt->sql_stat_start = TRUE;
 
3878
                } else {
 
3879
                        /* Ensure that there are no other table locks than
 
3880
                        LOCK_IX and LOCK_AUTO_INC on the destination table. */
 
3881
 
 
3882
                        if (!lock_is_table_exclusive(prebuilt->table,
 
3883
                                                        prebuilt->trx)) {
 
3884
                                goto no_commit;
 
3885
                        }
 
3886
 
 
3887
                        /* Commit the transaction.  This will release the table
 
3888
                        locks, so they have to be acquired again. */
 
3889
                        engine->commit(user_session, 1);
 
3890
                        /* Note that this transaction is still active. */
 
3891
                        prebuilt->trx->active_trans = 1;
 
3892
                        /* Re-acquire the table lock on the source table. */
 
3893
                        row_lock_table_for_mysql(prebuilt, src_table, mode);
 
3894
                        /* We will need an IX lock on the destination table. */
 
3895
                        prebuilt->sql_stat_start = TRUE;
 
3896
                }
 
3897
        }
 
3898
 
 
3899
        num_write_row++;
 
3900
 
 
3901
        /* This is the case where the table has an auto-increment column */
 
3902
        if (table->next_number_field && record == table->record[0]) {
 
3903
 
 
3904
                /* Reset the error code before calling
 
3905
                innobase_get_auto_increment(). */
 
3906
                prebuilt->autoinc_error = DB_SUCCESS;
 
3907
 
 
3908
                if ((error = update_auto_increment())) {
 
3909
 
 
3910
                        /* We don't want to mask autoinc overflow errors. */
 
3911
                        if (prebuilt->autoinc_error != DB_SUCCESS) {
 
3912
                                error = (int) prebuilt->autoinc_error;
 
3913
 
 
3914
                                goto report_error;
 
3915
                        }
 
3916
 
 
3917
                        /* MySQL errors are passed straight back. */
 
3918
                        error_result = (int) error;
 
3919
                        goto func_exit;
 
3920
                }
 
3921
 
 
3922
                auto_inc_used = TRUE;
 
3923
        }
 
3924
 
 
3925
        if (prebuilt->mysql_template == NULL
 
3926
            || prebuilt->template_type != ROW_MYSQL_WHOLE_ROW) {
 
3927
 
 
3928
                /* Build the template used in converting quickly between
 
3929
                the two database formats */
 
3930
 
 
3931
                build_template(prebuilt, NULL, table,
 
3932
                               ROW_MYSQL_WHOLE_ROW);
 
3933
        }
 
3934
 
 
3935
        innodb_srv_conc_enter_innodb(prebuilt->trx);
 
3936
 
 
3937
        error = row_insert_for_mysql((byte*) record, prebuilt);
 
3938
 
 
3939
        /* Handle duplicate key errors */
 
3940
        if (auto_inc_used) {
 
3941
                ulint           err;
 
3942
                uint64_t        auto_inc;
 
3943
                uint64_t        col_max_value;
 
3944
 
 
3945
                /* Note the number of rows processed for this statement, used
 
3946
                by get_auto_increment() to determine the number of AUTO-INC
 
3947
                values to reserve. This is only useful for a mult-value INSERT
 
3948
                and is a statement level counter.*/
 
3949
                if (trx->n_autoinc_rows > 0) {
 
3950
                        --trx->n_autoinc_rows;
 
3951
                }
 
3952
 
 
3953
                /* We need the upper limit of the col type to check for
 
3954
                whether we update the table autoinc counter or not. */
 
3955
                col_max_value = innobase_get_int_col_max_value(
 
3956
                        table->next_number_field);
 
3957
 
 
3958
                /* Get the value that MySQL attempted to store in the table.*/
 
3959
                auto_inc = table->next_number_field->val_int();
 
3960
 
 
3961
                switch (error) {
 
3962
                case DB_DUPLICATE_KEY:
 
3963
 
 
3964
                        /* A REPLACE command and LOAD DATA INFILE REPLACE
 
3965
                        handle a duplicate key error themselves, but we
 
3966
                        must update the autoinc counter if we are performing
 
3967
                        those statements. */
 
3968
 
 
3969
                        switch (sql_command) {
 
3970
                        case SQLCOM_LOAD:
 
3971
                                if ((trx->duplicates
 
3972
                                    & (TRX_DUP_IGNORE | TRX_DUP_REPLACE))) {
 
3973
 
 
3974
                                        goto set_max_autoinc;
 
3975
                                }
 
3976
                                break;
 
3977
 
 
3978
                        case SQLCOM_REPLACE:
 
3979
                        case SQLCOM_INSERT_SELECT:
 
3980
                        case SQLCOM_REPLACE_SELECT:
 
3981
                                goto set_max_autoinc;
 
3982
 
 
3983
                        default:
 
3984
                                break;
 
3985
                        }
 
3986
 
 
3987
                        break;
 
3988
 
 
3989
                case DB_SUCCESS:
 
3990
                        /* If the actual value inserted is greater than
 
3991
                        the upper limit of the interval, then we try and
 
3992
                        update the table upper limit. Note: last_value
 
3993
                        will be 0 if get_auto_increment() was not called.*/
 
3994
 
 
3995
                        if (auto_inc <= col_max_value
 
3996
                            && auto_inc >= prebuilt->autoinc_last_value) {
 
3997
set_max_autoinc:
 
3998
                                ut_a(prebuilt->autoinc_increment > 0);
 
3999
 
 
4000
                                uint64_t        need;
 
4001
                                uint64_t        offset;
 
4002
 
 
4003
                                offset = prebuilt->autoinc_offset;
 
4004
                                need = prebuilt->autoinc_increment;
 
4005
 
 
4006
                                auto_inc = innobase_next_autoinc(
 
4007
                                        auto_inc, need, offset, col_max_value);
 
4008
 
 
4009
                                err = innobase_set_max_autoinc(auto_inc);
 
4010
 
 
4011
                                if (err != DB_SUCCESS) {
 
4012
                                        error = err;
 
4013
                                }
 
4014
                        }
 
4015
                        break;
 
4016
                }
 
4017
        }
 
4018
 
 
4019
        innodb_srv_conc_exit_innodb(prebuilt->trx);
 
4020
 
 
4021
report_error:
 
4022
        error_result = convert_error_code_to_mysql((int) error,
 
4023
                                                   prebuilt->table->flags,
 
4024
                                                   user_session);
 
4025
 
 
4026
func_exit:
 
4027
        innobase_active_small();
 
4028
 
 
4029
        return(error_result);
 
4030
}
 
4031
 
 
4032
/**********************************************************************//**
 
4033
Checks which fields have changed in a row and stores information
 
4034
of them to an update vector.
 
4035
@return error number or 0 */
 
4036
static
 
4037
int
 
4038
calc_row_difference(
 
4039
/*================*/
 
4040
        upd_t*          uvect,          /*!< in/out: update vector */
 
4041
        unsigned char*          old_row,        /*!< in: old row in MySQL format */
 
4042
        unsigned char*          new_row,        /*!< in: new row in MySQL format */
 
4043
        Table* table,           /*!< in: table in MySQL data
 
4044
                                        dictionary */
 
4045
        unsigned char*  upd_buff,       /*!< in: buffer to use */
 
4046
        ulint           buff_len,       /*!< in: buffer length */
 
4047
        row_prebuilt_t* prebuilt,       /*!< in: InnoDB prebuilt struct */
 
4048
        Session*        )               /*!< in: user thread */
 
4049
{
 
4050
        unsigned char*          original_upd_buff = upd_buff;
 
4051
        Field*          field;
 
4052
        enum_field_types field_mysql_type;
 
4053
        uint            n_fields;
 
4054
        ulint           o_len;
 
4055
        ulint           n_len;
 
4056
        ulint           col_pack_len;
 
4057
        const byte*     new_mysql_row_col;
 
4058
        const byte*     o_ptr;
 
4059
        const byte*     n_ptr;
 
4060
        byte*           buf;
 
4061
        upd_field_t*    ufield;
 
4062
        ulint           col_type;
 
4063
        ulint           n_changed = 0;
 
4064
        dfield_t        dfield;
 
4065
        dict_index_t*   clust_index;
 
4066
        uint            i= 0;
 
4067
 
 
4068
        n_fields = table->s->fields;
 
4069
        clust_index = dict_table_get_first_index(prebuilt->table);
 
4070
 
 
4071
        /* We use upd_buff to convert changed fields */
 
4072
        buf = (byte*) upd_buff;
 
4073
 
 
4074
        for (i = 0; i < n_fields; i++) {
 
4075
                field = table->field[i];
 
4076
 
 
4077
                o_ptr = (const byte*) old_row + get_field_offset(table, field);
 
4078
                n_ptr = (const byte*) new_row + get_field_offset(table, field);
 
4079
 
 
4080
                /* Use new_mysql_row_col and col_pack_len save the values */
 
4081
 
 
4082
                new_mysql_row_col = n_ptr;
 
4083
                col_pack_len = field->pack_length();
 
4084
 
 
4085
                o_len = col_pack_len;
 
4086
                n_len = col_pack_len;
 
4087
 
 
4088
                /* We use o_ptr and n_ptr to dig up the actual data for
 
4089
                comparison. */
 
4090
 
 
4091
                field_mysql_type = field->type();
 
4092
 
 
4093
                col_type = prebuilt->table->cols[i].mtype;
 
4094
 
 
4095
                switch (col_type) {
 
4096
 
 
4097
                case DATA_BLOB:
 
4098
                        o_ptr = row_mysql_read_blob_ref(&o_len, o_ptr, o_len);
 
4099
                        n_ptr = row_mysql_read_blob_ref(&n_len, n_ptr, n_len);
 
4100
 
 
4101
                        break;
 
4102
 
 
4103
                case DATA_VARCHAR:
 
4104
                case DATA_BINARY:
 
4105
                case DATA_VARMYSQL:
 
4106
                        if (field_mysql_type == DRIZZLE_TYPE_VARCHAR) {
 
4107
                                /* This is a >= 5.0.3 type true VARCHAR where
 
4108
                                the real payload data length is stored in
 
4109
                                1 or 2 bytes */
 
4110
 
 
4111
                                o_ptr = row_mysql_read_true_varchar(
 
4112
                                        &o_len, o_ptr,
 
4113
                                        (ulint)
 
4114
                                        (((Field_varstring*)field)->length_bytes));
 
4115
 
 
4116
                                n_ptr = row_mysql_read_true_varchar(
 
4117
                                        &n_len, n_ptr,
 
4118
                                        (ulint)
 
4119
                                        (((Field_varstring*)field)->length_bytes));
 
4120
                        }
 
4121
 
 
4122
                        break;
 
4123
                default:
 
4124
                        ;
 
4125
                }
 
4126
 
 
4127
                if (field->null_ptr) {
 
4128
                        if (field_in_record_is_null(table, field,
 
4129
                                                        (char*) old_row)) {
 
4130
                                o_len = UNIV_SQL_NULL;
 
4131
                        }
 
4132
 
 
4133
                        if (field_in_record_is_null(table, field,
 
4134
                                                        (char*) new_row)) {
 
4135
                                n_len = UNIV_SQL_NULL;
 
4136
                        }
 
4137
                }
 
4138
 
 
4139
                if (o_len != n_len || (o_len != UNIV_SQL_NULL &&
 
4140
                                        0 != memcmp(o_ptr, n_ptr, o_len))) {
 
4141
                        /* The field has changed */
 
4142
 
 
4143
                        ufield = uvect->fields + n_changed;
 
4144
 
 
4145
                        /* Let us use a dummy dfield to make the conversion
 
4146
                        from the MySQL column format to the InnoDB format */
 
4147
 
 
4148
                        dict_col_copy_type(prebuilt->table->cols + i,
 
4149
                                                     &dfield.type);
 
4150
 
 
4151
                        if (n_len != UNIV_SQL_NULL) {
 
4152
                                buf = row_mysql_store_col_in_innobase_format(
 
4153
                                        &dfield,
 
4154
                                        (byte*)buf,
 
4155
                                        TRUE,
 
4156
                                        new_mysql_row_col,
 
4157
                                        col_pack_len,
 
4158
                                        dict_table_is_comp(prebuilt->table));
 
4159
                                dfield_copy_data(&ufield->new_val, &dfield);
 
4160
                        } else {
 
4161
                                dfield_set_null(&ufield->new_val);
 
4162
                        }
 
4163
 
 
4164
                        ufield->exp = NULL;
 
4165
                        ufield->orig_len = 0;
 
4166
                        ufield->field_no = dict_col_get_clust_pos(
 
4167
                                &prebuilt->table->cols[i], clust_index);
 
4168
                        n_changed++;
 
4169
                }
 
4170
        }
 
4171
 
 
4172
        uvect->n_fields = n_changed;
 
4173
        uvect->info_bits = 0;
 
4174
 
 
4175
        ut_a(buf <= (byte*)original_upd_buff + buff_len);
 
4176
 
 
4177
        return(0);
 
4178
}
 
4179
 
 
4180
/**********************************************************************//**
 
4181
Updates a row given as a parameter to a new value. Note that we are given
 
4182
whole rows, not just the fields which are updated: this incurs some
 
4183
overhead for CPU when we check which fields are actually updated.
 
4184
TODO: currently InnoDB does not prevent the 'Halloween problem':
 
4185
in a searched update a single row can get updated several times
 
4186
if its index columns are updated!
 
4187
@return error number or 0 */
 
4188
UNIV_INTERN
 
4189
int
 
4190
ha_innobase::update_row(
 
4191
/*====================*/
 
4192
        const unsigned char*    old_row,/*!< in: old row in MySQL format */
 
4193
        unsigned char*          new_row)/*!< in: new row in MySQL format */
 
4194
{
 
4195
        upd_t*          uvect;
 
4196
        int             error = 0;
 
4197
        trx_t*          trx = session_to_trx(user_session);
 
4198
 
 
4199
        ut_a(prebuilt->trx == trx);
 
4200
 
 
4201
        ha_statistic_increment(&SSV::ha_update_count);
 
4202
 
 
4203
        if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
 
4204
                table->timestamp_field->set_time();
 
4205
 
 
4206
        if (prebuilt->upd_node) {
 
4207
                uvect = prebuilt->upd_node->update;
 
4208
        } else {
 
4209
                uvect = row_get_prebuilt_update_vector(prebuilt);
 
4210
        }
 
4211
 
 
4212
        /* Build an update vector from the modified fields in the rows
 
4213
        (uses upd_buff of the handle) */
 
4214
 
 
4215
        calc_row_difference(uvect, (unsigned char*) old_row, new_row, table,
 
4216
                        upd_buff, (ulint)upd_and_key_val_buff_len,
 
4217
                        prebuilt, user_session);
 
4218
 
 
4219
        /* This is not a delete */
 
4220
        prebuilt->upd_node->is_delete = FALSE;
 
4221
 
 
4222
        ut_a(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW);
 
4223
 
 
4224
        innodb_srv_conc_enter_innodb(trx);
 
4225
 
 
4226
        error = row_update_for_mysql((byte*) old_row, prebuilt);
 
4227
 
 
4228
        /* We need to do some special AUTOINC handling for the following case:
 
4229
 
 
4230
        INSERT INTO t (c1,c2) VALUES(x,y) ON DUPLICATE KEY UPDATE ...
 
4231
 
 
4232
        We need to use the AUTOINC counter that was actually used by
 
4233
        MySQL in the UPDATE statement, which can be different from the
 
4234
        value used in the INSERT statement.*/
 
4235
 
 
4236
        if (error == DB_SUCCESS
 
4237
            && table->next_number_field
 
4238
            && new_row == table->record[0]
 
4239
            && session_sql_command(user_session) == SQLCOM_INSERT
 
4240
            && (trx->duplicates & (TRX_DUP_IGNORE | TRX_DUP_REPLACE))
 
4241
                == TRX_DUP_IGNORE)  {
 
4242
 
 
4243
                uint64_t        auto_inc;
 
4244
                uint64_t        col_max_value;
 
4245
 
 
4246
                auto_inc = table->next_number_field->val_int();
 
4247
 
 
4248
                /* We need the upper limit of the col type to check for
 
4249
                whether we update the table autoinc counter or not. */
 
4250
                col_max_value = innobase_get_int_col_max_value(
 
4251
                        table->next_number_field);
 
4252
 
 
4253
                if (auto_inc <= col_max_value && auto_inc != 0) {
 
4254
 
 
4255
                        uint64_t        need;
 
4256
                        uint64_t        offset;
 
4257
 
 
4258
                        offset = prebuilt->autoinc_offset;
 
4259
                        need = prebuilt->autoinc_increment;
 
4260
 
 
4261
                        auto_inc = innobase_next_autoinc(
 
4262
                                auto_inc, need, offset, col_max_value);
 
4263
 
 
4264
                        error = innobase_set_max_autoinc(auto_inc);
 
4265
                }
 
4266
        }
 
4267
 
 
4268
        innodb_srv_conc_exit_innodb(trx);
 
4269
 
 
4270
        error = convert_error_code_to_mysql(error,
 
4271
                                            prebuilt->table->flags,
 
4272
                                            user_session);
 
4273
 
 
4274
        if (error == 0 /* success */
 
4275
            && uvect->n_fields == 0 /* no columns were updated */) {
 
4276
 
 
4277
                /* This is the same as success, but instructs
 
4278
                MySQL that the row is not really updated and it
 
4279
                should not increase the count of updated rows.
 
4280
                This is fix for http://bugs.mysql.com/29157 */
 
4281
                error = HA_ERR_RECORD_IS_THE_SAME;
 
4282
        }
 
4283
 
 
4284
        /* Tell InnoDB server that there might be work for
 
4285
        utility threads: */
 
4286
 
 
4287
        innobase_active_small();
 
4288
 
 
4289
        return(error);
 
4290
}
 
4291
 
 
4292
/**********************************************************************//**
 
4293
Deletes a row given as the parameter.
 
4294
@return error number or 0 */
 
4295
UNIV_INTERN
 
4296
int
 
4297
ha_innobase::delete_row(
 
4298
/*====================*/
 
4299
        const unsigned char*    record) /*!< in: a row in MySQL format */
 
4300
{
 
4301
        int             error = 0;
 
4302
        trx_t*          trx = session_to_trx(user_session);
 
4303
 
 
4304
        ut_a(prebuilt->trx == trx);
 
4305
 
 
4306
        ha_statistic_increment(&SSV::ha_delete_count);
 
4307
 
 
4308
        if (!prebuilt->upd_node) {
 
4309
                row_get_prebuilt_update_vector(prebuilt);
 
4310
        }
 
4311
 
 
4312
        /* This is a delete */
 
4313
 
 
4314
        prebuilt->upd_node->is_delete = TRUE;
 
4315
 
 
4316
        innodb_srv_conc_enter_innodb(trx);
 
4317
 
 
4318
        error = row_update_for_mysql((byte*) record, prebuilt);
 
4319
 
 
4320
        innodb_srv_conc_exit_innodb(trx);
 
4321
 
 
4322
        error = convert_error_code_to_mysql(
 
4323
                error, prebuilt->table->flags, user_session);
 
4324
 
 
4325
        /* Tell the InnoDB server that there might be work for
 
4326
        utility threads: */
 
4327
 
 
4328
        innobase_active_small();
 
4329
 
 
4330
        return(error);
 
4331
}
 
4332
 
 
4333
/**********************************************************************//**
 
4334
Removes a new lock set on a row, if it was not read optimistically. This can
 
4335
be called after a row has been read in the processing of an UPDATE or a DELETE
 
4336
query, if the option innodb_locks_unsafe_for_binlog is set. */
 
4337
UNIV_INTERN
 
4338
void
 
4339
ha_innobase::unlock_row(void)
 
4340
/*=========================*/
 
4341
{
 
4342
        /* Consistent read does not take any locks, thus there is
 
4343
        nothing to unlock. */
 
4344
 
 
4345
        if (prebuilt->select_lock_type == LOCK_NONE) {
 
4346
          return;
 
4347
        }
 
4348
 
 
4349
        switch (prebuilt->row_read_type) {
 
4350
        case ROW_READ_WITH_LOCKS:
 
4351
                if (!srv_locks_unsafe_for_binlog
 
4352
                    && prebuilt->trx->isolation_level
 
4353
                    != TRX_ISO_READ_COMMITTED) {
 
4354
                        break;
 
4355
                }
 
4356
                /* fall through */
 
4357
        case ROW_READ_TRY_SEMI_CONSISTENT:
 
4358
                row_unlock_for_mysql(prebuilt, FALSE);
 
4359
                break;
 
4360
        case ROW_READ_DID_SEMI_CONSISTENT:
 
4361
                prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
 
4362
                break;
 
4363
        }
 
4364
 
 
4365
        return;
 
4366
}
 
4367
 
 
4368
/* See Cursor.h and row0mysql.h for docs on this function. */
 
4369
UNIV_INTERN
 
4370
bool
 
4371
ha_innobase::was_semi_consistent_read(void)
 
4372
/*=======================================*/
 
4373
{
 
4374
        return(prebuilt->row_read_type == ROW_READ_DID_SEMI_CONSISTENT);
 
4375
}
 
4376
 
 
4377
/* See Cursor.h and row0mysql.h for docs on this function. */
 
4378
UNIV_INTERN
 
4379
void
 
4380
ha_innobase::try_semi_consistent_read(bool yes)
 
4381
/*===========================================*/
 
4382
{
 
4383
        ut_a(prebuilt->trx == session_to_trx(ha_session()));
 
4384
 
 
4385
        /* Row read type is set to semi consistent read if this was
 
4386
        requested by the MySQL and either innodb_locks_unsafe_for_binlog
 
4387
        option is used or this session is using READ COMMITTED isolation
 
4388
        level. */
 
4389
 
 
4390
        if (yes
 
4391
            && (srv_locks_unsafe_for_binlog
 
4392
                || prebuilt->trx->isolation_level == TRX_ISO_READ_COMMITTED)) {
 
4393
                prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
 
4394
        } else {
 
4395
                prebuilt->row_read_type = ROW_READ_WITH_LOCKS;
 
4396
        }
 
4397
}
 
4398
 
 
4399
/******************************************************************//**
 
4400
Initializes a handle to use an index.
 
4401
@return 0 or error number */
 
4402
UNIV_INTERN
 
4403
int
 
4404
ha_innobase::index_init(
 
4405
/*====================*/
 
4406
        uint    keynr,  /*!< in: key (index) number */
 
4407
        bool )          /*!< in: 1 if result MUST be sorted according to index */
 
4408
{
 
4409
        return(change_active_index(keynr));
 
4410
}
 
4411
 
 
4412
/******************************************************************//**
 
4413
Currently does nothing.
 
4414
@return 0 */
 
4415
UNIV_INTERN
 
4416
int
 
4417
ha_innobase::index_end(void)
 
4418
/*========================*/
 
4419
{
 
4420
        int     error   = 0;
 
4421
        active_index=MAX_KEY;
 
4422
        return(error);
 
4423
}
 
4424
 
 
4425
/*********************************************************************//**
 
4426
Converts a search mode flag understood by MySQL to a flag understood
 
4427
by InnoDB. */
 
4428
static inline
 
4429
ulint
 
4430
convert_search_mode_to_innobase(
 
4431
/*============================*/
 
4432
        enum ha_rkey_function   find_flag)
 
4433
{
 
4434
        switch (find_flag) {
 
4435
        case HA_READ_KEY_EXACT:
 
4436
                /* this does not require the index to be UNIQUE */
 
4437
                return(PAGE_CUR_GE);
 
4438
        case HA_READ_KEY_OR_NEXT:
 
4439
                return(PAGE_CUR_GE);
 
4440
        case HA_READ_KEY_OR_PREV:
 
4441
                return(PAGE_CUR_LE);
 
4442
        case HA_READ_AFTER_KEY: 
 
4443
                return(PAGE_CUR_G);
 
4444
        case HA_READ_BEFORE_KEY:
 
4445
                return(PAGE_CUR_L);
 
4446
        case HA_READ_PREFIX:
 
4447
                return(PAGE_CUR_GE);
 
4448
        case HA_READ_PREFIX_LAST:
 
4449
                return(PAGE_CUR_LE);
 
4450
        case HA_READ_PREFIX_LAST_OR_PREV:
 
4451
                return(PAGE_CUR_LE);
 
4452
                /* In MySQL-4.0 HA_READ_PREFIX and HA_READ_PREFIX_LAST always
 
4453
                pass a complete-field prefix of a key value as the search
 
4454
                tuple. I.e., it is not allowed that the last field would
 
4455
                just contain n first bytes of the full field value.
 
4456
                MySQL uses a 'padding' trick to convert LIKE 'abc%'
 
4457
                type queries so that it can use as a search tuple
 
4458
                a complete-field-prefix of a key value. Thus, the InnoDB
 
4459
                search mode PAGE_CUR_LE_OR_EXTENDS is never used.
 
4460
                TODO: when/if MySQL starts to use also partial-field
 
4461
                prefixes, we have to deal with stripping of spaces
 
4462
                and comparison of non-latin1 char type fields in
 
4463
                innobase_mysql_cmp() to get PAGE_CUR_LE_OR_EXTENDS to
 
4464
                work correctly. */
 
4465
        case HA_READ_MBR_CONTAIN:
 
4466
        case HA_READ_MBR_INTERSECT:
 
4467
        case HA_READ_MBR_WITHIN:
 
4468
        case HA_READ_MBR_DISJOINT:
 
4469
        case HA_READ_MBR_EQUAL:
 
4470
                return(PAGE_CUR_UNSUPP);
 
4471
        /* do not use "default:" in order to produce a gcc warning:
 
4472
        enumeration value '...' not handled in switch
 
4473
        (if -Wswitch or -Wall is used) */
 
4474
        }
 
4475
 
 
4476
        my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "this functionality");
 
4477
 
 
4478
        return(PAGE_CUR_UNSUPP);
 
4479
}
 
4480
 
 
4481
/*
 
4482
   BACKGROUND INFO: HOW A SELECT SQL QUERY IS EXECUTED
 
4483
   ---------------------------------------------------
 
4484
The following does not cover all the details, but explains how we determine
 
4485
the start of a new SQL statement, and what is associated with it.
 
4486
 
 
4487
For each table in the database the MySQL interpreter may have several
 
4488
table handle instances in use, also in a single SQL query. For each table
 
4489
handle instance there is an InnoDB  'prebuilt' struct which contains most
 
4490
of the InnoDB data associated with this table handle instance.
 
4491
 
 
4492
  A) if the user has not explicitly set any MySQL table level locks:
 
4493
 
 
4494
  1) MySQL calls ::external_lock to set an 'intention' table level lock on
 
4495
the table of the handle instance. There we set
 
4496
prebuilt->sql_stat_start = TRUE. The flag sql_stat_start should be set
 
4497
true if we are taking this table handle instance to use in a new SQL
 
4498
statement issued by the user. We also increment trx->n_mysql_tables_in_use.
 
4499
 
 
4500
  2) If prebuilt->sql_stat_start == TRUE we 'pre-compile' the MySQL search
 
4501
instructions to prebuilt->template of the table handle instance in
 
4502
::index_read. The template is used to save CPU time in large joins.
 
4503
 
 
4504
  3) In row_search_for_mysql, if prebuilt->sql_stat_start is true, we
 
4505
allocate a new consistent read view for the trx if it does not yet have one,
 
4506
or in the case of a locking read, set an InnoDB 'intention' table level
 
4507
lock on the table.
 
4508
 
 
4509
  4) We do the SELECT. MySQL may repeatedly call ::index_read for the
 
4510
same table handle instance, if it is a join.
 
4511
 
 
4512
  5) When the SELECT ends, MySQL removes its intention table level locks
 
4513
in ::external_lock. When trx->n_mysql_tables_in_use drops to zero,
 
4514
 (a) we execute a COMMIT there if the autocommit is on,
 
4515
 (b) we also release possible 'SQL statement level resources' InnoDB may
 
4516
have for this SQL statement. The MySQL interpreter does NOT execute
 
4517
autocommit for pure read transactions, though it should. That is why the
 
4518
table Cursor in that case has to execute the COMMIT in ::external_lock.
 
4519
 
 
4520
  B) If the user has explicitly set MySQL table level locks, then MySQL
 
4521
does NOT call ::external_lock at the start of the statement. To determine
 
4522
when we are at the start of a new SQL statement we at the start of
 
4523
::index_read also compare the query id to the latest query id where the
 
4524
table handle instance was used. If it has changed, we know we are at the
 
4525
start of a new SQL statement. Since the query id can theoretically
 
4526
overwrap, we use this test only as a secondary way of determining the
 
4527
start of a new SQL statement. */
 
4528
 
 
4529
 
 
4530
/**********************************************************************//**
 
4531
Positions an index cursor to the index specified in the handle. Fetches the
 
4532
row if any.
 
4533
@return 0, HA_ERR_KEY_NOT_FOUND, or error number */
 
4534
UNIV_INTERN
 
4535
int
 
4536
ha_innobase::index_read(
 
4537
/*====================*/
 
4538
        unsigned char*          buf,    /*!< in/out: buffer for the returned
 
4539
                                        row */
 
4540
        const unsigned char*    key_ptr,/*!< in: key value; if this is NULL
 
4541
                                        we position the cursor at the
 
4542
                                        start or end of index; this can
 
4543
                                        also contain an InnoDB row id, in
 
4544
                                        which case key_len is the InnoDB
 
4545
                                        row id length; the key value can
 
4546
                                        also be a prefix of a full key value,
 
4547
                                        and the last column can be a prefix
 
4548
                                        of a full column */
 
4549
        uint                    key_len,/*!< in: key value length */
 
4550
        enum ha_rkey_function find_flag)/*!< in: search flags from my_base.h */
 
4551
{
 
4552
        ulint           mode;
 
4553
        dict_index_t*   index;
 
4554
        ulint           match_mode      = 0;
 
4555
        int             error;
 
4556
        ulint           ret;
 
4557
 
 
4558
        ut_a(prebuilt->trx == session_to_trx(user_session));
 
4559
 
 
4560
        ha_statistic_increment(&SSV::ha_read_key_count);
 
4561
 
 
4562
        index = prebuilt->index;
 
4563
 
 
4564
        /* Note that if the index for which the search template is built is not
 
4565
        necessarily prebuilt->index, but can also be the clustered index */
 
4566
 
 
4567
        if (prebuilt->sql_stat_start) {
 
4568
                build_template(prebuilt, user_session, table,
 
4569
                               ROW_MYSQL_REC_FIELDS);
 
4570
        }
 
4571
 
 
4572
        if (key_ptr) {
 
4573
                /* Convert the search key value to InnoDB format into
 
4574
                prebuilt->search_tuple */
 
4575
 
 
4576
                row_sel_convert_mysql_key_to_innobase(
 
4577
                        prebuilt->search_tuple,
 
4578
                        (byte*) key_val_buff,
 
4579
                        (ulint)upd_and_key_val_buff_len,
 
4580
                        index,
 
4581
                        (byte*) key_ptr,
 
4582
                        (ulint) key_len,
 
4583
                        prebuilt->trx);
 
4584
        } else {
 
4585
                /* We position the cursor to the last or the first entry
 
4586
                in the index */
 
4587
 
 
4588
                dtuple_set_n_fields(prebuilt->search_tuple, 0);
 
4589
        }
 
4590
 
 
4591
        mode = convert_search_mode_to_innobase(find_flag);
 
4592
 
 
4593
        match_mode = 0;
 
4594
 
 
4595
        if (find_flag == HA_READ_KEY_EXACT) {
 
4596
 
 
4597
                match_mode = ROW_SEL_EXACT;
 
4598
 
 
4599
        } else if (find_flag == HA_READ_PREFIX
 
4600
                   || find_flag == HA_READ_PREFIX_LAST) {
 
4601
 
 
4602
                match_mode = ROW_SEL_EXACT_PREFIX;
 
4603
        }
 
4604
 
 
4605
        last_match_mode = (uint) match_mode;
 
4606
 
 
4607
        if (mode != PAGE_CUR_UNSUPP) {
 
4608
 
 
4609
                innodb_srv_conc_enter_innodb(prebuilt->trx);
 
4610
 
 
4611
                ret = row_search_for_mysql((byte*) buf, mode, prebuilt,
 
4612
                                           match_mode, 0);
 
4613
 
 
4614
                innodb_srv_conc_exit_innodb(prebuilt->trx);
 
4615
        } else {
 
4616
 
 
4617
                ret = DB_UNSUPPORTED;
 
4618
        }
 
4619
 
 
4620
        switch (ret) {
 
4621
        case DB_SUCCESS:
 
4622
                error = 0;
 
4623
                table->status = 0;
 
4624
                break;
 
4625
        case DB_RECORD_NOT_FOUND:
 
4626
                error = HA_ERR_KEY_NOT_FOUND;
 
4627
                table->status = STATUS_NOT_FOUND;
 
4628
                break;
 
4629
        case DB_END_OF_INDEX:
 
4630
                error = HA_ERR_KEY_NOT_FOUND;
 
4631
                table->status = STATUS_NOT_FOUND;
 
4632
                break;
 
4633
        default:
 
4634
                error = convert_error_code_to_mysql((int) ret,
 
4635
                                                    prebuilt->table->flags,
 
4636
                                                    user_session);
 
4637
                table->status = STATUS_NOT_FOUND;
 
4638
                break;
 
4639
        }
 
4640
 
 
4641
        return(error);
 
4642
}
 
4643
 
 
4644
/*******************************************************************//**
 
4645
The following functions works like index_read, but it find the last
 
4646
row with the current key value or prefix.
 
4647
@return 0, HA_ERR_KEY_NOT_FOUND, or an error code */
 
4648
UNIV_INTERN
 
4649
int
 
4650
ha_innobase::index_read_last(
 
4651
/*=========================*/
 
4652
        unsigned char*  buf,    /*!< out: fetched row */
 
4653
        const unsigned char*    key_ptr,/*!< in: key value, or a prefix of a full
 
4654
                                key value */
 
4655
        uint            key_len)/*!< in: length of the key val or prefix
 
4656
                                in bytes */
 
4657
{
 
4658
        return(index_read(buf, key_ptr, key_len, HA_READ_PREFIX_LAST));
 
4659
}
 
4660
 
 
4661
/********************************************************************//**
 
4662
Get the index for a handle. Does not change active index.
 
4663
@return NULL or index instance. */
 
4664
UNIV_INTERN
 
4665
dict_index_t*
 
4666
ha_innobase::innobase_get_index(
 
4667
/*============================*/
 
4668
        uint            keynr)  /*!< in: use this index; MAX_KEY means always
 
4669
                                clustered index, even if it was internally
 
4670
                                generated by InnoDB */
 
4671
{
 
4672
        KEY*            key = 0;
 
4673
        dict_index_t*   index = 0;
 
4674
 
 
4675
        ha_statistic_increment(&SSV::ha_read_key_count);
 
4676
 
 
4677
        ut_ad(user_session == ha_session());
 
4678
        ut_a(prebuilt->trx == session_to_trx(user_session));
 
4679
 
 
4680
        if (keynr != MAX_KEY && table->s->keys > 0) {
 
4681
                key = table->key_info + keynr;
 
4682
 
 
4683
                index = dict_table_get_index_on_name(prebuilt->table,
 
4684
                                                     key->name);
 
4685
        } else {
 
4686
                index = dict_table_get_first_index(prebuilt->table);
 
4687
        }
 
4688
 
 
4689
        if (!index) {
 
4690
                errmsg_printf(ERRMSG_LVL_ERROR, 
 
4691
                        "Innodb could not find key n:o %u with name %s "
 
4692
                        "from dict cache for table %s",
 
4693
                        keynr, key ? key->name : "NULL",
 
4694
                        prebuilt->table->name);
 
4695
        }
 
4696
 
 
4697
        return(index);
 
4698
}
 
4699
 
 
4700
/********************************************************************//**
 
4701
Changes the active index of a handle.
 
4702
@return 0 or error code */
 
4703
UNIV_INTERN
 
4704
int
 
4705
ha_innobase::change_active_index(
 
4706
/*=============================*/
 
4707
        uint    keynr)  /*!< in: use this index; MAX_KEY means always clustered
 
4708
                        index, even if it was internally generated by
 
4709
                        InnoDB */
 
4710
{
 
4711
        ut_ad(user_session == ha_session());
 
4712
        ut_a(prebuilt->trx == session_to_trx(user_session));
 
4713
 
 
4714
        active_index = keynr;
 
4715
 
 
4716
        prebuilt->index = innobase_get_index(keynr);
 
4717
 
 
4718
        if (UNIV_UNLIKELY(!prebuilt->index)) {
 
4719
                errmsg_printf(ERRMSG_LVL_WARN, "InnoDB: change_active_index(%u) failed",
 
4720
                                  keynr);
 
4721
                return(1);
 
4722
        }
 
4723
 
 
4724
        prebuilt->index_usable = row_merge_is_index_usable(prebuilt->trx,
 
4725
                                                           prebuilt->index);
 
4726
 
 
4727
        if (UNIV_UNLIKELY(!prebuilt->index_usable)) {
 
4728
                errmsg_printf(ERRMSG_LVL_WARN,
 
4729
                                 "InnoDB: insufficient history for index %u",
 
4730
                                  keynr);
 
4731
                /* The caller seems to ignore this.  Thus, we must check
 
4732
                this again in row_search_for_mysql(). */
 
4733
                return(2);
 
4734
        }
 
4735
 
 
4736
        ut_a(prebuilt->search_tuple != 0);
 
4737
 
 
4738
        dtuple_set_n_fields(prebuilt->search_tuple, prebuilt->index->n_fields);
 
4739
 
 
4740
        dict_index_copy_types(prebuilt->search_tuple, prebuilt->index,
 
4741
                        prebuilt->index->n_fields);
 
4742
 
 
4743
        /* MySQL changes the active index for a handle also during some
 
4744
        queries, for example SELECT MAX(a), SUM(a) first retrieves the MAX()
 
4745
        and then calculates the sum. Previously we played safe and used
 
4746
        the flag ROW_MYSQL_WHOLE_ROW below, but that caused unnecessary
 
4747
        copying. Starting from MySQL-4.1 we use a more efficient flag here. */
 
4748
 
 
4749
        build_template(prebuilt, user_session, table, ROW_MYSQL_REC_FIELDS);
 
4750
 
 
4751
        return(0);
 
4752
}
 
4753
 
 
4754
/**********************************************************************//**
 
4755
Positions an index cursor to the index specified in keynr. Fetches the
 
4756
row if any.
 
4757
??? This is only used to read whole keys ???
 
4758
@return error number or 0 */
 
4759
UNIV_INTERN
 
4760
int
 
4761
ha_innobase::index_read_idx(
 
4762
/*========================*/
 
4763
        unsigned char*  buf,            /*!< in/out: buffer for the returned
 
4764
                                        row */
 
4765
        uint            keynr,          /*!< in: use this index */
 
4766
        const unsigned char*    key,    /*!< in: key value; if this is NULL
 
4767
                                        we position the cursor at the
 
4768
                                        start or end of index */
 
4769
        uint            key_len,        /*!< in: key value length */
 
4770
        enum ha_rkey_function find_flag)/*!< in: search flags from my_base.h */
 
4771
{
 
4772
        if (change_active_index(keynr)) {
 
4773
 
 
4774
                return(1);
 
4775
        }
 
4776
 
 
4777
        return(index_read(buf, key, key_len, find_flag));
 
4778
}
 
4779
 
 
4780
/***********************************************************************//**
 
4781
Reads the next or previous row from a cursor, which must have previously been
 
4782
positioned using index_read.
 
4783
@return 0, HA_ERR_END_OF_FILE, or error number */
 
4784
UNIV_INTERN
 
4785
int
 
4786
ha_innobase::general_fetch(
 
4787
/*=======================*/
 
4788
        unsigned char*  buf,    /*!< in/out: buffer for next row in MySQL
 
4789
                                format */
 
4790
        uint    direction,      /*!< in: ROW_SEL_NEXT or ROW_SEL_PREV */
 
4791
        uint    match_mode)     /*!< in: 0, ROW_SEL_EXACT, or
 
4792
                                ROW_SEL_EXACT_PREFIX */
 
4793
{
 
4794
        ulint           ret;
 
4795
        int             error   = 0;
 
4796
 
 
4797
        ut_a(prebuilt->trx == session_to_trx(user_session));
 
4798
 
 
4799
        innodb_srv_conc_enter_innodb(prebuilt->trx);
 
4800
 
 
4801
        ret = row_search_for_mysql(
 
4802
                (byte*)buf, 0, prebuilt, match_mode, direction);
 
4803
 
 
4804
        innodb_srv_conc_exit_innodb(prebuilt->trx);
 
4805
 
 
4806
        switch (ret) {
 
4807
        case DB_SUCCESS:
 
4808
                error = 0;
 
4809
                table->status = 0;
 
4810
                break;
 
4811
        case DB_RECORD_NOT_FOUND:
 
4812
                error = HA_ERR_END_OF_FILE;
 
4813
                table->status = STATUS_NOT_FOUND;
 
4814
                break;
 
4815
        case DB_END_OF_INDEX:
 
4816
                error = HA_ERR_END_OF_FILE;
 
4817
                table->status = STATUS_NOT_FOUND;
 
4818
                break;
 
4819
        default:
 
4820
                error = convert_error_code_to_mysql(
 
4821
                        (int) ret, prebuilt->table->flags, user_session);
 
4822
                table->status = STATUS_NOT_FOUND;
 
4823
                break;
 
4824
        }
 
4825
 
 
4826
        return(error);
 
4827
}
 
4828
 
 
4829
/***********************************************************************//**
 
4830
Reads the next row from a cursor, which must have previously been
 
4831
positioned using index_read.
 
4832
@return 0, HA_ERR_END_OF_FILE, or error number */
 
4833
UNIV_INTERN
 
4834
int
 
4835
ha_innobase::index_next(
 
4836
/*====================*/
 
4837
        unsigned char*  buf)    /*!< in/out: buffer for next row in MySQL
 
4838
                                format */
 
4839
{
 
4840
        ha_statistic_increment(&SSV::ha_read_next_count);
 
4841
 
 
4842
        return(general_fetch(buf, ROW_SEL_NEXT, 0));
 
4843
}
 
4844
 
 
4845
/*******************************************************************//**
 
4846
Reads the next row matching to the key value given as the parameter.
 
4847
@return 0, HA_ERR_END_OF_FILE, or error number */
 
4848
UNIV_INTERN
 
4849
int
 
4850
ha_innobase::index_next_same(
 
4851
/*=========================*/
 
4852
        unsigned char*          buf,    /*!< in/out: buffer for the row */
 
4853
        const unsigned char*    ,       /*!< in: key value */
 
4854
        uint            )       /*!< in: key value length */
 
4855
{
 
4856
        ha_statistic_increment(&SSV::ha_read_next_count);
 
4857
 
 
4858
        return(general_fetch(buf, ROW_SEL_NEXT, last_match_mode));
 
4859
}
 
4860
 
 
4861
/***********************************************************************//**
 
4862
Reads the previous row from a cursor, which must have previously been
 
4863
positioned using index_read.
 
4864
@return 0, HA_ERR_END_OF_FILE, or error number */
 
4865
UNIV_INTERN
 
4866
int
 
4867
ha_innobase::index_prev(
 
4868
/*====================*/
 
4869
        unsigned char*  buf)    /*!< in/out: buffer for previous row in MySQL format */
 
4870
{
 
4871
        ha_statistic_increment(&SSV::ha_read_prev_count);
 
4872
 
 
4873
        return(general_fetch(buf, ROW_SEL_PREV, 0));
 
4874
}
 
4875
 
 
4876
/********************************************************************//**
 
4877
Positions a cursor on the first record in an index and reads the
 
4878
corresponding row to buf.
 
4879
@return 0, HA_ERR_END_OF_FILE, or error code */
 
4880
UNIV_INTERN
 
4881
int
 
4882
ha_innobase::index_first(
 
4883
/*=====================*/
 
4884
        unsigned char*  buf)    /*!< in/out: buffer for the row */
 
4885
{
 
4886
        int     error;
 
4887
 
 
4888
        ha_statistic_increment(&SSV::ha_read_first_count);
 
4889
 
 
4890
        error = index_read(buf, NULL, 0, HA_READ_AFTER_KEY);
 
4891
 
 
4892
        /* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */
 
4893
 
 
4894
        if (error == HA_ERR_KEY_NOT_FOUND) {
 
4895
                error = HA_ERR_END_OF_FILE;
 
4896
        }
 
4897
 
 
4898
        return(error);
 
4899
}
 
4900
 
 
4901
/********************************************************************//**
 
4902
Positions a cursor on the last record in an index and reads the
 
4903
corresponding row to buf.
 
4904
@return 0, HA_ERR_END_OF_FILE, or error code */
 
4905
UNIV_INTERN
 
4906
int
 
4907
ha_innobase::index_last(
 
4908
/*====================*/
 
4909
        unsigned char*  buf)    /*!< in/out: buffer for the row */
 
4910
{
 
4911
        int     error;
 
4912
 
 
4913
        ha_statistic_increment(&SSV::ha_read_last_count);
 
4914
 
 
4915
        error = index_read(buf, NULL, 0, HA_READ_BEFORE_KEY);
 
4916
 
 
4917
        /* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */
 
4918
 
 
4919
        if (error == HA_ERR_KEY_NOT_FOUND) {
 
4920
                error = HA_ERR_END_OF_FILE;
 
4921
        }
 
4922
 
 
4923
        return(error);
 
4924
}
 
4925
 
 
4926
/****************************************************************//**
 
4927
Initialize a table scan.
 
4928
@return 0 or error number */
 
4929
UNIV_INTERN
 
4930
int
 
4931
ha_innobase::rnd_init(
 
4932
/*==================*/
 
4933
        bool    scan)   /*!< in: TRUE if table/index scan FALSE otherwise */
 
4934
{
 
4935
        int     err;
 
4936
 
 
4937
        /* Store the active index value so that we can restore the original
 
4938
        value after a scan */
 
4939
 
 
4940
        if (prebuilt->clust_index_was_generated) {
 
4941
                err = change_active_index(MAX_KEY);
 
4942
        } else {
 
4943
                err = change_active_index(primary_key);
 
4944
        }
 
4945
 
 
4946
        /* Don't use semi-consistent read in random row reads (by position).
 
4947
        This means we must disable semi_consistent_read if scan is false */
 
4948
 
 
4949
        if (!scan) {
 
4950
                try_semi_consistent_read(0);
 
4951
        }
 
4952
 
 
4953
        start_of_scan = 1;
 
4954
 
 
4955
        return(err);
 
4956
}
 
4957
 
 
4958
/*****************************************************************//**
 
4959
Ends a table scan.
 
4960
@return 0 or error number */
 
4961
UNIV_INTERN
 
4962
int
 
4963
ha_innobase::rnd_end(void)
 
4964
/*======================*/
 
4965
{
 
4966
        return(index_end());
 
4967
}
 
4968
 
 
4969
/*****************************************************************//**
 
4970
Reads the next row in a table scan (also used to read the FIRST row
 
4971
in a table scan).
 
4972
@return 0, HA_ERR_END_OF_FILE, or error number */
 
4973
UNIV_INTERN
 
4974
int
 
4975
ha_innobase::rnd_next(
 
4976
/*==================*/
 
4977
        unsigned char*  buf)    /*!< in/out: returns the row in this buffer,
 
4978
                        in MySQL format */
 
4979
{
 
4980
        int     error;
 
4981
 
 
4982
        ha_statistic_increment(&SSV::ha_read_rnd_next_count);
 
4983
 
 
4984
        if (start_of_scan) {
 
4985
                error = index_first(buf);
 
4986
 
 
4987
                if (error == HA_ERR_KEY_NOT_FOUND) {
 
4988
                        error = HA_ERR_END_OF_FILE;
 
4989
                }
 
4990
 
 
4991
                start_of_scan = 0;
 
4992
        } else {
 
4993
                error = general_fetch(buf, ROW_SEL_NEXT, 0);
 
4994
        }
 
4995
 
 
4996
        return(error);
 
4997
}
 
4998
 
 
4999
/**********************************************************************//**
 
5000
Fetches a row from the table based on a row reference.
 
5001
@return 0, HA_ERR_KEY_NOT_FOUND, or error code */
 
5002
UNIV_INTERN
 
5003
int
 
5004
ha_innobase::rnd_pos(
 
5005
/*=================*/
 
5006
        unsigned char*  buf,    /*!< in/out: buffer for the row */
 
5007
        unsigned char*  pos)    /*!< in: primary key value of the row in the
 
5008
                        MySQL format, or the row id if the clustered
 
5009
                        index was internally generated by InnoDB; the
 
5010
                        length of data in pos has to be ref_length */
 
5011
{
 
5012
        int             error;
 
5013
        uint            keynr   = active_index;
 
5014
 
 
5015
        ha_statistic_increment(&SSV::ha_read_rnd_count);
 
5016
 
 
5017
        ut_a(prebuilt->trx == session_to_trx(ha_session()));
 
5018
 
 
5019
        if (prebuilt->clust_index_was_generated) {
 
5020
                /* No primary key was defined for the table and we
 
5021
                generated the clustered index from the row id: the
 
5022
                row reference is the row id, not any key value
 
5023
                that MySQL knows of */
 
5024
 
 
5025
                error = change_active_index(MAX_KEY);
 
5026
        } else {
 
5027
                error = change_active_index(primary_key);
 
5028
        }
 
5029
 
 
5030
        if (error) {
 
5031
                return(error);
 
5032
        }
 
5033
 
 
5034
        /* Note that we assume the length of the row reference is fixed
 
5035
        for the table, and it is == ref_length */
 
5036
 
 
5037
        error = index_read(buf, pos, ref_length, HA_READ_KEY_EXACT);
 
5038
 
 
5039
        if (error) {
 
5040
        }
 
5041
 
 
5042
        change_active_index(keynr);
 
5043
 
 
5044
        return(error);
 
5045
}
 
5046
 
 
5047
/*********************************************************************//**
 
5048
Stores a reference to the current row to 'ref' field of the handle. Note
 
5049
that in the case where we have generated the clustered index for the
 
5050
table, the function parameter is illogical: we MUST ASSUME that 'record'
 
5051
is the current 'position' of the handle, because if row ref is actually
 
5052
the row id internally generated in InnoDB, then 'record' does not contain
 
5053
it. We just guess that the row id must be for the record where the handle
 
5054
was positioned the last time. */
 
5055
UNIV_INTERN
 
5056
void
 
5057
ha_innobase::position(
 
5058
/*==================*/
 
5059
        const unsigned char*    record) /*!< in: row in MySQL format */
 
5060
{
 
5061
        uint            len;
 
5062
 
 
5063
        ut_a(prebuilt->trx == session_to_trx(ha_session()));
 
5064
 
 
5065
        if (prebuilt->clust_index_was_generated) {
 
5066
                /* No primary key was defined for the table and we
 
5067
                generated the clustered index from row id: the
 
5068
                row reference will be the row id, not any key value
 
5069
                that MySQL knows of */
 
5070
 
 
5071
                len = DATA_ROW_ID_LEN;
 
5072
 
 
5073
                memcpy(ref, prebuilt->row_id, len);
 
5074
        } else {
 
5075
                len = store_key_val_for_row(primary_key, (char*)ref,
 
5076
                                                         ref_length, record);
 
5077
        }
 
5078
 
 
5079
        /* We assume that the 'ref' value len is always fixed for the same
 
5080
        table. */
 
5081
 
 
5082
        if (len != ref_length) {
 
5083
          errmsg_printf(ERRMSG_LVL_ERROR, "Stored ref len is %lu, but table ref len is %lu",
 
5084
                          (ulong) len, (ulong) ref_length);
 
5085
        }
 
5086
}
 
5087
 
 
5088
 
 
5089
/*****************************************************************//**
 
5090
Creates a table definition to an InnoDB database. */
 
5091
static
 
5092
int
 
5093
create_table_def(
 
5094
/*=============*/
 
5095
        trx_t*          trx,            /*!< in: InnoDB transaction handle */
 
5096
        Table*          form,           /*!< in: information on table
 
5097
                                        columns and indexes */
 
5098
        const char*     table_name,     /*!< in: table name */
 
5099
        const char*     path_of_temp_table,/*!< in: if this is a table explicitly
 
5100
                                        created by the user with the
 
5101
                                        TEMPORARY keyword, then this
 
5102
                                        parameter is the dir path where the
 
5103
                                        table should be placed if we create
 
5104
                                        an .ibd file for it (no .ibd extension
 
5105
                                        in the path, though); otherwise this
 
5106
                                        is NULL */
 
5107
        ulint           flags)          /*!< in: table flags */
 
5108
{
 
5109
        Field*          field;
 
5110
        dict_table_t*   table;
 
5111
        ulint           n_cols;
 
5112
        int             error;
 
5113
        ulint           col_type;
 
5114
        ulint           col_len;
 
5115
        ulint           nulls_allowed;
 
5116
        ulint           unsigned_type;
 
5117
        ulint           binary_type;
 
5118
        ulint           long_true_varchar;
 
5119
        ulint           charset_no;
 
5120
        ulint           i;
 
5121
 
 
5122
        n_cols = form->s->fields;
 
5123
 
 
5124
        /* We pass 0 as the space id, and determine at a lower level the space
 
5125
        id where to store the table */
 
5126
 
 
5127
        table = dict_mem_table_create(table_name, 0, n_cols, flags);
 
5128
 
 
5129
        if (path_of_temp_table) {
 
5130
                table->dir_path_of_temp_table =
 
5131
                        mem_heap_strdup(table->heap, path_of_temp_table);
 
5132
        }
 
5133
 
 
5134
        for (i = 0; i < n_cols; i++) {
 
5135
                field = form->field[i];
 
5136
 
 
5137
                col_type = get_innobase_type_from_mysql_type(&unsigned_type,
 
5138
                                                                        field);
 
5139
                if (field->null_ptr) {
 
5140
                        nulls_allowed = 0;
 
5141
                } else {
 
5142
                        nulls_allowed = DATA_NOT_NULL;
 
5143
                }
 
5144
 
 
5145
                if (field->binary()) {
 
5146
                        binary_type = DATA_BINARY_TYPE;
 
5147
                } else {
 
5148
                        binary_type = 0;
 
5149
                }
 
5150
 
 
5151
                charset_no = 0;
 
5152
 
 
5153
                if (dtype_is_string_type(col_type)) {
 
5154
 
 
5155
                        charset_no = (ulint)field->charset()->number;
 
5156
 
 
5157
                        if (UNIV_UNLIKELY(charset_no >= 256)) {
 
5158
                                /* in data0type.h we assume that the
 
5159
                                number fits in one byte in prtype */
 
5160
                                push_warning_printf(
 
5161
                                        (Session*) trx->mysql_thd,
 
5162
                                        DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
5163
                                        ER_CANT_CREATE_TABLE,
 
5164
                                        "In InnoDB, charset-collation codes"
 
5165
                                        " must be below 256."
 
5166
                                        " Unsupported code %lu.",
 
5167
                                        (ulong) charset_no);
 
5168
                                return(ER_CANT_CREATE_TABLE);
 
5169
                        }
 
5170
                }
 
5171
 
 
5172
                ut_a(field->type() < 256); /* we assume in dtype_form_prtype()
 
5173
                                           that this fits in one byte */
 
5174
                col_len = field->pack_length();
 
5175
 
 
5176
                /* The MySQL pack length contains 1 or 2 bytes length field
 
5177
                for a true VARCHAR. Let us subtract that, so that the InnoDB
 
5178
                column length in the InnoDB data dictionary is the real
 
5179
                maximum byte length of the actual data. */
 
5180
 
 
5181
                long_true_varchar = 0;
 
5182
 
 
5183
                if (field->type() == DRIZZLE_TYPE_VARCHAR) {
 
5184
                        col_len -= ((Field_varstring*)field)->length_bytes;
 
5185
 
 
5186
                        if (((Field_varstring*)field)->length_bytes == 2) {
 
5187
                                long_true_varchar = DATA_LONG_TRUE_VARCHAR;
 
5188
                        }
 
5189
                }
 
5190
 
 
5191
                dict_mem_table_add_col(table, table->heap,
 
5192
                        (char*) field->field_name,
 
5193
                        col_type,
 
5194
                        dtype_form_prtype(
 
5195
                                (ulint)field->type()
 
5196
                                | nulls_allowed | unsigned_type
 
5197
                                | binary_type | long_true_varchar,
 
5198
                                charset_no),
 
5199
                        col_len);
 
5200
        }
 
5201
 
 
5202
        error = row_create_table_for_mysql(table, trx);
 
5203
 
 
5204
        error = convert_error_code_to_mysql(error, flags, NULL);
 
5205
 
 
5206
        return(error);
 
5207
}
 
5208
 
 
5209
/*****************************************************************//**
 
5210
Creates an index in an InnoDB database. */
 
5211
static
 
5212
int
 
5213
create_index(
 
5214
/*=========*/
 
5215
        trx_t*          trx,            /*!< in: InnoDB transaction handle */
 
5216
        Table*          form,           /*!< in: information on table
 
5217
                                        columns and indexes */
 
5218
        ulint           flags,          /*!< in: InnoDB table flags */
 
5219
        const char*     table_name,     /*!< in: table name */
 
5220
        uint            key_num)        /*!< in: index number */
 
5221
{
 
5222
        Field*          field;
 
5223
        dict_index_t*   index;
 
5224
        int             error;
 
5225
        ulint           n_fields;
 
5226
        KEY*            key;
 
5227
        KEY_PART_INFO*  key_part;
 
5228
        ulint           ind_type;
 
5229
        ulint           col_type;
 
5230
        ulint           prefix_len;
 
5231
        ulint           is_unsigned;
 
5232
        ulint           i;
 
5233
        ulint           j;
 
5234
        ulint*          field_lengths;
 
5235
 
 
5236
        key = form->key_info + key_num;
 
5237
 
 
5238
        n_fields = key->key_parts;
 
5239
 
 
5240
        ind_type = 0;
 
5241
 
 
5242
        if (key_num == form->s->primary_key) {
 
5243
                ind_type = ind_type | DICT_CLUSTERED;
 
5244
        }
 
5245
 
 
5246
        if (key->flags & HA_NOSAME ) {
 
5247
                ind_type = ind_type | DICT_UNIQUE;
 
5248
        }
 
5249
 
 
5250
        /* We pass 0 as the space id, and determine at a lower level the space
 
5251
        id where to store the table */
 
5252
 
 
5253
        index = dict_mem_index_create(table_name, key->name, 0,
 
5254
                                      ind_type, n_fields);
 
5255
 
 
5256
        field_lengths = (ulint*) malloc(sizeof(ulint) * n_fields);
 
5257
 
 
5258
        for (i = 0; i < n_fields; i++) {
 
5259
                key_part = key->key_part + i;
 
5260
 
 
5261
                /* (The flag HA_PART_KEY_SEG denotes in MySQL a column prefix
 
5262
                field in an index: we only store a specified number of first
 
5263
                bytes of the column to the index field.) The flag does not
 
5264
                seem to be properly set by MySQL. Let us fall back on testing
 
5265
                the length of the key part versus the column. */
 
5266
 
 
5267
                field = NULL;
 
5268
                for (j = 0; j < form->s->fields; j++) {
 
5269
 
 
5270
                        field = form->field[j];
 
5271
 
 
5272
                        if (0 == innobase_strcasecmp(
 
5273
                                        field->field_name,
 
5274
                                        key_part->field->field_name)) {
 
5275
                                /* Found the corresponding column */
 
5276
 
 
5277
                                break;
 
5278
                        }
 
5279
                }
 
5280
 
 
5281
                ut_a(j < form->s->fields);
 
5282
 
 
5283
                col_type = get_innobase_type_from_mysql_type(
 
5284
                                        &is_unsigned, key_part->field);
 
5285
 
 
5286
                if (DATA_BLOB == col_type
 
5287
                        || (key_part->length < field->pack_length()
 
5288
                                && field->type() != DRIZZLE_TYPE_VARCHAR)
 
5289
                        || (field->type() == DRIZZLE_TYPE_VARCHAR
 
5290
                                && key_part->length < field->pack_length()
 
5291
                                - ((Field_varstring*)field)->length_bytes)) {
 
5292
 
 
5293
                        prefix_len = key_part->length;
 
5294
 
 
5295
                        if (col_type == DATA_INT
 
5296
                                || col_type == DATA_FLOAT
 
5297
                                || col_type == DATA_DOUBLE
 
5298
                                || col_type == DATA_DECIMAL) {
 
5299
                                errmsg_printf(ERRMSG_LVL_ERROR, 
 
5300
                                        "MySQL is trying to create a column "
 
5301
                                        "prefix index field, on an "
 
5302
                                        "inappropriate data type. Table "
 
5303
                                        "name %s, column name %s.",
 
5304
                                        table_name,
 
5305
                                        key_part->field->field_name);
 
5306
 
 
5307
                                prefix_len = 0;
 
5308
                        }
 
5309
                } else {
 
5310
                        prefix_len = 0;
 
5311
                }
 
5312
 
 
5313
                field_lengths[i] = key_part->length;
 
5314
 
 
5315
                dict_mem_index_add_field(index,
 
5316
                        (char*) key_part->field->field_name, prefix_len);
 
5317
        }
 
5318
 
 
5319
        /* Even though we've defined max_supported_key_part_length, we
 
5320
        still do our own checking using field_lengths to be absolutely
 
5321
        sure we don't create too long indexes. */
 
5322
        error = row_create_index_for_mysql(index, trx, field_lengths);
 
5323
 
 
5324
        error = convert_error_code_to_mysql(error, flags, NULL);
 
5325
 
 
5326
        free(field_lengths);
 
5327
 
 
5328
        return(error);
 
5329
}
 
5330
 
 
5331
/*****************************************************************//**
 
5332
Creates an index to an InnoDB table when the user has defined no
 
5333
primary index. */
 
5334
static
 
5335
int
 
5336
create_clustered_index_when_no_primary(
 
5337
/*===================================*/
 
5338
        trx_t*          trx,            /*!< in: InnoDB transaction handle */
 
5339
        ulint           flags,          /*!< in: InnoDB table flags */
 
5340
        const char*     table_name)     /*!< in: table name */
 
5341
{
 
5342
        dict_index_t*   index;
 
5343
        int             error;
 
5344
 
 
5345
        /* We pass 0 as the space id, and determine at a lower level the space
 
5346
        id where to store the table */
 
5347
 
 
5348
        index = dict_mem_index_create(table_name, "GEN_CLUST_INDEX",
 
5349
                                      0, DICT_CLUSTERED, 0);
 
5350
 
 
5351
        error = row_create_index_for_mysql(index, trx, NULL);
 
5352
 
 
5353
        error = convert_error_code_to_mysql(error, flags, NULL);
 
5354
 
 
5355
        return(error);
 
5356
}
 
5357
 
 
5358
/*****************************************************************//**
 
5359
Validates the create options. We may build on this function
 
5360
in future. For now, it checks two specifiers:
 
5361
KEY_BLOCK_SIZE and ROW_FORMAT
 
5362
If innodb_strict_mode is not set then this function is a no-op
 
5363
@return TRUE if valid. */
 
5364
static
 
5365
ibool
 
5366
create_options_are_valid(
 
5367
/*=====================*/
 
5368
        Session*        session,        /*!< in: connection thread. */
 
5369
        Table&          form,           /*!< in: information on table
 
5370
                                        columns and indexes */
 
5371
        drizzled::message::Table& create_proto)
 
5372
{
 
5373
        ibool   kbs_specified   = FALSE;
 
5374
        ibool   ret             = TRUE;
 
5375
 
 
5376
 
 
5377
        ut_ad(session != NULL);
 
5378
 
 
5379
        /* If innodb_strict_mode is not set don't do any validation. */
 
5380
        if (!(SessionVAR(session, strict_mode))) {
 
5381
                return(TRUE);
 
5382
        }
 
5383
 
 
5384
        /* First check if KEY_BLOCK_SIZE was specified. */
 
5385
        if (create_proto.options().has_key_block_size()) {
 
5386
 
 
5387
                kbs_specified = TRUE;
 
5388
                switch (create_proto.options().key_block_size()) {
 
5389
                case 1:
 
5390
                case 2:
 
5391
                case 4:
 
5392
                case 8:
 
5393
                case 16:
 
5394
                        /* Valid value. */
 
5395
                        break;
 
5396
                default:
 
5397
                        push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
5398
                                            ER_ILLEGAL_HA_CREATE_OPTION,
 
5399
                                            "InnoDB: invalid"
 
5400
                                            " KEY_BLOCK_SIZE = %lu."
 
5401
                                            " Valid values are"
 
5402
                                            " [1, 2, 4, 8, 16]",
 
5403
                                            create_proto.options().key_block_size());
 
5404
                        ret = FALSE;
 
5405
                }
 
5406
        }
 
5407
        
 
5408
        /* If KEY_BLOCK_SIZE was specified, check for its
 
5409
        dependencies. */
 
5410
        if (kbs_specified && !srv_file_per_table) {
 
5411
                push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
5412
                             ER_ILLEGAL_HA_CREATE_OPTION,
 
5413
                             "InnoDB: KEY_BLOCK_SIZE"
 
5414
                             " requires innodb_file_per_table.");
 
5415
                ret = FALSE;
 
5416
        }
 
5417
 
 
5418
        if (kbs_specified && srv_file_format < DICT_TF_FORMAT_ZIP) {
 
5419
                push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
5420
                             ER_ILLEGAL_HA_CREATE_OPTION,
 
5421
                             "InnoDB: KEY_BLOCK_SIZE"
 
5422
                             " requires innodb_file_format >"
 
5423
                             " Antelope.");
 
5424
                ret = FALSE;
 
5425
        }
 
5426
 
 
5427
        /* Now check for ROW_FORMAT specifier. */
 
5428
        if (create_proto.options().has_row_type()) {
 
5429
                switch (form.s->row_type) {
 
5430
                        const char* row_format_name;
 
5431
                case ROW_TYPE_COMPRESSED:
 
5432
                case ROW_TYPE_DYNAMIC:
 
5433
                        row_format_name
 
5434
                                = form.s->row_type == ROW_TYPE_COMPRESSED
 
5435
                                ? "COMPRESSED"
 
5436
                                : "DYNAMIC";
 
5437
 
 
5438
                        /* These two ROW_FORMATs require
 
5439
                        srv_file_per_table and srv_file_format */
 
5440
                        if (!srv_file_per_table) {
 
5441
                                push_warning_printf(
 
5442
                                        session,
 
5443
                                        DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
5444
                                        ER_ILLEGAL_HA_CREATE_OPTION,
 
5445
                                        "InnoDB: ROW_FORMAT=%s"
 
5446
                                        " requires innodb_file_per_table.",
 
5447
                                        row_format_name);
 
5448
                                        ret = FALSE;
 
5449
 
 
5450
                        }
 
5451
 
 
5452
                        if (srv_file_format < DICT_TF_FORMAT_ZIP) {
 
5453
                                push_warning_printf(
 
5454
                                        session,
 
5455
                                        DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
5456
                                        ER_ILLEGAL_HA_CREATE_OPTION,
 
5457
                                        "InnoDB: ROW_FORMAT=%s"
 
5458
                                        " requires innodb_file_format >"
 
5459
                                        " Antelope.",
 
5460
                                        row_format_name);
 
5461
                                        ret = FALSE;
 
5462
                        }
 
5463
 
 
5464
                        /* Cannot specify KEY_BLOCK_SIZE with
 
5465
                        ROW_FORMAT = DYNAMIC.
 
5466
                        However, we do allow COMPRESSED to be
 
5467
                        specified with KEY_BLOCK_SIZE. */
 
5468
                        if (kbs_specified
 
5469
                            && form.s->row_type == ROW_TYPE_DYNAMIC) {
 
5470
                                push_warning_printf(
 
5471
                                        session,
 
5472
                                        DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
5473
                                        ER_ILLEGAL_HA_CREATE_OPTION,
 
5474
                                        "InnoDB: cannot specify"
 
5475
                                        " ROW_FORMAT = DYNAMIC with"
 
5476
                                        " KEY_BLOCK_SIZE.");
 
5477
                                        ret = FALSE;
 
5478
                        }
 
5479
 
 
5480
                        break;
 
5481
 
 
5482
                case ROW_TYPE_REDUNDANT:
 
5483
                case ROW_TYPE_COMPACT:
 
5484
                case ROW_TYPE_DEFAULT:
 
5485
                        /* Default is COMPACT. */
 
5486
                        row_format_name
 
5487
                                = form.s->row_type == ROW_TYPE_REDUNDANT
 
5488
                                ? "REDUNDANT"
 
5489
                                : "COMPACT";
 
5490
 
 
5491
                        /* Cannot specify KEY_BLOCK_SIZE with these
 
5492
                        format specifiers. */
 
5493
                        if (kbs_specified) {
 
5494
                                push_warning_printf(
 
5495
                                        session,
 
5496
                                        DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
5497
                                        ER_ILLEGAL_HA_CREATE_OPTION,
 
5498
                                        "InnoDB: cannot specify"
 
5499
                                        " ROW_FORMAT = %s with"
 
5500
                                        " KEY_BLOCK_SIZE.",
 
5501
                                        row_format_name);
 
5502
                                        ret = FALSE;
 
5503
                        }
 
5504
 
 
5505
                        break;
 
5506
 
 
5507
                default:
 
5508
                        push_warning(session,
 
5509
                                     DRIZZLE_ERROR::WARN_LEVEL_ERROR,
 
5510
                                     ER_ILLEGAL_HA_CREATE_OPTION,
 
5511
                                     "InnoDB: invalid ROW_FORMAT specifier.");
 
5512
                        ret = FALSE;
 
5513
 
 
5514
                }
 
5515
        }
 
5516
 
 
5517
        return(ret);
 
5518
}
 
5519
 
 
5520
/*********************************************************************
 
5521
Creates a new table to an InnoDB database. */
 
5522
UNIV_INTERN
 
5523
int
 
5524
InnobaseEngine::doCreateTable(
 
5525
/*================*/
 
5526
        Session*        session,        /*!< in: Session */
 
5527
        const char*     table_name,     /*!< in: table name */
 
5528
        Table&          form,           /*!< in: information on table
 
5529
                                        columns and indexes */
 
5530
        drizzled::message::Table& create_proto)
 
5531
{
 
5532
        int             error;
 
5533
        dict_table_t*   innobase_table;
 
5534
        trx_t*          parent_trx;
 
5535
        trx_t*          trx;
 
5536
        int             primary_key_no;
 
5537
        uint            i;
 
5538
        char            name2[FN_REFLEN];
 
5539
        char            norm_name[FN_REFLEN];
 
5540
        ib_int64_t      auto_inc_value;
 
5541
        ulint           iflags;
 
5542
        /* Cache the value of innodb_file_format, in case it is
 
5543
        modified by another thread while the table is being created. */
 
5544
        const ulint     file_format = srv_file_format;
 
5545
        bool lex_identified_temp_table= (create_proto.type() == drizzled::message::Table::TEMPORARY);
 
5546
 
 
5547
        assert(session != NULL);
 
5548
 
 
5549
#ifdef __WIN__
 
5550
        /* Names passed in from server are in two formats:
 
5551
        1. <database_name>/<table_name>: for normal table creation
 
5552
        2. full path: for temp table creation, or sym link
 
5553
 
 
5554
        When srv_file_per_table is on, check for full path pattern, i.e.
 
5555
        X:\dir\...,             X is a driver letter, or
 
5556
        \\dir1\dir2\...,        UNC path
 
5557
        returns error if it is in full path format, but not creating a temp.
 
5558
        table. Currently InnoDB does not support symbolic link on Windows. */
 
5559
 
 
5560
        if (srv_file_per_table
 
5561
            && (! lex_identified_temp_table)) {
 
5562
 
 
5563
                if ((table_name[1] == ':')
 
5564
                    || (table_name[0] == '\\' && table_name[1] == '\\')) {
 
5565
                        errmsg_printf(ERRMSG_LVL_ERROR, "Cannot create table %s\n", table_name);
 
5566
                        return(HA_ERR_GENERIC);
 
5567
                }
 
5568
        }
 
5569
#endif
 
5570
 
 
5571
        if (form.s->fields > 1000) {
 
5572
                /* The limit probably should be REC_MAX_N_FIELDS - 3 = 1020,
 
5573
                but we play safe here */
 
5574
 
 
5575
                return(HA_ERR_TO_BIG_ROW);
 
5576
        }
 
5577
 
 
5578
        /* Get the transaction associated with the current session, or create one
 
5579
        if not yet created */
 
5580
 
 
5581
        parent_trx = check_trx_exists(session);
 
5582
 
 
5583
        /* In case MySQL calls this in the middle of a SELECT query, release
 
5584
        possible adaptive hash latch to avoid deadlocks of threads */
 
5585
 
 
5586
        trx_search_latch_release_if_reserved(parent_trx);
 
5587
 
 
5588
        trx = innobase_trx_allocate(session);
 
5589
 
 
5590
        srv_lower_case_table_names = TRUE;
 
5591
 
 
5592
        strcpy(name2, table_name);
 
5593
 
 
5594
        normalize_table_name(norm_name, name2);
 
5595
 
 
5596
        /* Latch the InnoDB data dictionary exclusively so that no deadlocks
 
5597
        or lock waits can happen in it during a table create operation.
 
5598
        Drop table etc. do this latching in row0mysql.c. */
 
5599
 
 
5600
        row_mysql_lock_data_dictionary(trx);
 
5601
 
 
5602
        /* Create the table definition in InnoDB */
 
5603
 
 
5604
        iflags = 0;
 
5605
 
 
5606
        /* Validate create options if innodb_strict_mode is set. */
 
5607
        if (! create_options_are_valid(session, form, create_proto)) {
 
5608
                error = ER_ILLEGAL_HA_CREATE_OPTION;
 
5609
                goto cleanup;
 
5610
        }
 
5611
 
 
5612
        if (create_proto.options().has_key_block_size()) {
 
5613
                /* Determine the page_zip.ssize corresponding to the
 
5614
                requested page size (key_block_size) in kilobytes. */
 
5615
 
 
5616
                ulint   ssize, ksize;
 
5617
                ulint   key_block_size = create_proto.options().key_block_size();
 
5618
 
 
5619
                for (ssize = ksize = 1; ssize <= DICT_TF_ZSSIZE_MAX;
 
5620
                     ssize++, ksize <<= 1) {
 
5621
                        if (key_block_size == ksize) {
 
5622
                                iflags = ssize << DICT_TF_ZSSIZE_SHIFT
 
5623
                                        | DICT_TF_COMPACT
 
5624
                                        | DICT_TF_FORMAT_ZIP
 
5625
                                          << DICT_TF_FORMAT_SHIFT;
 
5626
                                break;
 
5627
                        }
 
5628
                }
 
5629
 
 
5630
                if (!srv_file_per_table) {
 
5631
                        push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
5632
                                     ER_ILLEGAL_HA_CREATE_OPTION,
 
5633
                                     "InnoDB: KEY_BLOCK_SIZE"
 
5634
                                     " requires innodb_file_per_table.");
 
5635
                        iflags = 0;
 
5636
                }
 
5637
 
 
5638
                if (file_format < DICT_TF_FORMAT_ZIP) {
 
5639
                        push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
5640
                                     ER_ILLEGAL_HA_CREATE_OPTION,
 
5641
                                     "InnoDB: KEY_BLOCK_SIZE"
 
5642
                                     " requires innodb_file_format >"
 
5643
                                     " Antelope.");
 
5644
                        iflags = 0;
 
5645
                }
 
5646
 
 
5647
                if (!iflags) {
 
5648
                        push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
5649
                                            ER_ILLEGAL_HA_CREATE_OPTION,
 
5650
                                            "InnoDB: ignoring"
 
5651
                                            " KEY_BLOCK_SIZE=%lu.",
 
5652
                                            create_proto.options().key_block_size());
 
5653
                }
 
5654
        }
 
5655
 
 
5656
        if (create_proto.options().has_row_type()) {
 
5657
                if (iflags) {
 
5658
                        /* KEY_BLOCK_SIZE was specified. */
 
5659
                        if (form.s->row_type != ROW_TYPE_COMPRESSED) {
 
5660
                                /* ROW_FORMAT other than COMPRESSED
 
5661
                                ignores KEY_BLOCK_SIZE.  It does not
 
5662
                                make sense to reject conflicting
 
5663
                                KEY_BLOCK_SIZE and ROW_FORMAT, because
 
5664
                                such combinations can be obtained
 
5665
                                with ALTER TABLE anyway. */
 
5666
                                push_warning_printf(
 
5667
                                        session,
 
5668
                                        DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
5669
                                        ER_ILLEGAL_HA_CREATE_OPTION,
 
5670
                                        "InnoDB: ignoring KEY_BLOCK_SIZE=%lu"
 
5671
                                        " unless ROW_FORMAT=COMPRESSED.",
 
5672
                                        create_proto.options().key_block_size());
 
5673
                                iflags = 0;
 
5674
                        }
 
5675
                } else {
 
5676
                        /* No KEY_BLOCK_SIZE */
 
5677
                        if (form.s->row_type == ROW_TYPE_COMPRESSED) {
 
5678
                                /* ROW_FORMAT=COMPRESSED without
 
5679
                                KEY_BLOCK_SIZE implies half the
 
5680
                                maximum KEY_BLOCK_SIZE. */
 
5681
                                iflags = (DICT_TF_ZSSIZE_MAX - 1)
 
5682
                                        << DICT_TF_ZSSIZE_SHIFT
 
5683
                                        | DICT_TF_COMPACT
 
5684
                                        | DICT_TF_FORMAT_ZIP
 
5685
                                        << DICT_TF_FORMAT_SHIFT;
 
5686
#if DICT_TF_ZSSIZE_MAX < 1
 
5687
# error "DICT_TF_ZSSIZE_MAX < 1"
 
5688
#endif
 
5689
                        }
 
5690
                }
 
5691
 
 
5692
                switch (form.s->row_type) {
 
5693
                        const char* row_format_name;
 
5694
                case ROW_TYPE_REDUNDANT:
 
5695
                        break;
 
5696
                case ROW_TYPE_COMPRESSED:
 
5697
                case ROW_TYPE_DYNAMIC:
 
5698
                        row_format_name
 
5699
                                = form.s->row_type == ROW_TYPE_COMPRESSED
 
5700
                                ? "COMPRESSED"
 
5701
                                : "DYNAMIC";
 
5702
 
 
5703
                        if (!srv_file_per_table) {
 
5704
                                push_warning_printf(
 
5705
                                        session,
 
5706
                                        DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
5707
                                        ER_ILLEGAL_HA_CREATE_OPTION,
 
5708
                                        "InnoDB: ROW_FORMAT=%s"
 
5709
                                        " requires innodb_file_per_table.",
 
5710
                                        row_format_name);
 
5711
                        } else if (file_format < DICT_TF_FORMAT_ZIP) {
 
5712
                                push_warning_printf(
 
5713
                                        session,
 
5714
                                        DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
5715
                                        ER_ILLEGAL_HA_CREATE_OPTION,
 
5716
                                        "InnoDB: ROW_FORMAT=%s"
 
5717
                                        " requires innodb_file_format >"
 
5718
                                        " Antelope.",
 
5719
                                        row_format_name);
 
5720
                        } else {
 
5721
                                iflags |= DICT_TF_COMPACT
 
5722
                                        | (DICT_TF_FORMAT_ZIP
 
5723
                                           << DICT_TF_FORMAT_SHIFT);
 
5724
                                break;
 
5725
                        }
 
5726
 
 
5727
                        /* fall through */
 
5728
                case ROW_TYPE_NOT_USED:
 
5729
                case ROW_TYPE_FIXED:
 
5730
                default:
 
5731
                        error = ER_ILLEGAL_HA_CREATE_OPTION;
 
5732
                        goto cleanup;
 
5733
                case ROW_TYPE_DEFAULT:
 
5734
                case ROW_TYPE_COMPACT:
 
5735
                        iflags = DICT_TF_COMPACT;
 
5736
                        break;
 
5737
                }
 
5738
        } else if (!iflags) {
 
5739
                /* No KEY_BLOCK_SIZE or ROW_FORMAT specified:
 
5740
                use ROW_FORMAT=COMPACT by default. */
 
5741
                iflags = DICT_TF_COMPACT;
 
5742
        }
 
5743
 
 
5744
        error = create_table_def(trx, &form, norm_name,
 
5745
                lex_identified_temp_table ? name2 : NULL,
 
5746
                iflags);
 
5747
 
 
5748
        if (error) {
 
5749
                goto cleanup;
 
5750
        }
 
5751
 
 
5752
        /* Look for a primary key */
 
5753
 
 
5754
        primary_key_no= (form.s->primary_key != MAX_KEY ?
 
5755
                         (int) form.s->primary_key :
 
5756
                         -1);
 
5757
 
 
5758
        /* Our function row_get_mysql_key_number_for_index assumes
 
5759
        the primary key is always number 0, if it exists */
 
5760
 
 
5761
        assert(primary_key_no == -1 || primary_key_no == 0);
 
5762
 
 
5763
        /* Create the keys */
 
5764
 
 
5765
        if (form.s->keys == 0 || primary_key_no == -1) {
 
5766
                /* Create an index which is used as the clustered index;
 
5767
                order the rows by their row id which is internally generated
 
5768
                by InnoDB */
 
5769
 
 
5770
                error = create_clustered_index_when_no_primary(
 
5771
                        trx, iflags, norm_name);
 
5772
                if (error) {
 
5773
                        goto cleanup;
 
5774
                }
 
5775
        }
 
5776
 
 
5777
        if (primary_key_no != -1) {
 
5778
                /* In InnoDB the clustered index must always be created
 
5779
                first */
 
5780
                if ((error = create_index(trx, &form, iflags, norm_name,
 
5781
                                          (uint) primary_key_no))) {
 
5782
                        goto cleanup;
 
5783
                }
 
5784
        }
 
5785
 
 
5786
        for (i = 0; i < form.s->keys; i++) {
 
5787
 
 
5788
                if (i != (uint) primary_key_no) {
 
5789
 
 
5790
                        if ((error = create_index(trx, &form, iflags, norm_name,
 
5791
                                                  i))) {
 
5792
                                goto cleanup;
 
5793
                        }
 
5794
                }
 
5795
        }
 
5796
 
 
5797
        if (*trx->mysql_query_str) {
 
5798
                error = row_table_add_foreign_constraints(trx,
 
5799
                        *trx->mysql_query_str, norm_name,
 
5800
                        lex_identified_temp_table);
 
5801
 
 
5802
                error = convert_error_code_to_mysql(error, iflags, NULL);
 
5803
 
 
5804
                if (error) {
 
5805
                        goto cleanup;
 
5806
                }
 
5807
        }
 
5808
 
 
5809
        innobase_commit_low(trx);
 
5810
 
 
5811
        row_mysql_unlock_data_dictionary(trx);
 
5812
 
 
5813
        /* Flush the log to reduce probability that the .frm files and
 
5814
        the InnoDB data dictionary get out-of-sync if the user runs
 
5815
        with innodb_flush_log_at_trx_commit = 0 */
 
5816
 
 
5817
        log_buffer_flush_to_disk();
 
5818
 
 
5819
        innobase_table = dict_table_get(norm_name, FALSE);
 
5820
 
 
5821
        assert(innobase_table != 0);
 
5822
 
 
5823
        if (innobase_table) {
 
5824
                /* We update the highest file format in the system table
 
5825
                space, if this table has higher file format setting. */
 
5826
 
 
5827
                trx_sys_file_format_max_upgrade(
 
5828
                        (const char**) &innobase_file_format_check,
 
5829
                        dict_table_get_format(innobase_table));
 
5830
        }
 
5831
 
 
5832
        /* Note: We can't call update_session() as prebuilt will not be
 
5833
        setup at this stage and so we use session. */
 
5834
 
 
5835
        /* We need to copy the AUTOINC value from the old table if
 
5836
        this is an ALTER TABLE. */
 
5837
 
 
5838
        if ((create_proto.options().has_auto_increment_value()
 
5839
            || session_sql_command(session) == SQLCOM_ALTER_TABLE)
 
5840
            && create_proto.options().auto_increment_value() != 0) {
 
5841
 
 
5842
                /* Query was ALTER TABLE...AUTO_INCREMENT = x; or
 
5843
                CREATE TABLE ...AUTO_INCREMENT = x; Find out a table
 
5844
                definition from the dictionary and get the current value
 
5845
                of the auto increment field. Set a new value to the
 
5846
                auto increment field if the value is greater than the
 
5847
                maximum value in the column. */
 
5848
 
 
5849
                auto_inc_value = create_proto.options().auto_increment_value();
 
5850
 
 
5851
                dict_table_autoinc_lock(innobase_table);
 
5852
                dict_table_autoinc_initialize(innobase_table, auto_inc_value);
 
5853
                dict_table_autoinc_unlock(innobase_table);
 
5854
        }
 
5855
 
 
5856
        /* Tell the InnoDB server that there might be work for
 
5857
        utility threads: */
 
5858
 
 
5859
        srv_active_wake_master_thread();
 
5860
 
 
5861
        trx_free_for_mysql(trx);
 
5862
 
 
5863
        return(0);
 
5864
 
 
5865
cleanup:
 
5866
        innobase_commit_low(trx);
 
5867
 
 
5868
        row_mysql_unlock_data_dictionary(trx);
 
5869
 
 
5870
        trx_free_for_mysql(trx);
 
5871
 
 
5872
        return(error);
 
5873
}
 
5874
 
 
5875
/*****************************************************************//**
 
5876
Discards or imports an InnoDB tablespace.
 
5877
@return 0 == success, -1 == error */
 
5878
UNIV_INTERN
 
5879
int
 
5880
ha_innobase::discard_or_import_tablespace(
 
5881
/*======================================*/
 
5882
        my_bool discard)        /*!< in: TRUE if discard, else import */
 
5883
{
 
5884
        dict_table_t*   dict_table;
 
5885
        trx_t*          trx;
 
5886
        int             err;
 
5887
 
 
5888
        ut_a(prebuilt->trx);
 
5889
        ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
 
5890
        ut_a(prebuilt->trx == session_to_trx(ha_session()));
 
5891
 
 
5892
        dict_table = prebuilt->table;
 
5893
        trx = prebuilt->trx;
 
5894
 
 
5895
        if (discard) {
 
5896
                err = row_discard_tablespace_for_mysql(dict_table->name, trx);
 
5897
        } else {
 
5898
                err = row_import_tablespace_for_mysql(dict_table->name, trx);
 
5899
        }
 
5900
 
 
5901
        err = convert_error_code_to_mysql(err, dict_table->flags, NULL);
 
5902
 
 
5903
        return(err);
 
5904
}
 
5905
 
 
5906
/*****************************************************************//**
 
5907
Deletes all rows of an InnoDB table.
 
5908
@return error number */
 
5909
UNIV_INTERN
 
5910
int
 
5911
ha_innobase::delete_all_rows(void)
 
5912
/*==============================*/
 
5913
{
 
5914
        int             error;
 
5915
 
 
5916
        /* Get the transaction associated with the current session, or create one
 
5917
        if not yet created, and update prebuilt->trx */
 
5918
 
 
5919
        update_session(ha_session());
 
5920
 
 
5921
        if (session_sql_command(user_session) != SQLCOM_TRUNCATE) {
 
5922
        fallback:
 
5923
                /* We only handle TRUNCATE TABLE t as a special case.
 
5924
                DELETE FROM t will have to use ha_innobase::delete_row(),
 
5925
                because DELETE is transactional while TRUNCATE is not. */
 
5926
                return(errno=HA_ERR_WRONG_COMMAND);
 
5927
        }
 
5928
 
 
5929
        /* Truncate the table in InnoDB */
 
5930
 
 
5931
        error = row_truncate_table_for_mysql(prebuilt->table, prebuilt->trx);
 
5932
        if (error == DB_ERROR) {
 
5933
                /* Cannot truncate; resort to ha_innobase::delete_row() */
 
5934
                goto fallback;
 
5935
        }
 
5936
 
 
5937
        error = convert_error_code_to_mysql(error, prebuilt->table->flags,
 
5938
                                            NULL);
 
5939
 
 
5940
        return(error);
 
5941
}
 
5942
 
 
5943
/*****************************************************************//**
 
5944
Drops a table from an InnoDB database. Before calling this function,
 
5945
MySQL calls innobase_commit to commit the transaction of the current user.
 
5946
Then the current user cannot have locks set on the table. Drop table
 
5947
operation inside InnoDB will remove all locks any user has on the table
 
5948
inside InnoDB.
 
5949
@return error number */
 
5950
UNIV_INTERN
 
5951
int
 
5952
InnobaseEngine::doDropTable(
 
5953
/*======================*/
 
5954
        Session& session,
 
5955
        const string table_path)        /* in: table name */
 
5956
{
 
5957
        int     error;
 
5958
        trx_t*  parent_trx;
 
5959
        trx_t*  trx;
 
5960
        char    norm_name[1000];
 
5961
 
 
5962
        ut_a(table_path.length() < 1000);
 
5963
 
 
5964
        /* Strangely, MySQL passes the table name without the '.frm'
 
5965
        extension, in contrast to ::create */
 
5966
        normalize_table_name(norm_name, table_path.c_str());
 
5967
 
 
5968
        /* Get the transaction associated with the current session, or create one
 
5969
        if not yet created */
 
5970
 
 
5971
        parent_trx = check_trx_exists(&session);
 
5972
 
 
5973
        /* In case MySQL calls this in the middle of a SELECT query, release
 
5974
        possible adaptive hash latch to avoid deadlocks of threads */
 
5975
 
 
5976
        trx_search_latch_release_if_reserved(parent_trx);
 
5977
 
 
5978
        trx = innobase_trx_allocate(&session);
 
5979
 
 
5980
        srv_lower_case_table_names = TRUE;
 
5981
 
 
5982
        /* Drop the table in InnoDB */
 
5983
 
 
5984
        error = row_drop_table_for_mysql(norm_name, trx,
 
5985
                                         session_sql_command(&session)
 
5986
                                         == SQLCOM_DROP_DB);
 
5987
 
 
5988
        /* Flush the log to reduce probability that the .frm files and
 
5989
        the InnoDB data dictionary get out-of-sync if the user runs
 
5990
        with innodb_flush_log_at_trx_commit = 0 */
 
5991
 
 
5992
        log_buffer_flush_to_disk();
 
5993
 
 
5994
        /* Tell the InnoDB server that there might be work for
 
5995
        utility threads: */
 
5996
 
 
5997
        srv_active_wake_master_thread();
 
5998
 
 
5999
        innobase_commit_low(trx);
 
6000
 
 
6001
        trx_free_for_mysql(trx);
 
6002
 
 
6003
        if(error!=ENOENT)
 
6004
          error = convert_error_code_to_mysql(error, 0, NULL);
 
6005
 
 
6006
        return(error);
 
6007
}
 
6008
 
 
6009
/*****************************************************************//**
 
6010
Removes all tables in the named database inside InnoDB. */
 
6011
void
 
6012
InnobaseEngine::drop_database(
 
6013
/*===================*/
 
6014
        char*   path)   /*!< in: database path; inside InnoDB the name
 
6015
                        of the last directory in the path is used as
 
6016
                        the database name: for example, in 'mysql/data/test'
 
6017
                        the database name is 'test' */
 
6018
{
 
6019
        ulint   len             = 0;
 
6020
        trx_t*  trx;
 
6021
        char*   ptr;
 
6022
        int     error;
 
6023
        char*   namebuf;
 
6024
        Session*        session         = current_session;
 
6025
 
 
6026
        /* Get the transaction associated with the current session, or create one
 
6027
        if not yet created */
 
6028
 
 
6029
        assert(this == innodb_engine_ptr);
 
6030
 
 
6031
        /* In the Windows plugin, session = current_session is always NULL */
 
6032
        if (session) {
 
6033
                trx_t*  parent_trx = check_trx_exists(session);
 
6034
 
 
6035
                /* In case Drizzle calls this in the middle of a SELECT
 
6036
                query, release possible adaptive hash latch to avoid
 
6037
                deadlocks of threads */
 
6038
 
 
6039
                trx_search_latch_release_if_reserved(parent_trx);
 
6040
        }
 
6041
 
 
6042
        ptr = strchr(path, '\0') - 2;
 
6043
 
 
6044
        while (ptr >= path && *ptr != '\\' && *ptr != '/') {
 
6045
                ptr--;
 
6046
                len++;
 
6047
        }
 
6048
 
 
6049
        ptr++;
 
6050
        namebuf = (char*) malloc((uint) len + 2);
 
6051
 
 
6052
        memcpy(namebuf, ptr, len);
 
6053
        namebuf[len] = '/';
 
6054
        namebuf[len + 1] = '\0';
 
6055
#ifdef  __WIN__
 
6056
        innobase_casedn_str(namebuf);
 
6057
#endif
 
6058
#if defined __WIN__ && !defined MYSQL_SERVER
 
6059
        /* In the Windows plugin, thd = current_thd is always NULL */
 
6060
        trx = trx_allocate_for_mysql();
 
6061
        trx->mysql_thd = NULL;
 
6062
        trx->mysql_query_str = NULL;
 
6063
#else
 
6064
        trx = innobase_trx_allocate(session);
 
6065
#endif
 
6066
        error = row_drop_database_for_mysql(namebuf, trx);
 
6067
        free(namebuf);
 
6068
 
 
6069
        /* Flush the log to reduce probability that the .frm files and
 
6070
        the InnoDB data dictionary get out-of-sync if the user runs
 
6071
        with innodb_flush_log_at_trx_commit = 0 */
 
6072
 
 
6073
        log_buffer_flush_to_disk();
 
6074
 
 
6075
        /* Tell the InnoDB server that there might be work for
 
6076
        utility threads: */
 
6077
 
 
6078
        srv_active_wake_master_thread();
 
6079
 
 
6080
        innobase_commit_low(trx);
 
6081
        trx_free_for_mysql(trx);
 
6082
}
 
6083
/*********************************************************************//**
 
6084
Renames an InnoDB table.
 
6085
@return 0 or error code */
 
6086
static
 
6087
int
 
6088
innobase_rename_table(
 
6089
/*==================*/
 
6090
        trx_t*          trx,    /*!< in: transaction */
 
6091
        const char*     from,   /*!< in: old name of the table */
 
6092
        const char*     to,     /*!< in: new name of the table */
 
6093
        ibool           lock_and_commit)
 
6094
                                /*!< in: TRUE=lock data dictionary and commit */
 
6095
{
 
6096
        int     error;
 
6097
        char*   norm_to;
 
6098
        char*   norm_from;
 
6099
 
 
6100
        srv_lower_case_table_names = TRUE;
 
6101
 
 
6102
        // Magic number 64 arbitrary
 
6103
        norm_to = (char*) malloc(strlen(to) + 64);
 
6104
        norm_from = (char*) malloc(strlen(from) + 64);
 
6105
 
 
6106
        normalize_table_name(norm_to, to);
 
6107
        normalize_table_name(norm_from, from);
 
6108
 
 
6109
        /* Serialize data dictionary operations with dictionary mutex:
 
6110
        no deadlocks can occur then in these operations */
 
6111
 
 
6112
        if (lock_and_commit) {
 
6113
                row_mysql_lock_data_dictionary(trx);
 
6114
        }
 
6115
 
 
6116
        error = row_rename_table_for_mysql(
 
6117
                norm_from, norm_to, trx, lock_and_commit);
 
6118
 
 
6119
        if (error != DB_SUCCESS) {
 
6120
                FILE* ef = dict_foreign_err_file;
 
6121
 
 
6122
                fputs("InnoDB: Renaming table ", ef);
 
6123
                ut_print_name(ef, trx, TRUE, norm_from);
 
6124
                fputs(" to ", ef);
 
6125
                ut_print_name(ef, trx, TRUE, norm_to);
 
6126
                fputs(" failed!\n", ef);
 
6127
        }
 
6128
 
 
6129
        if (lock_and_commit) {
 
6130
                row_mysql_unlock_data_dictionary(trx);
 
6131
 
 
6132
                /* Flush the log to reduce probability that the .frm
 
6133
                files and the InnoDB data dictionary get out-of-sync
 
6134
                if the user runs with innodb_flush_log_at_trx_commit = 0 */
 
6135
 
 
6136
                log_buffer_flush_to_disk();
 
6137
        }
 
6138
 
 
6139
        free(norm_to);
 
6140
        free(norm_from);
 
6141
 
 
6142
        return error;
 
6143
}
 
6144
/*********************************************************************//**
 
6145
Renames an InnoDB table.
 
6146
@return 0 or error code */
 
6147
UNIV_INTERN
 
6148
int
 
6149
InnobaseEngine::doRenameTable(
 
6150
/*======================*/
 
6151
        Session*        session,
 
6152
        const char*     from,   /*!< in: old name of the table */
 
6153
        const char*     to)     /*!< in: new name of the table */
 
6154
{
 
6155
        trx_t*  trx;
 
6156
        int     error;
 
6157
        trx_t*  parent_trx;
 
6158
 
 
6159
        /* Get the transaction associated with the current session, or create one
 
6160
        if not yet created */
 
6161
 
 
6162
        parent_trx = check_trx_exists(session);
 
6163
 
 
6164
        /* In case MySQL calls this in the middle of a SELECT query, release
 
6165
        possible adaptive hash latch to avoid deadlocks of threads */
 
6166
 
 
6167
        trx_search_latch_release_if_reserved(parent_trx);
 
6168
 
 
6169
        trx = innobase_trx_allocate(session);
 
6170
 
 
6171
        error = innobase_rename_table(trx, from, to, TRUE);
 
6172
 
 
6173
        /* Tell the InnoDB server that there might be work for
 
6174
        utility threads: */
 
6175
 
 
6176
        srv_active_wake_master_thread();
 
6177
 
 
6178
        innobase_commit_low(trx);
 
6179
        trx_free_for_mysql(trx);
 
6180
 
 
6181
        error = convert_error_code_to_mysql(error, 0, NULL);
 
6182
 
 
6183
        return(error);
 
6184
}
 
6185
 
 
6186
/*********************************************************************//**
 
6187
Estimates the number of index records in a range.
 
6188
@return estimated number of rows */
 
6189
UNIV_INTERN
 
6190
ha_rows
 
6191
ha_innobase::records_in_range(
 
6192
/*==========================*/
 
6193
        uint                    keynr,          /*!< in: index number */
 
6194
        key_range               *min_key,       /*!< in: start key value of the
 
6195
                                                   range, may also be 0 */
 
6196
        key_range               *max_key)       /*!< in: range end key val, may
 
6197
                                                   also be 0 */
 
6198
{
 
6199
        KEY*            key;
 
6200
        dict_index_t*   index;
 
6201
        unsigned char*          key_val_buff2   = (unsigned char*) malloc(
 
6202
                                                  table->s->stored_rec_length
 
6203
                                        + table->s->max_key_length + 100);
 
6204
        ulint           buff2_len = table->s->stored_rec_length
 
6205
                                        + table->s->max_key_length + 100;
 
6206
        dtuple_t*       range_start;
 
6207
        dtuple_t*       range_end;
 
6208
        ib_int64_t      n_rows;
 
6209
        ulint           mode1;
 
6210
        ulint           mode2;
 
6211
        mem_heap_t*     heap;
 
6212
 
 
6213
        ut_a(prebuilt->trx == session_to_trx(ha_session()));
 
6214
 
 
6215
        prebuilt->trx->op_info = (char*)"estimating records in index range";
 
6216
 
 
6217
        /* In case MySQL calls this in the middle of a SELECT query, release
 
6218
        possible adaptive hash latch to avoid deadlocks of threads */
 
6219
 
 
6220
        trx_search_latch_release_if_reserved(prebuilt->trx);
 
6221
 
 
6222
        active_index = keynr;
 
6223
 
 
6224
        key = table->key_info + active_index;
 
6225
 
 
6226
        index = dict_table_get_index_on_name(prebuilt->table, key->name);
 
6227
 
 
6228
        /* MySQL knows about this index and so we must be able to find it.*/
 
6229
        ut_a(index);
 
6230
 
 
6231
        heap = mem_heap_create(2 * (key->key_parts * sizeof(dfield_t)
 
6232
                                    + sizeof(dtuple_t)));
 
6233
 
 
6234
        range_start = dtuple_create(heap, key->key_parts);
 
6235
        dict_index_copy_types(range_start, index, key->key_parts);
 
6236
 
 
6237
        range_end = dtuple_create(heap, key->key_parts);
 
6238
        dict_index_copy_types(range_end, index, key->key_parts);
 
6239
 
 
6240
        row_sel_convert_mysql_key_to_innobase(
 
6241
                                range_start, (byte*) key_val_buff,
 
6242
                                (ulint)upd_and_key_val_buff_len,
 
6243
                                index,
 
6244
                                (byte*) (min_key ? min_key->key :
 
6245
                                         (const unsigned char*) 0),
 
6246
                                (ulint) (min_key ? min_key->length : 0),
 
6247
                                prebuilt->trx);
 
6248
 
 
6249
        row_sel_convert_mysql_key_to_innobase(
 
6250
                                range_end, (byte*) key_val_buff2,
 
6251
                                buff2_len, index,
 
6252
                                (byte*) (max_key ? max_key->key :
 
6253
                                         (const unsigned char*) 0),
 
6254
                                (ulint) (max_key ? max_key->length : 0),
 
6255
                                prebuilt->trx);
 
6256
 
 
6257
        mode1 = convert_search_mode_to_innobase(min_key ? min_key->flag :
 
6258
                                                HA_READ_KEY_EXACT);
 
6259
        mode2 = convert_search_mode_to_innobase(max_key ? max_key->flag :
 
6260
                                                HA_READ_KEY_EXACT);
 
6261
 
 
6262
        if (mode1 != PAGE_CUR_UNSUPP && mode2 != PAGE_CUR_UNSUPP) {
 
6263
 
 
6264
                n_rows = btr_estimate_n_rows_in_range(index, range_start,
 
6265
                                                      mode1, range_end,
 
6266
                                                      mode2);
 
6267
        } else {
 
6268
 
 
6269
                n_rows = HA_POS_ERROR;
 
6270
        }
 
6271
 
 
6272
        mem_heap_free(heap);
 
6273
 
 
6274
        free(key_val_buff2);
 
6275
 
 
6276
        prebuilt->trx->op_info = (char*)"";
 
6277
 
 
6278
        /* The MySQL optimizer seems to believe an estimate of 0 rows is
 
6279
        always accurate and may return the result 'Empty set' based on that.
 
6280
        The accuracy is not guaranteed, and even if it were, for a locking
 
6281
        read we should anyway perform the search to set the next-key lock.
 
6282
        Add 1 to the value to make sure MySQL does not make the assumption! */
 
6283
 
 
6284
        if (n_rows == 0) {
 
6285
                n_rows = 1;
 
6286
        }
 
6287
 
 
6288
        return((ha_rows) n_rows);
 
6289
}
 
6290
 
 
6291
/*********************************************************************//**
 
6292
Gives an UPPER BOUND to the number of rows in a table. This is used in
 
6293
filesort.cc.
 
6294
@return upper bound of rows */
 
6295
UNIV_INTERN
 
6296
ha_rows
 
6297
ha_innobase::estimate_rows_upper_bound(void)
 
6298
/*======================================*/
 
6299
{
 
6300
        dict_index_t*   index;
 
6301
        uint64_t        estimate;
 
6302
        uint64_t        local_data_file_length;
 
6303
 
 
6304
        /* We do not know if MySQL can call this function before calling
 
6305
        external_lock(). To be safe, update the session of the current table
 
6306
        handle. */
 
6307
 
 
6308
        update_session(ha_session());
 
6309
 
 
6310
        prebuilt->trx->op_info = (char*)
 
6311
                                 "calculating upper bound for table rows";
 
6312
 
 
6313
        /* In case MySQL calls this in the middle of a SELECT query, release
 
6314
        possible adaptive hash latch to avoid deadlocks of threads */
 
6315
 
 
6316
        trx_search_latch_release_if_reserved(prebuilt->trx);
 
6317
 
 
6318
        index = dict_table_get_first_index(prebuilt->table);
 
6319
 
 
6320
        ut_a(index->stat_n_leaf_pages > 0);
 
6321
 
 
6322
        local_data_file_length =
 
6323
                ((uint64_t) index->stat_n_leaf_pages) * UNIV_PAGE_SIZE;
 
6324
 
 
6325
 
 
6326
        /* Calculate a minimum length for a clustered index record and from
 
6327
        that an upper bound for the number of rows. Since we only calculate
 
6328
        new statistics in row0mysql.c when a table has grown by a threshold
 
6329
        factor, we must add a safety factor 2 in front of the formula below. */
 
6330
 
 
6331
        estimate = 2 * local_data_file_length /
 
6332
                                         dict_index_calc_min_rec_len(index);
 
6333
 
 
6334
        prebuilt->trx->op_info = (char*)"";
 
6335
 
 
6336
        return((ha_rows) estimate);
 
6337
}
 
6338
 
 
6339
/*********************************************************************//**
 
6340
How many seeks it will take to read through the table. This is to be
 
6341
comparable to the number returned by records_in_range so that we can
 
6342
decide if we should scan the table or use keys.
 
6343
@return estimated time measured in disk seeks */
 
6344
UNIV_INTERN
 
6345
double
 
6346
ha_innobase::scan_time()
 
6347
/*====================*/
 
6348
{
 
6349
        /* Since MySQL seems to favor table scans too much over index
 
6350
        searches, we pretend that a sequential read takes the same time
 
6351
        as a random disk read, that is, we do not divide the following
 
6352
        by 10, which would be physically realistic. */
 
6353
 
 
6354
        return((double) (prebuilt->table->stat_clustered_index_size));
 
6355
}
 
6356
 
 
6357
/******************************************************************//**
 
6358
Calculate the time it takes to read a set of ranges through an index
 
6359
This enables us to optimise reads for clustered indexes.
 
6360
@return estimated time measured in disk seeks */
 
6361
UNIV_INTERN
 
6362
double
 
6363
ha_innobase::read_time(
 
6364
/*===================*/
 
6365
        uint    index,  /*!< in: key number */
 
6366
        uint    ranges, /*!< in: how many ranges */
 
6367
        ha_rows rows)   /*!< in: estimated number of rows in the ranges */
 
6368
{
 
6369
        ha_rows total_rows;
 
6370
        double  time_for_scan;
 
6371
 
 
6372
        if (index != table->s->primary_key) {
 
6373
                /* Not clustered */
 
6374
                return(Cursor::read_time(index, ranges, rows));
 
6375
        }
 
6376
 
 
6377
        if (rows <= 2) {
 
6378
 
 
6379
                return((double) rows);
 
6380
        }
 
6381
 
 
6382
        /* Assume that the read time is proportional to the scan time for all
 
6383
        rows + at most one seek per range. */
 
6384
 
 
6385
        time_for_scan = scan_time();
 
6386
 
 
6387
        if ((total_rows = estimate_rows_upper_bound()) < rows) {
 
6388
 
 
6389
                return(time_for_scan);
 
6390
        }
 
6391
 
 
6392
        return(ranges + (double) rows / (double) total_rows * time_for_scan);
 
6393
}
 
6394
 
 
6395
/*********************************************************************//**
 
6396
Returns statistics information of the table to the MySQL interpreter,
 
6397
in various fields of the handle object. */
 
6398
UNIV_INTERN
 
6399
int
 
6400
ha_innobase::info(
 
6401
/*==============*/
 
6402
        uint flag)      /*!< in: what information MySQL requests */
 
6403
{
 
6404
        dict_table_t*   ib_table;
 
6405
        dict_index_t*   index;
 
6406
        ha_rows         rec_per_key;
 
6407
        ib_int64_t      n_rows;
 
6408
        ulong           j;
 
6409
        ulong           i;
 
6410
        char            path[FN_REFLEN];
 
6411
        os_file_stat_t  stat_info;
 
6412
 
 
6413
        /* If we are forcing recovery at a high level, we will suppress
 
6414
        statistics calculation on tables, because that may crash the
 
6415
        server if an index is badly corrupted. */
 
6416
 
 
6417
        if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
 
6418
 
 
6419
                /* We return success (0) instead of HA_ERR_CRASHED,
 
6420
                because we want MySQL to process this query and not
 
6421
                stop, like it would do if it received the error code
 
6422
                HA_ERR_CRASHED. */
 
6423
 
 
6424
                return(0);
 
6425
        }
 
6426
 
 
6427
        /* We do not know if MySQL can call this function before calling
 
6428
        external_lock(). To be safe, update the session of the current table
 
6429
        handle. */
 
6430
 
 
6431
        update_session(ha_session());
 
6432
 
 
6433
        /* In case MySQL calls this in the middle of a SELECT query, release
 
6434
        possible adaptive hash latch to avoid deadlocks of threads */
 
6435
 
 
6436
        prebuilt->trx->op_info = (char*)"returning various info to MySQL";
 
6437
 
 
6438
        trx_search_latch_release_if_reserved(prebuilt->trx);
 
6439
 
 
6440
        ib_table = prebuilt->table;
 
6441
 
 
6442
        if (flag & HA_STATUS_TIME) {
 
6443
                if (innobase_stats_on_metadata) {
 
6444
                        /* In sql_show we call with this flag: update
 
6445
                        then statistics so that they are up-to-date */
 
6446
 
 
6447
                        prebuilt->trx->op_info = "updating table statistics";
 
6448
 
 
6449
                        dict_update_statistics(ib_table);
 
6450
 
 
6451
                        prebuilt->trx->op_info = "returning various info to MySQL";
 
6452
                }
 
6453
 
 
6454
                snprintf(path, sizeof(path), "%s/%s%s",
 
6455
                               drizzle_data_home, ib_table->name, ".dfe");
 
6456
 
 
6457
                unpack_filename(path,path);
 
6458
 
 
6459
                /* Note that we do not know the access time of the table,
 
6460
                nor the CHECK TABLE time, nor the UPDATE or INSERT time. */
 
6461
 
 
6462
                if (os_file_get_status(path,&stat_info)) {
 
6463
                        stats.create_time = (ulong) stat_info.ctime;
 
6464
                }
 
6465
        }
 
6466
 
 
6467
        if (flag & HA_STATUS_VARIABLE) {
 
6468
                n_rows = ib_table->stat_n_rows;
 
6469
 
 
6470
                /* Because we do not protect stat_n_rows by any mutex in a
 
6471
                delete, it is theoretically possible that the value can be
 
6472
                smaller than zero! TODO: fix this race.
 
6473
 
 
6474
                The MySQL optimizer seems to assume in a left join that n_rows
 
6475
                is an accurate estimate if it is zero. Of course, it is not,
 
6476
                since we do not have any locks on the rows yet at this phase.
 
6477
                Since SHOW TABLE STATUS seems to call this function with the
 
6478
                HA_STATUS_TIME flag set, while the left join optimizer does not
 
6479
                set that flag, we add one to a zero value if the flag is not
 
6480
                set. That way SHOW TABLE STATUS will show the best estimate,
 
6481
                while the optimizer never sees the table empty. */
 
6482
 
 
6483
                if (n_rows < 0) {
 
6484
                        n_rows = 0;
 
6485
                }
 
6486
 
 
6487
                if (n_rows == 0 && !(flag & HA_STATUS_TIME)) {
 
6488
                        n_rows++;
 
6489
                }
 
6490
 
 
6491
                /* Fix bug#40386: Not flushing query cache after truncate.
 
6492
                n_rows can not be 0 unless the table is empty, set to 1
 
6493
                instead. The original problem of bug#29507 is actually
 
6494
                fixed in the server code. */
 
6495
                if (session_sql_command(user_session) == SQLCOM_TRUNCATE) {
 
6496
 
 
6497
                        n_rows = 1;
 
6498
 
 
6499
                        /* We need to reset the prebuilt value too, otherwise
 
6500
                        checks for values greater than the last value written
 
6501
                        to the table will fail and the autoinc counter will
 
6502
                        not be updated. This will force write_row() into
 
6503
                        attempting an update of the table's AUTOINC counter. */
 
6504
 
 
6505
                        prebuilt->autoinc_last_value = 0;
 
6506
                }
 
6507
 
 
6508
                stats.records = (ha_rows)n_rows;
 
6509
                stats.deleted = 0;
 
6510
                stats.data_file_length = ((uint64_t)
 
6511
                                ib_table->stat_clustered_index_size)
 
6512
                                        * UNIV_PAGE_SIZE;
 
6513
                stats.index_file_length = ((uint64_t)
 
6514
                                ib_table->stat_sum_of_other_index_sizes)
 
6515
                                        * UNIV_PAGE_SIZE;
 
6516
 
 
6517
                /* Since fsp_get_available_space_in_free_extents() is
 
6518
                acquiring latches inside InnoDB, we do not call it if we
 
6519
                are asked by MySQL to avoid locking. Another reason to
 
6520
                avoid the call is that it uses quite a lot of CPU.
 
6521
                See Bug#38185.
 
6522
                We do not update delete_length if no locking is requested
 
6523
                so the "old" value can remain. delete_length is initialized
 
6524
                to 0 in the ha_statistics' constructor. */
 
6525
                if (!(flag & HA_STATUS_NO_LOCK)) {
 
6526
 
 
6527
                        /* lock the data dictionary to avoid races with
 
6528
                        ibd_file_missing and tablespace_discarded */
 
6529
                        row_mysql_lock_data_dictionary(prebuilt->trx);
 
6530
 
 
6531
                        /* ib_table->space must be an existent tablespace */
 
6532
                        if (!ib_table->ibd_file_missing
 
6533
                            && !ib_table->tablespace_discarded) {
 
6534
 
 
6535
                                stats.delete_length =
 
6536
                                        fsp_get_available_space_in_free_extents(
 
6537
                                                ib_table->space) * 1024;
 
6538
                        } else {
 
6539
 
 
6540
                                Session*        session;
 
6541
 
 
6542
                                session = ha_session();
 
6543
 
 
6544
                                push_warning_printf(
 
6545
                                        session,
 
6546
                                        DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
6547
                                        ER_CANT_GET_STAT,
 
6548
                                        "InnoDB: Trying to get the free "
 
6549
                                        "space for table %s but its "
 
6550
                                        "tablespace has been discarded or "
 
6551
                                        "the .ibd file is missing. Setting "
 
6552
                                        "the free space to zero.",
 
6553
                                        ib_table->name);
 
6554
 
 
6555
                                stats.delete_length = 0;
 
6556
                        }
 
6557
 
 
6558
                        row_mysql_unlock_data_dictionary(prebuilt->trx);
 
6559
                }
 
6560
 
 
6561
                stats.check_time = 0;
 
6562
 
 
6563
                if (stats.records == 0) {
 
6564
                        stats.mean_rec_length = 0;
 
6565
                } else {
 
6566
                        stats.mean_rec_length = (ulong) (stats.data_file_length / stats.records);
 
6567
                }
 
6568
        }
 
6569
 
 
6570
        if (flag & HA_STATUS_CONST) {
 
6571
                index = dict_table_get_first_index(ib_table);
 
6572
 
 
6573
                if (prebuilt->clust_index_was_generated) {
 
6574
                        index = dict_table_get_next_index(index);
 
6575
                }
 
6576
 
 
6577
                for (i = 0; i < table->s->keys; i++) {
 
6578
                        if (index == NULL) {
 
6579
                                errmsg_printf(ERRMSG_LVL_ERROR, "Table %s contains fewer "
 
6580
                                                "indexes inside InnoDB than "
 
6581
                                                "are defined in the MySQL "
 
6582
                                                ".frm file. Have you mixed up "
 
6583
                                                ".frm files from different "
 
6584
                                                "installations? See "
 
6585
                                                REFMAN
 
6586
                                                "innodb-troubleshooting.html\n",
 
6587
                                                ib_table->name);
 
6588
                                break;
 
6589
                        }
 
6590
 
 
6591
                        for (j = 0; j < table->key_info[i].key_parts; j++) {
 
6592
 
 
6593
                                if (j + 1 > index->n_uniq) {
 
6594
                                        errmsg_printf(ERRMSG_LVL_ERROR, 
 
6595
"Index %s of %s has %lu columns unique inside InnoDB, but MySQL is asking "
 
6596
"statistics for %lu columns. Have you mixed up .frm files from different "
 
6597
"installations? "
 
6598
"See " REFMAN "innodb-troubleshooting.html\n",
 
6599
                                                        index->name,
 
6600
                                                        ib_table->name,
 
6601
                                                        (unsigned long)
 
6602
                                                        index->n_uniq, j + 1);
 
6603
                                        break;
 
6604
                                }
 
6605
 
 
6606
                                if (index->stat_n_diff_key_vals[j + 1] == 0) {
 
6607
 
 
6608
                                        rec_per_key = stats.records;
 
6609
                                } else {
 
6610
                                        rec_per_key = (ha_rows)(stats.records /
 
6611
                                         index->stat_n_diff_key_vals[j + 1]);
 
6612
                                }
 
6613
 
 
6614
                                /* Since MySQL seems to favor table scans
 
6615
                                too much over index searches, we pretend
 
6616
                                index selectivity is 2 times better than
 
6617
                                our estimate: */
 
6618
 
 
6619
                                rec_per_key = rec_per_key / 2;
 
6620
 
 
6621
                                if (rec_per_key == 0) {
 
6622
                                        rec_per_key = 1;
 
6623
                                }
 
6624
 
 
6625
                                table->key_info[i].rec_per_key[j]=
 
6626
                                  rec_per_key >= ~(ulong) 0 ? ~(ulong) 0 :
 
6627
                                  (ulong) rec_per_key;
 
6628
                        }
 
6629
 
 
6630
                        index = dict_table_get_next_index(index);
 
6631
                }
 
6632
        }
 
6633
 
 
6634
        if (flag & HA_STATUS_ERRKEY) {
 
6635
                const dict_index_t*     err_index;
 
6636
 
 
6637
                ut_a(prebuilt->trx);
 
6638
                ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
 
6639
 
 
6640
                err_index = trx_get_error_info(prebuilt->trx);
 
6641
 
 
6642
                if (err_index) {
 
6643
                        errkey = (unsigned int)
 
6644
                                row_get_mysql_key_number_for_index(err_index);
 
6645
                } else {
 
6646
                        errkey = (unsigned int) prebuilt->trx->error_key_num;
 
6647
                }
 
6648
        }
 
6649
 
 
6650
        if ((flag & HA_STATUS_AUTO) && table->found_next_number_field) {
 
6651
                stats.auto_increment_value = innobase_peek_autoinc();
 
6652
        }
 
6653
 
 
6654
        prebuilt->trx->op_info = (char*)"";
 
6655
 
 
6656
        return(0);
 
6657
}
 
6658
 
 
6659
/**********************************************************************//**
 
6660
Updates index cardinalities of the table, based on 8 random dives into
 
6661
each index tree. This does NOT calculate exact statistics on the table.
 
6662
@return returns always 0 (success) */
 
6663
UNIV_INTERN
 
6664
int
 
6665
ha_innobase::analyze(
 
6666
/*=================*/
 
6667
        Session*)               /*!< in: connection thread handle */
 
6668
{
 
6669
        /* Simply call ::info() with all the flags */
 
6670
        info(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE);
 
6671
 
 
6672
        return(0);
 
6673
}
 
6674
 
 
6675
/*******************************************************************//**
 
6676
Tries to check that an InnoDB table is not corrupted. If corruption is
 
6677
noticed, prints to stderr information about it. In case of corruption
 
6678
may also assert a failure and crash the server.
 
6679
@return HA_ADMIN_CORRUPT or HA_ADMIN_OK */
 
6680
UNIV_INTERN
 
6681
int
 
6682
ha_innobase::check(
 
6683
/*===============*/
 
6684
        Session*        session)        /*!< in: user thread handle */
 
6685
{
 
6686
        ulint           ret;
 
6687
 
 
6688
        assert(session == ha_session());
 
6689
        ut_a(prebuilt->trx);
 
6690
        ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
 
6691
        ut_a(prebuilt->trx == session_to_trx(session));
 
6692
 
 
6693
        if (prebuilt->mysql_template == NULL) {
 
6694
                /* Build the template; we will use a dummy template
 
6695
                in index scans done in checking */
 
6696
 
 
6697
                build_template(prebuilt, NULL, table, ROW_MYSQL_WHOLE_ROW);
 
6698
        }
 
6699
 
 
6700
        ret = row_check_table_for_mysql(prebuilt);
 
6701
 
 
6702
        if (ret == DB_SUCCESS) {
 
6703
                return(HA_ADMIN_OK);
 
6704
        }
 
6705
 
 
6706
        return(HA_ADMIN_CORRUPT);
 
6707
}
 
6708
 
 
6709
/*************************************************************//**
 
6710
Adds information about free space in the InnoDB tablespace to a table comment
 
6711
which is printed out when a user calls SHOW TABLE STATUS. Adds also info on
 
6712
foreign keys.
 
6713
@return table comment + InnoDB free space + info on foreign keys */
 
6714
UNIV_INTERN
 
6715
char*
 
6716
ha_innobase::update_table_comment(
 
6717
/*==============================*/
 
6718
        const char*     comment)/*!< in: table comment defined by user */
 
6719
{
 
6720
        uint    length = (uint) strlen(comment);
 
6721
        char*   str;
 
6722
        long    flen;
 
6723
 
 
6724
        /* We do not know if MySQL can call this function before calling
 
6725
        external_lock(). To be safe, update the session of the current table
 
6726
        handle. */
 
6727
 
 
6728
        if (length > 64000 - 3) {
 
6729
                return((char*)comment); /* string too long */
 
6730
        }
 
6731
 
 
6732
        update_session(ha_session());
 
6733
 
 
6734
        prebuilt->trx->op_info = (char*)"returning table comment";
 
6735
 
 
6736
        /* In case MySQL calls this in the middle of a SELECT query, release
 
6737
        possible adaptive hash latch to avoid deadlocks of threads */
 
6738
 
 
6739
        trx_search_latch_release_if_reserved(prebuilt->trx);
 
6740
        str = NULL;
 
6741
 
 
6742
        /* output the data to a temporary file */
 
6743
 
 
6744
        mutex_enter(&srv_dict_tmpfile_mutex);
 
6745
        rewind(srv_dict_tmpfile);
 
6746
 
 
6747
        fprintf(srv_dict_tmpfile, "InnoDB free: %llu kB",
 
6748
                fsp_get_available_space_in_free_extents(
 
6749
                        prebuilt->table->space));
 
6750
 
 
6751
        dict_print_info_on_foreign_keys(FALSE, srv_dict_tmpfile,
 
6752
                                prebuilt->trx, prebuilt->table);
 
6753
        flen = ftell(srv_dict_tmpfile);
 
6754
        if (flen < 0) {
 
6755
                flen = 0;
 
6756
        } else if (length + flen + 3 > 64000) {
 
6757
                flen = 64000 - 3 - length;
 
6758
        }
 
6759
 
 
6760
        /* allocate buffer for the full string, and
 
6761
        read the contents of the temporary file */
 
6762
 
 
6763
        str = (char*) malloc(length + flen + 3);
 
6764
 
 
6765
        if (str) {
 
6766
                char* pos       = str + length;
 
6767
                if (length) {
 
6768
                        memcpy(str, comment, length);
 
6769
                        *pos++ = ';';
 
6770
                        *pos++ = ' ';
 
6771
                }
 
6772
                rewind(srv_dict_tmpfile);
 
6773
                flen = (uint) fread(pos, 1, flen, srv_dict_tmpfile);
 
6774
                pos[flen] = 0;
 
6775
        }
 
6776
 
 
6777
        mutex_exit(&srv_dict_tmpfile_mutex);
 
6778
 
 
6779
        prebuilt->trx->op_info = (char*)"";
 
6780
 
 
6781
        return(str ? str : (char*) comment);
 
6782
}
 
6783
 
 
6784
/*******************************************************************//**
 
6785
Gets the foreign key create info for a table stored in InnoDB.
 
6786
@return own: character string in the form which can be inserted to the
 
6787
CREATE TABLE statement, MUST be freed with
 
6788
ha_innobase::free_foreign_key_create_info */
 
6789
UNIV_INTERN
 
6790
char*
 
6791
ha_innobase::get_foreign_key_create_info(void)
 
6792
/*==========================================*/
 
6793
{
 
6794
        char*   str     = 0;
 
6795
        long    flen;
 
6796
 
 
6797
        ut_a(prebuilt != NULL);
 
6798
 
 
6799
        /* We do not know if MySQL can call this function before calling
 
6800
        external_lock(). To be safe, update the session of the current table
 
6801
        handle. */
 
6802
 
 
6803
        update_session(ha_session());
 
6804
 
 
6805
        prebuilt->trx->op_info = (char*)"getting info on foreign keys";
 
6806
 
 
6807
        /* In case MySQL calls this in the middle of a SELECT query,
 
6808
        release possible adaptive hash latch to avoid
 
6809
        deadlocks of threads */
 
6810
 
 
6811
        trx_search_latch_release_if_reserved(prebuilt->trx);
 
6812
 
 
6813
        mutex_enter(&srv_dict_tmpfile_mutex);
 
6814
        rewind(srv_dict_tmpfile);
 
6815
 
 
6816
        /* output the data to a temporary file */
 
6817
        dict_print_info_on_foreign_keys(TRUE, srv_dict_tmpfile,
 
6818
                                prebuilt->trx, prebuilt->table);
 
6819
        prebuilt->trx->op_info = (char*)"";
 
6820
 
 
6821
        flen = ftell(srv_dict_tmpfile);
 
6822
        if (flen < 0) {
 
6823
                flen = 0;
 
6824
        } else if (flen > 64000 - 1) {
 
6825
                flen = 64000 - 1;
 
6826
        }
 
6827
 
 
6828
        /* allocate buffer for the string, and
 
6829
        read the contents of the temporary file */
 
6830
 
 
6831
        str = (char*) malloc(flen + 1);
 
6832
 
 
6833
        if (str) {
 
6834
                rewind(srv_dict_tmpfile);
 
6835
                flen = (uint) fread(str, 1, flen, srv_dict_tmpfile);
 
6836
                str[flen] = 0;
 
6837
        }
 
6838
 
 
6839
        mutex_exit(&srv_dict_tmpfile_mutex);
 
6840
 
 
6841
        return(str);
 
6842
}
 
6843
 
 
6844
 
 
6845
UNIV_INTERN
 
6846
int
 
6847
ha_innobase::get_foreign_key_list(Session *session, List<FOREIGN_KEY_INFO> *f_key_list)
 
6848
{
 
6849
  dict_foreign_t* foreign;
 
6850
 
 
6851
  ut_a(prebuilt != NULL);
 
6852
  update_session(ha_session());
 
6853
  prebuilt->trx->op_info = (char*)"getting list of foreign keys";
 
6854
  trx_search_latch_release_if_reserved(prebuilt->trx);
 
6855
  mutex_enter(&(dict_sys->mutex));
 
6856
  foreign = UT_LIST_GET_FIRST(prebuilt->table->foreign_list);
 
6857
 
 
6858
  while (foreign != NULL) {
 
6859
          uint i;
 
6860
          FOREIGN_KEY_INFO f_key_info;
 
6861
          LEX_STRING *name= 0;
 
6862
          uint ulen;
 
6863
          char uname[NAME_LEN+1];           /* Unencoded name */
 
6864
          char db_name[NAME_LEN+1];
 
6865
          const char *tmp_buff;
 
6866
 
 
6867
          tmp_buff= foreign->id;
 
6868
          i= 0;
 
6869
          while (tmp_buff[i] != '/')
 
6870
                  i++;
 
6871
          tmp_buff+= i + 1;
 
6872
          f_key_info.forein_id = session->make_lex_string(NULL, tmp_buff, strlen(tmp_buff), true);
 
6873
          tmp_buff= foreign->referenced_table_name;
 
6874
 
 
6875
          /* Database name */
 
6876
          i= 0;
 
6877
          while (tmp_buff[i] != '/')
 
6878
          {
 
6879
            db_name[i]= tmp_buff[i];
 
6880
            i++;
 
6881
          }
 
6882
          db_name[i]= 0;
 
6883
          ulen= filename_to_tablename(db_name, uname, sizeof(uname));
 
6884
          f_key_info.referenced_db = session->make_lex_string(NULL, uname, ulen, true);
 
6885
 
 
6886
          /* Table name */
 
6887
          tmp_buff+= i + 1;
 
6888
          ulen= filename_to_tablename(tmp_buff, uname, sizeof(uname));
 
6889
          f_key_info.referenced_table = session->make_lex_string(NULL, uname, ulen, true);
 
6890
 
 
6891
          for (i= 0;;) {
 
6892
                  tmp_buff= foreign->foreign_col_names[i];
 
6893
                  name = session->make_lex_string(name, tmp_buff, strlen(tmp_buff), true);
 
6894
                  f_key_info.foreign_fields.push_back(name);
 
6895
                  tmp_buff= foreign->referenced_col_names[i];
 
6896
                  name = session->make_lex_string(name, tmp_buff, strlen(tmp_buff), true);
 
6897
                  f_key_info.referenced_fields.push_back(name);
 
6898
                  if (++i >= foreign->n_fields)
 
6899
                          break;
 
6900
          }
 
6901
 
 
6902
          ulong length;
 
6903
          if (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE)
 
6904
          {
 
6905
            length=7;
 
6906
            tmp_buff= "CASCADE";
 
6907
          }
 
6908
          else if (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL)
 
6909
          {
 
6910
            length=8;
 
6911
            tmp_buff= "SET NULL";
 
6912
          }
 
6913
          else if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION)
 
6914
          {
 
6915
            length=9;
 
6916
            tmp_buff= "NO ACTION";
 
6917
          }
 
6918
          else
 
6919
          {
 
6920
            length=8;
 
6921
            tmp_buff= "RESTRICT";
 
6922
          }
 
6923
          f_key_info.delete_method = session->make_lex_string(
 
6924
                  f_key_info.delete_method, tmp_buff, length, true);
 
6925
 
 
6926
 
 
6927
          if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE)
 
6928
          {
 
6929
            length=7;
 
6930
            tmp_buff= "CASCADE";
 
6931
          }
 
6932
          else if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL)
 
6933
          {
 
6934
            length=8;
 
6935
            tmp_buff= "SET NULL";
 
6936
          }
 
6937
          else if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION)
 
6938
          {
 
6939
            length=9;
 
6940
            tmp_buff= "NO ACTION";
 
6941
          }
 
6942
          else
 
6943
          {
 
6944
            length=8;
 
6945
            tmp_buff= "RESTRICT";
 
6946
          }
 
6947
          f_key_info.update_method = session->make_lex_string(
 
6948
                  f_key_info.update_method, tmp_buff, length, true);
 
6949
          if (foreign->referenced_index &&
 
6950
              foreign->referenced_index->name)
 
6951
          {
 
6952
            f_key_info.referenced_key_name = session->make_lex_string(
 
6953
                    f_key_info.referenced_key_name,
 
6954
                    foreign->referenced_index->name,
 
6955
                    strlen(foreign->referenced_index->name), true);
 
6956
          }
 
6957
          else
 
6958
            f_key_info.referenced_key_name= 0;
 
6959
 
 
6960
          FOREIGN_KEY_INFO *pf_key_info = (FOREIGN_KEY_INFO *)
 
6961
                  session_memdup(session, &f_key_info, sizeof(FOREIGN_KEY_INFO));
 
6962
          f_key_list->push_back(pf_key_info);
 
6963
          foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
 
6964
  }
 
6965
  mutex_exit(&(dict_sys->mutex));
 
6966
  prebuilt->trx->op_info = (char*)"";
 
6967
 
 
6968
  return(0);
 
6969
}
 
6970
 
 
6971
/*****************************************************************//**
 
6972
Checks if ALTER TABLE may change the storage engine of the table.
 
6973
Changing storage engines is not allowed for tables for which there
 
6974
are foreign key constraints (parent or child tables).
 
6975
@return TRUE if can switch engines */
 
6976
UNIV_INTERN
 
6977
bool
 
6978
ha_innobase::can_switch_engines(void)
 
6979
/*=================================*/
 
6980
{
 
6981
        bool    can_switch;
 
6982
 
 
6983
        ut_a(prebuilt->trx == session_to_trx(ha_session()));
 
6984
 
 
6985
        prebuilt->trx->op_info =
 
6986
                        "determining if there are foreign key constraints";
 
6987
        row_mysql_lock_data_dictionary(prebuilt->trx);
 
6988
 
 
6989
        can_switch = !UT_LIST_GET_FIRST(prebuilt->table->referenced_list)
 
6990
                        && !UT_LIST_GET_FIRST(prebuilt->table->foreign_list);
 
6991
 
 
6992
        row_mysql_unlock_data_dictionary(prebuilt->trx);
 
6993
        prebuilt->trx->op_info = "";
 
6994
 
 
6995
        return(can_switch);
 
6996
}
 
6997
 
 
6998
/*******************************************************************//**
 
6999
Checks if a table is referenced by a foreign key. The MySQL manual states that
 
7000
a REPLACE is either equivalent to an INSERT, or DELETE(s) + INSERT. Only a
 
7001
delete is then allowed internally to resolve a duplicate key conflict in
 
7002
REPLACE, not an update.
 
7003
@return > 0 if referenced by a FOREIGN KEY */
 
7004
UNIV_INTERN
 
7005
uint
 
7006
ha_innobase::referenced_by_foreign_key(void)
 
7007
/*========================================*/
 
7008
{
 
7009
        if (dict_table_is_referenced_by_foreign_key(prebuilt->table)) {
 
7010
 
 
7011
                return(1);
 
7012
        }
 
7013
 
 
7014
        return(0);
 
7015
}
 
7016
 
 
7017
/*******************************************************************//**
 
7018
Frees the foreign key create info for a table stored in InnoDB, if it is
 
7019
non-NULL. */
 
7020
UNIV_INTERN
 
7021
void
 
7022
ha_innobase::free_foreign_key_create_info(
 
7023
/*======================================*/
 
7024
        char*   str)    /*!< in, own: create info string to free */
 
7025
{
 
7026
        if (str) {
 
7027
                free(str);
 
7028
        }
 
7029
}
 
7030
 
 
7031
/*******************************************************************//**
 
7032
Tells something additional to the Cursor about how to do things.
 
7033
@return 0 or error number */
 
7034
UNIV_INTERN
 
7035
int
 
7036
ha_innobase::extra(
 
7037
/*===============*/
 
7038
        enum ha_extra_function operation)
 
7039
                           /*!< in: HA_EXTRA_FLUSH or some other flag */
 
7040
{
 
7041
        /* Warning: since it is not sure that MySQL calls external_lock
 
7042
        before calling this function, the trx field in prebuilt can be
 
7043
        obsolete! */
 
7044
 
 
7045
        switch (operation) {
 
7046
                case HA_EXTRA_FLUSH:
 
7047
                        if (prebuilt->blob_heap) {
 
7048
                                row_mysql_prebuilt_free_blob_heap(prebuilt);
 
7049
                        }
 
7050
                        break;
 
7051
                case HA_EXTRA_RESET_STATE:
 
7052
                        reset_template(prebuilt);
 
7053
                        break;
 
7054
                case HA_EXTRA_NO_KEYREAD:
 
7055
                        prebuilt->read_just_key = 0;
 
7056
                        break;
 
7057
                case HA_EXTRA_KEYREAD:
 
7058
                        prebuilt->read_just_key = 1;
 
7059
                        break;
 
7060
                case HA_EXTRA_KEYREAD_PRESERVE_FIELDS:
 
7061
                        prebuilt->keep_other_fields_on_keyread = 1;
 
7062
                        break;
 
7063
 
 
7064
                        /* IMPORTANT: prebuilt->trx can be obsolete in
 
7065
                        this method, because it is not sure that MySQL
 
7066
                        calls external_lock before this method with the
 
7067
                        parameters below.  We must not invoke update_session()
 
7068
                        either, because the calling threads may change.
 
7069
                        CAREFUL HERE, OR MEMORY CORRUPTION MAY OCCUR! */
 
7070
                case HA_EXTRA_IGNORE_DUP_KEY:
 
7071
                        session_to_trx(ha_session())->duplicates |= TRX_DUP_IGNORE;
 
7072
                        break;
 
7073
                case HA_EXTRA_WRITE_CAN_REPLACE:
 
7074
                        session_to_trx(ha_session())->duplicates |= TRX_DUP_REPLACE;
 
7075
                        break;
 
7076
                case HA_EXTRA_WRITE_CANNOT_REPLACE:
 
7077
                        session_to_trx(ha_session())->duplicates &= ~TRX_DUP_REPLACE;
 
7078
                        break;
 
7079
                case HA_EXTRA_NO_IGNORE_DUP_KEY:
 
7080
                        session_to_trx(ha_session())->duplicates &=
 
7081
                                ~(TRX_DUP_IGNORE | TRX_DUP_REPLACE);
 
7082
                        break;
 
7083
                default:/* Do nothing */
 
7084
                        ;
 
7085
        }
 
7086
 
 
7087
        return(0);
 
7088
}
 
7089
 
 
7090
UNIV_INTERN
 
7091
int
 
7092
ha_innobase::reset()
 
7093
{
 
7094
        if (prebuilt->blob_heap) {
 
7095
                row_mysql_prebuilt_free_blob_heap(prebuilt);
 
7096
        }
 
7097
 
 
7098
        reset_template(prebuilt);
 
7099
 
 
7100
        /* TODO: This should really be reset in reset_template() but for now
 
7101
        it's safer to do it explicitly here. */
 
7102
 
 
7103
        /* This is a statement level counter. */
 
7104
        prebuilt->autoinc_last_value = 0;
 
7105
 
 
7106
        return(0);
 
7107
}
 
7108
 
 
7109
/******************************************************************//**
 
7110
MySQL calls this function at the start of each SQL statement inside LOCK
 
7111
TABLES. Inside LOCK TABLES the ::external_lock method does not work to
 
7112
mark SQL statement borders. Note also a special case: if a temporary table
 
7113
is created inside LOCK TABLES, MySQL has not called external_lock() at all
 
7114
on that table.
 
7115
MySQL-5.0 also calls this before each statement in an execution of a stored
 
7116
procedure. To make the execution more deterministic for binlogging, MySQL-5.0
 
7117
locks all tables involved in a stored procedure with full explicit table
 
7118
locks (session_in_lock_tables(session) holds in store_lock()) before executing
 
7119
the procedure.
 
7120
@return 0 or error code */
 
7121
UNIV_INTERN
 
7122
int
 
7123
ha_innobase::start_stmt(
 
7124
/*====================*/
 
7125
        Session*        session,        /*!< in: handle to the user thread */
 
7126
        thr_lock_type   lock_type)
 
7127
{
 
7128
        trx_t*          trx;
 
7129
 
 
7130
        update_session(session);
 
7131
 
 
7132
        trx = prebuilt->trx;
 
7133
 
 
7134
        /* Here we release the search latch and the InnoDB thread FIFO ticket
 
7135
        if they were reserved. They should have been released already at the
 
7136
        end of the previous statement, but because inside LOCK TABLES the
 
7137
        lock count method does not work to mark the end of a SELECT statement,
 
7138
        that may not be the case. We MUST release the search latch before an
 
7139
        INSERT, for example. */
 
7140
 
 
7141
        innobase_release_stat_resources(trx);
 
7142
 
 
7143
        /* Reset the AUTOINC statement level counter for multi-row INSERTs. */
 
7144
        trx->n_autoinc_rows = 0;
 
7145
 
 
7146
        prebuilt->sql_stat_start = TRUE;
 
7147
        prebuilt->hint_need_to_fetch_extra_cols = 0;
 
7148
        reset_template(prebuilt);
 
7149
 
 
7150
        if (!prebuilt->mysql_has_locked) {
 
7151
                /* This handle is for a temporary table created inside
 
7152
                this same LOCK TABLES; since MySQL does NOT call external_lock
 
7153
                in this case, we must use x-row locks inside InnoDB to be
 
7154
                prepared for an update of a row */
 
7155
 
 
7156
                prebuilt->select_lock_type = LOCK_X;
 
7157
        } else {
 
7158
                if (trx->isolation_level != TRX_ISO_SERIALIZABLE
 
7159
                        && session_sql_command(session) == SQLCOM_SELECT
 
7160
                        && lock_type == TL_READ) {
 
7161
 
 
7162
                        /* For other than temporary tables, we obtain
 
7163
                        no lock for consistent read (plain SELECT). */
 
7164
 
 
7165
                        prebuilt->select_lock_type = LOCK_NONE;
 
7166
                } else {
 
7167
                        /* Not a consistent read: restore the
 
7168
                        select_lock_type value. The value of
 
7169
                        stored_select_lock_type was decided in:
 
7170
                        1) ::store_lock(),
 
7171
                        2) ::external_lock(),
 
7172
                        3) ::init_table_handle_for_HANDLER(), and
 
7173
                      */
 
7174
 
 
7175
                        prebuilt->select_lock_type =
 
7176
                                prebuilt->stored_select_lock_type;
 
7177
                }
 
7178
        }
 
7179
 
 
7180
        trx->detailed_error[0] = '\0';
 
7181
 
 
7182
        /* Set the MySQL flag to mark that there is an active transaction */
 
7183
        if (trx->active_trans == 0) {
 
7184
 
 
7185
                innobase_register_trx_and_stmt(engine, session);
 
7186
                trx->active_trans = 1;
 
7187
        } else {
 
7188
                innobase_register_stmt(engine, session);
 
7189
        }
 
7190
 
 
7191
        return(0);
 
7192
}
 
7193
 
 
7194
/******************************************************************//**
 
7195
Maps a MySQL trx isolation level code to the InnoDB isolation level code
 
7196
@return InnoDB isolation level */
 
7197
static inline
 
7198
ulint
 
7199
innobase_map_isolation_level(
 
7200
/*=========================*/
 
7201
        enum_tx_isolation       iso)    /*!< in: MySQL isolation level code */
 
7202
{
 
7203
        switch(iso) {
 
7204
                case ISO_REPEATABLE_READ: return(TRX_ISO_REPEATABLE_READ);
 
7205
                case ISO_READ_COMMITTED: return(TRX_ISO_READ_COMMITTED);
 
7206
                case ISO_SERIALIZABLE: return(TRX_ISO_SERIALIZABLE);
 
7207
                case ISO_READ_UNCOMMITTED: return(TRX_ISO_READ_UNCOMMITTED);
 
7208
                default: ut_a(0); return(0);
 
7209
        }
 
7210
}
 
7211
 
 
7212
/******************************************************************//**
 
7213
As MySQL will execute an external lock for every new table it uses when it
 
7214
starts to process an SQL statement (an exception is when MySQL calls
 
7215
start_stmt for the handle) we can use this function to store the pointer to
 
7216
the Session in the handle. We will also use this function to communicate
 
7217
to InnoDB that a new SQL statement has started and that we must store a
 
7218
savepoint to our transaction handle, so that we are able to roll back
 
7219
the SQL statement in case of an error.
 
7220
@return 0 */
 
7221
UNIV_INTERN
 
7222
int
 
7223
ha_innobase::external_lock(
 
7224
/*=======================*/
 
7225
        Session*        session,        /*!< in: handle to the user thread */
 
7226
        int     lock_type)      /*!< in: lock type */
 
7227
{
 
7228
        trx_t*          trx;
 
7229
 
 
7230
 
 
7231
        update_session(session);
 
7232
 
 
7233
        trx = prebuilt->trx;
 
7234
 
 
7235
        prebuilt->sql_stat_start = TRUE;
 
7236
        prebuilt->hint_need_to_fetch_extra_cols = 0;
 
7237
 
 
7238
        reset_template(prebuilt);
 
7239
 
 
7240
        if (lock_type == F_WRLCK) {
 
7241
 
 
7242
                /* If this is a SELECT, then it is in UPDATE TABLE ...
 
7243
                or SELECT ... FOR UPDATE */
 
7244
                prebuilt->select_lock_type = LOCK_X;
 
7245
                prebuilt->stored_select_lock_type = LOCK_X;
 
7246
        }
 
7247
 
 
7248
        if (lock_type != F_UNLCK) {
 
7249
                /* MySQL is setting a new table lock */
 
7250
 
 
7251
                trx->detailed_error[0] = '\0';
 
7252
 
 
7253
                /* Set the MySQL flag to mark that there is an active
 
7254
                transaction */
 
7255
                if (trx->active_trans == 0) {
 
7256
 
 
7257
                        innobase_register_trx_and_stmt(engine, session);
 
7258
                        trx->active_trans = 1;
 
7259
                } else if (trx->n_mysql_tables_in_use == 0) {
 
7260
                        innobase_register_stmt(engine, session);
 
7261
                }
 
7262
 
 
7263
                if (trx->isolation_level == TRX_ISO_SERIALIZABLE
 
7264
                        && prebuilt->select_lock_type == LOCK_NONE
 
7265
                        && session_test_options(session,
 
7266
                                OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
 
7267
 
 
7268
                        /* To get serializable execution, we let InnoDB
 
7269
                        conceptually add 'LOCK IN SHARE MODE' to all SELECTs
 
7270
                        which otherwise would have been consistent reads. An
 
7271
                        exception is consistent reads in the AUTOCOMMIT=1 mode:
 
7272
                        we know that they are read-only transactions, and they
 
7273
                        can be serialized also if performed as consistent
 
7274
                        reads. */
 
7275
 
 
7276
                        prebuilt->select_lock_type = LOCK_S;
 
7277
                        prebuilt->stored_select_lock_type = LOCK_S;
 
7278
                }
 
7279
 
 
7280
                /* Starting from 4.1.9, no InnoDB table lock is taken in LOCK
 
7281
                TABLES if AUTOCOMMIT=1. It does not make much sense to acquire
 
7282
                an InnoDB table lock if it is released immediately at the end
 
7283
                of LOCK TABLES, and InnoDB's table locks in that case cause
 
7284
                VERY easily deadlocks.
 
7285
 
 
7286
                We do not set InnoDB table locks if user has not explicitly
 
7287
                requested a table lock. Note that session_in_lock_tables(session)
 
7288
                can hold in some cases, e.g., at the start of a stored
 
7289
                procedure call (SQLCOM_CALL). */
 
7290
 
 
7291
                if (prebuilt->select_lock_type != LOCK_NONE) {
 
7292
                        trx->mysql_n_tables_locked++;
 
7293
                }
 
7294
 
 
7295
                trx->n_mysql_tables_in_use++;
 
7296
                prebuilt->mysql_has_locked = TRUE;
 
7297
 
 
7298
                return(0);
 
7299
        }
 
7300
 
 
7301
        /* MySQL is releasing a table lock */
 
7302
 
 
7303
        trx->n_mysql_tables_in_use--;
 
7304
        prebuilt->mysql_has_locked = FALSE;
 
7305
 
 
7306
        /* Release a possible FIFO ticket and search latch. Since we
 
7307
        may reserve the kernel mutex, we have to release the search
 
7308
        system latch first to obey the latching order. */
 
7309
 
 
7310
        innobase_release_stat_resources(trx);
 
7311
 
 
7312
        /* If the MySQL lock count drops to zero we know that the current SQL
 
7313
        statement has ended */
 
7314
 
 
7315
        if (trx->n_mysql_tables_in_use == 0) {
 
7316
 
 
7317
                trx->mysql_n_tables_locked = 0;
 
7318
                prebuilt->used_in_HANDLER = FALSE;
 
7319
 
 
7320
                if (!session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
 
7321
                        if (trx->active_trans != 0) {
 
7322
                                engine->commit(session, TRUE);
 
7323
                        }
 
7324
                } else {
 
7325
                        if (trx->isolation_level <= TRX_ISO_READ_COMMITTED
 
7326
                                                && trx->global_read_view) {
 
7327
 
 
7328
                                /* At low transaction isolation levels we let
 
7329
                                each consistent read set its own snapshot */
 
7330
 
 
7331
                                read_view_close_for_mysql(trx);
 
7332
                        }
 
7333
                }
 
7334
        }
 
7335
 
 
7336
        return(0);
 
7337
}
 
7338
 
 
7339
/************************************************************************//**
 
7340
Here we export InnoDB status variables to MySQL. */
 
7341
static
 
7342
void
 
7343
innodb_export_status(void)
 
7344
/*======================*/
 
7345
{
 
7346
        if (innodb_inited) {
 
7347
                srv_export_innodb_status();
 
7348
        }
 
7349
}
 
7350
 
 
7351
/************************************************************************//**
 
7352
Implements the SHOW INNODB STATUS command. Sends the output of the InnoDB
 
7353
Monitor to the client. */
 
7354
static
 
7355
bool
 
7356
innodb_show_status(
 
7357
/*===============*/
 
7358
        drizzled::plugin::StorageEngine*        engine, /*!< in: the innodb StorageEngine */
 
7359
        Session*        session,/*!< in: the MySQL query thread of the caller */
 
7360
        stat_print_fn *stat_print)
 
7361
{
 
7362
        trx_t*                  trx;
 
7363
        static const char       truncated_msg[] = "... truncated...\n";
 
7364
        const long              MAX_STATUS_SIZE = 64000;
 
7365
        ulint                   trx_list_start = ULINT_UNDEFINED;
 
7366
        ulint                   trx_list_end = ULINT_UNDEFINED;
 
7367
 
 
7368
        assert(engine == innodb_engine_ptr);
 
7369
 
 
7370
        trx = check_trx_exists(session);
 
7371
 
 
7372
        innobase_release_stat_resources(trx);
 
7373
 
 
7374
        /* We let the InnoDB Monitor to output at most MAX_STATUS_SIZE
 
7375
        bytes of text. */
 
7376
 
 
7377
        long    flen, usable_len;
 
7378
        char*   str;
 
7379
 
 
7380
        mutex_enter(&srv_monitor_file_mutex);
 
7381
        rewind(srv_monitor_file);
 
7382
        srv_printf_innodb_monitor(srv_monitor_file,
 
7383
                                &trx_list_start, &trx_list_end);
 
7384
        flen = ftell(srv_monitor_file);
 
7385
        os_file_set_eof(srv_monitor_file);
 
7386
 
 
7387
        if (flen < 0) {
 
7388
                flen = 0;
 
7389
        }
 
7390
 
 
7391
        if (flen > MAX_STATUS_SIZE) {
 
7392
                usable_len = MAX_STATUS_SIZE;
 
7393
        } else {
 
7394
                usable_len = flen;
 
7395
        }
 
7396
 
 
7397
        /* allocate buffer for the string, and
 
7398
        read the contents of the temporary file */
 
7399
 
 
7400
        if (!(str = (char*) malloc(usable_len + 1))) {
 
7401
          mutex_exit(&srv_monitor_file_mutex);
 
7402
          return(TRUE);
 
7403
        }
 
7404
 
 
7405
        rewind(srv_monitor_file);
 
7406
        if (flen < MAX_STATUS_SIZE) {
 
7407
                /* Display the entire output. */
 
7408
                flen = (long) fread(str, 1, flen, srv_monitor_file);
 
7409
        } else if (trx_list_end < (ulint) flen
 
7410
                        && trx_list_start < trx_list_end
 
7411
                        && trx_list_start + (flen - trx_list_end)
 
7412
                        < MAX_STATUS_SIZE - sizeof truncated_msg - 1) {
 
7413
                /* Omit the beginning of the list of active transactions. */
 
7414
                long len = (long) fread(str, 1, trx_list_start, srv_monitor_file);
 
7415
                memcpy(str + len, truncated_msg, sizeof truncated_msg - 1);
 
7416
                len += sizeof truncated_msg - 1;
 
7417
                usable_len = (MAX_STATUS_SIZE - 1) - len;
 
7418
                fseek(srv_monitor_file, flen - usable_len, SEEK_SET);
 
7419
                len += (long) fread(str + len, 1, usable_len, srv_monitor_file);
 
7420
                flen = len;
 
7421
        } else {
 
7422
                /* Omit the end of the output. */
 
7423
                flen = (long) fread(str, 1, MAX_STATUS_SIZE - 1, srv_monitor_file);
 
7424
        }
 
7425
 
 
7426
        mutex_exit(&srv_monitor_file_mutex);
 
7427
 
 
7428
        bool result = FALSE;
 
7429
 
 
7430
        if (stat_print(session, innobase_engine_name, strlen(innobase_engine_name),
 
7431
                        STRING_WITH_LEN(""), str, flen)) {
 
7432
                result= TRUE;
 
7433
        }
 
7434
        free(str);
 
7435
 
 
7436
        return(FALSE);
 
7437
}
 
7438
 
 
7439
/************************************************************************//**
 
7440
Implements the SHOW MUTEX STATUS command. . */
 
7441
static
 
7442
bool
 
7443
innodb_mutex_show_status(
 
7444
/*=====================*/
 
7445
        drizzled::plugin::StorageEngine*        engine,         /*!< in: the innodb StorageEngine */
 
7446
        Session*        session,        /*!< in: the MySQL query thread of the
 
7447
                                        caller */
 
7448
        stat_print_fn*  stat_print)
 
7449
{
 
7450
        char buf1[IO_SIZE], buf2[IO_SIZE];
 
7451
        mutex_t*        mutex;
 
7452
        rw_lock_t*      lock;
 
7453
#ifdef UNIV_DEBUG
 
7454
        ulint     rw_lock_count= 0;
 
7455
        ulint     rw_lock_count_spin_loop= 0;
 
7456
        ulint     rw_lock_count_spin_rounds= 0;
 
7457
        ulint     rw_lock_count_os_wait= 0;
 
7458
        ulint     rw_lock_count_os_yield= 0;
 
7459
        uint64_t rw_lock_wait_time= 0;
 
7460
#endif /* UNIV_DEBUG */
 
7461
        uint      engine_name_len= strlen(innobase_engine_name), buf1len, buf2len;
 
7462
        assert(engine == innodb_engine_ptr);
 
7463
 
 
7464
        mutex_enter(&mutex_list_mutex);
 
7465
 
 
7466
        mutex = UT_LIST_GET_FIRST(mutex_list);
 
7467
 
 
7468
        while (mutex != NULL) {
 
7469
                if (mutex->count_os_wait == 0
 
7470
                    || buf_pool_is_block_mutex(mutex)) {
 
7471
                        goto next_mutex;
 
7472
                }
 
7473
#ifdef UNIV_DEBUG
 
7474
                if (mutex->mutex_type != 1) {
 
7475
                        if (mutex->count_using > 0) {
 
7476
                                buf1len= my_snprintf(buf1, sizeof(buf1),
 
7477
                                        "%s:%s",
 
7478
                                        mutex->cmutex_name, mutex->cfile_name);
 
7479
                                buf2len= my_snprintf(buf2, sizeof(buf2),
 
7480
                                        "count=%lu, spin_waits=%lu,"
 
7481
                                        " spin_rounds=%lu, "
 
7482
                                        "os_waits=%lu, os_yields=%lu,"
 
7483
                                        " os_wait_times=%lu",
 
7484
                                        mutex->count_using,
 
7485
                                        mutex->count_spin_loop,
 
7486
                                        mutex->count_spin_rounds,
 
7487
                                        mutex->count_os_wait,
 
7488
                                        mutex->count_os_yield,
 
7489
                                        (ulong) (mutex->lspent_time/1000));
 
7490
 
 
7491
                                if (stat_print(session, innobase_engine_name,
 
7492
                                                engine_name_len, buf1, buf1len,
 
7493
                                                buf2, buf2len)) {
 
7494
                                        mutex_exit(&mutex_list_mutex);
 
7495
                                        return(1);
 
7496
                                }
 
7497
                        }
 
7498
                }
 
7499
                else {
 
7500
                        rw_lock_count += mutex->count_using;
 
7501
                        rw_lock_count_spin_loop += mutex->count_spin_loop;
 
7502
                        rw_lock_count_spin_rounds += mutex->count_spin_rounds;
 
7503
                        rw_lock_count_os_wait += mutex->count_os_wait;
 
7504
                        rw_lock_count_os_yield += mutex->count_os_yield;
 
7505
                        rw_lock_wait_time += mutex->lspent_time;
 
7506
                }
 
7507
#else /* UNIV_DEBUG */
 
7508
                buf1len= snprintf(buf1, sizeof(buf1), "%s:%lu",
 
7509
                                  mutex->cfile_name, (ulong) mutex->cline);
 
7510
                buf2len= snprintf(buf2, sizeof(buf2), "os_waits=%lu",
 
7511
                                  mutex->count_os_wait);
 
7512
 
 
7513
                if (stat_print(session, innobase_engine_name,
 
7514
                               engine_name_len, buf1, buf1len,
 
7515
                               buf2, buf2len)) {
 
7516
                        mutex_exit(&mutex_list_mutex);
 
7517
                        return(1);
 
7518
                }
 
7519
#endif /* UNIV_DEBUG */
 
7520
 
 
7521
next_mutex:
 
7522
                mutex = UT_LIST_GET_NEXT(list, mutex);
 
7523
        }
 
7524
 
 
7525
        mutex_exit(&mutex_list_mutex);
 
7526
 
 
7527
        mutex_enter(&rw_lock_list_mutex);
 
7528
 
 
7529
        lock = UT_LIST_GET_FIRST(rw_lock_list);
 
7530
 
 
7531
        while (lock != NULL) {
 
7532
                if (lock->count_os_wait
 
7533
                    && !buf_pool_is_block_lock(lock)) {
 
7534
                        buf1len= snprintf(buf1, sizeof(buf1), "%s:%lu",
 
7535
                                    lock->cfile_name, (unsigned long) lock->cline);
 
7536
                        buf2len= snprintf(buf2, sizeof(buf2),
 
7537
                                    "os_waits=%lu", lock->count_os_wait);
 
7538
 
 
7539
                        if (stat_print(session, innobase_engine_name,
 
7540
                                       engine_name_len, buf1, buf1len,
 
7541
                                       buf2, buf2len)) {
 
7542
                                mutex_exit(&rw_lock_list_mutex);
 
7543
                                return(1);
 
7544
                        }
 
7545
                }
 
7546
                lock = UT_LIST_GET_NEXT(list, lock);
 
7547
        }
 
7548
 
 
7549
        mutex_exit(&rw_lock_list_mutex);
 
7550
 
 
7551
#ifdef UNIV_DEBUG
 
7552
        buf2len= my_snprintf(buf2, sizeof(buf2),
 
7553
                "count=%lu, spin_waits=%lu, spin_rounds=%lu, "
 
7554
                "os_waits=%lu, os_yields=%lu, os_wait_times=%lu",
 
7555
                rw_lock_count, rw_lock_count_spin_loop,
 
7556
                rw_lock_count_spin_rounds,
 
7557
                rw_lock_count_os_wait, rw_lock_count_os_yield,
 
7558
                (ulong) (rw_lock_wait_time/1000));
 
7559
 
 
7560
        if (stat_print(session, innobase_engine_name, engine_name_len,
 
7561
                        STRING_WITH_LEN("rw_lock_mutexes"), buf2, buf2len)) {
 
7562
                return(1);
 
7563
        }
 
7564
#endif /* UNIV_DEBUG */
 
7565
 
 
7566
        return(FALSE);
 
7567
}
 
7568
 
 
7569
bool InnobaseEngine::show_status(Session* session, 
 
7570
                                 stat_print_fn* stat_print,
 
7571
                                 enum ha_stat_type stat_type)
 
7572
{
 
7573
        assert(this == innodb_engine_ptr);
 
7574
 
 
7575
        switch (stat_type) {
 
7576
        case HA_ENGINE_STATUS:
 
7577
                return innodb_show_status(this, session, stat_print);
 
7578
        case HA_ENGINE_MUTEX:
 
7579
                return innodb_mutex_show_status(this, session, stat_print);
 
7580
        default:
 
7581
                return(FALSE);
 
7582
        }
 
7583
}
 
7584
 
 
7585
/************************************************************************//**
 
7586
 Handling the shared INNOBASE_SHARE structure that is needed to provide table
 
7587
 locking.
 
7588
****************************************************************************/
 
7589
 
 
7590
static INNOBASE_SHARE* get_share(const char* table_name)
 
7591
{
 
7592
        INNOBASE_SHARE *share;
 
7593
        pthread_mutex_lock(&innobase_share_mutex);
 
7594
 
 
7595
        ulint   fold = ut_fold_string(table_name);
 
7596
 
 
7597
        HASH_SEARCH(table_name_hash, innobase_open_tables, fold,
 
7598
                    INNOBASE_SHARE*, share,
 
7599
                    ut_ad(share->use_count > 0),
 
7600
                    !strcmp(share->table_name, table_name));
 
7601
 
 
7602
        if (!share) {
 
7603
 
 
7604
                uint length = (uint) strlen(table_name);
 
7605
 
 
7606
                /* TODO: invoke HASH_MIGRATE if innobase_open_tables
 
7607
                grows too big */
 
7608
 
 
7609
                share = (INNOBASE_SHARE *) malloc(sizeof(*share)+length+1);
 
7610
                memset(share, 0, sizeof(*share)+length+1);
 
7611
 
 
7612
                share->table_name = (char*) memcpy(share + 1,
 
7613
                                                   table_name, length + 1);
 
7614
 
 
7615
                HASH_INSERT(INNOBASE_SHARE, table_name_hash,
 
7616
                            innobase_open_tables, fold, share);
 
7617
 
 
7618
                thr_lock_init(&share->lock);
 
7619
        }
 
7620
 
 
7621
        share->use_count++;
 
7622
        pthread_mutex_unlock(&innobase_share_mutex);
 
7623
 
 
7624
        return(share);
 
7625
}
 
7626
 
 
7627
static void free_share(INNOBASE_SHARE* share)
 
7628
{
 
7629
        pthread_mutex_lock(&innobase_share_mutex);
 
7630
 
 
7631
#ifdef UNIV_DEBUG
 
7632
        INNOBASE_SHARE* share2;
 
7633
        ulint   fold = ut_fold_string(share->table_name);
 
7634
 
 
7635
        HASH_SEARCH(table_name_hash, innobase_open_tables, fold,
 
7636
                    INNOBASE_SHARE*, share2,
 
7637
                    ut_ad(share->use_count > 0),
 
7638
                    !strcmp(share->table_name, share2->table_name));
 
7639
 
 
7640
        ut_a(share2 == share);
 
7641
#endif /* UNIV_DEBUG */
 
7642
 
 
7643
        if (!--share->use_count) {
 
7644
                ulint   fold = ut_fold_string(share->table_name);
 
7645
 
 
7646
                HASH_DELETE(INNOBASE_SHARE, table_name_hash,
 
7647
                            innobase_open_tables, fold, share);
 
7648
                thr_lock_delete(&share->lock);
 
7649
                free(share);
 
7650
 
 
7651
                /* TODO: invoke HASH_MIGRATE if innobase_open_tables
 
7652
                shrinks too much */
 
7653
        }
 
7654
 
 
7655
        pthread_mutex_unlock(&innobase_share_mutex);
 
7656
}
 
7657
 
 
7658
/*****************************************************************//**
 
7659
Converts a MySQL table lock stored in the 'lock' field of the handle to
 
7660
a proper type before storing pointer to the lock into an array of pointers.
 
7661
MySQL also calls this if it wants to reset some table locks to a not-locked
 
7662
state during the processing of an SQL query. An example is that during a
 
7663
SELECT the read lock is released early on the 'const' tables where we only
 
7664
fetch one row. MySQL does not call this when it releases all locks at the
 
7665
end of an SQL statement.
 
7666
@return pointer to the next element in the 'to' array */
 
7667
UNIV_INTERN
 
7668
THR_LOCK_DATA**
 
7669
ha_innobase::store_lock(
 
7670
/*====================*/
 
7671
        Session*                session,        /*!< in: user thread handle */
 
7672
        THR_LOCK_DATA**         to,             /*!< in: pointer to an array
 
7673
                                                of pointers to lock structs;
 
7674
                                                pointer to the 'lock' field
 
7675
                                                of current handle is stored
 
7676
                                                next to this array */
 
7677
        enum thr_lock_type      lock_type)      /*!< in: lock type to store in
 
7678
                                                'lock'; this may also be
 
7679
                                                TL_IGNORE */
 
7680
{
 
7681
        trx_t*          trx;
 
7682
 
 
7683
        /* Note that trx in this function is NOT necessarily prebuilt->trx
 
7684
        because we call update_session() later, in ::external_lock()! Failure to
 
7685
        understand this caused a serious memory corruption bug in 5.1.11. */
 
7686
 
 
7687
        trx = check_trx_exists(session);
 
7688
 
 
7689
        /* NOTE: MySQL can call this function with lock 'type' TL_IGNORE!
 
7690
        Be careful to ignore TL_IGNORE if we are going to do something with
 
7691
        only 'real' locks! */
 
7692
 
 
7693
        /* If no MySQL table is in use, we need to set the isolation level
 
7694
        of the transaction. */
 
7695
 
 
7696
        if (lock_type != TL_IGNORE
 
7697
            && trx->n_mysql_tables_in_use == 0) {
 
7698
                trx->isolation_level = innobase_map_isolation_level(
 
7699
                        (enum_tx_isolation) session_tx_isolation(session));
 
7700
 
 
7701
                if (trx->isolation_level <= TRX_ISO_READ_COMMITTED
 
7702
                    && trx->global_read_view) {
 
7703
 
 
7704
                        /* At low transaction isolation levels we let
 
7705
                        each consistent read set its own snapshot */
 
7706
 
 
7707
                        read_view_close_for_mysql(trx);
 
7708
                }
 
7709
        }
 
7710
 
 
7711
        assert(EQ_CURRENT_SESSION(session));
 
7712
        const uint32_t sql_command = session_sql_command(session);
 
7713
 
 
7714
        if (sql_command == SQLCOM_DROP_TABLE) {
 
7715
 
 
7716
                /* MySQL calls this function in DROP Table though this table
 
7717
                handle may belong to another session that is running a query.
 
7718
                Let us in that case skip any changes to the prebuilt struct. */ 
 
7719
 
 
7720
        } else if (lock_type == TL_READ_WITH_SHARED_LOCKS
 
7721
                   || lock_type == TL_READ_NO_INSERT
 
7722
                   || (lock_type != TL_IGNORE
 
7723
                       && sql_command != SQLCOM_SELECT)) {
 
7724
 
 
7725
                /* The OR cases above are in this order:
 
7726
                1) MySQL is doing LOCK TABLES ... READ LOCAL, or we
 
7727
                are processing a stored procedure or function, or
 
7728
                2) (we do not know when TL_READ_HIGH_PRIORITY is used), or
 
7729
                3) this is a SELECT ... IN SHARE MODE, or
 
7730
                4) we are doing a complex SQL statement like
 
7731
                INSERT INTO ... SELECT ... and the logical logging (MySQL
 
7732
                binlog) requires the use of a locking read, or
 
7733
                MySQL is doing LOCK TABLES ... READ.
 
7734
                5) we let InnoDB do locking reads for all SQL statements that
 
7735
                are not simple SELECTs; note that select_lock_type in this
 
7736
                case may get strengthened in ::external_lock() to LOCK_X.
 
7737
                Note that we MUST use a locking read in all data modifying
 
7738
                SQL statements, because otherwise the execution would not be
 
7739
                serializable, and also the results from the update could be
 
7740
                unexpected if an obsolete consistent read view would be
 
7741
                used. */
 
7742
 
 
7743
                ulint   isolation_level;
 
7744
 
 
7745
                isolation_level = trx->isolation_level;
 
7746
 
 
7747
                if ((srv_locks_unsafe_for_binlog
 
7748
                     || isolation_level == TRX_ISO_READ_COMMITTED)
 
7749
                    && isolation_level != TRX_ISO_SERIALIZABLE
 
7750
                    && (lock_type == TL_READ || lock_type == TL_READ_NO_INSERT)
 
7751
                    && (sql_command == SQLCOM_INSERT_SELECT
 
7752
                        || sql_command == SQLCOM_UPDATE
 
7753
                        || sql_command == SQLCOM_CREATE_TABLE)) {
 
7754
 
 
7755
                        /* If we either have innobase_locks_unsafe_for_binlog
 
7756
                        option set or this session is using READ COMMITTED
 
7757
                        isolation level and isolation level of the transaction
 
7758
                        is not set to serializable and MySQL is doing
 
7759
                        INSERT INTO...SELECT or UPDATE ... = (SELECT ...) or
 
7760
                        CREATE  ... SELECT... without FOR UPDATE or
 
7761
                        IN SHARE MODE in select, then we use consistent
 
7762
                        read for select. */
 
7763
 
 
7764
                        prebuilt->select_lock_type = LOCK_NONE;
 
7765
                        prebuilt->stored_select_lock_type = LOCK_NONE;
 
7766
                } else if (sql_command == SQLCOM_CHECKSUM) {
 
7767
                        /* Use consistent read for checksum table */
 
7768
 
 
7769
                        prebuilt->select_lock_type = LOCK_NONE;
 
7770
                        prebuilt->stored_select_lock_type = LOCK_NONE;
 
7771
                } else {
 
7772
                        prebuilt->select_lock_type = LOCK_S;
 
7773
                        prebuilt->stored_select_lock_type = LOCK_S;
 
7774
                }
 
7775
 
 
7776
        } else if (lock_type != TL_IGNORE) {
 
7777
 
 
7778
                /* We set possible LOCK_X value in external_lock, not yet
 
7779
                here even if this would be SELECT ... FOR UPDATE */
 
7780
 
 
7781
                prebuilt->select_lock_type = LOCK_NONE;
 
7782
                prebuilt->stored_select_lock_type = LOCK_NONE;
 
7783
        }
 
7784
 
 
7785
        if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) {
 
7786
 
 
7787
                /* If we are not doing a LOCK TABLE, DISCARD/IMPORT
 
7788
                TABLESPACE or TRUNCATE TABLE then allow multiple
 
7789
                writers. Note that ALTER TABLE uses a TL_WRITE_ALLOW_READ
 
7790
                < TL_WRITE_CONCURRENT_INSERT.
 
7791
 
 
7792
                We especially allow multiple writers if MySQL is at the
 
7793
                start of a stored procedure call (SQLCOM_CALL) or a
 
7794
                stored function call (MySQL does have in_lock_tables
 
7795
                TRUE there). */
 
7796
 
 
7797
                if ((lock_type >= TL_WRITE_CONCURRENT_INSERT
 
7798
                     && lock_type <= TL_WRITE)
 
7799
                    && !session_tablespace_op(session)
 
7800
                    && sql_command != SQLCOM_TRUNCATE
 
7801
                    && sql_command != SQLCOM_CREATE_TABLE) {
 
7802
 
 
7803
                        lock_type = TL_WRITE_ALLOW_WRITE;
 
7804
                }
 
7805
 
 
7806
                /* In queries of type INSERT INTO t1 SELECT ... FROM t2 ...
 
7807
                MySQL would use the lock TL_READ_NO_INSERT on t2, and that
 
7808
                would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts
 
7809
                to t2. Convert the lock to a normal read lock to allow
 
7810
                concurrent inserts to t2.
 
7811
 
 
7812
                We especially allow concurrent inserts if MySQL is at the
 
7813
                start of a stored procedure call (SQLCOM_CALL)
 
7814
                (MySQL does have session_in_lock_tables() TRUE there). */
 
7815
 
 
7816
                if (lock_type == TL_READ_NO_INSERT) {
 
7817
 
 
7818
                        lock_type = TL_READ;
 
7819
                }
 
7820
 
 
7821
                lock.type = lock_type;
 
7822
        }
 
7823
 
 
7824
        *to++= &lock;
 
7825
 
 
7826
        return(to);
 
7827
}
 
7828
 
 
7829
/*********************************************************************//**
 
7830
Read the next autoinc value. Acquire the relevant locks before reading
 
7831
the AUTOINC value. If SUCCESS then the table AUTOINC mutex will be locked
 
7832
on return and all relevant locks acquired.
 
7833
@return DB_SUCCESS or error code */
 
7834
UNIV_INTERN
 
7835
ulint
 
7836
ha_innobase::innobase_get_autoinc(
 
7837
/*==============================*/
 
7838
        uint64_t*       value)          /*!< out: autoinc value */
 
7839
{
 
7840
        *value = 0;
 
7841
 
 
7842
        prebuilt->autoinc_error = innobase_lock_autoinc();
 
7843
 
 
7844
        if (prebuilt->autoinc_error == DB_SUCCESS) {
 
7845
 
 
7846
                /* Determine the first value of the interval */
 
7847
                *value = dict_table_autoinc_read(prebuilt->table);
 
7848
 
 
7849
                /* It should have been initialized during open. */
 
7850
                ut_a(*value != 0);
 
7851
        }
 
7852
 
 
7853
        return(prebuilt->autoinc_error);
 
7854
}
 
7855
 
 
7856
/*******************************************************************//**
 
7857
This function reads the global auto-inc counter. It doesn't use the 
 
7858
AUTOINC lock even if the lock mode is set to TRADITIONAL.
 
7859
@return the autoinc value */
 
7860
UNIV_INTERN
 
7861
uint64_t
 
7862
ha_innobase::innobase_peek_autoinc(void)
 
7863
/*====================================*/
 
7864
{
 
7865
        uint64_t        auto_inc;
 
7866
        dict_table_t*   innodb_table;
 
7867
 
 
7868
        ut_a(prebuilt != NULL);
 
7869
        ut_a(prebuilt->table != NULL);
 
7870
 
 
7871
        innodb_table = prebuilt->table;
 
7872
 
 
7873
        dict_table_autoinc_lock(innodb_table);
 
7874
 
 
7875
        auto_inc = dict_table_autoinc_read(innodb_table);
 
7876
 
 
7877
        ut_a(auto_inc > 0);
 
7878
 
 
7879
        dict_table_autoinc_unlock(innodb_table);
 
7880
 
 
7881
        return(auto_inc);
 
7882
}
 
7883
 
 
7884
/*********************************************************************//**
 
7885
This function initializes the auto-inc counter if it has not been
 
7886
initialized yet. This function does not change the value of the auto-inc
 
7887
counter if it already has been initialized. Returns the value of the
 
7888
auto-inc counter in *first_value, and UINT64_T_MAX in *nb_reserved_values (as
 
7889
we have a table-level lock). offset, increment, nb_desired_values are ignored.
 
7890
*first_value is set to -1 if error (deadlock or lock wait timeout) */
 
7891
UNIV_INTERN
 
7892
void
 
7893
ha_innobase::get_auto_increment(
 
7894
/*============================*/
 
7895
        uint64_t        offset,              /*!< in: table autoinc offset */
 
7896
        uint64_t        increment,           /*!< in: table autoinc increment */
 
7897
        uint64_t        nb_desired_values,   /*!< in: number of values reqd */
 
7898
        uint64_t        *first_value,        /*!< out: the autoinc value */
 
7899
        uint64_t        *nb_reserved_values) /*!< out: count of reserved values */
 
7900
{
 
7901
        trx_t*          trx;
 
7902
        ulint           error;
 
7903
        uint64_t        autoinc = 0;
 
7904
 
 
7905
        /* Prepare prebuilt->trx in the table handle */
 
7906
        update_session(ha_session());
 
7907
 
 
7908
        error = innobase_get_autoinc(&autoinc);
 
7909
 
 
7910
        if (error != DB_SUCCESS) {
 
7911
                *first_value = (~(uint64_t) 0);
 
7912
                return;
 
7913
        }
 
7914
 
 
7915
        /* This is a hack, since nb_desired_values seems to be accurate only
 
7916
        for the first call to get_auto_increment() for multi-row INSERT and
 
7917
        meaningless for other statements e.g, LOAD etc. Subsequent calls to
 
7918
        this method for the same statement results in different values which
 
7919
        don't make sense. Therefore we store the value the first time we are
 
7920
        called and count down from that as rows are written (see write_row()).
 
7921
        */
 
7922
 
 
7923
        trx = prebuilt->trx;
 
7924
 
 
7925
        /* Note: We can't rely on *first_value since some MySQL engines,
 
7926
        in particular the partition engine, don't initialize it to 0 when
 
7927
        invoking this method. So we are not sure if it's guaranteed to
 
7928
        be 0 or not. */
 
7929
 
 
7930
        /* Called for the first time ? */
 
7931
        if (trx->n_autoinc_rows == 0) {
 
7932
 
 
7933
                trx->n_autoinc_rows = (ulint) nb_desired_values;
 
7934
 
 
7935
                /* It's possible for nb_desired_values to be 0:
 
7936
                e.g., INSERT INTO T1(C) SELECT C FROM T2; */
 
7937
                if (nb_desired_values == 0) {
 
7938
 
 
7939
                        trx->n_autoinc_rows = 1;
 
7940
                }
 
7941
 
 
7942
                set_if_bigger(*first_value, autoinc);
 
7943
        /* Not in the middle of a mult-row INSERT. */
 
7944
        } else if (prebuilt->autoinc_last_value == 0) {
 
7945
                set_if_bigger(*first_value, autoinc);
 
7946
        }
 
7947
 
 
7948
        *nb_reserved_values = trx->n_autoinc_rows;
 
7949
 
 
7950
        /* With old style AUTOINC locking we only update the table's
 
7951
        AUTOINC counter after attempting to insert the row. */
 
7952
        if (innobase_autoinc_lock_mode != AUTOINC_OLD_STYLE_LOCKING) {
 
7953
                uint64_t        need;
 
7954
                uint64_t        next_value;
 
7955
                uint64_t        col_max_value;
 
7956
 
 
7957
                /* We need the upper limit of the col type to check for
 
7958
                whether we update the table autoinc counter or not. */
 
7959
                col_max_value = innobase_get_int_col_max_value(
 
7960
                        table->next_number_field);
 
7961
 
 
7962
                need = *nb_reserved_values * increment;
 
7963
 
 
7964
                /* Compute the last value in the interval */
 
7965
                next_value = innobase_next_autoinc(
 
7966
                        *first_value, need, offset, col_max_value);
 
7967
 
 
7968
                prebuilt->autoinc_last_value = next_value;
 
7969
 
 
7970
                if (prebuilt->autoinc_last_value < *first_value) {
 
7971
                        *first_value = (~(unsigned long long) 0);
 
7972
                } else {
 
7973
                        /* Update the table autoinc variable */
 
7974
                        dict_table_autoinc_update_if_greater(
 
7975
                                prebuilt->table, prebuilt->autoinc_last_value);
 
7976
                }
 
7977
        } else {
 
7978
                /* This will force write_row() into attempting an update
 
7979
                of the table's AUTOINC counter. */
 
7980
                prebuilt->autoinc_last_value = 0;
 
7981
        }
 
7982
 
 
7983
        /* The increment to be used to increase the AUTOINC value, we use
 
7984
        this in write_row() and update_row() to increase the autoinc counter
 
7985
        for columns that are filled by the user. We need the offset and
 
7986
        the increment. */
 
7987
        prebuilt->autoinc_offset = offset;
 
7988
        prebuilt->autoinc_increment = increment;
 
7989
 
 
7990
        dict_table_autoinc_unlock(prebuilt->table);
 
7991
}
 
7992
 
 
7993
/*******************************************************************//**
 
7994
Reset the auto-increment counter to the given value, i.e. the next row
 
7995
inserted will get the given value. This is called e.g. after TRUNCATE
 
7996
is emulated by doing a 'DELETE FROM t'. HA_ERR_WRONG_COMMAND is
 
7997
returned by storage engines that don't support this operation.
 
7998
@return 0 or error code */
 
7999
UNIV_INTERN
 
8000
int
 
8001
ha_innobase::reset_auto_increment(
 
8002
/*==============================*/
 
8003
        uint64_t        value)          /*!< in: new value for table autoinc */
 
8004
{
 
8005
        int     error;
 
8006
 
 
8007
        update_session(ha_session());
 
8008
 
 
8009
        error = row_lock_table_autoinc_for_mysql(prebuilt);
 
8010
 
 
8011
        if (error != DB_SUCCESS) {
 
8012
                error = convert_error_code_to_mysql(error,
 
8013
                                                    prebuilt->table->flags,
 
8014
                                                    user_session);
 
8015
 
 
8016
                return(error);
 
8017
        }
 
8018
 
 
8019
        /* The next value can never be 0. */
 
8020
        if (value == 0) {
 
8021
                value = 1;
 
8022
        }
 
8023
 
 
8024
        innobase_reset_autoinc(value);
 
8025
 
 
8026
        return 0;
 
8027
}
 
8028
 
 
8029
/* See comment in Cursor.cc */
 
8030
UNIV_INTERN
 
8031
bool
 
8032
InnobaseEngine::get_error_message(int, String *buf)
 
8033
{
 
8034
        trx_t*  trx = check_trx_exists(current_session);
 
8035
 
 
8036
        buf->copy(trx->detailed_error, (uint) strlen(trx->detailed_error),
 
8037
                system_charset_info);
 
8038
 
 
8039
        return(FALSE);
 
8040
}
 
8041
 
 
8042
/*******************************************************************//**
 
8043
Compares two 'refs'. A 'ref' is the (internal) primary key value of the row.
 
8044
If there is no explicitly declared non-null unique key or a primary key, then
 
8045
InnoDB internally uses the row id as the primary key.
 
8046
@return < 0 if ref1 < ref2, 0 if equal, else > 0 */
 
8047
UNIV_INTERN
 
8048
int
 
8049
ha_innobase::cmp_ref(
 
8050
/*=================*/
 
8051
        const unsigned char*    ref1,   /*!< in: an (internal) primary key value in the
 
8052
                                MySQL key value format */
 
8053
        const unsigned char*    ref2)   /*!< in: an (internal) primary key value in the
 
8054
                                MySQL key value format */
 
8055
{
 
8056
        enum_field_types mysql_type;
 
8057
        Field*          field;
 
8058
        KEY_PART_INFO*  key_part;
 
8059
        KEY_PART_INFO*  key_part_end;
 
8060
        uint            len1;
 
8061
        uint            len2;
 
8062
        int             result;
 
8063
 
 
8064
        if (prebuilt->clust_index_was_generated) {
 
8065
                /* The 'ref' is an InnoDB row id */
 
8066
 
 
8067
                return(memcmp(ref1, ref2, DATA_ROW_ID_LEN));
 
8068
        }
 
8069
 
 
8070
        /* Do a type-aware comparison of primary key fields. PK fields
 
8071
        are always NOT NULL, so no checks for NULL are performed. */
 
8072
 
 
8073
        key_part = table->key_info[table->s->primary_key].key_part;
 
8074
 
 
8075
        key_part_end = key_part
 
8076
                        + table->key_info[table->s->primary_key].key_parts;
 
8077
 
 
8078
        for (; key_part != key_part_end; ++key_part) {
 
8079
                field = key_part->field;
 
8080
                mysql_type = field->type();
 
8081
 
 
8082
                if (mysql_type == DRIZZLE_TYPE_BLOB) {
 
8083
 
 
8084
                        /* In the MySQL key value format, a column prefix of
 
8085
                        a BLOB is preceded by a 2-byte length field */
 
8086
 
 
8087
                        len1 = innobase_read_from_2_little_endian(ref1);
 
8088
                        len2 = innobase_read_from_2_little_endian(ref2);
 
8089
 
 
8090
                        ref1 += 2;
 
8091
                        ref2 += 2;
 
8092
                        result = ((Field_blob*)field)->cmp( ref1, len1,
 
8093
                                                            ref2, len2);
 
8094
                } else {
 
8095
                        result = field->key_cmp(ref1, ref2);
 
8096
                }
 
8097
 
 
8098
                if (result) {
 
8099
 
 
8100
                        return(result);
 
8101
                }
 
8102
 
 
8103
                ref1 += key_part->store_length;
 
8104
                ref2 += key_part->store_length;
 
8105
        }
 
8106
 
 
8107
        return(0);
 
8108
}
 
8109
 
 
8110
/**********************************************************************
 
8111
This function is used to find the storage length in bytes of the first n
 
8112
characters for prefix indexes using a multibyte character set. The function
 
8113
finds charset information and returns length of prefix_len characters in the
 
8114
index field in bytes.
 
8115
@return number of bytes occupied by the first n characters */
 
8116
extern "C" UNIV_INTERN
 
8117
ulint
 
8118
innobase_get_at_most_n_mbchars(
 
8119
/*===========================*/
 
8120
        ulint charset_id,       /*!< in: character set id */
 
8121
        ulint prefix_len,       /*!< in: prefix length in bytes of the index
 
8122
                                (this has to be divided by mbmaxlen to get the
 
8123
                                number of CHARACTERS n in the prefix) */
 
8124
        ulint data_len,         /*!< in: length of the string in bytes */
 
8125
        const char* str);       /*!< in: character string */
 
8126
 
 
8127
ulint
 
8128
innobase_get_at_most_n_mbchars(
 
8129
/*===========================*/
 
8130
        ulint charset_id,       /*!< in: character set id */
 
8131
        ulint prefix_len,       /*!< in: prefix length in bytes of the index
 
8132
                                (this has to be divided by mbmaxlen to get the
 
8133
                                number of CHARACTERS n in the prefix) */
 
8134
        ulint data_len,         /*!< in: length of the string in bytes */
 
8135
        const char* str)        /*!< in: character string */
 
8136
{
 
8137
        ulint char_length;              /*!< character length in bytes */
 
8138
        ulint n_chars;                  /*!< number of characters in prefix */
 
8139
        const CHARSET_INFO* charset;    /*!< charset used in the field */
 
8140
 
 
8141
        charset = get_charset((uint) charset_id);
 
8142
 
 
8143
        ut_ad(charset);
 
8144
        ut_ad(charset->mbmaxlen);
 
8145
 
 
8146
        /* Calculate how many characters at most the prefix index contains */
 
8147
 
 
8148
        n_chars = prefix_len / charset->mbmaxlen;
 
8149
 
 
8150
        /* If the charset is multi-byte, then we must find the length of the
 
8151
        first at most n chars in the string. If the string contains less
 
8152
        characters than n, then we return the length to the end of the last
 
8153
        character. */
 
8154
 
 
8155
        if (charset->mbmaxlen > 1) {
 
8156
                /* my_charpos() returns the byte length of the first n_chars
 
8157
                characters, or a value bigger than the length of str, if
 
8158
                there were not enough full characters in str.
 
8159
 
 
8160
                Why does the code below work:
 
8161
                Suppose that we are looking for n UTF-8 characters.
 
8162
 
 
8163
                1) If the string is long enough, then the prefix contains at
 
8164
                least n complete UTF-8 characters + maybe some extra
 
8165
                characters + an incomplete UTF-8 character. No problem in
 
8166
                this case. The function returns the pointer to the
 
8167
                end of the nth character.
 
8168
 
 
8169
                2) If the string is not long enough, then the string contains
 
8170
                the complete value of a column, that is, only complete UTF-8
 
8171
                characters, and we can store in the column prefix index the
 
8172
                whole string. */
 
8173
 
 
8174
                char_length = my_charpos(charset, str,
 
8175
                                                str + data_len, (int) n_chars);
 
8176
                if (char_length > data_len) {
 
8177
                        char_length = data_len;
 
8178
                }
 
8179
        } else {
 
8180
                if (data_len < prefix_len) {
 
8181
                        char_length = data_len;
 
8182
                } else {
 
8183
                        char_length = prefix_len;
 
8184
                }
 
8185
        }
 
8186
 
 
8187
        return(char_length);
 
8188
}
 
8189
 
 
8190
/*******************************************************************//**
 
8191
This function is used to prepare an X/Open XA distributed transaction.
 
8192
@return 0 or error number */
 
8193
int
 
8194
InnobaseEngine::prepare(
 
8195
/*================*/
 
8196
        Session*        session,/*!< in: handle to the MySQL thread of
 
8197
                                the user whose XA transaction should
 
8198
                                be prepared */
 
8199
        bool            all)    /*!< in: TRUE - commit transaction
 
8200
                                FALSE - the current SQL statement
 
8201
                                ended */
 
8202
{
 
8203
        int error = 0;
 
8204
        trx_t* trx = check_trx_exists(session);
 
8205
 
 
8206
        assert(this == innodb_engine_ptr);
 
8207
 
 
8208
        /* we use support_xa value as it was seen at transaction start
 
8209
        time, not the current session variable value. Any possible changes
 
8210
        to the session variable take effect only in the next transaction */
 
8211
        if (!trx->support_xa) {
 
8212
 
 
8213
                return(0);
 
8214
        }
 
8215
 
 
8216
        session_get_xid(session, reinterpret_cast<DRIZZLE_XID*>(&trx->xid));
 
8217
 
 
8218
        /* Release a possible FIFO ticket and search latch. Since we will
 
8219
        reserve the kernel mutex, we have to release the search system latch
 
8220
        first to obey the latching order. */
 
8221
 
 
8222
        innobase_release_stat_resources(trx);
 
8223
 
 
8224
        if (trx->active_trans == 0 && trx->conc_state != TRX_NOT_STARTED) {
 
8225
 
 
8226
          errmsg_printf(ERRMSG_LVL_ERROR,
 
8227
                        "trx->active_trans == 0, but trx->conc_state != "
 
8228
                        "TRX_NOT_STARTED");
 
8229
        }
 
8230
 
 
8231
        if (all
 
8232
                || (!session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
 
8233
 
 
8234
                /* We were instructed to prepare the whole transaction, or
 
8235
                this is an SQL statement end and autocommit is on */
 
8236
 
 
8237
                ut_ad(trx->active_trans);
 
8238
 
 
8239
                error = (int) trx_prepare_for_mysql(trx);
 
8240
        } else {
 
8241
                /* We just mark the SQL statement ended and do not do a
 
8242
                transaction prepare */
 
8243
 
 
8244
                /* If we had reserved the auto-inc lock for some
 
8245
                table in this SQL statement we release it now */
 
8246
 
 
8247
                row_unlock_table_autoinc_for_mysql(trx);
 
8248
 
 
8249
                /* Store the current undo_no of the transaction so that we
 
8250
                know where to roll back if we have to roll back the next
 
8251
                SQL statement */
 
8252
 
 
8253
                trx_mark_sql_stat_end(trx);
 
8254
        }
 
8255
 
 
8256
        /* Tell the InnoDB server that there might be work for utility
 
8257
        threads: */
 
8258
 
 
8259
        srv_active_wake_master_thread();
 
8260
 
 
8261
        if (all || !session_test_options(session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
 
8262
        {
 
8263
 
 
8264
                /* For ibbackup to work the order of transactions in binlog
 
8265
                and InnoDB must be the same. Consider the situation
 
8266
 
 
8267
                  thread1> prepare; write to binlog; ...
 
8268
                          <context switch>
 
8269
                  thread2> prepare; write to binlog; commit
 
8270
                  thread1>                           ... commit
 
8271
 
 
8272
                To ensure this will not happen we're taking the mutex on
 
8273
                prepare, and releasing it on commit.
 
8274
 
 
8275
                Note: only do it for normal commits, done via ha_commit_trans.
 
8276
                If 2pc protocol is executed by external transaction
 
8277
                coordinator, it will be just a regular MySQL client
 
8278
                executing XA PREPARE and XA COMMIT commands.
 
8279
                In this case we cannot know how many minutes or hours
 
8280
                will be between XA PREPARE and XA COMMIT, and we don't want
 
8281
                to block for undefined period of time.
 
8282
                */
 
8283
                pthread_mutex_lock(&prepare_commit_mutex);
 
8284
                trx->active_trans = 2;
 
8285
        }
 
8286
        return(error);
 
8287
}
 
8288
 
 
8289
/*******************************************************************//**
 
8290
This function is used to recover X/Open XA distributed transactions.
 
8291
@return number of prepared transactions stored in xid_list */
 
8292
int
 
8293
InnobaseEngine::recover(
 
8294
/*================*/
 
8295
        XID*            xid_list,/*!< in/out: prepared transactions */
 
8296
        uint            len)    /*!< in: number of slots in xid_list */
 
8297
{
 
8298
        assert(this == innodb_engine_ptr);
 
8299
 
 
8300
        if (len == 0 || xid_list == NULL) {
 
8301
 
 
8302
                return(0);
 
8303
        }
 
8304
 
 
8305
        return(trx_recover_for_mysql(xid_list, len));
 
8306
}
 
8307
 
 
8308
/*******************************************************************//**
 
8309
This function is used to commit one X/Open XA distributed transaction
 
8310
which is in the prepared state
 
8311
@return 0 or error number */
 
8312
int
 
8313
InnobaseEngine::commit_by_xid(
 
8314
/*===================*/
 
8315
        XID*    xid)    /*!< in: X/Open XA transaction identification */
 
8316
{
 
8317
        trx_t*  trx;
 
8318
 
 
8319
        assert(this == innodb_engine_ptr);
 
8320
 
 
8321
        trx = trx_get_trx_by_xid(xid);
 
8322
 
 
8323
        if (trx) {
 
8324
                innobase_commit_low(trx);
 
8325
 
 
8326
                return(XA_OK);
 
8327
        } else {
 
8328
                return(XAER_NOTA);
 
8329
        }
 
8330
}
 
8331
 
 
8332
/*******************************************************************//**
 
8333
This function is used to rollback one X/Open XA distributed transaction
 
8334
which is in the prepared state
 
8335
@return 0 or error number */
 
8336
int
 
8337
InnobaseEngine::rollback_by_xid(
 
8338
/*=====================*/
 
8339
        XID*            xid)    /*!< in: X/Open XA transaction
 
8340
                                identification */
 
8341
{
 
8342
        trx_t*  trx;
 
8343
 
 
8344
        assert(this == innodb_engine_ptr);
 
8345
 
 
8346
        trx = trx_get_trx_by_xid(xid);
 
8347
 
 
8348
        if (trx) {
 
8349
                return(innobase_rollback_trx(trx));
 
8350
        } else {
 
8351
                return(XAER_NOTA);
 
8352
        }
 
8353
}
 
8354
 
 
8355
 
 
8356
/************************************************************//**
 
8357
Validate the file format name and return its corresponding id.
 
8358
@return valid file format id */
 
8359
static
 
8360
uint
 
8361
innobase_file_format_name_lookup(
 
8362
/*=============================*/
 
8363
        const char*     format_name)    /*!< in: pointer to file format name */
 
8364
{
 
8365
        char*   endp;
 
8366
        uint    format_id;
 
8367
 
 
8368
        ut_a(format_name != NULL);
 
8369
 
 
8370
        /* The format name can contain the format id itself instead of
 
8371
        the name and we check for that. */
 
8372
        format_id = (uint) strtoul(format_name, &endp, 10);
 
8373
 
 
8374
        /* Check for valid parse. */
 
8375
        if (*endp == '\0' && *format_name != '\0') {
 
8376
 
 
8377
                if (format_id <= DICT_TF_FORMAT_MAX) {
 
8378
 
 
8379
                        return(format_id);
 
8380
                }
 
8381
        } else {
 
8382
 
 
8383
                for (format_id = 0; format_id <= DICT_TF_FORMAT_MAX;
 
8384
                     format_id++) {
 
8385
                        const char*     name;
 
8386
 
 
8387
                        name = trx_sys_file_format_id_to_name(format_id);
 
8388
 
 
8389
                        if (!innobase_strcasecmp(format_name, name)) {
 
8390
 
 
8391
                                return(format_id);
 
8392
                        }
 
8393
                }
 
8394
        }
 
8395
 
 
8396
        return(DICT_TF_FORMAT_MAX + 1);
 
8397
}
 
8398
 
 
8399
/************************************************************//**
 
8400
Validate the file format check value, is it one of "on" or "off",
 
8401
as a side effect it sets the srv_check_file_format_at_startup variable.
 
8402
@return true if config value one of "on" or  "off" */
 
8403
static
 
8404
bool
 
8405
innobase_file_format_check_on_off(
 
8406
/*==============================*/
 
8407
        const char*     format_check)   /*!< in: parameter value */
 
8408
{
 
8409
        bool            ret = true;
 
8410
 
 
8411
        if (!innobase_strcasecmp(format_check, "off")) {
 
8412
 
 
8413
                /* Set the value to disable checking. */
 
8414
                srv_check_file_format_at_startup = DICT_TF_FORMAT_MAX + 1;
 
8415
 
 
8416
        } else if (!innobase_strcasecmp(format_check, "on")) {
 
8417
 
 
8418
                /* Set the value to the lowest supported format. */
 
8419
                srv_check_file_format_at_startup = DICT_TF_FORMAT_51;
 
8420
        } else {
 
8421
                ret = FALSE;
 
8422
        }
 
8423
 
 
8424
        return(ret);
 
8425
}
 
8426
 
 
8427
/************************************************************//**
 
8428
Validate the file format check config parameters, as a side effect it
 
8429
sets the srv_check_file_format_at_startup variable.
 
8430
@return true if valid config value */
 
8431
static
 
8432
bool
 
8433
innobase_file_format_check_validate(
 
8434
/*================================*/
 
8435
        const char*     format_check)   /*!< in: parameter value */
 
8436
{
 
8437
        uint            format_id;
 
8438
        bool            ret = true;
 
8439
 
 
8440
        format_id = innobase_file_format_name_lookup(format_check);
 
8441
 
 
8442
        if (format_id < DICT_TF_FORMAT_MAX + 1) {
 
8443
                srv_check_file_format_at_startup = format_id;
 
8444
        } else {
 
8445
                ret = false;
 
8446
        }
 
8447
 
 
8448
        return(ret);
 
8449
}
 
8450
 
 
8451
/*************************************************************//**
 
8452
Check if it is a valid file format. This function is registered as
 
8453
a callback with MySQL.
 
8454
@return 0 for valid file format */
 
8455
static
 
8456
int
 
8457
innodb_file_format_name_validate(
 
8458
/*=============================*/
 
8459
        Session*                        ,       /*!< in: thread handle */
 
8460
        drizzle_sys_var*        ,       /*!< in: pointer to system
 
8461
                                                variable */
 
8462
        void*                           save,   /*!< out: immediate result
 
8463
                                                for update function */
 
8464
        drizzle_value*          value)  /*!< in: incoming string */
 
8465
{
 
8466
        const char*     file_format_input;
 
8467
        char            buff[STRING_BUFFER_USUAL_SIZE];
 
8468
        int             len = sizeof(buff);
 
8469
 
 
8470
        ut_a(save != NULL);
 
8471
        ut_a(value != NULL);
 
8472
 
 
8473
        file_format_input = value->val_str(value, buff, &len);
 
8474
 
 
8475
        if (file_format_input != NULL) {
 
8476
                uint    format_id;
 
8477
 
 
8478
                format_id = innobase_file_format_name_lookup(
 
8479
                        file_format_input);
 
8480
 
 
8481
                if (format_id <= DICT_TF_FORMAT_MAX) {
 
8482
 
 
8483
                        *static_cast<const char**>(save) = file_format_input;
 
8484
                        return(0);
 
8485
                }
 
8486
        }
 
8487
 
 
8488
        *static_cast<const char**>(save) = NULL;
 
8489
        return(1);
 
8490
}
 
8491
 
 
8492
/****************************************************************//**
 
8493
Update the system variable innodb_file_format using the "saved"
 
8494
value. This function is registered as a callback with MySQL. */
 
8495
static
 
8496
void
 
8497
innodb_file_format_name_update(
 
8498
/*===========================*/
 
8499
        Session*                        ,               /*!< in: thread handle */
 
8500
        drizzle_sys_var*        ,               /*!< in: pointer to
 
8501
                                                        system variable */
 
8502
        void*                           var_ptr,        /*!< out: where the
 
8503
                                                        formal string goes */
 
8504
        const void*                     save)           /*!< in: immediate result
 
8505
                                                        from check function */
 
8506
{
 
8507
        const char* format_name;
 
8508
 
 
8509
        ut_a(var_ptr != NULL);
 
8510
        ut_a(save != NULL);
 
8511
 
 
8512
        format_name = *static_cast<const char*const*>(save);
 
8513
 
 
8514
        if (format_name) {
 
8515
                uint    format_id;
 
8516
 
 
8517
                format_id = innobase_file_format_name_lookup(format_name);
 
8518
 
 
8519
                if (format_id <= DICT_TF_FORMAT_MAX) {
 
8520
                        srv_file_format = format_id;
 
8521
                }
 
8522
        }
 
8523
 
 
8524
        *static_cast<const char**>(var_ptr)
 
8525
                = trx_sys_file_format_id_to_name(srv_file_format);
 
8526
}
 
8527
 
 
8528
/*************************************************************//**
 
8529
Check if valid argument to innodb_file_format_check. This
 
8530
function is registered as a callback with MySQL.
 
8531
@return 0 for valid file format */
 
8532
static
 
8533
int
 
8534
innodb_file_format_check_validate(
 
8535
/*==============================*/
 
8536
        Session*                        ,       /*!< in: thread handle */
 
8537
        drizzle_sys_var*        ,       /*!< in: pointer to system
 
8538
                                                variable */
 
8539
        void*                           save,   /*!< out: immediate result
 
8540
                                                for update function */
 
8541
        drizzle_value*          value)  /*!< in: incoming string */
 
8542
{
 
8543
        const char*     file_format_input;
 
8544
        char            buff[STRING_BUFFER_USUAL_SIZE];
 
8545
        int             len = sizeof(buff);
 
8546
 
 
8547
        ut_a(save != NULL);
 
8548
        ut_a(value != NULL);
 
8549
 
 
8550
        file_format_input = value->val_str(value, buff, &len);
 
8551
 
 
8552
        if (file_format_input != NULL) {
 
8553
 
 
8554
                /* Check if user set on/off, we want to print a suitable
 
8555
                message if they did so. */
 
8556
 
 
8557
                if (innobase_file_format_check_on_off(file_format_input)) {
 
8558
                        errmsg_printf(ERRMSG_LVL_WARN, 
 
8559
                                "InnoDB: invalid innodb_file_format_check "
 
8560
                                "value; on/off can only be set at startup or "
 
8561
                                "in the configuration file");
 
8562
                } else if (innobase_file_format_check_validate(
 
8563
                                file_format_input)) {
 
8564
 
 
8565
                        *static_cast<const char**>(save) = file_format_input;
 
8566
 
 
8567
                        return(0);
 
8568
 
 
8569
                } else {
 
8570
                        errmsg_printf(ERRMSG_LVL_WARN, 
 
8571
                                "InnoDB: invalid innodb_file_format_check "
 
8572
                                "value; can be any format up to %s "
 
8573
                                "or its equivalent numeric id",
 
8574
                                trx_sys_file_format_id_to_name(
 
8575
                                        DICT_TF_FORMAT_MAX));
 
8576
                }
 
8577
        }
 
8578
 
 
8579
        *static_cast<const char**>(save) = NULL;
 
8580
        return(1);
 
8581
}
 
8582
 
 
8583
/****************************************************************//**
 
8584
Update the system variable innodb_file_format_check using the "saved"
 
8585
value. This function is registered as a callback with MySQL. */
 
8586
static
 
8587
void
 
8588
innodb_file_format_check_update(
 
8589
/*============================*/
 
8590
        Session*                        session,        /*!< in: thread handle */
 
8591
        drizzle_sys_var*        ,               /*!< in: pointer to
 
8592
                                                        system variable */
 
8593
        void*                           var_ptr,        /*!< out: where the
 
8594
                                                        formal string goes */
 
8595
        const void*                     save)           /*!< in: immediate result
 
8596
                                                        from check function */
 
8597
{
 
8598
        const char*     format_name_in;
 
8599
        const char**    format_name_out;
 
8600
        uint            format_id;
 
8601
 
 
8602
        ut_a(save != NULL);
 
8603
        ut_a(var_ptr != NULL);
 
8604
 
 
8605
        format_name_in = *static_cast<const char*const*>(save);
 
8606
 
 
8607
        if (!format_name_in) {
 
8608
 
 
8609
                return;
 
8610
        }
 
8611
 
 
8612
        format_id = innobase_file_format_name_lookup(format_name_in);
 
8613
 
 
8614
        if (format_id > DICT_TF_FORMAT_MAX) {
 
8615
                /* DEFAULT is "on", which is invalid at runtime. */
 
8616
                push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
8617
                                    ER_WRONG_ARGUMENTS,
 
8618
                                    "Ignoring SET innodb_file_format=%s",
 
8619
                                    format_name_in);
 
8620
                return;
 
8621
        }
 
8622
 
 
8623
        format_name_out = static_cast<const char**>(var_ptr);
 
8624
 
 
8625
        /* Update the max format id in the system tablespace. */
 
8626
        if (trx_sys_file_format_max_set(format_id, format_name_out)) {
 
8627
                ut_print_timestamp(stderr);
 
8628
                fprintf(stderr,
 
8629
                        " [Info] InnoDB: the file format in the system "
 
8630
                        "tablespace is now set to %s.\n", *format_name_out);
 
8631
        }
 
8632
}
 
8633
 
 
8634
/****************************************************************//**
 
8635
Update the system variable innodb_adaptive_hash_index using the "saved"
 
8636
value. This function is registered as a callback with MySQL. */
 
8637
static
 
8638
void
 
8639
innodb_adaptive_hash_index_update(
 
8640
/*==============================*/
 
8641
        Session*                        ,               /*!< in: thread handle */
 
8642
        drizzle_sys_var*        ,               /*!< in: pointer to
 
8643
                                                        system variable */
 
8644
        void*                           ,       /*!< out: where the
 
8645
                                                        formal string goes */
 
8646
        const void*                     save)           /*!< in: immediate result
 
8647
                                                        from check function */
 
8648
{
 
8649
        if (*(bool*) save) {
 
8650
                btr_search_enable();
 
8651
        } else {
 
8652
                btr_search_disable();
 
8653
        }
 
8654
}
 
8655
 
 
8656
/*************************************************************//**
 
8657
Check if it is a valid value of innodb_change_buffering.  This function is
 
8658
registered as a callback with MySQL.
 
8659
@return 0 for valid innodb_change_buffering */
 
8660
static
 
8661
int
 
8662
innodb_change_buffering_validate(
 
8663
/*=============================*/
 
8664
        Session*                        ,       /*!< in: thread handle */
 
8665
        drizzle_sys_var*        ,       /*!< in: pointer to system
 
8666
                                                variable */
 
8667
        void*                           save,   /*!< out: immediate result
 
8668
                                                for update function */
 
8669
        drizzle_value*          value)  /*!< in: incoming string */
 
8670
{
 
8671
        const char*     change_buffering_input;
 
8672
        char            buff[STRING_BUFFER_USUAL_SIZE];
 
8673
        int             len = sizeof(buff);
 
8674
 
 
8675
        ut_a(save != NULL);
 
8676
        ut_a(value != NULL);
 
8677
 
 
8678
        change_buffering_input = value->val_str(value, buff, &len);
 
8679
 
 
8680
        if (change_buffering_input != NULL) {
 
8681
                ulint   use;
 
8682
 
 
8683
                for (use = 0; use < UT_ARR_SIZE(innobase_change_buffering_values);
 
8684
                     use++) {
 
8685
                        if (!innobase_strcasecmp(
 
8686
                                    change_buffering_input,
 
8687
                                    innobase_change_buffering_values[use])) {
 
8688
                                *(ibuf_use_t*) save = (ibuf_use_t) use;
 
8689
                                return(0);
 
8690
                        }
 
8691
                }
 
8692
        }
 
8693
 
 
8694
        return(1);
 
8695
}
 
8696
 
 
8697
/****************************************************************//**
 
8698
Update the system variable innodb_change_buffering using the "saved"
 
8699
value. This function is registered as a callback with MySQL. */
 
8700
static
 
8701
void
 
8702
innodb_change_buffering_update(
 
8703
/*===========================*/
 
8704
        Session*                        ,               /*!< in: thread handle */
 
8705
        drizzle_sys_var*        ,               /*!< in: pointer to
 
8706
                                                        system variable */
 
8707
        void*                           var_ptr,        /*!< out: where the
 
8708
                                                        formal string goes */
 
8709
        const void*                     save)           /*!< in: immediate result
 
8710
                                                        from check function */
 
8711
{
 
8712
        ut_a(var_ptr != NULL);
 
8713
        ut_a(save != NULL);
 
8714
        ut_a((*(ibuf_use_t*) save) < IBUF_USE_COUNT);
 
8715
 
 
8716
        ibuf_use = *(const ibuf_use_t*) save;
 
8717
 
 
8718
        *(const char**) var_ptr = innobase_change_buffering_values[ibuf_use];
 
8719
}
 
8720
 
 
8721
static int show_innodb_vars(SHOW_VAR *var, char *)
 
8722
{
 
8723
  innodb_export_status();
 
8724
  var->type= SHOW_ARRAY;
 
8725
  var->value= (char *) &innodb_status_variables;
 
8726
  return 0;
 
8727
}
 
8728
 
 
8729
static st_show_var_func_container
 
8730
show_innodb_vars_cont = { &show_innodb_vars };
 
8731
 
 
8732
static SHOW_VAR innodb_status_variables_export[]= {
 
8733
  {"Innodb",                   (char*) &show_innodb_vars_cont, SHOW_FUNC},
 
8734
  {NULL, NULL, SHOW_LONG}
 
8735
};
 
8736
 
 
8737
 
 
8738
/* plugin options */
 
8739
static DRIZZLE_SYSVAR_BOOL(checksums, innobase_use_checksums,
 
8740
  PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
 
8741
  "Enable InnoDB checksums validation (enabled by default). "
 
8742
  "Disable with --skip-innodb-checksums.",
 
8743
  NULL, NULL, TRUE);
 
8744
 
 
8745
static DRIZZLE_SYSVAR_STR(data_home_dir, innobase_data_home_dir,
 
8746
  PLUGIN_VAR_READONLY,
 
8747
  "The common part for InnoDB table spaces.",
 
8748
  NULL, NULL, NULL);
 
8749
 
 
8750
static DRIZZLE_SYSVAR_BOOL(doublewrite, innobase_use_doublewrite,
 
8751
  PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
 
8752
  "Enable InnoDB doublewrite buffer (enabled by default). "
 
8753
  "Disable with --skip-innodb-doublewrite.",
 
8754
  NULL, NULL, TRUE);
 
8755
 
 
8756
static DRIZZLE_SYSVAR_ULONG(io_capacity, srv_io_capacity,
 
8757
  PLUGIN_VAR_RQCMDARG,
 
8758
  "Number of IOPs the server can do. Tunes the background IO rate",
 
8759
  NULL, NULL, 200, 100, ~0L, 0);
 
8760
 
 
8761
static DRIZZLE_SYSVAR_ULONG(fast_shutdown, innobase_fast_shutdown,
 
8762
  PLUGIN_VAR_OPCMDARG,
 
8763
  "Speeds up the shutdown process of the InnoDB storage engine. Possible "
 
8764
  "values are 0, 1 (faster)"
 
8765
  " or 2 (fastest - crash-like)"
 
8766
  ".",
 
8767
  NULL, NULL, 1, 0, 2, 0);
 
8768
 
 
8769
static DRIZZLE_SYSVAR_BOOL(file_per_table, srv_file_per_table,
 
8770
  PLUGIN_VAR_NOCMDARG,
 
8771
  "Stores each InnoDB table to an .ibd file in the database dir.",
 
8772
  NULL, NULL, FALSE);
 
8773
 
 
8774
static DRIZZLE_SYSVAR_STR(file_format, innobase_file_format_name,
 
8775
  PLUGIN_VAR_RQCMDARG,
 
8776
  "File format to use for new tables in .ibd files.",
 
8777
  innodb_file_format_name_validate,
 
8778
  innodb_file_format_name_update, "Antelope");
 
8779
 
 
8780
static DRIZZLE_SYSVAR_STR(file_format_check, innobase_file_format_check,
 
8781
  PLUGIN_VAR_OPCMDARG,
 
8782
  "The highest file format in the tablespace.",
 
8783
  innodb_file_format_check_validate,
 
8784
  innodb_file_format_check_update,
 
8785
  "on");
 
8786
 
 
8787
static DRIZZLE_SYSVAR_ULONG(flush_log_at_trx_commit, srv_flush_log_at_trx_commit,
 
8788
  PLUGIN_VAR_OPCMDARG,
 
8789
  "Set to 0 (write and flush once per second),"
 
8790
  " 1 (write and flush at each commit)"
 
8791
  " or 2 (write at commit, flush once per second).",
 
8792
  NULL, NULL, 1, 0, 2, 0);
 
8793
 
 
8794
static DRIZZLE_SYSVAR_STR(flush_method, innobase_unix_file_flush_method,
 
8795
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
8796
  "With which method to flush data.", NULL, NULL, NULL);
 
8797
 
 
8798
static DRIZZLE_SYSVAR_BOOL(locks_unsafe_for_binlog, innobase_locks_unsafe_for_binlog,
 
8799
  PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
 
8800
  "Force InnoDB to not use next-key locking, to use only row-level locking.",
 
8801
  NULL, NULL, TRUE);
 
8802
 
 
8803
#ifdef UNIV_LOG_ARCHIVE
 
8804
static DRIZZLE_SYSVAR_STR(log_arch_dir, innobase_log_arch_dir,
 
8805
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
8806
  "Where full logs should be archived.", NULL, NULL, NULL);
 
8807
 
 
8808
static DRIZZLE_SYSVAR_BOOL(log_archive, innobase_log_archive,
 
8809
  PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
 
8810
  "Set to 1 if you want to have logs archived.", NULL, NULL, FALSE);
 
8811
#endif /* UNIV_LOG_ARCHIVE */
 
8812
 
 
8813
static DRIZZLE_SYSVAR_STR(log_group_home_dir, innobase_log_group_home_dir,
 
8814
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
8815
  "Path to InnoDB log files.", NULL, NULL, NULL);
 
8816
 
 
8817
static DRIZZLE_SYSVAR_ULONG(max_dirty_pages_pct, srv_max_buf_pool_modified_pct,
 
8818
  PLUGIN_VAR_RQCMDARG,
 
8819
  "Percentage of dirty pages allowed in bufferpool.",
 
8820
  NULL, NULL, 75, 0, 99, 0);
 
8821
 
 
8822
static DRIZZLE_SYSVAR_BOOL(adaptive_flushing, srv_adaptive_flushing,
 
8823
  PLUGIN_VAR_NOCMDARG,
 
8824
  "Attempt flushing dirty pages to avoid IO bursts at checkpoints.",
 
8825
  NULL, NULL, TRUE);
 
8826
 
 
8827
static DRIZZLE_SYSVAR_ULONG(max_purge_lag, srv_max_purge_lag,
 
8828
  PLUGIN_VAR_RQCMDARG,
 
8829
  "Desired maximum length of the purge queue (0 = no limit)",
 
8830
  NULL, NULL, 0, 0, ~0L, 0);
 
8831
 
 
8832
static DRIZZLE_SYSVAR_BOOL(rollback_on_timeout, innobase_rollback_on_timeout,
 
8833
  PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
 
8834
  "Roll back the complete transaction on lock wait timeout, for 4.x compatibility (disabled by default)",
 
8835
  NULL, NULL, FALSE);
 
8836
 
 
8837
static DRIZZLE_SYSVAR_BOOL(status_file, innobase_create_status_file,
 
8838
  PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_NOSYSVAR,
 
8839
  "Enable SHOW INNODB STATUS output in the innodb_status.<pid> file",
 
8840
  NULL, NULL, FALSE);
 
8841
 
 
8842
static DRIZZLE_SYSVAR_BOOL(stats_on_metadata, innobase_stats_on_metadata,
 
8843
  PLUGIN_VAR_OPCMDARG,
 
8844
  "Enable statistics gathering for metadata commands such as SHOW TABLE STATUS (on by default)",
 
8845
  NULL, NULL, TRUE);
 
8846
 
 
8847
static DRIZZLE_SYSVAR_ULONGLONG(stats_sample_pages, srv_stats_sample_pages,
 
8848
  PLUGIN_VAR_RQCMDARG,
 
8849
  "The number of index pages to sample when calculating statistics (default 8)",
 
8850
  NULL, NULL, 8, 1, ~0ULL, 0);
 
8851
 
 
8852
static DRIZZLE_SYSVAR_BOOL(adaptive_hash_index, btr_search_enabled,
 
8853
  PLUGIN_VAR_OPCMDARG,
 
8854
  "Enable InnoDB adaptive hash index (enabled by default).  "
 
8855
  "Disable with --skip-innodb-adaptive-hash-index.",
 
8856
  NULL, innodb_adaptive_hash_index_update, TRUE);
 
8857
 
 
8858
static DRIZZLE_SYSVAR_ULONG(replication_delay, srv_replication_delay,
 
8859
  PLUGIN_VAR_RQCMDARG,
 
8860
  "Replication thread delay (ms) on the slave server if "
 
8861
  "innodb_thread_concurrency is reached (0 by default)",
 
8862
  NULL, NULL, 0, 0, ~0UL, 0);
 
8863
 
 
8864
static DRIZZLE_SYSVAR_LONG(additional_mem_pool_size, innobase_additional_mem_pool_size,
 
8865
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
8866
  "Size of a memory pool InnoDB uses to store data dictionary information and other internal data structures.",
 
8867
  NULL, NULL, 8*1024*1024L, 512*1024L, LONG_MAX, 1024);
 
8868
 
 
8869
static DRIZZLE_SYSVAR_UINT(autoextend_increment, srv_auto_extend_increment,
 
8870
  PLUGIN_VAR_RQCMDARG,
 
8871
  "Data file autoextend increment in megabytes",
 
8872
  NULL, NULL, 8L, 1L, 1000L, 0);
 
8873
 
 
8874
static DRIZZLE_SYSVAR_LONGLONG(buffer_pool_size, innobase_buffer_pool_size,
 
8875
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
8876
  "The size of the memory buffer InnoDB uses to cache data and indexes of its tables.",
 
8877
  NULL, NULL, 128*1024*1024L, 5*1024*1024L, INT64_MAX, 1024*1024L);
 
8878
 
 
8879
static DRIZZLE_SYSVAR_ULONG(commit_concurrency, innobase_commit_concurrency,
 
8880
  PLUGIN_VAR_RQCMDARG,
 
8881
  "Helps in performance tuning in heavily concurrent environments.",
 
8882
  innobase_commit_concurrency_validate, NULL, 0, 0, 1000, 0);
 
8883
 
 
8884
static DRIZZLE_SYSVAR_ULONG(concurrency_tickets, srv_n_free_tickets_to_enter,
 
8885
  PLUGIN_VAR_RQCMDARG,
 
8886
  "Number of times a thread is allowed to enter InnoDB within the same SQL query after it has once got the ticket",
 
8887
  NULL, NULL, 500L, 1L, ~0L, 0);
 
8888
 
 
8889
static DRIZZLE_SYSVAR_LONG(file_io_threads, innobase_file_io_threads,
 
8890
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
8891
  "Number of file I/O threads in InnoDB.",
 
8892
  NULL, NULL, 4, 4, 64, 0);
 
8893
 
 
8894
static DRIZZLE_SYSVAR_ULONG(read_io_threads, innobase_read_io_threads,
 
8895
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
8896
  "Number of background read I/O threads in InnoDB.",
 
8897
  NULL, NULL, 4, 1, 64, 0);
 
8898
 
 
8899
static DRIZZLE_SYSVAR_ULONG(write_io_threads, innobase_write_io_threads,
 
8900
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
8901
  "Number of background write I/O threads in InnoDB.",
 
8902
  NULL, NULL, 4, 1, 64, 0);
 
8903
 
 
8904
static DRIZZLE_SYSVAR_LONG(force_recovery, innobase_force_recovery,
 
8905
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
8906
  "Helps to save your data in case the disk image of the database becomes corrupt.",
 
8907
  NULL, NULL, 0, 0, 6, 0);
 
8908
 
 
8909
static DRIZZLE_SYSVAR_LONG(log_buffer_size, innobase_log_buffer_size,
 
8910
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
8911
  "The size of the buffer which InnoDB uses to write log to the log files on disk.",
 
8912
  NULL, NULL, 8*1024*1024L, 256*1024L, LONG_MAX, 1024);
 
8913
 
 
8914
static DRIZZLE_SYSVAR_LONGLONG(log_file_size, innobase_log_file_size,
 
8915
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
8916
  "Size of each log file in a log group.",
 
8917
  NULL, NULL, 5*1024*1024L, 1*1024*1024L, INT64_MAX, 1024*1024L);
 
8918
 
 
8919
static DRIZZLE_SYSVAR_LONG(log_files_in_group, innobase_log_files_in_group,
 
8920
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
8921
  "Number of log files in the log group. InnoDB writes to the files in a circular fashion. Value 3 is recommended here.",
 
8922
  NULL, NULL, 2, 2, 100, 0);
 
8923
 
 
8924
static DRIZZLE_SYSVAR_LONG(mirrored_log_groups, innobase_mirrored_log_groups,
 
8925
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
8926
  "Number of identical copies of log groups we keep for the database. Currently this should be set to 1.",
 
8927
  NULL, NULL, 1, 1, 10, 0);
 
8928
 
 
8929
static DRIZZLE_SYSVAR_LONG(open_files, innobase_open_files,
 
8930
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
8931
  "How many files at the maximum InnoDB keeps open at the same time.",
 
8932
  NULL, NULL, 300L, 10L, LONG_MAX, 0);
 
8933
 
 
8934
static DRIZZLE_SYSVAR_ULONG(sync_spin_loops, srv_n_spin_wait_rounds,
 
8935
  PLUGIN_VAR_RQCMDARG,
 
8936
  "Count of spin-loop rounds in InnoDB mutexes (30 by default)",
 
8937
  NULL, NULL, 30L, 0L, ~0L, 0);
 
8938
 
 
8939
static DRIZZLE_SYSVAR_ULONG(spin_wait_delay, srv_spin_wait_delay,
 
8940
  PLUGIN_VAR_OPCMDARG,
 
8941
  "Maximum delay between polling for a spin lock (6 by default)",
 
8942
  NULL, NULL, 6L, 0L, ~0L, 0);
 
8943
 
 
8944
static DRIZZLE_SYSVAR_ULONG(thread_concurrency, srv_thread_concurrency,
 
8945
  PLUGIN_VAR_RQCMDARG,
 
8946
  "Helps in performance tuning in heavily concurrent environments. Sets the maximum number of threads allowed inside InnoDB. Value 0 will disable the thread throttling.",
 
8947
  NULL, NULL, 0, 0, 1000, 0);
 
8948
 
 
8949
static DRIZZLE_SYSVAR_ULONG(thread_sleep_delay, srv_thread_sleep_delay,
 
8950
  PLUGIN_VAR_RQCMDARG,
 
8951
  "Time of innodb thread sleeping before joining InnoDB queue (usec). Value 0 disable a sleep",
 
8952
  NULL, NULL, 10000L, 0L, ~0L, 0);
 
8953
 
 
8954
static DRIZZLE_SYSVAR_STR(data_file_path, innobase_data_file_path,
 
8955
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
8956
  "Path to individual files and their sizes.",
 
8957
  NULL, NULL, NULL);
 
8958
 
 
8959
static DRIZZLE_SYSVAR_LONG(autoinc_lock_mode, innobase_autoinc_lock_mode,
 
8960
  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
8961
  "The AUTOINC lock modes supported by InnoDB:               "
 
8962
  "0 => Old style AUTOINC locking (for backward"
 
8963
  " compatibility)                                           "
 
8964
  "1 => New style AUTOINC locking                            "
 
8965
  "2 => No AUTOINC locking (unsafe for SBR)",
 
8966
  NULL, NULL,
 
8967
  AUTOINC_NO_LOCKING,   /* Default setting */
 
8968
  AUTOINC_OLD_STYLE_LOCKING,    /* Minimum value */
 
8969
  AUTOINC_NO_LOCKING, 0);       /* Maximum value */
 
8970
 
 
8971
static DRIZZLE_SYSVAR_STR(version, innodb_version_str,
 
8972
  PLUGIN_VAR_NOCMDOPT | PLUGIN_VAR_READONLY,
 
8973
  "InnoDB version", NULL, NULL, INNODB_VERSION_STR);
 
8974
 
 
8975
static DRIZZLE_SYSVAR_BOOL(use_sys_malloc, srv_use_sys_malloc,
 
8976
  PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
 
8977
  "Use OS memory allocator instead of InnoDB's internal memory allocator",
 
8978
  NULL, NULL, TRUE);
 
8979
 
 
8980
static DRIZZLE_SYSVAR_STR(change_buffering, innobase_change_buffering,
 
8981
  PLUGIN_VAR_RQCMDARG,
 
8982
  "Buffer changes to reduce random access: "
 
8983
  "OFF, ON, inserting, deleting, changing, or purging.",
 
8984
  innodb_change_buffering_validate,
 
8985
  innodb_change_buffering_update, NULL);
 
8986
 
 
8987
static DRIZZLE_SYSVAR_ULONG(read_ahead_threshold, srv_read_ahead_threshold,
 
8988
  PLUGIN_VAR_RQCMDARG,
 
8989
  "Number of pages that must be accessed sequentially for InnoDB to"
 
8990
  "trigger a readahead.",
 
8991
  NULL, NULL, 56, 0, 64, 0);
 
8992
 
 
8993
static drizzle_sys_var* innobase_system_variables[]= {
 
8994
  DRIZZLE_SYSVAR(additional_mem_pool_size),
 
8995
  DRIZZLE_SYSVAR(autoextend_increment),
 
8996
  DRIZZLE_SYSVAR(buffer_pool_size),
 
8997
  DRIZZLE_SYSVAR(checksums),
 
8998
  DRIZZLE_SYSVAR(commit_concurrency),
 
8999
  DRIZZLE_SYSVAR(concurrency_tickets),
 
9000
  DRIZZLE_SYSVAR(data_file_path),
 
9001
  DRIZZLE_SYSVAR(data_home_dir),
 
9002
  DRIZZLE_SYSVAR(doublewrite),
 
9003
  DRIZZLE_SYSVAR(fast_shutdown),
 
9004
  DRIZZLE_SYSVAR(file_io_threads),
 
9005
  DRIZZLE_SYSVAR(read_io_threads),
 
9006
  DRIZZLE_SYSVAR(write_io_threads),
 
9007
  DRIZZLE_SYSVAR(file_per_table),
 
9008
  DRIZZLE_SYSVAR(file_format),
 
9009
  DRIZZLE_SYSVAR(file_format_check),
 
9010
  DRIZZLE_SYSVAR(flush_log_at_trx_commit),
 
9011
  DRIZZLE_SYSVAR(flush_method),
 
9012
  DRIZZLE_SYSVAR(force_recovery),
 
9013
  DRIZZLE_SYSVAR(locks_unsafe_for_binlog),
 
9014
  DRIZZLE_SYSVAR(lock_wait_timeout),
 
9015
#ifdef UNIV_LOG_ARCHIVE
 
9016
  DRIZZLE_SYSVAR(log_arch_dir),
 
9017
  DRIZZLE_SYSVAR(log_archive),
 
9018
#endif /* UNIV_LOG_ARCHIVE */
 
9019
  DRIZZLE_SYSVAR(log_buffer_size),
 
9020
  DRIZZLE_SYSVAR(log_file_size),
 
9021
  DRIZZLE_SYSVAR(log_files_in_group),
 
9022
  DRIZZLE_SYSVAR(log_group_home_dir),
 
9023
  DRIZZLE_SYSVAR(max_dirty_pages_pct),
 
9024
  DRIZZLE_SYSVAR(max_purge_lag),
 
9025
  DRIZZLE_SYSVAR(adaptive_flushing),
 
9026
  DRIZZLE_SYSVAR(mirrored_log_groups),
 
9027
  DRIZZLE_SYSVAR(open_files),
 
9028
  DRIZZLE_SYSVAR(rollback_on_timeout),
 
9029
  DRIZZLE_SYSVAR(stats_on_metadata),
 
9030
  DRIZZLE_SYSVAR(stats_sample_pages),
 
9031
  DRIZZLE_SYSVAR(adaptive_hash_index),
 
9032
  DRIZZLE_SYSVAR(replication_delay),
 
9033
  DRIZZLE_SYSVAR(status_file),
 
9034
  DRIZZLE_SYSVAR(strict_mode),
 
9035
  DRIZZLE_SYSVAR(support_xa),
 
9036
  DRIZZLE_SYSVAR(sync_spin_loops),
 
9037
  DRIZZLE_SYSVAR(spin_wait_delay),
 
9038
  DRIZZLE_SYSVAR(table_locks),
 
9039
  DRIZZLE_SYSVAR(thread_concurrency),
 
9040
  DRIZZLE_SYSVAR(thread_sleep_delay),
 
9041
  DRIZZLE_SYSVAR(autoinc_lock_mode),
 
9042
  DRIZZLE_SYSVAR(version),
 
9043
  DRIZZLE_SYSVAR(use_sys_malloc),
 
9044
  DRIZZLE_SYSVAR(change_buffering),
 
9045
  DRIZZLE_SYSVAR(read_ahead_threshold),
 
9046
  DRIZZLE_SYSVAR(io_capacity),
 
9047
  NULL
 
9048
};
 
9049
 
 
9050
DRIZZLE_DECLARE_PLUGIN
 
9051
{
 
9052
  DRIZZLE_VERSION_ID,
 
9053
  innobase_engine_name,
 
9054
  INNODB_VERSION_STR,
 
9055
  "Innobase Oy",
 
9056
  "Supports transactions, row-level locking, and foreign keys",
 
9057
  PLUGIN_LICENSE_GPL,
 
9058
  innobase_init, /* Plugin Init */
 
9059
  innobase_deinit, /* Plugin Deinit */
 
9060
  innodb_status_variables_export,/* status variables             */
 
9061
  innobase_system_variables, /* system variables */
 
9062
  NULL /* reserved */
 
9063
}
 
9064
DRIZZLE_DECLARE_PLUGIN_END;
 
9065
 
 
9066
int ha_innobase::read_range_first(const key_range *start_key,
 
9067
                                  const key_range *end_key,
 
9068
                                  bool eq_range_arg,
 
9069
                                  bool sorted)
 
9070
{
 
9071
  int res;
 
9072
  //if (!eq_range_arg)
 
9073
    //in_range_read= TRUE;
 
9074
  res= Cursor::read_range_first(start_key, end_key, eq_range_arg, sorted);
 
9075
  //if (res)
 
9076
  //  in_range_read= FALSE;
 
9077
  return res;
 
9078
}
 
9079
 
 
9080
 
 
9081
int ha_innobase::read_range_next()
 
9082
{
 
9083
  int res= Cursor::read_range_next();
 
9084
  //if (res)
 
9085
  //  in_range_read= FALSE;
 
9086
  return res;
 
9087
}
 
9088
 
 
9089
/** @brief Initialize the default value of innodb_commit_concurrency.
 
9090
 
 
9091
Once InnoDB is running, the innodb_commit_concurrency must not change
 
9092
from zero to nonzero. (Bug #42101)
 
9093
 
 
9094
The initial default value is 0, and without this extra initialization,
 
9095
SET GLOBAL innodb_commit_concurrency=DEFAULT would set the parameter
 
9096
to 0, even if it was initially set to nonzero at the command line
 
9097
or configuration file. */
 
9098
static
 
9099
void
 
9100
innobase_commit_concurrency_init_default(void)
 
9101
/*==========================================*/
 
9102
{
 
9103
        DRIZZLE_SYSVAR_NAME(commit_concurrency).def_val
 
9104
                = innobase_commit_concurrency;
 
9105
}
 
9106
 
 
9107
#ifdef UNIV_COMPILE_TEST_FUNCS
 
9108
 
 
9109
typedef struct innobase_convert_name_test_struct {
 
9110
        char*           buf;
 
9111
        ulint           buflen;
 
9112
        const char*     id;
 
9113
        ulint           idlen;
 
9114
        void*           session;
 
9115
        ibool           file_id;
 
9116
 
 
9117
        const char*     expected;
 
9118
} innobase_convert_name_test_t;
 
9119
 
 
9120
void
 
9121
test_innobase_convert_name()
 
9122
{
 
9123
        char    buf[1024];
 
9124
        ulint   i;
 
9125
 
 
9126
        innobase_convert_name_test_t test_input[] = {
 
9127
                {buf, sizeof(buf), "abcd", 4, NULL, TRUE, "\"abcd\""},
 
9128
                {buf, 7, "abcd", 4, NULL, TRUE, "\"abcd\""},
 
9129
                {buf, 6, "abcd", 4, NULL, TRUE, "\"abcd\""},
 
9130
                {buf, 5, "abcd", 4, NULL, TRUE, "\"abc\""},
 
9131
                {buf, 4, "abcd", 4, NULL, TRUE, "\"ab\""},
 
9132
 
 
9133
                {buf, sizeof(buf), "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
 
9134
                {buf, 9, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
 
9135
                {buf, 8, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
 
9136
                {buf, 7, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
 
9137
                {buf, 6, "ab@0060cd", 9, NULL, TRUE, "\"ab`c\""},
 
9138
                {buf, 5, "ab@0060cd", 9, NULL, TRUE, "\"ab`\""},
 
9139
                {buf, 4, "ab@0060cd", 9, NULL, TRUE, "\"ab\""},
 
9140
 
 
9141
                {buf, sizeof(buf), "ab\"cd", 5, NULL, TRUE,
 
9142
                        "\"#mysql50#ab\"\"cd\""},
 
9143
                {buf, 17, "ab\"cd", 5, NULL, TRUE,
 
9144
                        "\"#mysql50#ab\"\"cd\""},
 
9145
                {buf, 16, "ab\"cd", 5, NULL, TRUE,
 
9146
                        "\"#mysql50#ab\"\"c\""},
 
9147
                {buf, 15, "ab\"cd", 5, NULL, TRUE,
 
9148
                        "\"#mysql50#ab\"\"\""},
 
9149
                {buf, 14, "ab\"cd", 5, NULL, TRUE,
 
9150
                        "\"#mysql50#ab\""},
 
9151
                {buf, 13, "ab\"cd", 5, NULL, TRUE,
 
9152
                        "\"#mysql50#ab\""},
 
9153
                {buf, 12, "ab\"cd", 5, NULL, TRUE,
 
9154
                        "\"#mysql50#a\""},
 
9155
                {buf, 11, "ab\"cd", 5, NULL, TRUE,
 
9156
                        "\"#mysql50#\""},
 
9157
                {buf, 10, "ab\"cd", 5, NULL, TRUE,
 
9158
                        "\"#mysql50\""},
 
9159
 
 
9160
                {buf, sizeof(buf), "ab/cd", 5, NULL, TRUE, "\"ab\".\"cd\""},
 
9161
                {buf, 9, "ab/cd", 5, NULL, TRUE, "\"ab\".\"cd\""},
 
9162
                {buf, 8, "ab/cd", 5, NULL, TRUE, "\"ab\".\"c\""},
 
9163
                {buf, 7, "ab/cd", 5, NULL, TRUE, "\"ab\".\"\""},
 
9164
                {buf, 6, "ab/cd", 5, NULL, TRUE, "\"ab\"."},
 
9165
                {buf, 5, "ab/cd", 5, NULL, TRUE, "\"ab\"."},
 
9166
                {buf, 4, "ab/cd", 5, NULL, TRUE, "\"ab\""},
 
9167
                {buf, 3, "ab/cd", 5, NULL, TRUE, "\"a\""},
 
9168
                {buf, 2, "ab/cd", 5, NULL, TRUE, "\"\""},
 
9169
                /* XXX probably "" is a better result in this case
 
9170
                {buf, 1, "ab/cd", 5, NULL, TRUE, "."},
 
9171
                */
 
9172
                {buf, 0, "ab/cd", 5, NULL, TRUE, ""},
 
9173
        };
 
9174
 
 
9175
        for (i = 0; i < sizeof(test_input) / sizeof(test_input[0]); i++) {
 
9176
 
 
9177
                char*   end;
 
9178
                ibool   ok = TRUE;
 
9179
                size_t  res_len;
 
9180
 
 
9181
                fprintf(stderr, "TESTING %lu, %s, %lu, %s\n",
 
9182
                        test_input[i].buflen,
 
9183
                        test_input[i].id,
 
9184
                        test_input[i].idlen,
 
9185
                        test_input[i].expected);
 
9186
 
 
9187
                end = innobase_convert_name(
 
9188
                        test_input[i].buf,
 
9189
                        test_input[i].buflen,
 
9190
                        test_input[i].id,
 
9191
                        test_input[i].idlen,
 
9192
                        test_input[i].session,
 
9193
                        test_input[i].file_id);
 
9194
 
 
9195
                res_len = (size_t) (end - test_input[i].buf);
 
9196
 
 
9197
                if (res_len != strlen(test_input[i].expected)) {
 
9198
 
 
9199
                        fprintf(stderr, "unexpected len of the result: %u, "
 
9200
                                "expected: %u\n", (unsigned) res_len,
 
9201
                                (unsigned) strlen(test_input[i].expected));
 
9202
                        ok = FALSE;
 
9203
                }
 
9204
 
 
9205
                if (memcmp(test_input[i].buf,
 
9206
                           test_input[i].expected,
 
9207
                           strlen(test_input[i].expected)) != 0
 
9208
                    || !ok) {
 
9209
 
 
9210
                        fprintf(stderr, "unexpected result: %.*s, "
 
9211
                                "expected: %s\n", (int) res_len,
 
9212
                                test_input[i].buf,
 
9213
                                test_input[i].expected);
 
9214
                        ok = FALSE;
 
9215
                }
 
9216
 
 
9217
                if (ok) {
 
9218
                        fprintf(stderr, "OK: res: %.*s\n\n", (int) res_len,
 
9219
                                buf);
 
9220
                } else {
 
9221
                        fprintf(stderr, "FAILED\n\n");
 
9222
                        return;
 
9223
                }
 
9224
        }
 
9225
}
 
9226
 
 
9227
#endif /* UNIV_COMPILE_TEST_FUNCS */