~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Brian Aker
  • Date: 2008-10-06 06:47:29 UTC
  • Revision ID: brian@tangent.org-20081006064729-2i9mhjkzyvow9xsm
RemoveĀ uint.

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