~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Brian Aker
  • Date: 2008-10-29 13:46:43 UTC
  • Revision ID: brian@tangent.org-20081029134643-z6jcwjvyruhk2vlu
Updates for ignore file.

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