~ubuntu-branches/ubuntu/saucy/drizzle/saucy-proposed

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Monty Taylor
  • Date: 2010-03-18 12:12:31 UTC
  • Revision ID: james.westby@ubuntu.com-20100318121231-k6g1xe6cshbwa0f8
Tags: upstream-2010.03.1347
ImportĀ upstreamĀ versionĀ 2010.03.1347

Show diffs side-by-side

added added

removed removed

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