~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Monty Taylor
  • Date: 2008-10-09 22:38:27 UTC
  • mto: This revision was merged to the branch mainline in revision 497.
  • Revision ID: monty@inaugust.com-20081009223827-bc9gvpiplsmvpwyq
Moved test() to its own file.
Made a new function to possibly replace int10_to_str.

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