~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Daniel Nichter
  • Date: 2011-10-23 16:01:37 UTC
  • mto: This revision was merged to the branch mainline in revision 2448.
  • Revision ID: daniel@percona.com-20111023160137-7ac3blgz8z4tf8za
Add Administration Getting Started and Logging.  Capitalize SQL clause keywords.

Show diffs side-by-side

added added

removed removed

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